Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cw20-base migration #67

Merged
merged 9 commits into from
Aug 28, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 4 additions & 10 deletions contracts/cw1-subkeys/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use cw1_whitelist::{
msg::InitMsg,
state::admin_list_read,
};
use cw2::{set_contract_version, ContractVersion};
use cw2::set_contract_version;

use crate::msg::{AllAllowancesResponse, AllowanceInfo, HandleMsg, QueryMsg};
use crate::state::{allowances, allowances_read, Allowance};
Expand All @@ -27,15 +27,9 @@ pub fn init<S: Storage, A: Api, Q: Querier>(
env: Env,
msg: InitMsg,
) -> StdResult<InitResponse> {
let version = ContractVersion {
contract: CONTRACT_NAME.to_string(),
version: CONTRACT_VERSION.to_string(),
};
let result = whitelist_init(deps, env, msg);
if result.is_ok() {
set_contract_version(&mut deps.storage, &version)?;
};
result
let result = whitelist_init(deps, env, msg)?;
set_contract_version(&mut deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?;
Ok(result)
}

pub fn handle<S: Storage, A: Api, Q: Querier>(
Expand Down
8 changes: 2 additions & 6 deletions contracts/cw1-whitelist/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use cosmwasm_std::{
HumanAddr, InitResponse, Querier, StdError, StdResult, Storage,
};
use cw1::CanSendResponse;
use cw2::{set_contract_version, ContractVersion};
use cw2::set_contract_version;

use crate::msg::{AdminListResponse, HandleMsg, InitMsg, QueryMsg};
use crate::state::{admin_list, admin_list_read, AdminList};
Expand All @@ -20,11 +20,7 @@ pub fn init<S: Storage, A: Api, Q: Querier>(
_env: Env,
msg: InitMsg,
) -> StdResult<InitResponse> {
let version = ContractVersion {
contract: CONTRACT_NAME.to_string(),
version: CONTRACT_VERSION.to_string(),
};
set_contract_version(&mut deps.storage, &version)?;
set_contract_version(&mut deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?;
let cfg = AdminList {
admins: map_canonical(&deps.api, &msg.admins)?,
mutable: msg.mutable,
Expand Down
3 changes: 2 additions & 1 deletion contracts/cw20-base/examples/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use cw20::{
AllAccountsResponse, AllAllowancesResponse, AllowanceResponse, BalanceResponse,
TokenInfoResponse,
};
use cw20_base::msg::{HandleMsg, InitMsg, QueryMsg};
use cw20_base::msg::{HandleMsg, InitMsg, MigrateMsg, QueryMsg};

fn main() {
let mut out_dir = current_dir().unwrap();
Expand All @@ -18,6 +18,7 @@ fn main() {
export_schema(&schema_for!(InitMsg), &out_dir);
export_schema(&schema_for!(HandleMsg), &out_dir);
export_schema(&schema_for!(QueryMsg), &out_dir);
export_schema(&schema_for!(MigrateMsg), &out_dir);
export_schema(&schema_for!(AllowanceResponse), &out_dir);
export_schema(&schema_for!(BalanceResponse), &out_dir);
export_schema(&schema_for!(TokenInfoResponse), &out_dir);
Expand Down
6 changes: 6 additions & 0 deletions contracts/cw20-base/schema/migrate_msg.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "MigrateMsg",
"description": "We currently take no arguments for migrations",
"type": "object"
}
148 changes: 137 additions & 11 deletions contracts/cw20-base/src/contract.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
use cosmwasm_std::{
log, to_binary, Api, Binary, Env, Extern, HandleResponse, HumanAddr, InitResponse, Querier,
StdError, StdResult, Storage, Uint128,
log, to_binary, Api, Binary, Env, Extern, HandleResponse, HumanAddr, InitResponse,
MigrateResponse, Querier, StdError, StdResult, Storage, Uint128,
};
use cw2::{set_contract_version, ContractVersion};
use cw2::{get_contract_version, set_contract_version};
use cw20::{BalanceResponse, Cw20ReceiveMsg, MinterResponse, TokenInfoResponse};

use crate::allowances::{
handle_burn_from, handle_decrease_allowance, handle_increase_allowance, handle_send_from,
handle_transfer_from, query_allowance,
};
use crate::enumerable::{query_all_accounts, query_all_allowances};
use crate::msg::{HandleMsg, InitMsg, InitialBalance, QueryMsg};
use crate::migrations::migrate_v01_to_v02;
use crate::msg::{HandleMsg, InitMsg, InitialBalance, MigrateMsg, QueryMsg};
use crate::state::{balances, balances_read, token_info, token_info_read, MinterData, TokenInfo};

// version info for migration info
Expand All @@ -22,11 +23,7 @@ pub fn init<S: Storage, A: Api, Q: Querier>(
_env: Env,
msg: InitMsg,
) -> StdResult<InitResponse> {
let version = ContractVersion {
contract: CONTRACT_NAME.to_string(),
version: CONTRACT_VERSION.to_string(),
};
set_contract_version(&mut deps.storage, &version)?;
set_contract_version(&mut deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?;
// check valid token info
msg.validate()?;
// create initial accounts
Expand Down Expand Up @@ -315,11 +312,41 @@ pub fn query_minter<S: Storage, A: Api, Q: Querier>(
Ok(minter)
}

pub fn migrate<S: Storage, A: Api, Q: Querier>(
deps: &mut Extern<S, A, Q>,
_env: Env,
_msg: MigrateMsg,
) -> StdResult<MigrateResponse> {
let old_version = get_contract_version(&deps.storage)?;
if old_version.contract != CONTRACT_NAME {
return Err(StdError::generic_err(format!(
"This is {}, cannot migrate from {}",
CONTRACT_NAME, old_version.contract
)));
}
// note: v0.1.0 were not auto-generated and started with v0.
// more recent versions do not have the v prefix
if old_version.version.starts_with("v0.1.") {
migrate_v01_to_v02(&mut deps.storage)?;
set_contract_version(&mut deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?;
return Ok(MigrateResponse::default());
}
Err(StdError::generic_err(format!(
"Unknown version {}",
old_version.version
)))
}

#[cfg(test)]
mod tests {
use super::*;
use cosmwasm_std::testing::{mock_dependencies, mock_env};
use cosmwasm_std::{coins, from_binary, CosmosMsg, StdError, WasmMsg};
use cosmwasm_std::{coins, from_binary, CosmosMsg, Order, StdError, WasmMsg};
use cw2::ContractVersion;

use super::*;
use crate::migrations::generate_v01_test_data;
use crate::state::allowances_read;
use cw20::{AllowanceResponse, Expiration};

const CANONICAL_LENGTH: usize = 20;

Expand Down Expand Up @@ -789,4 +816,103 @@ mod tests {
assert_eq!(get_balance(&deps, &contract), transfer);
assert_eq!(query_token_info(&deps).unwrap().total_supply, amount1);
}

#[test]
fn migrate_from_v01() {
let mut deps = mock_dependencies(20, &[]);

generate_v01_test_data(&mut deps.storage, &deps.api).unwrap();
// make sure this really is 0.1.0
assert_eq!(
get_contract_version(&deps.storage).unwrap(),
ContractVersion {
contract: CONTRACT_NAME.to_string(),
version: "v0.1.0".to_string(),
}
);

// run the migration
let env = mock_env(HumanAddr::from("admin"), &[]);
migrate(&mut deps, env, MigrateMsg {}).unwrap();

// make sure the version is updated
assert_eq!(
get_contract_version(&deps.storage).unwrap(),
ContractVersion {
contract: CONTRACT_NAME.to_string(),
version: CONTRACT_VERSION.to_string(),
}
);

// check all the data (against the spec in generate_v01_test_data)
let info = token_info_read(&deps.storage).load().unwrap();
assert_eq!(
info,
TokenInfo {
name: "Sample Coin".to_string(),
symbol: "SAMP".to_string(),
decimals: 2,
total_supply: Uint128(777777),
mint: None,
}
);

// 2 users
let user1 = deps
.api
.canonical_address(&HumanAddr::from("user1"))
.unwrap();
let user2 = deps
.api
.canonical_address(&HumanAddr::from("user2"))
.unwrap();

let bal = balances_read(&deps.storage);
assert_eq!(2, bal.range(None, None, Order::Descending).count());
assert_eq!(bal.load(user1.as_slice()).unwrap(), Uint128(123456));
assert_eq!(bal.load(user2.as_slice()).unwrap(), Uint128(654321));

let spender1 = deps
.api
.canonical_address(&HumanAddr::from("spender1"))
.unwrap();
let spender2 = deps
.api
.canonical_address(&HumanAddr::from("spender2"))
.unwrap();

let num_allows = allowances_read(&deps.storage, &user1)
.range(None, None, Order::Ascending)
.count();
assert_eq!(num_allows, 1);
let allow = allowances_read(&deps.storage, &user1)
.load(spender1.as_slice())
.unwrap();
let expect = AllowanceResponse {
allowance: Uint128(5000),
expires: Expiration::AtHeight(5000),
};
assert_eq!(allow, expect);

let num_allows = allowances_read(&deps.storage, &user2)
.range(None, None, Order::Ascending)
.count();
assert_eq!(num_allows, 2);
let allow = allowances_read(&deps.storage, &user2)
.load(spender1.as_slice())
.unwrap();
let expect = AllowanceResponse {
allowance: Uint128(15000),
expires: Expiration::AtTime(1598647517),
};
assert_eq!(allow, expect);
let allow = allowances_read(&deps.storage, &user2)
.load(spender2.as_slice())
.unwrap();
let expect = AllowanceResponse {
allowance: Uint128(77777),
expires: Expiration::Never {},
};
assert_eq!(allow, expect);
}
}
4 changes: 3 additions & 1 deletion contracts/cw20-base/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,7 @@ pub mod enumerable;
pub mod msg;
pub mod state;

mod migrations;

#[cfg(all(target_arch = "wasm32", not(feature = "library")))]
cosmwasm_std::create_entry_points!(contract);
cosmwasm_std::create_entry_points_with_migration!(contract);
4 changes: 4 additions & 0 deletions contracts/cw20-base/src/migrations/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Migrations

This includes older data types so we can migrate older contracts to
newer versions of the codebase
4 changes: 4 additions & 0 deletions contracts/cw20-base/src/migrations/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
mod v01;

pub use v01::migrate_v01_to_v02;
pub use v01::testing::generate_v01_test_data;
Loading