- Docs
- Developers
- CW-Errors module
Introduction
The x/cw-errors
module provides a standardized way for smart contracts to handle errors in relation to transactions initiated by the Archway protocol. With the introduction of the x/callback
and x/cwica
modules, it is now possible for the Archway protocol to execute smart contract actions via Sudo endpoints implemented by your contracts. However, when errors occur during these executions, they go unnoticed as they get lost in node logs. The x/cw-errors
module aims to address this by providing mechanisms to notify contracts of such errors, which should enhance error awareness and response capabilities.
Possible error scenarios
x/callback
When the protocol executes a callback
, there could be errors thrown due to:
- The contract not having the expected sudo entrypoint
- The callback execution consuming more gas than is allowed
- There could be an error thrown by the contract
x/cwica
When a contract wants to execute an ICA transaction on another chain, there could be errors thrown due to:
- The counterparty could not unmarshall the message, or did not recognize the message
- The counterparty transaction execution failed
- The IBC packet timing out
Opt-in to receive error callbacks
You have two methods for accessing errors from within your smart contracts: one is to have your contract subscribe to the CW-Errors module to receive callbacks for these errors, and the other is to query the CW-Errors module directly. This section focuses on how to subscribe to receive error callbacks.
Let's look back at the code in the ICA guide. The State
struct has an errors
field which is used to store any error information generated by the cw-errors
module for any ICA actions executed after a error callback is executed.
pub struct State { pub owner: Addr, pub connection_id: String, pub ica_address: String, pub voted: bool, pub errors: String, pub timeout: bool,}
To receive an Error callback, the contract must implement the SudoMsg::Error
message so it can receive and handle errors. This error callback is automatically executed by the Archway protocol. The following is an example:
#[cfg_attr(not(feature = "library"), entry_point)]pub fn sudo(deps: DepsMut, env: Env, msg: SudoMsg) -> StdResult<Response> { match msg { SudoMsg::Error { module_name, error_code, contract_address: _, input_payload, error_message } => sudo::error(deps, env, module_name, error_code, input_payload, error_message), }}pub mod sudo { use crate::msg::{ICAResponse, AccountRegistered}; use super::*; pub fn error(deps: DepsMut, _env: Env, module_name: String, error_code: u32, _payload: String, error_message: String) -> StdResult<Response> { let _ = STATE.update(deps.storage, |mut state| -> Result<_, ContractError> { if module_name == "cwica" { if error_code == 1 { // packet timeout error state.timeout = true; } if error_code == 2 { // submittx execution error state.errors = error_message; } else { // unknown error } } Ok(state) }); Ok(Response::new()) }}
A few things to note:
- Errors are stored in the
cw-errors
module state for a specified number of blocks. The duration is dependent on a module parameter which can be changed via governance. - The max gas allowed for these sudoErr executions will be as small as possible while still being useful. This execution is only meant for error handling and not for complex logic prosessing.
Before the protocol will execute such a callback in relation to errors generated from the ICA
or Callback
modules, the contract must register for a subscription to the CW-Errors module which might have a fee attached. Currently there is no fee being charged for subscribing but this can be changed via governance. From the CLI you can access the fee via archwayd q cwerrors params
. The subscription is only valid up to a certain block height.
To register for such a subscription, the follwong CW-Errors module message must be executed:
service Msg {
// SubscribeToError defines an operation which will register a contract for a sudo callback on errors
rpc SubscribeToError(MsgSubscribeToError) returns (MsgSubscribeToErrorResponse);
}
message MsgSubscribeToError {
// sender is the address of who is registering the contarcts for callback on error
string sender = 1;
// contract is the address of the contract that will be called on error
string contract_address = 2;
// fee is the subscription fee for the feature (current no fee is charged for this feature)
cosmos.base.v1beta1.Coin fee = 3 ;
}
message MsgSubscribeToErrorResponse {
// subscription_valid_till is the block height till which the subscription is valid
int64 subscription_valid_till = 1;
}
This can be executed via:
- CLI:
archwayd tx cwerrors subscribe-to-error [contract-address] [fee-amount] [flags]
- Stargate message with type URL:
archway.cwerrors.v1.MsgSubscribeToError
Querying the error module
Another means of accessing errors being stored in the CW-Errors module state is by querying the state. This can be queried by the contract using the Stargate Querier. The type URL would be archway.cwerrors.v1.QueryErrorsRequest
and can be found here:
service Query {
// Errors queries all the errors for a given contract.
rpc Errors(QueryErrorsRequest) returns (QueryErrorsResponse) {
option (google.api.http).get = "/archway/cwerrors/v1/errors";
}
}
message QueryErrorsRequest {
// contract_address is the address of the contract whose errors to query for
string contract_address = 1;
}
message QueryErrorsResponse {
// errors defines all the contract errors which will be returned
repeated SudoError errors = 1 [ (gogoproto.nullable) = false ];
}
The following is an example of how to query the CW-Errors module from your contract:
#[allow(clippy::derive_partial_eq_without_eq)]#[derive(Clone, PartialEq, ::prost::Message)]pub struct QueryErrorsRequest { #[prost(string, tag = "1")] pub contract_address: ::prost::alloc::string::String,}pub mod query { use super::*; pub fn query_cw_errors( deps: Deps, _env: Env, ) -> StdResult<Option<QueryErrorsResponse>> { let contract_address = env.contract.address.to_string(); let msg = QueryErrorsRequest { contract_address: contract_address.clone(), }; let res =deps.querier.query(&cosmwasm_std::QueryRequest::Stargate { path: "/archway.cwerrors.v1.Query/Errors".to_string(), data: Binary::from(prost::Message::encode_to_vec(&msg)),, })?; Ok(res) }}
CW-Errors test contract
The CW-ICA test contract implements CW-Errors. You can find the test contract here.