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 called. Unlike native applications, which have only a single main
entry
point, smart contracts have a couple corresponding to different message types: instantiate
,
execute
, query
, sudo
, migrate
and more.
To start, we will go with three basic entry points:
instantiate
which 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 are able to modify contract state - they are used to perform some actual actions.query
for handling messages requesting some information from a contract; unlike execute, they can never affect any contract state, and are used just like database queries.
We will start with the instantiate entry point:
use cosmwasm_std::{entry_point, DepsMut, Empty, Env, MessageInfo, Response, StdResult};
#[entry_point]
pub fn instantiate(_deps: DepsMut, _env: Env, _info: MessageInfo, _msg: Empty) -> StdResult<Response> {
Ok(Response::new())
}
In fact, instantiate
is the only entry point required for a smart contract to be valid. It is not
very useful in this form, but it is a start. Let's take a closer look at the entry point structure.
First, we start with importing a couple of types just for more consistent usage. Then we define our
entry point. The instantiate
takes four arguments:
deps: DepsMut
(opens in a new tab) is a utility type for communicating with the outer world - it allows querying and updating the contract state, querying other contracts state, and gives access to anApi
object with a couple of helper functions for dealing with CW addresses.env: Env
(opens in a new tab) is an object representing the blockchains state when executing the message - the chain height and id, current timestamp, and the called contract address.info: MessageInfo
(opens in a new tab) contains metainformation about the message that triggered the execution - an address that sends the message, and chain native tokens sent with the message.msg: Empty
(opens in a new tab) is the message triggering execution itself - for now, it is theEmpty
type that represents{}
JSON, but the type of this argument can be anything that is deserializable, and we will pass more complex types here in the future.
If you are new to the blockchain, those arguments may not make much sense to you, but as you work through this guide, I will explain their usage one by one.
Notice an essential attribute decorating our entry point
#[entry_point]
(opens in a new tab). Its
purpose is to wrap the whole entry point to the form Wasm runtime understands. 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 rather 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.
The next thing to look at is the return type. I used
StdResult<Response>
(opens in a new tab) for
this simple example, which is an alias for Result<Response, StdError>
. The return entry point type
would always be a Result
(opens in a new tab) type, with some
error type implementing ToString
(opens in a new tab) trait
and a well-defined type for the success case. For most entry points, an "Ok" case would be the
Response
(opens in a new tab) type that allows
fitting the contract into our actor model, which we will discuss very soon.
The body of the entry point is as simple as it could be - it always succeeds with a trivial empty response.