HumanAddr
has been deprecated in favour of simplyString
. It never added any significant safety bonus overString
and was just a marker type. The new typeAddr
was created to hold validated addresses. Those can be created viaAddr::unchecked
,Api::addr_validate
,Api::addr_humanize
and JSON deserialization. In order to maintain type safety, deserialization intoAddr
must only be done from trusted sources like a contract's state or a query response. User inputs must be deserialized intoString
.deps.api.human_address(&CanonicalAddr)
=>deps.api.addr_humanize(&CanonicalAddr)
deps.api.canonical_address(&HumanAddr)
=>deps.api.addr_canonicalize(&str)
Use the new entry point system. From lib.rs remove
#[cfg(target_arch = "wasm32")]
cosmwasm_std::create_entry_points!(contract);
// or
#[cfg(target_arch = "wasm32")]
cosmwasm_std::create_entry_points_with_migration!(contract);
Then add the macro attribute #[cfg_attr(not(feature = "library"), entry_point)]
to your contract.rs as follows:
init
Env
split intoEnv
andMessageInfo
InitResponse
andInitResult
deprecated, please useResponse
- function name changed from
init
toinstantiate
pub fn init<S: Storage, A: Api, Q: Querier>(
deps: &mut Extern<S, A, Q>,
env: Env,
msg: InitMsg,
) -> StdResult<InitResponse> {
// into
#[cfg_attr(not(feature = "library"), entry_point)]
pub fn instantiate(
deps: DepsMut,
env: Env,
info: MessageInfo,
msg: InstantiateMsg,
) -> StdResult<Response> {
handle
Env
split intoEnv
andMessageInfo
HandleResponse
andHandleResult
deprecated, please useResponse
- function name changed from
handle
toexecute
pub fn handle<S: Storage, A: Api, Q: Querier>(
deps: &mut Extern<S, A, Q>,
env: Env,
msg: HandleMsg,
) -> HandleResult {
// into
#[cfg_attr(not(feature = "library"), entry_point)]
pub fn execute(deps: DepsMut, env: Env, info: MessageInfo, msg: ExecuteMsg) -> StdResult<Response> {
query
- new argument
Env
added
- new argument
pub fn query<S: Storage, A: Api, Q: Querier>(
deps: &Extern<S, A, Q>,
msg: QueryMsg,
) -> StdResult<Binary> {
// into
#[cfg_attr(not(feature = "library"), entry_point)]
pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult<Binary> {
migrate
Env
split intoEnv
andMessageInfo
MigrateResponse
andMigrateResult
deprecated, please useResponse
pub fn migrate<S: Storage, A: Api, Q: Querier>(
deps: &mut Extern<S, A, Q>,
env: Env,
msg: MigrateMsg,
) -> MigrateResult {
// into
#[cfg_attr(not(feature = "library"), entry_point)]
pub fn migrate(_deps: DepsMut, _env: Env, _msg: MigrateMsg) -> StdResult<Response> {
Response
can no longer be built using a struct literal. Please use Response::new
as well as relevant builder-style setters to set the data.
This is a step toward better API stability.
let send = BankMsg::Send { to_address, amount };
- Ok(Response {
- messages: vec![SubMsg::new(send)],
- attributes: vec![attr("action", "burn"), attr("payout", msg.payout)],
- events: vec![],
- data: Some(data_msg.into()),
- })
+ Ok(Response::new()
+ .add_message(send)
+ .add_attribute("action", "burn")
+ .add_attribute("payout", msg.payout)
+ .set_data(data_msg))
The sub-messages feature can be used to get the response data or events from the executed contract. For example, if a contract wants to get the address of the child contract which is instantiated from the contract. The contract can send MsgInstantiate
as sub-messages with ReplyOn::Success
option like https://github.com/terraswap/terraswap/blob/7cf47f5e811fe0c4643a7cd09500702c1e7f3a6b/contracts/terraswap_factory/src/contract.rs#L128-L142.
Then the reply is only executed when the instantiate is successful with the instantiate response data. https://github.com/terraswap/terraswap/blob/7cf47f5e811fe0c4643a7cd09500702c1e7f3a6b/contracts/terraswap_factory/src/contract.rs#L148-L170.
Rename the type Extern
to Deps
, and radically simplify the init/handle/migrate/query
entrypoints. Rather than &mut Extern<S, A, Q>
, use DepsMut
. And instead of &Extern<S, A, Q>
, use Deps
. If you ever pass eg. foo<A: Api>(api: A)
around, you must now use dynamic trait pointers: foo(api: &dyn Api)
. Here is the quick search-replace guide on how to fix contract.rs:
In production (non-test) code:
<S: Storage, A: Api, Q: Querier> => ``
&mut Extern<S, A, Q> => DepsMut
&Extern<S, A, Q> => Deps
&mut deps.storage => deps.storage where passing into state.rs helpers
&deps.storage => deps.storage where passing into state.rs helpers
On the top, remove use cosmwasm_std::{Api, Extern, Querier, Storage}. Add use cosmwasm_std::{Deps, DepsMut}.
In test code only:
&mut deps, => deps.as_mut(),
&deps, => deps.as_ref(),
You may have to add use cosmwasm_std::{Storage} if the compile complains about the trait
If you use cosmwasm-storage, in state.rs:
<S: Storage> => ``
<S: ReadonlyStorage> => ``
<S, => <
&mut S => &mut dyn Storage
&S => &dyn Storage
If you have any references to ReadonlyStorage left after the above, please replace them with Storage
We can still use singleton
and bucket
. But if you want more advanced storage access, you can use cw-storage-plus
with following migration steps.
-
cowmasm_storage::Singleton
->cw_stroage_plus::Item
- Remove
read_*
andstore_*
functions - Define
Item
as following (must prepend the length of key)
pub const CONFIG: Item<Config> = Item::new("\u{0}\u{6}config"); // store CONFIG.save(deps.storage, &config)?; // read let mut config: Config = CONFIG.load(deps.storage)?;
- Remove
-
cosmwasm_storage::Bucket
->cw_storage_plus::Map
- Remove
read_*
andstore_*
functions - Define
Map
as following
pub const PAIRS: Map<Addr, PairInfoRaw> = Map::new("pair_info"); // store PAIRS.save(deps.storage, &addr, &pair_info)?; // read let pair_info: PairInfoRaw = PAIRS.load(deps.storage, &addr)?;
- Remove
The core now just returns raw bytes without json encoding, so we can receive the query response as what the data was stored.
- let res: Binary = deps.querier.query(&QueryRequest::Wasm(WasmQuery::Raw {
...
- let pair_info: PairInfoRaw = from_binary(&res)?;
// into
+ let pair_info: PairInfoRaw = deps.querier.query(&QueryRequest::Wasm(WasmQuery::Raw {
...
Also, mock_querier
has to remove one to_binary
from its raw query response.