Entry points
Typical Rust application starts with the fn main()
function called by the operating system.
Smart contracts are not significantly different. When the message is sent to the contract, a
function called "entry point" is executed. Unlike native applications, which have only a single
main
entry point, smart contracts have a couple of them, each corresponding to different
message type: instantiate
, execute
, query
, sudo
, migrate
and more.
To start, we will go with three basic entry points:
instantiate
is called once per smart contract lifetime; you can think about it as a constructor or initializer of a contract.execute
for handling messages which can modify contract state; they are used to perform some actual actions.query
for handling messages requesting some information from a contract; unlikeexecute
, they can never alter any contract state, and are used in a similar manner to database queries.
Generate entry points
Sylvia provides an attribute macro named entry_points
.
In most cases, your entry point will just dispatch received messages to the handler,
so it's not necessary to manually create them, and we can rely on a macro to do that for us.
Let's add the entry_points
attribute macro to our contract:
use cosmwasm_std::{Response, StdResult};
use sylvia::types::InstantiateCtx;
use sylvia::{contract, entry_points};
pub struct CounterContract;
#[entry_points]
#[contract]
impl CounterContract {
pub const fn new() -> Self {
Self
}
#[sv::msg(instantiate)]
pub fn instantiate(&self, _ctx: InstantiateCtx) -> StdResult<Response> {
Ok(Response::default())
}
}
Note that #[entry_points]
is added above the #[contract]
.
It is because #[contract]
removes attributes like #[sv::msg(...)]
on which both these macros rely.
Always remember to place #[entry_points]
first.
Sylvia generates entry points with #[entry_point]
attribute macro. Its purpose is to wrap the whole entry point to the form the Wasm runtime understands.
The proper Wasm entry points can use only basic types supported natively by Wasm specification, and
Rust structures and enums are not in this set. Working with such entry points would be
overcomplicated, so CosmWasm creators delivered the entry_point
macro. It creates the raw Wasm
entry point, calling the decorated function internally and doing all the magic required to build our
high-level Rust arguments from arguments passed by Wasm runtime.
Now, when our contract has a proper entry point, let's build it and check if it's correctly defined:
contract $ cargo build --release --target wasm32-unknown-unknown --lib
Finished release [optimized] target(s) in 0.03s
contract $ cosmwasm-check target/wasm32-unknown-unknown/release/contract.wasm
Available capabilities: {"stargate", "cosmwasm_1_3", "cosmwasm_1_1", "cosmwasm_1_2", "staking", "iterator"}
target/wasm32-unknown-unknown/release/contract.wasm: pass
All contracts (1) passed checks!
Next step
Well done! We have now a proper CosmWasm
contract.
Let's add some state to it, so it will actually be able to do something.