This site requires Javascript to be enabled.

Understanding Result and Option

In Rust, Result and Option are powerful enum types used to handle success, failure, and optional values in a type-safe manner. These types are essential when developing smart contracts in CosmWasm, as they help manage various outcomes in contract logic.

Result

The Result type is an enum that represents either success (Ok) or failure (Err). It is commonly used in functions that can return errors, such as contract entry points and handlers.

Definition

enum Result<T, E> {    Ok(T),   // Represents success and contains a value of type T    Err(E),  // Represents failure and contains an error of type E}

Usage in contracts

In CosmWasm, contract entry points and handlers often return Result<Response, ContractError>. This type signifies that the function can either succeed and return a Response or fail and return a ContractError.

Example: handling a transfer in a CW20 contract

Let's look at how Result is used in the execute_transfer function from a CW20 contract:

pub fn execute_transfer(    deps: DepsMut,    _env: Env,    info: MessageInfo,    recipient: String,    amount: Uint128,) -> Result<Response, ContractError> {    if amount.is_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)}

Key Points

  • Ok(T): Represents a successful operation, returning a value of type T (in this case, a Response).
  • Err(E): Represents a failed operation, returning an error of type E (in this case, a ContractError).

The function uses Result to ensure that any errors in the process (such as invalid addresses or insufficient balances) are handled gracefully.

StdResult

StdResult is a type alias commonly used in CosmWasm. It is defined as:

type StdResult<T> = Result<T, StdError>;

StdResult is frequently used in query handlers and other functions where the error type is a standard StdError rather than a custom ContractError.

Example: using StdResult in a query handler

In the nameservice contract, the query function returns a StdResult<Binary>:

#[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()?),    }}

Implementation of 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)}

Key points

  • StdResult: A convenient alias for Result<T, StdError>, simplifying error handling in common scenarios.
  • Pattern Matching: The match statement is used to handle the Result and Option types, making the code more readable and safe.

Option

The Option type in Rust represents the possibility of a value being either present (Some) or absent (None). Unlike many other programming languages that use null or nil, Rust explicitly handles optional values with the Option enum.

Definition:=

enum Option<T> {    Some(T),  // Contains a value of type T    None,     // Represents the absence of a value}

Usage in contracts:

Option is often used in smart contracts to handle optional parameters or states that may not always have a value.

Example: handling optional prices

Consider a contract that allows optional purchase_price and transfer_price values:

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

Handling Option with match

To work with Option values, you typically use the match statement:

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

Key Points

  • Some(T): Wraps an inner value of type T, which can be accessed using .unwrap() or safely handled using pattern matching.
  • None: Represents the absence of a value and is often used as a default or placeholder when a value is not present.

Best practices for handling None

If returning None would indicate an error, it’s generally better to handle the error explicitly rather than letting it propagate silently. This can prevent unexpected behavior and make your code more robust.

Practical tips for developers

  1. Use Result for Error Handling: When writing smart contracts, always use Result to handle potential errors. This ensures that errors are caught and handled gracefully, improving the reliability of your contract.
  2. Leverage StdResult in Queries: For standard queries, use StdResult to simplify your error handling and make your code more consistent with CosmWasm conventions.
  3. Handle Option Safely: Avoid using .unwrap() on Option unless you are certain that the value exists. Instead, use pattern matching to handle both Some and None cases.
  4. Pattern Matching: Use Rust’s powerful pattern matching to work with Result and Option types. This makes your code clearer and safer.
  5. Error Propagation with ?: Use the ? operator to propagate errors up the call stack. This keeps your code clean and makes error handling more straightforward.

Further Learning

To deepen your understanding of handling Result and Option in CosmWasm, consider exploring the following resources: