This site requires Javascript to be enabled.

Result and option

In Rust, Result and Option are enum types, which means they contain values within their variants:

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


Result is an enum type, Result<T, E>, where both T and E are generics, representing success and failure. Result types are often used in entry points and handlers:

  • Ok(T) : a Result container which has succeeded, containing T
  • Err(E) : a Result container which has failed, containing E

Many contract entry points are typed Result<Response, ContractError>, where Response is the Right or Success branch, while ContractError is the Left or failure case. For example, looking at the CW20-base we can see that execute is typed Result<Response, ContractError>, and the function call that matches ExecuteMsg::Transfer would be execute_transfer which shows 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(,    &info.sender,    |balance: Option<Uint128>| -> StdResult<_> {      Ok(balance.unwrap_or_default().checked_sub(amount)?)    },  )?;  BALANCES.update(,    &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)}


It is also important to be mindful of StdResult, as it is frequently utilized in query handlers and the functions invoked by them.

For instance, in the nameservice contract, you can observe the StdResult, which functions similarly to Result, but lacks a specified 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(,  }}

Let's see the 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( {    Some(record) => Some(String::from(&record.owner)),    None => None,  };  let resp = ResolveRecordResponse { address };  to_binary(&resp)}

It is essential to match or unwrap your container types accurately, enabling you to work with the values contained within them.


In Rust, there is no concept of nil or null, unlike in most other mainstream programming languages. Instead, Rust employs the Option type, which encapsulates the notion of presence or absence within a container type.

Option is an enum type, with two variants:

  • Some(): Wraps an inner value, which can be accessed via .unwrap(). -None: Represents the absence of a value and is often used as a default or placeholder value when a value is not yet known or cannot be determined.

The following code snippet is an example of how Rust's Option can be used to allow for 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>,}

For instances of the InstantiateMsg above, there will either be a result, or nothing. To handle this scenario, it is common to use the match operator to pattern match the two cases:

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

If returning None would indicate an error state, it is conventionally recommended to throw an error instead of handling the None value.