Migrate

This is another special endpoint. It is, just like instantiate, not called frequently.

migrate is only called once you upload a new version to the chain and lets you run all the required changes to the storage.

Let's say your storage has the following layout, expressed as JSON for simplicity's sake:

structure.json
{
  "user_count": 205,
  "call_count": 543,
  "balance": 43
}

But then you notice "Hey! Why don't I nest all the counts into an own object? That way I don't have that redundant postfix, making the keys smaller".

So you go ahead and rework your logic to query the data from the following structure:

structure.json
{
  "count": {
    "user": 205,
    "call": 543
  },
  "balance": 43
}

But your storage on-chain still stores the old format. You need to somehow transform it.

That's what you do in the migrate entrypoint. You transform the structure of the storage in there.

Example

contract.rs
const CONTRACT_NAME: &str = "my_contract";
const STATE_VERSION: &str = "v2";
 
#[cfg_attr(not(feature = "library"), entry_point)]
pub fn migrate(deps: DepsMut, _env: Env, _msg: MigrateMsg) -> StdResult<Response> {
    // Check if the state version is older than the current one and update it
    cw2::ensure_from_older_version(deps.storage, CONTRACT_NAME, STATE_VERSION)?;
 
    // Load the old data
    let Some(old_data) = deps.storage.get(b"persisted_data") else {
      return Err(StdError::generic_err("Data not found"));
    };
    // Deserialize it from the old format
    let old_data: OldData = cosmwasm_std::from_json(&old_data)?;
 
    // Transform it
    let new_data = transform(old_data);
 
    // Serialize the new data
    let new_data = cosmwasm_std::to_json_vec(&new_data)?;
    // Store the new data
    deps.storage.set(b"persisted_data", &new_data);
 
    Ok(Response::default())
}

Definition

contract.rs
#[cfg_attr(not(feature = "library"), entry_point)]
pub fn migrate(deps: DepsMut, _env: Env, _msg: MigrateMsg) -> StdResult<Response> {
    Ok(Response::default())
}