- Docs
- Developers
- Interacting with your contract
Interacting with your contract
Now that your contract is deployed and instantiated, it's time to start interacting with it. This involves generating transactions and retrieving information from the contract.
Querying contract data
Queries read data from the blockchain without altering any stored information, so they do not incur any gas fees.
There are several types of queries we can perform, but a common type of query we are interested in is the contract-state query, which we will execute in smart mode. This allows us to run queries with specific arguments to filter the resultset instead of retrieving the entire contract data or metadata.
If you have created the increment contract project, we will show you how to use the Archway Developer CLI
and archwayd
to get the contract's count
state.
Query using Archway Developer CLI
The following is the general command structure for executing a query:
archway contracts query smart CONTRACT [STDININPUT] [--json] [--log-level debug|error|info|warn] [--no-validation] [--args <value> | --args-file <value>| ]
A basic example for the increment
contract would be:
archway contracts query smart increment --args '{"get_count": {}}'
An example of the output would be:
{ "count": 0}
Query using archwayd
Please make sure to substitute [CONTRACT-ADDRESS]
for your contract's address.
mainnet
testnet
archwayd query wasm contract-state smart [CONTRACT-ADDRESS] '{"get_count": {}}' --node https://rpc.mainnet.archway.io:443 --chain-id archway-1
An example of the output would be:
data:
count: 1
Deeper dive
Why was the query argument {"get_count": {}}?
The query argument {"get_count": {}} is used to match the expected input format defined in the smart contract's Rust code. This specific JSON structure corresponds to the QueryMsg::GetCount
variant in the contract's query function.
If we open src/contract.rs in your project and inspect the function pub fn query, you will see the case matching statement that corresponds to our JSON query:
pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult<Binary> { match msg { QueryMsg::GetCount {} => to_binary(&query_count(deps)?), // Here it is }}
Here's a detailed breakdown:
- pub fn query: This is the query function that handles all the queries for the contract. It takes three parameters:
deps
(dependencies),_env
(environment), andmsg
(message). - msg: QueryMsg: The
msg
parameter is of typeQueryMsg
, which is an enum representing different types of query messages the contract can handle. - match msg: This line matches the
msg
parameter against different possible variants of theQueryMsg
enum. - QueryMsg::GetCount {}: This variant corresponds to the {"get_count": {}} query argument. When this variant is matched, it calls the
query_count
function to get the current count. - to_binary(&query_count(deps)?): This line converts the result of the
query_count
function into a binary format suitable for returning to the caller.
To understand why the query argument is structured this way, let's look at the QueryMsg
enum, which is defined in src/msg.rs:
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]#[serde(rename_all = "snake_case")]pub enum QueryMsg { GetCount {},}
- #derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema): This line uses Rust macros to automatically generate code for serialization, deserialization, cloning, debugging, partial equality, and JSON schema.
- #serde(rename_all = "snake_case"): This attribute ensures that all enum variants are converted to snake_case when serialized to JSON.
- pub enum QueryMsg: This defines the
QueryMsg
enum. - GetCount {}: This variant represents a query to get the current count.
When you execute the query command with {"get_count": {}}, it gets serialized into a QueryMsg::GetCount {}
variant and passed to the query
function. The match
statement in the query
function identifies this variant and calls the query_count
function, which retrieves the current count and returns it as a binary response.
By understanding this structure, you can see how the JSON query argument maps directly to the Rust code in the smart contract, enabling precise and effective interactions with the contract's state.
Executing transactions
To increment the counter value, you'll need to execute a transaction that calls the function pub fn try_increment in src/contract.rs. This function is already public, but the transaction execution is handled by the function pub fn execute in src/contract.rs, which does pattern matching to call try_increment.
Increment count using the Archway Developer CLI
archway contracts execute increment --args '{"increment": {}}'
Info
If you ever receive an out of gas error you can always use the --gas-adjustment flag and set a value of 1.5 or more.
Sending an Increment transaction using archwayd
Please make sure to substitute [CONTRACT-ADDRESS]
for your contract's address.
mainnet
testnet
archwayd tx wasm execute --chain-id archway-1 [CONTRACT-ADDRESS] '{"increment": {}}' --from my-wallet --node https://rpc.mainnet.archway.io:443 --gas auto --gas-prices $(archwayd q rewards estimate-fees 1 --node 'https://rpc.mainnet.archway.io:443' --output json | jq -r '.gas_unit_price | (.amount + .denom)') --gas-adjustment 1.3
Example output:
✔ Enter the name or address of the account that will send the transaction … mywalletExecuting contract increment2 Chain: constantine-3 Signer: mywallet✅ Executed contract increment2-0.1.0 Transaction: CEFC1B9F6AE482249C3F6F3ED1C723F25FA8C129F53F5169544931207769311A
Why is the Argument {"increment": {}}?
The argument {"increment": {}} is used to match the expected input format defined in the smart contract's Rust code. This specific JSON structure corresponds to the ExecuteMsg::Increment
variant in the contract's execute function.
If we open src/contract.rs and inspect the pub fn execute function, we will see the pattern matching statement that corresponds to our JSON argument:
pub fn execute( deps: DepsMut, _env: Env, info: MessageInfo, msg: ExecuteMsg,) -> Result<Response, ContractError> { match msg { ExecuteMsg::Increment {} => try_increment(deps), // Here it is ExecuteMsg::Reset { count } => try_reset(deps, info, count), }}
Understanding the execute
Function
Here's a detailed breakdown:
- pub fn execute: This is the main function that handles all the execute messages for the contract. It takes four parameters:
deps
(mutable dependencies),_env
(environment),info
(message information), andmsg
(message). - msg: ExecuteMsg: The
msg
parameter is of typeExecuteMsg
, which is an enum representing different types of execute messages the contract can handle. - match msg: This line matches the
msg
parameter against different possible variants of theExecuteMsg
enum. - ExecuteMsg::Increment {}: This variant corresponds to the {"increment": {}} JSON argument. When this variant is matched, it calls the
try_increment
function to increment the count. - ExecuteMsg::Reset { count }: This variant matches the {"reset": {"count":
}} JSON argument. When this variant is matched, it calls thetry_reset
function to reset the count to the specified value.
Understanding the ExecuteMsg
Enum
To understand why the execute argument is structured this way, let's look at the ExecuteMsg
enum, which is typically defined in src/msg.rs:
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]#[serde(rename_all = "snake_case")]pub enum ExecuteMsg { Increment {}, Reset { count: i32 },}
- #derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema): This line uses Rust macros to automatically generate code for serialization, deserialization, cloning, debugging, partial equality, and JSON schema.
- #serde(rename_all = "snake_case"): This attribute ensures that all enum variants are converted to snake_case when serialized to JSON.
- pub enum ExecuteMsg: This defines the
ExecuteMsg
enum. - Increment {}: This variant represents a message to increment the count.
- Reset { count: i32 }: This variant represents a message to reset the count to a specific value.
How the Execute Command Works
When you execute the command with {"increment": {}}, it gets serialized into an ExecuteMsg::Increment {}
variant and passed to the execute
function. The match
statement in the execute
function identifies this variant and calls the try_increment
function, which increments the count and returns a response.
By understanding this structure, you can see how the JSON execute argument maps directly to the Rust code in the smart contract, enabling precise and effective interactions with the contract's state.
If our {"increment": {}} transaction succeeded and we query count again, it will have increased by 1:
archway contracts query smart increment --args '{"get_count": {}}'
Now outputs:
{ "count": 1}
This shows that the contract's state has been updated as expected.
Why is the argument {"increment": {}}?
If we open src/contract.rs and inspect the pub fn execute function, we'll see a pattern matching statement that matches our JSON argument:
pub fn execute( deps: DepsMut, _env: Env, info: MessageInfo, msg: ExecuteMsg,) -> Result<Response, ContractError> { match msg { ExecuteMsg::Increment {} => try_increment(deps), // Here it is ExecuteMsg::Reset { count } => try_reset(deps, info, count), }}
As you can see, enum attributes again are converted. ExecuteMsg::Increment {} becomes {"increment": {}} in the CLI.
If our { "increment": {}} transaction succeeded and we query count again, it will have increased by 1*:
archway contracts query smart increment --args '{"get_count": {}}'
Now outputs:
{ "count": 1}