XION
DiscordGithub
  • Welcome to XION
  • XION'S Core
    • Concepts
      • Generalized Chain Abstraction
      • Intro to Account Abstraction
      • XION's Meta Accounts
      • Meta Accounts Design
      • Architecture & Tech Glossary
      • Use Cases
  • developers
    • XION Quick Start
      • Zero to App in 5 Minutes
        • Launch a User Map App on XION in 5 Minutes
        • React Native Mobile App on XION in 5 Minutes
        • Todo App
          • Build a TODO App using the Collection-Document Storage Smart Contract
          • Build a TODO Mobile App using the DocuStore Contract
    • Mobile App Development
      • Set up your XION Mobile Development Environment
      • Build a TODO Mobile App using the DocuStore Contract
      • Create Mobile App and Integrate Meta Account Authentication
      • Building a React Native Mobile App with Abstraxion (Xion.js)
    • Getting Started (Advanced)
      • Set Up Local Environment
        • Setting up your Local Smart Contract Development Environment for XION
          • Setting up your XION Smart Contract Development Environment on Windows (WSL2 + Ubuntu)
        • Set Up an Integrated Development Environment (IDE)
        • Interacting with Xion Chain using Xion Daemon
      • Your First Contract
        • Deploying Your First Smart Contract on XION
      • Gasless UX & Permission Grants
        • Enabling Gasless Transactions with Treasury Contracts
      • App Development
        • Account Abstraction with Gasless Transactions
        • Interact with XION via your Backend Service
    • Re-using Existing Contracts
      • Deployed Contracts on XION
      • Non-Fungible Tokens (NFTs)
      • Fungible Tokens
      • Marketplace
      • Multisig
      • Proxy Contracts
      • Membership Management
      • Governance
      • Valuts
      • SCV Audited Contracts
    • Web3 for Web2 Developers
      • Web2 vs Web3 App Architecture: A Comparison
      • Misconceptions and Misapplied Web2 Patterns
      • Recommended Architecture for Apps on XION
    • Building for Mainnet
      • Xion Testnet: Your Development Playground
      • Building with Audited & Battle-Tested Contracts
      • Community Engagement: Building Support for Your app
      • Deploying to Xion Mainnet
        • Smart Contract Audits: Process, Costs & Support
        • Governance Process to Deploying Smart Contracts to Mainnet
    • Learn & Build
      • Token Factory
        • Creating, Minting, and Interacting with a Token Factory Token
        • Building a React dApp to Interact with Token Factory Tokens
        • Integrating a Token Factory Token in a Smart Contract
      • Websockets
        • WebSockets with Xion: Real-Time Communication
      • Oracles
        • Creating a Smart Contract with Pyth Oracle Integration
      • Indexers: Optimized Data Retrieval
        • SubQuery
      • Use Cases
        • Building a Per-User Data Storage App
        • Build a TODO App using the Collection-Document Storage Smart Contract
      • Crossmint Integration
        • Crossmint Digital Collectibles Checkout via Credit Card
    • Reference and Resources
      • Requesting XION Testnet Tokens
      • Public Endpoints & Resources
      • Block Explorers
      • Governance
        • Deploying Smart Contracts to Mainnet
      • Developer Tools: Abstract
      • IBC Denoms on XION Networks
      • Frequently Asked Questions
      • XION Token Contract Addresses on EVM Chains
  • Nodes & Validators
    • Run a Node
      • System Specifications
      • Build the Xion Daemon
      • Download the Xion Daemon
      • Configure the Xion Daemon
        • app.toml
        • client.toml
        • config.toml
      • Join the XION Network
        • xion-testnet-1
      • Confirm node is running
    • Become a Validator
      • Initial Setup
      • Obtain a XION Wallet Address
      • Obtain Funds
        • Testnet
      • Create Validator
    • IBC Relayers and Tokens
  • Others
    • Resources
Powered by GitBook
On this page
  • Result
  • StdResult
  • The Significance of StdResult
  • Illustration from the Nameservice Contract
  • Option
  • Handling Absence in Rust
  • The Option Enum Type

Was this helpful?

Edit on GitHub
  1. developers
  2. Reference and Resources
  3. CosmWasm Resources
  4. Contract Semantics

Result and Option

In the Rust programming language, Result and Option are enum types that encompass values within their respective variants:

enum Option<T> {
  Some(T),
  // existence
  None, // non-existence
}
enum Result<T, E> {
  Ok(T),
  // success
  Err(E), // failure
}

Result

Result is an enum type, Result<T, E>, where both T and E are generics, symbolizing success and failure. Result types find common use in entry points and handlers:

Ok(T): A Result container signifying success, containing the value T.

Err(E): A Result container indicating failure, containing the value E.

Numerous contract entry points are of the type Result<Response, ContractError. In this context, Response represents the Right or Success branch, while ContractError corresponds to the Left or failure case.

For instance, in the case of CW20-base, the execute function is typed as Result<Response, ContractError. Specifically, for the function that corresponds to ExecuteMsg::Transfer, namely execute_transfer, this demonstrates how the result is returned.

pub fn execute_transfer(
  deps: DepsMut,
  _env: Env,
  info: MessageInfo,
  recipient: String,
  amount: Uint128,
) -> Result<Response, ContractError> {
  if amount == Uint128::zero() {
    return Err(ContractError::InvalidZeroAmount {});
  }
  let rcpt_addr = deps.api.addr_validate(&recipient)?;
  BALANCES.update(
    deps.storage,
    &info.sender,
    |balance: Option<Uint128>| -> StdResult<_> {
      Ok(balance.unwrap_or_default().checked_sub(amount)?)
    },
  )?;
  BALANCES.update(
    deps.storage,
    &rcpt_addr,
    |balance: Option<Uint128>| -> StdResult<_> { Ok(balance.unwrap_or_default() + amount) },
  )?;
  let res = Response::new()
    .add_attribute("action", "transfer")
    .add_attribute("from", info.sender)
    .add_attribute("to", recipient)
    .add_attribute("amount", amount);
  Ok(res)
}

StdResult

The Significance of StdResult

It is equally essential to remain vigilant about StdResult, given its common application in query handlers and the associated functions.

Illustration from the Nameservice Contract

For instance, in the nameservice contract, you can readily identify the utilization of StdResult. This construct operates in a manner akin to Result but does not include a predefined error branch.

#[cfg_attr(not(feature = "library"), entry_point)]
pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> StdResult<Binary> {
  match msg {
    QueryMsg::ResolveRecord { name } => query_resolver(deps, env, name),
    QueryMsg::Config {} => to_binary(&config_read(deps.storage).load()?),
  }
}

Let's examine the implementation of the query_resolver:

fn query_resolver(deps: Deps, _env: Env, name: String) -> StdResult<Binary> {
  let key = name.as_bytes();
  let address = match resolver_read(deps.storage).may_load(key)? {
    Some(record) => Some(String::from(&record.owner)),
    None => None,
  };
  let resp = ResolveRecordResponse { address };
  to_binary(&resp)
}

Precisely matching or unwrapping your container types is crucial to effectively access and manipulate the enclosed values.

Option

Handling Absence in Rust

In the Rust programming language, there is no concept of nil or null, a departure from many other widely used programming languages. Instead, Rust employs the Option type to capture the idea of presence or absence within a container type.

The Option Enum Type

Option is an enum type that features two variants:

Some(): It wraps an inner value, which can be accessed using .unwrap().

None: This variant signifies the absence of a value and is frequently employed as a default or placeholder value when a value is either not yet known or cannot be determined.

Example Usage

The following code snippet provides an example of how Rust's Option is utilized to handle optional values of purchase_price and transfer_price

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub struct InstantiateMsg {
  pub purchase_price: Option<Coin>,
  pub transfer_price: Option<Coin>,
}

When dealing with instances of the InstantiateMsg mentioned earlier, there will be either an outcome or nothing. To address this situation, it is customary to utilize the match operator for pattern matching the two possible cases.

let address = match resolver_read(deps.storage).may_load(key)? {
  Some(record) => Some(String::from( & record.owner)),
  None => None,
};

If utilizing None to signify an error state, the conventional recommendation is to raise an error rather than dealing with the None value.

Last updated 1 year ago

Was this helpful?