From aae235b6f64363fd1decb34ebe02a0aaec6cdf03 Mon Sep 17 00:00:00 2001 From: Georges Chouchani Date: Wed, 29 Jun 2022 11:26:19 +0300 Subject: [PATCH 01/65] removed cw721-off-chain template --- .idea/.gitignore | 8 + .idea/archway-templates.iml | 8 + .idea/modules.xml | 8 + .idea/vcs.xml | 6 + cw20/base/src/allowances.rs | 744 ------- cw20/base/src/contract.rs | 1923 ----------------- cw20/base/src/enumerable.rs | 210 -- cw20/base/src/error.rs | 35 - cw20/base/src/lib.rs | 138 +- cw20/base/src/msg.rs | 113 - cw20/base/src/state.rs | 36 - cw721/off-chain-metadata/.cargo/config | 5 - cw721/off-chain-metadata/.circleci/config.yml | 61 - cw721/off-chain-metadata/.editorconfig | 11 - cw721/off-chain-metadata/.genignore | 1 - .../.github/workflows/Basic.yml | 83 - cw721/off-chain-metadata/.gitignore | 16 - cw721/off-chain-metadata/.gitpod.Dockerfile | 17 - cw721/off-chain-metadata/.gitpod.yml | 10 - cw721/off-chain-metadata/Cargo.toml | 54 - cw721/off-chain-metadata/Developing.md | 96 - cw721/off-chain-metadata/Importing.md | 62 - cw721/off-chain-metadata/LICENSE | 202 -- cw721/off-chain-metadata/NOTICE | 13 - cw721/off-chain-metadata/Publishing.md | 115 - cw721/off-chain-metadata/README.md | 90 - cw721/off-chain-metadata/cargo-generate.toml | 5 - cw721/off-chain-metadata/examples/schema.rs | 39 - cw721/off-chain-metadata/meta/README.md | 16 - cw721/off-chain-metadata/meta/appveyor.yml | 61 - .../off-chain-metadata/meta/test_generate.sh | 37 - cw721/off-chain-metadata/rustfmt.toml | 15 - .../schema/all_nft_info_response.json | 155 -- .../schema/approval_response.json | 94 - .../schema/approvals_response.json | 97 - .../schema/approved_for_all_response.json | 97 - .../schema/contract_info_response.json | 17 - .../schema/execute_msg.json | 310 --- .../schema/instantiate_msg.json | 24 - .../schema/minter_response.json | 14 - .../schema/nft_info_response.json | 31 - .../schema/num_tokens_response.json | 15 - .../schema/operators_response.json | 97 - .../schema/owner_of_response.json | 103 - .../off-chain-metadata/schema/query_msg.json | 285 --- .../schema/tokens_response.json | 17 - cw721/off-chain-metadata/src/error.rs | 20 - cw721/off-chain-metadata/src/execute.rs | 397 ---- cw721/off-chain-metadata/src/helpers.rs | 179 -- cw721/off-chain-metadata/src/lib.rs | 53 - cw721/off-chain-metadata/src/msg.rs | 154 -- cw721/off-chain-metadata/src/query.rs | 308 --- cw721/off-chain-metadata/src/state.rs | 140 -- cw721/off-chain-metadata/src/tests.rs | 751 ------- 54 files changed, 160 insertions(+), 7436 deletions(-) create mode 100644 .idea/.gitignore create mode 100644 .idea/archway-templates.iml create mode 100644 .idea/modules.xml create mode 100644 .idea/vcs.xml delete mode 100644 cw20/base/src/allowances.rs delete mode 100644 cw20/base/src/contract.rs delete mode 100644 cw20/base/src/enumerable.rs delete mode 100644 cw20/base/src/error.rs delete mode 100644 cw20/base/src/msg.rs delete mode 100644 cw20/base/src/state.rs delete mode 100644 cw721/off-chain-metadata/.cargo/config delete mode 100644 cw721/off-chain-metadata/.circleci/config.yml delete mode 100644 cw721/off-chain-metadata/.editorconfig delete mode 100644 cw721/off-chain-metadata/.genignore delete mode 100644 cw721/off-chain-metadata/.github/workflows/Basic.yml delete mode 100644 cw721/off-chain-metadata/.gitignore delete mode 100644 cw721/off-chain-metadata/.gitpod.Dockerfile delete mode 100644 cw721/off-chain-metadata/.gitpod.yml delete mode 100644 cw721/off-chain-metadata/Cargo.toml delete mode 100644 cw721/off-chain-metadata/Developing.md delete mode 100644 cw721/off-chain-metadata/Importing.md delete mode 100644 cw721/off-chain-metadata/LICENSE delete mode 100644 cw721/off-chain-metadata/NOTICE delete mode 100644 cw721/off-chain-metadata/Publishing.md delete mode 100644 cw721/off-chain-metadata/README.md delete mode 100644 cw721/off-chain-metadata/cargo-generate.toml delete mode 100644 cw721/off-chain-metadata/examples/schema.rs delete mode 100644 cw721/off-chain-metadata/meta/README.md delete mode 100644 cw721/off-chain-metadata/meta/appveyor.yml delete mode 100755 cw721/off-chain-metadata/meta/test_generate.sh delete mode 100644 cw721/off-chain-metadata/rustfmt.toml delete mode 100644 cw721/off-chain-metadata/schema/all_nft_info_response.json delete mode 100644 cw721/off-chain-metadata/schema/approval_response.json delete mode 100644 cw721/off-chain-metadata/schema/approvals_response.json delete mode 100644 cw721/off-chain-metadata/schema/approved_for_all_response.json delete mode 100644 cw721/off-chain-metadata/schema/contract_info_response.json delete mode 100644 cw721/off-chain-metadata/schema/execute_msg.json delete mode 100644 cw721/off-chain-metadata/schema/instantiate_msg.json delete mode 100644 cw721/off-chain-metadata/schema/minter_response.json delete mode 100644 cw721/off-chain-metadata/schema/nft_info_response.json delete mode 100644 cw721/off-chain-metadata/schema/num_tokens_response.json delete mode 100644 cw721/off-chain-metadata/schema/operators_response.json delete mode 100644 cw721/off-chain-metadata/schema/owner_of_response.json delete mode 100644 cw721/off-chain-metadata/schema/query_msg.json delete mode 100644 cw721/off-chain-metadata/schema/tokens_response.json delete mode 100644 cw721/off-chain-metadata/src/error.rs delete mode 100644 cw721/off-chain-metadata/src/execute.rs delete mode 100644 cw721/off-chain-metadata/src/helpers.rs delete mode 100644 cw721/off-chain-metadata/src/lib.rs delete mode 100644 cw721/off-chain-metadata/src/msg.rs delete mode 100644 cw721/off-chain-metadata/src/query.rs delete mode 100644 cw721/off-chain-metadata/src/state.rs delete mode 100644 cw721/off-chain-metadata/src/tests.rs diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/archway-templates.iml b/.idea/archway-templates.iml new file mode 100644 index 0000000..bc2cd87 --- /dev/null +++ b/.idea/archway-templates.iml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..064e119 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/cw20/base/src/allowances.rs b/cw20/base/src/allowances.rs deleted file mode 100644 index 663d808..0000000 --- a/cw20/base/src/allowances.rs +++ /dev/null @@ -1,744 +0,0 @@ -use cosmwasm_std::{ - attr, Addr, Binary, BlockInfo, Deps, DepsMut, Env, MessageInfo, Response, StdError, StdResult, - Storage, Uint128, -}; -use cw20::{AllowanceResponse, Cw20ReceiveMsg, Expiration}; - -use crate::error::ContractError; -use crate::state::{ALLOWANCES, BALANCES, TOKEN_INFO}; - -pub fn execute_increase_allowance( - deps: DepsMut, - _env: Env, - info: MessageInfo, - spender: String, - amount: Uint128, - expires: Option, -) -> Result { - let spender_addr = deps.api.addr_validate(&spender)?; - if spender_addr == info.sender { - return Err(ContractError::CannotSetOwnAccount {}); - } - - ALLOWANCES.update( - deps.storage, - (&info.sender, &spender_addr), - |allow| -> StdResult<_> { - let mut val = allow.unwrap_or_default(); - if let Some(exp) = expires { - val.expires = exp; - } - val.allowance += amount; - Ok(val) - }, - )?; - - let res = Response::new().add_attributes(vec![ - attr("action", "increase_allowance"), - attr("owner", info.sender), - attr("spender", spender), - attr("amount", amount), - ]); - Ok(res) -} - -pub fn execute_decrease_allowance( - deps: DepsMut, - _env: Env, - info: MessageInfo, - spender: String, - amount: Uint128, - expires: Option, -) -> Result { - let spender_addr = deps.api.addr_validate(&spender)?; - if spender_addr == info.sender { - return Err(ContractError::CannotSetOwnAccount {}); - } - - let key = (&info.sender, &spender_addr); - // load value and delete if it hits 0, or update otherwise - let mut allowance = ALLOWANCES.load(deps.storage, key)?; - if amount < allowance.allowance { - // update the new amount - allowance.allowance = allowance - .allowance - .checked_sub(amount) - .map_err(StdError::overflow)?; - if let Some(exp) = expires { - allowance.expires = exp; - } - ALLOWANCES.save(deps.storage, key, &allowance)?; - } else { - ALLOWANCES.remove(deps.storage, key); - } - - let res = Response::new().add_attributes(vec![ - attr("action", "decrease_allowance"), - attr("owner", info.sender), - attr("spender", spender), - attr("amount", amount), - ]); - Ok(res) -} - -// this can be used to update a lower allowance - call bucket.update with proper keys -pub fn deduct_allowance( - storage: &mut dyn Storage, - owner: &Addr, - spender: &Addr, - block: &BlockInfo, - amount: Uint128, -) -> Result { - ALLOWANCES.update(storage, (owner, spender), |current| { - match current { - Some(mut a) => { - if a.expires.is_expired(block) { - Err(ContractError::Expired {}) - } else { - // deduct the allowance if enough - a.allowance = a - .allowance - .checked_sub(amount) - .map_err(StdError::overflow)?; - Ok(a) - } - } - None => Err(ContractError::NoAllowance {}), - } - }) -} - -pub fn execute_transfer_from( - deps: DepsMut, - env: Env, - info: MessageInfo, - owner: String, - recipient: String, - amount: Uint128, -) -> Result { - let rcpt_addr = deps.api.addr_validate(&recipient)?; - let owner_addr = deps.api.addr_validate(&owner)?; - - // deduct allowance before doing anything else have enough allowance - deduct_allowance(deps.storage, &owner_addr, &info.sender, &env.block, amount)?; - - BALANCES.update( - deps.storage, - &owner_addr, - |balance: Option| -> StdResult<_> { - Ok(balance.unwrap_or_default().checked_sub(amount)?) - }, - )?; - BALANCES.update( - deps.storage, - &rcpt_addr, - |balance: Option| -> StdResult<_> { Ok(balance.unwrap_or_default() + amount) }, - )?; - - let res = Response::new().add_attributes(vec![ - attr("action", "transfer_from"), - attr("from", owner), - attr("to", recipient), - attr("by", info.sender), - attr("amount", amount), - ]); - Ok(res) -} - -pub fn execute_burn_from( - deps: DepsMut, - - env: Env, - info: MessageInfo, - owner: String, - amount: Uint128, -) -> Result { - let owner_addr = deps.api.addr_validate(&owner)?; - - // deduct allowance before doing anything else have enough allowance - deduct_allowance(deps.storage, &owner_addr, &info.sender, &env.block, amount)?; - - // lower balance - BALANCES.update( - deps.storage, - &owner_addr, - |balance: Option| -> StdResult<_> { - Ok(balance.unwrap_or_default().checked_sub(amount)?) - }, - )?; - // reduce total_supply - TOKEN_INFO.update(deps.storage, |mut meta| -> StdResult<_> { - meta.total_supply = meta.total_supply.checked_sub(amount)?; - Ok(meta) - })?; - - let res = Response::new().add_attributes(vec![ - attr("action", "burn_from"), - attr("from", owner), - attr("by", info.sender), - attr("amount", amount), - ]); - Ok(res) -} - -pub fn execute_send_from( - deps: DepsMut, - env: Env, - info: MessageInfo, - owner: String, - contract: String, - amount: Uint128, - msg: Binary, -) -> Result { - let rcpt_addr = deps.api.addr_validate(&contract)?; - let owner_addr = deps.api.addr_validate(&owner)?; - - // deduct allowance before doing anything else have enough allowance - deduct_allowance(deps.storage, &owner_addr, &info.sender, &env.block, amount)?; - - // move the tokens to the contract - BALANCES.update( - deps.storage, - &owner_addr, - |balance: Option| -> StdResult<_> { - Ok(balance.unwrap_or_default().checked_sub(amount)?) - }, - )?; - BALANCES.update( - deps.storage, - &rcpt_addr, - |balance: Option| -> StdResult<_> { Ok(balance.unwrap_or_default() + amount) }, - )?; - - let attrs = vec![ - attr("action", "send_from"), - attr("from", &owner), - attr("to", &contract), - attr("by", &info.sender), - attr("amount", amount), - ]; - - // create a send message - let msg = Cw20ReceiveMsg { - sender: info.sender.into(), - amount, - msg, - } - .into_cosmos_msg(contract)?; - - let res = Response::new().add_message(msg).add_attributes(attrs); - Ok(res) -} - -pub fn query_allowance(deps: Deps, owner: String, spender: String) -> StdResult { - let owner_addr = deps.api.addr_validate(&owner)?; - let spender_addr = deps.api.addr_validate(&spender)?; - let allowance = ALLOWANCES - .may_load(deps.storage, (&owner_addr, &spender_addr))? - .unwrap_or_default(); - Ok(allowance) -} - -#[cfg(test)] -mod tests { - use super::*; - - use cosmwasm_std::testing::{mock_dependencies_with_balance, mock_env, mock_info}; - use cosmwasm_std::{coins, CosmosMsg, SubMsg, Timestamp, WasmMsg}; - use cw20::{Cw20Coin, TokenInfoResponse}; - - use crate::contract::{execute, instantiate, query_balance, query_token_info}; - use crate::msg::{ExecuteMsg, InstantiateMsg}; - - fn get_balance>(deps: Deps, address: T) -> Uint128 { - query_balance(deps, address.into()).unwrap().balance - } - - // this will set up the instantiation for other tests - fn do_instantiate>( - mut deps: DepsMut, - addr: T, - amount: Uint128, - ) -> TokenInfoResponse { - let instantiate_msg = InstantiateMsg { - name: "Auto Gen".to_string(), - symbol: "AUTO".to_string(), - decimals: 3, - initial_balances: vec![Cw20Coin { - address: addr.into(), - amount, - }], - mint: None, - marketing: None, - }; - let info = mock_info("creator", &[]); - let env = mock_env(); - instantiate(deps.branch(), env, info, instantiate_msg).unwrap(); - query_token_info(deps.as_ref()).unwrap() - } - - #[test] - fn increase_decrease_allowances() { - let mut deps = mock_dependencies_with_balance(&coins(2, "token")); - - let owner = String::from("addr0001"); - let spender = String::from("addr0002"); - let info = mock_info(owner.as_ref(), &[]); - let env = mock_env(); - do_instantiate(deps.as_mut(), owner.clone(), Uint128::new(12340000)); - - // no allowance to start - let allowance = query_allowance(deps.as_ref(), owner.clone(), spender.clone()).unwrap(); - assert_eq!(allowance, AllowanceResponse::default()); - - // set allowance with height expiration - let allow1 = Uint128::new(7777); - let expires = Expiration::AtHeight(5432); - let msg = ExecuteMsg::IncreaseAllowance { - spender: spender.clone(), - amount: allow1, - expires: Some(expires), - }; - execute(deps.as_mut(), env.clone(), info.clone(), msg).unwrap(); - - // ensure it looks good - let allowance = query_allowance(deps.as_ref(), owner.clone(), spender.clone()).unwrap(); - assert_eq!( - allowance, - AllowanceResponse { - allowance: allow1, - expires - } - ); - - // decrease it a bit with no expire set - stays the same - let lower = Uint128::new(4444); - let allow2 = allow1.checked_sub(lower).unwrap(); - let msg = ExecuteMsg::DecreaseAllowance { - spender: spender.clone(), - amount: lower, - expires: None, - }; - execute(deps.as_mut(), env.clone(), info.clone(), msg).unwrap(); - let allowance = query_allowance(deps.as_ref(), owner.clone(), spender.clone()).unwrap(); - assert_eq!( - allowance, - AllowanceResponse { - allowance: allow2, - expires - } - ); - - // increase it some more and override the expires - let raise = Uint128::new(87654); - let allow3 = allow2 + raise; - let new_expire = Expiration::AtTime(Timestamp::from_seconds(8888888888)); - let msg = ExecuteMsg::IncreaseAllowance { - spender: spender.clone(), - amount: raise, - expires: Some(new_expire), - }; - execute(deps.as_mut(), env.clone(), info.clone(), msg).unwrap(); - let allowance = query_allowance(deps.as_ref(), owner.clone(), spender.clone()).unwrap(); - assert_eq!( - allowance, - AllowanceResponse { - allowance: allow3, - expires: new_expire - } - ); - - // decrease it below 0 - let msg = ExecuteMsg::DecreaseAllowance { - spender: spender.clone(), - amount: Uint128::new(99988647623876347), - expires: None, - }; - execute(deps.as_mut(), env, info, msg).unwrap(); - let allowance = query_allowance(deps.as_ref(), owner, spender).unwrap(); - assert_eq!(allowance, AllowanceResponse::default()); - } - - #[test] - fn allowances_independent() { - let mut deps = mock_dependencies_with_balance(&coins(2, "token")); - - let owner = String::from("addr0001"); - let spender = String::from("addr0002"); - let spender2 = String::from("addr0003"); - let info = mock_info(owner.as_ref(), &[]); - let env = mock_env(); - do_instantiate(deps.as_mut(), &owner, Uint128::new(12340000)); - - // no allowance to start - assert_eq!( - query_allowance(deps.as_ref(), owner.clone(), spender.clone()).unwrap(), - AllowanceResponse::default() - ); - assert_eq!( - query_allowance(deps.as_ref(), owner.clone(), spender2.clone()).unwrap(), - AllowanceResponse::default() - ); - assert_eq!( - query_allowance(deps.as_ref(), spender.clone(), spender2.clone()).unwrap(), - AllowanceResponse::default() - ); - - // set allowance with height expiration - let allow1 = Uint128::new(7777); - let expires = Expiration::AtHeight(5432); - let msg = ExecuteMsg::IncreaseAllowance { - spender: spender.clone(), - amount: allow1, - expires: Some(expires), - }; - execute(deps.as_mut(), env.clone(), info.clone(), msg).unwrap(); - - // set other allowance with no expiration - let allow2 = Uint128::new(87654); - let msg = ExecuteMsg::IncreaseAllowance { - spender: spender2.clone(), - amount: allow2, - expires: None, - }; - execute(deps.as_mut(), env, info, msg).unwrap(); - - // check they are proper - let expect_one = AllowanceResponse { - allowance: allow1, - expires, - }; - let expect_two = AllowanceResponse { - allowance: allow2, - expires: Expiration::Never {}, - }; - assert_eq!( - query_allowance(deps.as_ref(), owner.clone(), spender.clone()).unwrap(), - expect_one - ); - assert_eq!( - query_allowance(deps.as_ref(), owner.clone(), spender2.clone()).unwrap(), - expect_two - ); - assert_eq!( - query_allowance(deps.as_ref(), spender.clone(), spender2.clone()).unwrap(), - AllowanceResponse::default() - ); - - // also allow spender -> spender2 with no interference - let info = mock_info(spender.as_ref(), &[]); - let env = mock_env(); - let allow3 = Uint128::new(1821); - let expires3 = Expiration::AtTime(Timestamp::from_seconds(3767626296)); - let msg = ExecuteMsg::IncreaseAllowance { - spender: spender2.clone(), - amount: allow3, - expires: Some(expires3), - }; - execute(deps.as_mut(), env, info, msg).unwrap(); - let expect_three = AllowanceResponse { - allowance: allow3, - expires: expires3, - }; - assert_eq!( - query_allowance(deps.as_ref(), owner.clone(), spender.clone()).unwrap(), - expect_one - ); - assert_eq!( - query_allowance(deps.as_ref(), owner, spender2.clone()).unwrap(), - expect_two - ); - assert_eq!( - query_allowance(deps.as_ref(), spender, spender2).unwrap(), - expect_three - ); - } - - #[test] - fn no_self_allowance() { - let mut deps = mock_dependencies_with_balance(&coins(2, "token")); - - let owner = String::from("addr0001"); - let info = mock_info(owner.as_ref(), &[]); - let env = mock_env(); - do_instantiate(deps.as_mut(), &owner, Uint128::new(12340000)); - - // self-allowance - let msg = ExecuteMsg::IncreaseAllowance { - spender: owner.clone(), - amount: Uint128::new(7777), - expires: None, - }; - let err = execute(deps.as_mut(), env.clone(), info.clone(), msg).unwrap_err(); - assert_eq!(err, ContractError::CannotSetOwnAccount {}); - - // decrease self-allowance - let msg = ExecuteMsg::DecreaseAllowance { - spender: owner, - amount: Uint128::new(7777), - expires: None, - }; - let err = execute(deps.as_mut(), env, info, msg).unwrap_err(); - assert_eq!(err, ContractError::CannotSetOwnAccount {}); - } - - #[test] - fn transfer_from_respects_limits() { - let mut deps = mock_dependencies_with_balance(&[]); - let owner = String::from("addr0001"); - let spender = String::from("addr0002"); - let rcpt = String::from("addr0003"); - - let start = Uint128::new(999999); - do_instantiate(deps.as_mut(), &owner, start); - - // provide an allowance - let allow1 = Uint128::new(77777); - let msg = ExecuteMsg::IncreaseAllowance { - spender: spender.clone(), - amount: allow1, - expires: None, - }; - let info = mock_info(owner.as_ref(), &[]); - let env = mock_env(); - execute(deps.as_mut(), env, info, msg).unwrap(); - - // valid transfer of part of the allowance - let transfer = Uint128::new(44444); - let msg = ExecuteMsg::TransferFrom { - owner: owner.clone(), - recipient: rcpt.clone(), - amount: transfer, - }; - let info = mock_info(spender.as_ref(), &[]); - let env = mock_env(); - let res = execute(deps.as_mut(), env, info, msg).unwrap(); - assert_eq!(res.attributes[0], attr("action", "transfer_from")); - - // make sure money arrived - assert_eq!( - get_balance(deps.as_ref(), owner.clone()), - start.checked_sub(transfer).unwrap() - ); - assert_eq!(get_balance(deps.as_ref(), rcpt.clone()), transfer); - - // ensure it looks good - let allowance = query_allowance(deps.as_ref(), owner.clone(), spender.clone()).unwrap(); - let expect = AllowanceResponse { - allowance: allow1.checked_sub(transfer).unwrap(), - expires: Expiration::Never {}, - }; - assert_eq!(expect, allowance); - - // cannot send more than the allowance - let msg = ExecuteMsg::TransferFrom { - owner: owner.clone(), - recipient: rcpt.clone(), - amount: Uint128::new(33443), - }; - let info = mock_info(spender.as_ref(), &[]); - let env = mock_env(); - let err = execute(deps.as_mut(), env, info, msg).unwrap_err(); - assert!(matches!(err, ContractError::Std(StdError::Overflow { .. }))); - - // let us increase limit, but set the expiration (default env height is 12_345) - let info = mock_info(owner.as_ref(), &[]); - let env = mock_env(); - let msg = ExecuteMsg::IncreaseAllowance { - spender: spender.clone(), - amount: Uint128::new(1000), - expires: Some(Expiration::AtHeight(env.block.height)), - }; - execute(deps.as_mut(), env, info, msg).unwrap(); - - // we should now get the expiration error - let msg = ExecuteMsg::TransferFrom { - owner, - recipient: rcpt, - amount: Uint128::new(33443), - }; - let info = mock_info(spender.as_ref(), &[]); - let env = mock_env(); - let err = execute(deps.as_mut(), env, info, msg).unwrap_err(); - assert_eq!(err, ContractError::Expired {}); - } - - #[test] - fn burn_from_respects_limits() { - let mut deps = mock_dependencies_with_balance(&[]); - let owner = String::from("addr0001"); - let spender = String::from("addr0002"); - - let start = Uint128::new(999999); - do_instantiate(deps.as_mut(), &owner, start); - - // provide an allowance - let allow1 = Uint128::new(77777); - let msg = ExecuteMsg::IncreaseAllowance { - spender: spender.clone(), - amount: allow1, - expires: None, - }; - let info = mock_info(owner.as_ref(), &[]); - let env = mock_env(); - execute(deps.as_mut(), env, info, msg).unwrap(); - - // valid burn of part of the allowance - let transfer = Uint128::new(44444); - let msg = ExecuteMsg::BurnFrom { - owner: owner.clone(), - amount: transfer, - }; - let info = mock_info(spender.as_ref(), &[]); - let env = mock_env(); - let res = execute(deps.as_mut(), env, info, msg).unwrap(); - assert_eq!(res.attributes[0], attr("action", "burn_from")); - - // make sure money burnt - assert_eq!( - get_balance(deps.as_ref(), owner.clone()), - start.checked_sub(transfer).unwrap() - ); - - // ensure it looks good - let allowance = query_allowance(deps.as_ref(), owner.clone(), spender.clone()).unwrap(); - let expect = AllowanceResponse { - allowance: allow1.checked_sub(transfer).unwrap(), - expires: Expiration::Never {}, - }; - assert_eq!(expect, allowance); - - // cannot burn more than the allowance - let msg = ExecuteMsg::BurnFrom { - owner: owner.clone(), - amount: Uint128::new(33443), - }; - let info = mock_info(spender.as_ref(), &[]); - let env = mock_env(); - let err = execute(deps.as_mut(), env, info, msg).unwrap_err(); - assert!(matches!(err, ContractError::Std(StdError::Overflow { .. }))); - - // let us increase limit, but set the expiration (default env height is 12_345) - let info = mock_info(owner.as_ref(), &[]); - let env = mock_env(); - let msg = ExecuteMsg::IncreaseAllowance { - spender: spender.clone(), - amount: Uint128::new(1000), - expires: Some(Expiration::AtHeight(env.block.height)), - }; - execute(deps.as_mut(), env, info, msg).unwrap(); - - // we should now get the expiration error - let msg = ExecuteMsg::BurnFrom { - owner, - amount: Uint128::new(33443), - }; - let info = mock_info(spender.as_ref(), &[]); - let env = mock_env(); - let err = execute(deps.as_mut(), env, info, msg).unwrap_err(); - assert_eq!(err, ContractError::Expired {}); - } - - #[test] - fn send_from_respects_limits() { - let mut deps = mock_dependencies_with_balance(&[]); - let owner = String::from("addr0001"); - let spender = String::from("addr0002"); - let contract = String::from("cool-dex"); - let send_msg = Binary::from(r#"{"some":123}"#.as_bytes()); - - let start = Uint128::new(999999); - do_instantiate(deps.as_mut(), &owner, start); - - // provide an allowance - let allow1 = Uint128::new(77777); - let msg = ExecuteMsg::IncreaseAllowance { - spender: spender.clone(), - amount: allow1, - expires: None, - }; - let info = mock_info(owner.as_ref(), &[]); - let env = mock_env(); - execute(deps.as_mut(), env, info, msg).unwrap(); - - // valid send of part of the allowance - let transfer = Uint128::new(44444); - let msg = ExecuteMsg::SendFrom { - owner: owner.clone(), - amount: transfer, - contract: contract.clone(), - msg: send_msg.clone(), - }; - let info = mock_info(spender.as_ref(), &[]); - let env = mock_env(); - let res = execute(deps.as_mut(), env, info, msg).unwrap(); - assert_eq!(res.attributes[0], attr("action", "send_from")); - assert_eq!(1, res.messages.len()); - - // we record this as sent by the one who requested, not the one who was paying - let binary_msg = Cw20ReceiveMsg { - sender: spender.clone(), - amount: transfer, - msg: send_msg.clone(), - } - .into_binary() - .unwrap(); - assert_eq!( - res.messages[0], - SubMsg::new(CosmosMsg::Wasm(WasmMsg::Execute { - contract_addr: contract.clone(), - msg: binary_msg, - funds: vec![], - })) - ); - - // make sure money sent - assert_eq!( - get_balance(deps.as_ref(), owner.clone()), - start.checked_sub(transfer).unwrap() - ); - assert_eq!(get_balance(deps.as_ref(), contract.clone()), transfer); - - // ensure it looks good - let allowance = query_allowance(deps.as_ref(), owner.clone(), spender.clone()).unwrap(); - let expect = AllowanceResponse { - allowance: allow1.checked_sub(transfer).unwrap(), - expires: Expiration::Never {}, - }; - assert_eq!(expect, allowance); - - // cannot send more than the allowance - let msg = ExecuteMsg::SendFrom { - owner: owner.clone(), - amount: Uint128::new(33443), - contract: contract.clone(), - msg: send_msg.clone(), - }; - let info = mock_info(spender.as_ref(), &[]); - let env = mock_env(); - let err = execute(deps.as_mut(), env, info, msg).unwrap_err(); - assert!(matches!(err, ContractError::Std(StdError::Overflow { .. }))); - - // let us increase limit, but set the expiration to current block (expired) - let info = mock_info(owner.as_ref(), &[]); - let env = mock_env(); - let msg = ExecuteMsg::IncreaseAllowance { - spender: spender.clone(), - amount: Uint128::new(1000), - expires: Some(Expiration::AtHeight(env.block.height)), - }; - execute(deps.as_mut(), env, info, msg).unwrap(); - - // we should now get the expiration error - let msg = ExecuteMsg::SendFrom { - owner, - amount: Uint128::new(33443), - contract, - msg: send_msg, - }; - let info = mock_info(spender.as_ref(), &[]); - let env = mock_env(); - let err = execute(deps.as_mut(), env, info, msg).unwrap_err(); - assert_eq!(err, ContractError::Expired {}); - } -} diff --git a/cw20/base/src/contract.rs b/cw20/base/src/contract.rs deleted file mode 100644 index 7e999fd..0000000 --- a/cw20/base/src/contract.rs +++ /dev/null @@ -1,1923 +0,0 @@ -#[cfg(not(feature = "library"))] -use cosmwasm_std::entry_point; -use cosmwasm_std::{ - to_binary, Binary, Deps, DepsMut, Env, MessageInfo, Response, StdError, StdResult, Uint128, -}; - -use cw2::set_contract_version; -use cw20::{ - BalanceResponse, Cw20Coin, Cw20ReceiveMsg, DownloadLogoResponse, EmbeddedLogo, Logo, LogoInfo, - MarketingInfoResponse, MinterResponse, TokenInfoResponse, -}; - -use crate::allowances::{ - execute_burn_from, execute_decrease_allowance, execute_increase_allowance, execute_send_from, - execute_transfer_from, query_allowance, -}; -use crate::enumerable::{query_all_accounts, query_all_allowances}; -use crate::error::ContractError; -use crate::msg::{ExecuteMsg, InstantiateMsg, QueryMsg}; -use crate::state::{MinterData, TokenInfo, BALANCES, LOGO, MARKETING_INFO, TOKEN_INFO}; - -// version info for migration info -const CONTRACT_NAME: &str = "crates.io:{{project-name}}"; -const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION"); - -const LOGO_SIZE_CAP: usize = 5 * 1024; - -/// Checks if data starts with XML preamble -fn verify_xml_preamble(data: &[u8]) -> Result<(), ContractError> { - // The easiest way to perform this check would be just match on regex, however regex - // compilation is heavy and probably not worth it. - - let preamble = data - .split_inclusive(|c| *c == b'>') - .next() - .ok_or(ContractError::InvalidXmlPreamble {})?; - - const PREFIX: &[u8] = b""; - - if !(preamble.starts_with(PREFIX) && preamble.ends_with(POSTFIX)) { - Err(ContractError::InvalidXmlPreamble {}) - } else { - Ok(()) - } - - // Additionally attributes format could be validated as they are well defined, as well as - // comments presence inside of preable, but it is probably not worth it. -} - -/// Validates XML logo -fn verify_xml_logo(logo: &[u8]) -> Result<(), ContractError> { - verify_xml_preamble(logo)?; - - if logo.len() > LOGO_SIZE_CAP { - Err(ContractError::LogoTooBig {}) - } else { - Ok(()) - } -} - -/// Validates png logo -fn verify_png_logo(logo: &[u8]) -> Result<(), ContractError> { - // PNG header format: - // 0x89 - magic byte, out of ASCII table to fail on 7-bit systems - // "PNG" ascii representation - // [0x0d, 0x0a] - dos style line ending - // 0x1a - dos control character, stop displaying rest of the file - // 0x0a - unix style line ending - const HEADER: [u8; 8] = [0x89, b'P', b'N', b'G', 0x0d, 0x0a, 0x1a, 0x0a]; - if logo.len() > LOGO_SIZE_CAP { - Err(ContractError::LogoTooBig {}) - } else if !logo.starts_with(&HEADER) { - Err(ContractError::InvalidPngHeader {}) - } else { - Ok(()) - } -} - -/// Checks if passed logo is correct, and if not, returns an error -fn verify_logo(logo: &Logo) -> Result<(), ContractError> { - match logo { - Logo::Embedded(EmbeddedLogo::Svg(logo)) => verify_xml_logo(logo), - Logo::Embedded(EmbeddedLogo::Png(logo)) => verify_png_logo(logo), - Logo::Url(_) => Ok(()), // Any reasonable url validation would be regex based, probably not worth it - } -} - -#[cfg_attr(not(feature = "library"), entry_point)] -pub fn instantiate( - mut deps: DepsMut, - _env: Env, - _info: MessageInfo, - msg: InstantiateMsg, -) -> Result { - set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; - // check valid token info - msg.validate()?; - // create initial accounts - let total_supply = create_accounts(&mut deps, &msg.initial_balances)?; - - if let Some(limit) = msg.get_cap() { - if total_supply > limit { - return Err(StdError::generic_err("Initial supply greater than cap").into()); - } - } - - let mint = match msg.mint { - Some(m) => Some(MinterData { - minter: deps.api.addr_validate(&m.minter)?, - cap: m.cap, - }), - None => None, - }; - - // store token info - let data = TokenInfo { - name: msg.name, - symbol: msg.symbol, - decimals: msg.decimals, - total_supply, - mint, - }; - TOKEN_INFO.save(deps.storage, &data)?; - - if let Some(marketing) = msg.marketing { - let logo = if let Some(logo) = marketing.logo { - verify_logo(&logo)?; - LOGO.save(deps.storage, &logo)?; - - match logo { - Logo::Url(url) => Some(LogoInfo::Url(url)), - Logo::Embedded(_) => Some(LogoInfo::Embedded), - } - } else { - None - }; - - let data = MarketingInfoResponse { - project: marketing.project, - description: marketing.description, - marketing: marketing - .marketing - .map(|addr| deps.api.addr_validate(&addr)) - .transpose()?, - logo, - }; - MARKETING_INFO.save(deps.storage, &data)?; - } - - Ok(Response::default()) -} - -pub fn create_accounts(deps: &mut DepsMut, accounts: &[Cw20Coin]) -> StdResult { - let mut total_supply = Uint128::zero(); - for row in accounts { - let address = deps.api.addr_validate(&row.address)?; - BALANCES.save(deps.storage, &address, &row.amount)?; - total_supply += row.amount; - } - Ok(total_supply) -} - -#[cfg_attr(not(feature = "library"), entry_point)] -pub fn execute( - deps: DepsMut, - env: Env, - info: MessageInfo, - msg: ExecuteMsg, -) -> Result { - match msg { - ExecuteMsg::Transfer { recipient, amount } => { - execute_transfer(deps, env, info, recipient, amount) - } - ExecuteMsg::Burn { amount } => execute_burn(deps, env, info, amount), - ExecuteMsg::Send { - contract, - amount, - msg, - } => execute_send(deps, env, info, contract, amount, msg), - ExecuteMsg::Mint { recipient, amount } => execute_mint(deps, env, info, recipient, amount), - ExecuteMsg::IncreaseAllowance { - spender, - amount, - expires, - } => execute_increase_allowance(deps, env, info, spender, amount, expires), - ExecuteMsg::DecreaseAllowance { - spender, - amount, - expires, - } => execute_decrease_allowance(deps, env, info, spender, amount, expires), - ExecuteMsg::TransferFrom { - owner, - recipient, - amount, - } => execute_transfer_from(deps, env, info, owner, recipient, amount), - ExecuteMsg::BurnFrom { owner, amount } => execute_burn_from(deps, env, info, owner, amount), - ExecuteMsg::SendFrom { - owner, - contract, - amount, - msg, - } => execute_send_from(deps, env, info, owner, contract, amount, msg), - ExecuteMsg::UpdateMarketing { - project, - description, - marketing, - } => execute_update_marketing(deps, env, info, project, description, marketing), - ExecuteMsg::UploadLogo(logo) => execute_upload_logo(deps, env, info, logo), - } -} - -pub fn execute_transfer( - deps: DepsMut, - _env: Env, - info: MessageInfo, - recipient: String, - amount: Uint128, -) -> Result { - if amount == Uint128::zero() { - return Err(ContractError::InvalidZeroAmount {}); - } - - let rcpt_addr = deps.api.addr_validate(&recipient)?; - - BALANCES.update( - deps.storage, - &info.sender, - |balance: Option| -> StdResult<_> { - Ok(balance.unwrap_or_default().checked_sub(amount)?) - }, - )?; - BALANCES.update( - deps.storage, - &rcpt_addr, - |balance: Option| -> StdResult<_> { Ok(balance.unwrap_or_default() + amount) }, - )?; - - let res = Response::new() - .add_attribute("action", "transfer") - .add_attribute("from", info.sender) - .add_attribute("to", recipient) - .add_attribute("amount", amount); - Ok(res) -} - -pub fn execute_burn( - deps: DepsMut, - _env: Env, - info: MessageInfo, - amount: Uint128, -) -> Result { - if amount == Uint128::zero() { - return Err(ContractError::InvalidZeroAmount {}); - } - - // lower balance - BALANCES.update( - deps.storage, - &info.sender, - |balance: Option| -> StdResult<_> { - Ok(balance.unwrap_or_default().checked_sub(amount)?) - }, - )?; - // reduce total_supply - TOKEN_INFO.update(deps.storage, |mut info| -> StdResult<_> { - info.total_supply = info.total_supply.checked_sub(amount)?; - Ok(info) - })?; - - let res = Response::new() - .add_attribute("action", "burn") - .add_attribute("from", info.sender) - .add_attribute("amount", amount); - Ok(res) -} - -pub fn execute_mint( - deps: DepsMut, - _env: Env, - info: MessageInfo, - recipient: String, - amount: Uint128, -) -> Result { - if amount == Uint128::zero() { - return Err(ContractError::InvalidZeroAmount {}); - } - - let mut config = TOKEN_INFO.load(deps.storage)?; - if config.mint.is_none() || config.mint.as_ref().unwrap().minter != info.sender { - return Err(ContractError::Unauthorized {}); - } - - // update supply and enforce cap - config.total_supply += amount; - if let Some(limit) = config.get_cap() { - if config.total_supply > limit { - return Err(ContractError::CannotExceedCap {}); - } - } - TOKEN_INFO.save(deps.storage, &config)?; - - // add amount to recipient balance - let rcpt_addr = deps.api.addr_validate(&recipient)?; - BALANCES.update( - deps.storage, - &rcpt_addr, - |balance: Option| -> StdResult<_> { Ok(balance.unwrap_or_default() + amount) }, - )?; - - let res = Response::new() - .add_attribute("action", "mint") - .add_attribute("to", recipient) - .add_attribute("amount", amount); - Ok(res) -} - -pub fn execute_send( - deps: DepsMut, - _env: Env, - info: MessageInfo, - contract: String, - amount: Uint128, - msg: Binary, -) -> Result { - if amount == Uint128::zero() { - return Err(ContractError::InvalidZeroAmount {}); - } - - let rcpt_addr = deps.api.addr_validate(&contract)?; - - // move the tokens to the contract - BALANCES.update( - deps.storage, - &info.sender, - |balance: Option| -> StdResult<_> { - Ok(balance.unwrap_or_default().checked_sub(amount)?) - }, - )?; - BALANCES.update( - deps.storage, - &rcpt_addr, - |balance: Option| -> StdResult<_> { Ok(balance.unwrap_or_default() + amount) }, - )?; - - let res = Response::new() - .add_attribute("action", "send") - .add_attribute("from", &info.sender) - .add_attribute("to", &contract) - .add_attribute("amount", amount) - .add_message( - Cw20ReceiveMsg { - sender: info.sender.into(), - amount, - msg, - } - .into_cosmos_msg(contract)?, - ); - Ok(res) -} - -pub fn execute_update_marketing( - deps: DepsMut, - _env: Env, - info: MessageInfo, - project: Option, - description: Option, - marketing: Option, -) -> Result { - let mut marketing_info = MARKETING_INFO - .may_load(deps.storage)? - .ok_or(ContractError::Unauthorized {})?; - - if marketing_info - .marketing - .as_ref() - .ok_or(ContractError::Unauthorized {})? - != &info.sender - { - return Err(ContractError::Unauthorized {}); - } - - match project { - Some(empty) if empty.trim().is_empty() => marketing_info.project = None, - Some(project) => marketing_info.project = Some(project), - None => (), - } - - match description { - Some(empty) if empty.trim().is_empty() => marketing_info.description = None, - Some(description) => marketing_info.description = Some(description), - None => (), - } - - match marketing { - Some(empty) if empty.trim().is_empty() => marketing_info.marketing = None, - Some(marketing) => marketing_info.marketing = Some(deps.api.addr_validate(&marketing)?), - None => (), - } - - if marketing_info.project.is_none() - && marketing_info.description.is_none() - && marketing_info.marketing.is_none() - && marketing_info.logo.is_none() - { - MARKETING_INFO.remove(deps.storage); - } else { - MARKETING_INFO.save(deps.storage, &marketing_info)?; - } - - let res = Response::new().add_attribute("action", "update_marketing"); - Ok(res) -} - -pub fn execute_upload_logo( - deps: DepsMut, - _env: Env, - info: MessageInfo, - logo: Logo, -) -> Result { - let mut marketing_info = MARKETING_INFO - .may_load(deps.storage)? - .ok_or(ContractError::Unauthorized {})?; - - verify_logo(&logo)?; - - if marketing_info - .marketing - .as_ref() - .ok_or(ContractError::Unauthorized {})? - != &info.sender - { - return Err(ContractError::Unauthorized {}); - } - - LOGO.save(deps.storage, &logo)?; - - let logo_info = match logo { - Logo::Url(url) => LogoInfo::Url(url), - Logo::Embedded(_) => LogoInfo::Embedded, - }; - - marketing_info.logo = Some(logo_info); - MARKETING_INFO.save(deps.storage, &marketing_info)?; - - let res = Response::new().add_attribute("action", "upload_logo"); - Ok(res) -} - -#[cfg_attr(not(feature = "library"), entry_point)] -pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult { - match msg { - QueryMsg::Balance { address } => to_binary(&query_balance(deps, address)?), - QueryMsg::TokenInfo {} => to_binary(&query_token_info(deps)?), - QueryMsg::Minter {} => to_binary(&query_minter(deps)?), - QueryMsg::Allowance { owner, spender } => { - to_binary(&query_allowance(deps, owner, spender)?) - } - QueryMsg::AllAllowances { - owner, - start_after, - limit, - } => to_binary(&query_all_allowances(deps, owner, start_after, limit)?), - QueryMsg::AllAccounts { start_after, limit } => { - to_binary(&query_all_accounts(deps, start_after, limit)?) - } - QueryMsg::MarketingInfo {} => to_binary(&query_marketing_info(deps)?), - QueryMsg::DownloadLogo {} => to_binary(&query_download_logo(deps)?), - } -} - -pub fn query_balance(deps: Deps, address: String) -> StdResult { - let address = deps.api.addr_validate(&address)?; - let balance = BALANCES - .may_load(deps.storage, &address)? - .unwrap_or_default(); - Ok(BalanceResponse { balance }) -} - -pub fn query_token_info(deps: Deps) -> StdResult { - let info = TOKEN_INFO.load(deps.storage)?; - let res = TokenInfoResponse { - name: info.name, - symbol: info.symbol, - decimals: info.decimals, - total_supply: info.total_supply, - }; - Ok(res) -} - -pub fn query_minter(deps: Deps) -> StdResult> { - let meta = TOKEN_INFO.load(deps.storage)?; - let minter = match meta.mint { - Some(m) => Some(MinterResponse { - minter: m.minter.into(), - cap: m.cap, - }), - None => None, - }; - Ok(minter) -} - -pub fn query_marketing_info(deps: Deps) -> StdResult { - Ok(MARKETING_INFO.may_load(deps.storage)?.unwrap_or_default()) -} - -pub fn query_download_logo(deps: Deps) -> StdResult { - let logo = LOGO.load(deps.storage)?; - match logo { - Logo::Embedded(EmbeddedLogo::Svg(logo)) => Ok(DownloadLogoResponse { - mime_type: "image/svg+xml".to_owned(), - data: logo, - }), - Logo::Embedded(EmbeddedLogo::Png(logo)) => Ok(DownloadLogoResponse { - mime_type: "image/png".to_owned(), - data: logo, - }), - Logo::Url(_) => Err(StdError::not_found("logo")), - } -} - -#[cfg(test)] -mod tests { - use cosmwasm_std::testing::{ - mock_dependencies, mock_dependencies_with_balance, mock_env, mock_info, - }; - use cosmwasm_std::{coins, from_binary, Addr, CosmosMsg, StdError, SubMsg, WasmMsg}; - - use super::*; - use crate::msg::InstantiateMarketingInfo; - - fn get_balance>(deps: Deps, address: T) -> Uint128 { - query_balance(deps, address.into()).unwrap().balance - } - - // this will set up the instantiation for other tests - fn do_instantiate_with_minter( - deps: DepsMut, - addr: &str, - amount: Uint128, - minter: &str, - cap: Option, - ) -> TokenInfoResponse { - _do_instantiate( - deps, - addr, - amount, - Some(MinterResponse { - minter: minter.to_string(), - cap, - }), - ) - } - - // this will set up the instantiation for other tests - fn do_instantiate(deps: DepsMut, addr: &str, amount: Uint128) -> TokenInfoResponse { - _do_instantiate(deps, addr, amount, None) - } - - // this will set up the instantiation for other tests - fn _do_instantiate( - mut deps: DepsMut, - addr: &str, - amount: Uint128, - mint: Option, - ) -> TokenInfoResponse { - let instantiate_msg = InstantiateMsg { - name: "Auto Gen".to_string(), - symbol: "AUTO".to_string(), - decimals: 3, - initial_balances: vec![Cw20Coin { - address: addr.to_string(), - amount, - }], - mint: mint.clone(), - marketing: None, - }; - let info = mock_info("creator", &[]); - let env = mock_env(); - let res = instantiate(deps.branch(), env, info, instantiate_msg).unwrap(); - assert_eq!(0, res.messages.len()); - - let meta = query_token_info(deps.as_ref()).unwrap(); - assert_eq!( - meta, - TokenInfoResponse { - name: "Auto Gen".to_string(), - symbol: "AUTO".to_string(), - decimals: 3, - total_supply: amount, - } - ); - assert_eq!(get_balance(deps.as_ref(), addr), amount); - assert_eq!(query_minter(deps.as_ref()).unwrap(), mint,); - meta - } - - const PNG_HEADER: [u8; 8] = [0x89, b'P', b'N', b'G', 0x0d, 0x0a, 0x1a, 0x0a]; - - mod instantiate { - use super::*; - - #[test] - fn basic() { - let mut deps = mock_dependencies(); - let amount = Uint128::from(11223344u128); - let instantiate_msg = InstantiateMsg { - name: "Cash Token".to_string(), - symbol: "CASH".to_string(), - decimals: 9, - initial_balances: vec![Cw20Coin { - address: String::from("addr0000"), - amount, - }], - mint: None, - marketing: None, - }; - let info = mock_info("creator", &[]); - let env = mock_env(); - let res = instantiate(deps.as_mut(), env, info, instantiate_msg).unwrap(); - assert_eq!(0, res.messages.len()); - - assert_eq!( - query_token_info(deps.as_ref()).unwrap(), - TokenInfoResponse { - name: "Cash Token".to_string(), - symbol: "CASH".to_string(), - decimals: 9, - total_supply: amount, - } - ); - assert_eq!( - get_balance(deps.as_ref(), "addr0000"), - Uint128::new(11223344) - ); - } - - #[test] - fn mintable() { - let mut deps = mock_dependencies(); - let amount = Uint128::new(11223344); - let minter = String::from("asmodat"); - let limit = Uint128::new(511223344); - let instantiate_msg = InstantiateMsg { - name: "Cash Token".to_string(), - symbol: "CASH".to_string(), - decimals: 9, - initial_balances: vec![Cw20Coin { - address: "addr0000".into(), - amount, - }], - mint: Some(MinterResponse { - minter: minter.clone(), - cap: Some(limit), - }), - marketing: None, - }; - let info = mock_info("creator", &[]); - let env = mock_env(); - let res = instantiate(deps.as_mut(), env, info, instantiate_msg).unwrap(); - assert_eq!(0, res.messages.len()); - - assert_eq!( - query_token_info(deps.as_ref()).unwrap(), - TokenInfoResponse { - name: "Cash Token".to_string(), - symbol: "CASH".to_string(), - decimals: 9, - total_supply: amount, - } - ); - assert_eq!( - get_balance(deps.as_ref(), "addr0000"), - Uint128::new(11223344) - ); - assert_eq!( - query_minter(deps.as_ref()).unwrap(), - Some(MinterResponse { - minter, - cap: Some(limit), - }), - ); - } - - #[test] - fn mintable_over_cap() { - let mut deps = mock_dependencies(); - let amount = Uint128::new(11223344); - let minter = String::from("asmodat"); - let limit = Uint128::new(11223300); - let instantiate_msg = InstantiateMsg { - name: "Cash Token".to_string(), - symbol: "CASH".to_string(), - decimals: 9, - initial_balances: vec![Cw20Coin { - address: String::from("addr0000"), - amount, - }], - mint: Some(MinterResponse { - minter, - cap: Some(limit), - }), - marketing: None, - }; - let info = mock_info("creator", &[]); - let env = mock_env(); - let err = instantiate(deps.as_mut(), env, info, instantiate_msg).unwrap_err(); - assert_eq!( - err, - StdError::generic_err("Initial supply greater than cap").into() - ); - } - - mod marketing { - use super::*; - - #[test] - fn basic() { - let mut deps = mock_dependencies(); - let instantiate_msg = InstantiateMsg { - name: "Cash Token".to_string(), - symbol: "CASH".to_string(), - decimals: 9, - initial_balances: vec![], - mint: None, - marketing: Some(InstantiateMarketingInfo { - project: Some("Project".to_owned()), - description: Some("Description".to_owned()), - marketing: Some("marketing".to_owned()), - logo: Some(Logo::Url("url".to_owned())), - }), - }; - - let info = mock_info("creator", &[]); - let env = mock_env(); - let res = instantiate(deps.as_mut(), env, info, instantiate_msg).unwrap(); - assert_eq!(0, res.messages.len()); - - assert_eq!( - query_marketing_info(deps.as_ref()).unwrap(), - MarketingInfoResponse { - project: Some("Project".to_owned()), - description: Some("Description".to_owned()), - marketing: Some(Addr::unchecked("marketing")), - logo: Some(LogoInfo::Url("url".to_owned())), - } - ); - - let err = query_download_logo(deps.as_ref()).unwrap_err(); - assert!( - matches!(err, StdError::NotFound { .. }), - "Expected StdError::NotFound, received {}", - err - ); - } - - #[test] - fn invalid_marketing() { - let mut deps = mock_dependencies(); - let instantiate_msg = InstantiateMsg { - name: "Cash Token".to_string(), - symbol: "CASH".to_string(), - decimals: 9, - initial_balances: vec![], - mint: None, - marketing: Some(InstantiateMarketingInfo { - project: Some("Project".to_owned()), - description: Some("Description".to_owned()), - marketing: Some("m".to_owned()), - logo: Some(Logo::Url("url".to_owned())), - }), - }; - - let info = mock_info("creator", &[]); - let env = mock_env(); - instantiate(deps.as_mut(), env, info, instantiate_msg).unwrap_err(); - - let err = query_download_logo(deps.as_ref()).unwrap_err(); - assert!( - matches!(err, StdError::NotFound { .. }), - "Expected StdError::NotFound, received {}", - err - ); - } - } - } - - #[test] - fn can_mint_by_minter() { - let mut deps = mock_dependencies(); - - let genesis = String::from("genesis"); - let amount = Uint128::new(11223344); - let minter = String::from("asmodat"); - let limit = Uint128::new(511223344); - do_instantiate_with_minter(deps.as_mut(), &genesis, amount, &minter, Some(limit)); - - // minter can mint coins to some winner - let winner = String::from("lucky"); - let prize = Uint128::new(222_222_222); - let msg = ExecuteMsg::Mint { - recipient: winner.clone(), - amount: prize, - }; - - let info = mock_info(minter.as_ref(), &[]); - let env = mock_env(); - let res = execute(deps.as_mut(), env, info, msg).unwrap(); - assert_eq!(0, res.messages.len()); - assert_eq!(get_balance(deps.as_ref(), genesis), amount); - assert_eq!(get_balance(deps.as_ref(), winner.clone()), prize); - - // but cannot mint nothing - let msg = ExecuteMsg::Mint { - recipient: winner.clone(), - amount: Uint128::zero(), - }; - let info = mock_info(minter.as_ref(), &[]); - let env = mock_env(); - let err = execute(deps.as_mut(), env, info, msg).unwrap_err(); - assert_eq!(err, ContractError::InvalidZeroAmount {}); - - // but if it exceeds cap (even over multiple rounds), it fails - // cap is enforced - let msg = ExecuteMsg::Mint { - recipient: winner, - amount: Uint128::new(333_222_222), - }; - let info = mock_info(minter.as_ref(), &[]); - let env = mock_env(); - let err = execute(deps.as_mut(), env, info, msg).unwrap_err(); - assert_eq!(err, ContractError::CannotExceedCap {}); - } - - #[test] - fn others_cannot_mint() { - let mut deps = mock_dependencies(); - do_instantiate_with_minter( - deps.as_mut(), - &String::from("genesis"), - Uint128::new(1234), - &String::from("minter"), - None, - ); - - let msg = ExecuteMsg::Mint { - recipient: String::from("lucky"), - amount: Uint128::new(222), - }; - let info = mock_info("anyone else", &[]); - let env = mock_env(); - let err = execute(deps.as_mut(), env, info, msg).unwrap_err(); - assert_eq!(err, ContractError::Unauthorized {}); - } - - #[test] - fn no_one_mints_if_minter_unset() { - let mut deps = mock_dependencies(); - do_instantiate(deps.as_mut(), &String::from("genesis"), Uint128::new(1234)); - - let msg = ExecuteMsg::Mint { - recipient: String::from("lucky"), - amount: Uint128::new(222), - }; - let info = mock_info("genesis", &[]); - let env = mock_env(); - let err = execute(deps.as_mut(), env, info, msg).unwrap_err(); - assert_eq!(err, ContractError::Unauthorized {}); - } - - #[test] - fn instantiate_multiple_accounts() { - let mut deps = mock_dependencies(); - let amount1 = Uint128::from(11223344u128); - let addr1 = String::from("addr0001"); - let amount2 = Uint128::from(7890987u128); - let addr2 = String::from("addr0002"); - let instantiate_msg = InstantiateMsg { - name: "Bash Shell".to_string(), - symbol: "BASH".to_string(), - decimals: 6, - initial_balances: vec![ - Cw20Coin { - address: addr1.clone(), - amount: amount1, - }, - Cw20Coin { - address: addr2.clone(), - amount: amount2, - }, - ], - mint: None, - marketing: None, - }; - let info = mock_info("creator", &[]); - let env = mock_env(); - let res = instantiate(deps.as_mut(), env, info, instantiate_msg).unwrap(); - assert_eq!(0, res.messages.len()); - - assert_eq!( - query_token_info(deps.as_ref()).unwrap(), - TokenInfoResponse { - name: "Bash Shell".to_string(), - symbol: "BASH".to_string(), - decimals: 6, - total_supply: amount1 + amount2, - } - ); - assert_eq!(get_balance(deps.as_ref(), addr1), amount1); - assert_eq!(get_balance(deps.as_ref(), addr2), amount2); - } - - #[test] - fn queries_work() { - let mut deps = mock_dependencies_with_balance(&coins(2, "token")); - let addr1 = String::from("addr0001"); - let amount1 = Uint128::from(12340000u128); - - let expected = do_instantiate(deps.as_mut(), &addr1, amount1); - - // check meta query - let loaded = query_token_info(deps.as_ref()).unwrap(); - assert_eq!(expected, loaded); - - let _info = mock_info("test", &[]); - let env = mock_env(); - // check balance query (full) - let data = query( - deps.as_ref(), - env.clone(), - QueryMsg::Balance { address: addr1 }, - ) - .unwrap(); - let loaded: BalanceResponse = from_binary(&data).unwrap(); - assert_eq!(loaded.balance, amount1); - - // check balance query (empty) - let data = query( - deps.as_ref(), - env, - QueryMsg::Balance { - address: String::from("addr0002"), - }, - ) - .unwrap(); - let loaded: BalanceResponse = from_binary(&data).unwrap(); - assert_eq!(loaded.balance, Uint128::zero()); - } - - #[test] - fn transfer() { - let mut deps = mock_dependencies_with_balance(&coins(2, "token")); - let addr1 = String::from("addr0001"); - let addr2 = String::from("addr0002"); - let amount1 = Uint128::from(12340000u128); - let transfer = Uint128::from(76543u128); - let too_much = Uint128::from(12340321u128); - - do_instantiate(deps.as_mut(), &addr1, amount1); - - // cannot transfer nothing - let info = mock_info(addr1.as_ref(), &[]); - let env = mock_env(); - let msg = ExecuteMsg::Transfer { - recipient: addr2.clone(), - amount: Uint128::zero(), - }; - let err = execute(deps.as_mut(), env, info, msg).unwrap_err(); - assert_eq!(err, ContractError::InvalidZeroAmount {}); - - // cannot send more than we have - let info = mock_info(addr1.as_ref(), &[]); - let env = mock_env(); - let msg = ExecuteMsg::Transfer { - recipient: addr2.clone(), - amount: too_much, - }; - let err = execute(deps.as_mut(), env, info, msg).unwrap_err(); - assert!(matches!(err, ContractError::Std(StdError::Overflow { .. }))); - - // cannot send from empty account - let info = mock_info(addr2.as_ref(), &[]); - let env = mock_env(); - let msg = ExecuteMsg::Transfer { - recipient: addr1.clone(), - amount: transfer, - }; - let err = execute(deps.as_mut(), env, info, msg).unwrap_err(); - assert!(matches!(err, ContractError::Std(StdError::Overflow { .. }))); - - // valid transfer - let info = mock_info(addr1.as_ref(), &[]); - let env = mock_env(); - let msg = ExecuteMsg::Transfer { - recipient: addr2.clone(), - amount: transfer, - }; - let res = execute(deps.as_mut(), env, info, msg).unwrap(); - assert_eq!(res.messages.len(), 0); - - let remainder = amount1.checked_sub(transfer).unwrap(); - assert_eq!(get_balance(deps.as_ref(), addr1), remainder); - assert_eq!(get_balance(deps.as_ref(), addr2), transfer); - assert_eq!( - query_token_info(deps.as_ref()).unwrap().total_supply, - amount1 - ); - } - - #[test] - fn burn() { - let mut deps = mock_dependencies_with_balance(&coins(2, "token")); - let addr1 = String::from("addr0001"); - let amount1 = Uint128::from(12340000u128); - let burn = Uint128::from(76543u128); - let too_much = Uint128::from(12340321u128); - - do_instantiate(deps.as_mut(), &addr1, amount1); - - // cannot burn nothing - let info = mock_info(addr1.as_ref(), &[]); - let env = mock_env(); - let msg = ExecuteMsg::Burn { - amount: Uint128::zero(), - }; - let err = execute(deps.as_mut(), env, info, msg).unwrap_err(); - assert_eq!(err, ContractError::InvalidZeroAmount {}); - assert_eq!( - query_token_info(deps.as_ref()).unwrap().total_supply, - amount1 - ); - - // cannot burn more than we have - let info = mock_info(addr1.as_ref(), &[]); - let env = mock_env(); - let msg = ExecuteMsg::Burn { amount: too_much }; - let err = execute(deps.as_mut(), env, info, msg).unwrap_err(); - assert!(matches!(err, ContractError::Std(StdError::Overflow { .. }))); - assert_eq!( - query_token_info(deps.as_ref()).unwrap().total_supply, - amount1 - ); - - // valid burn reduces total supply - let info = mock_info(addr1.as_ref(), &[]); - let env = mock_env(); - let msg = ExecuteMsg::Burn { amount: burn }; - let res = execute(deps.as_mut(), env, info, msg).unwrap(); - assert_eq!(res.messages.len(), 0); - - let remainder = amount1.checked_sub(burn).unwrap(); - assert_eq!(get_balance(deps.as_ref(), addr1), remainder); - assert_eq!( - query_token_info(deps.as_ref()).unwrap().total_supply, - remainder - ); - } - - #[test] - fn send() { - let mut deps = mock_dependencies_with_balance(&coins(2, "token")); - let addr1 = String::from("addr0001"); - let contract = String::from("addr0002"); - let amount1 = Uint128::from(12340000u128); - let transfer = Uint128::from(76543u128); - let too_much = Uint128::from(12340321u128); - let send_msg = Binary::from(r#"{"some":123}"#.as_bytes()); - - do_instantiate(deps.as_mut(), &addr1, amount1); - - // cannot send nothing - let info = mock_info(addr1.as_ref(), &[]); - let env = mock_env(); - let msg = ExecuteMsg::Send { - contract: contract.clone(), - amount: Uint128::zero(), - msg: send_msg.clone(), - }; - let err = execute(deps.as_mut(), env, info, msg).unwrap_err(); - assert_eq!(err, ContractError::InvalidZeroAmount {}); - - // cannot send more than we have - let info = mock_info(addr1.as_ref(), &[]); - let env = mock_env(); - let msg = ExecuteMsg::Send { - contract: contract.clone(), - amount: too_much, - msg: send_msg.clone(), - }; - let err = execute(deps.as_mut(), env, info, msg).unwrap_err(); - assert!(matches!(err, ContractError::Std(StdError::Overflow { .. }))); - - // valid transfer - let info = mock_info(addr1.as_ref(), &[]); - let env = mock_env(); - let msg = ExecuteMsg::Send { - contract: contract.clone(), - amount: transfer, - msg: send_msg.clone(), - }; - let res = execute(deps.as_mut(), env, info, msg).unwrap(); - assert_eq!(res.messages.len(), 1); - - // ensure proper send message sent - // this is the message we want delivered to the other side - let binary_msg = Cw20ReceiveMsg { - sender: addr1.clone(), - amount: transfer, - msg: send_msg, - } - .into_binary() - .unwrap(); - // and this is how it must be wrapped for the vm to process it - assert_eq!( - res.messages[0], - SubMsg::new(CosmosMsg::Wasm(WasmMsg::Execute { - contract_addr: contract.clone(), - msg: binary_msg, - funds: vec![], - })) - ); - - // ensure balance is properly transferred - let remainder = amount1.checked_sub(transfer).unwrap(); - assert_eq!(get_balance(deps.as_ref(), addr1), remainder); - assert_eq!(get_balance(deps.as_ref(), contract), transfer); - assert_eq!( - query_token_info(deps.as_ref()).unwrap().total_supply, - amount1 - ); - } - - mod marketing { - use super::*; - - #[test] - fn update_unauthorised() { - let mut deps = mock_dependencies(); - let instantiate_msg = InstantiateMsg { - name: "Cash Token".to_string(), - symbol: "CASH".to_string(), - decimals: 9, - initial_balances: vec![], - mint: None, - marketing: Some(InstantiateMarketingInfo { - project: Some("Project".to_owned()), - description: Some("Description".to_owned()), - marketing: Some("marketing".to_owned()), - logo: Some(Logo::Url("url".to_owned())), - }), - }; - - let info = mock_info("creator", &[]); - - instantiate(deps.as_mut(), mock_env(), info.clone(), instantiate_msg).unwrap(); - - let err = execute( - deps.as_mut(), - mock_env(), - info, - ExecuteMsg::UpdateMarketing { - project: Some("New project".to_owned()), - description: Some("Better description".to_owned()), - marketing: Some("creator".to_owned()), - }, - ) - .unwrap_err(); - - assert_eq!(err, ContractError::Unauthorized {}); - - // Ensure marketing didn't change - assert_eq!( - query_marketing_info(deps.as_ref()).unwrap(), - MarketingInfoResponse { - project: Some("Project".to_owned()), - description: Some("Description".to_owned()), - marketing: Some(Addr::unchecked("marketing")), - logo: Some(LogoInfo::Url("url".to_owned())), - } - ); - - let err = query_download_logo(deps.as_ref()).unwrap_err(); - assert!( - matches!(err, StdError::NotFound { .. }), - "Expected StdError::NotFound, received {}", - err - ); - } - - #[test] - fn update_project() { - let mut deps = mock_dependencies(); - let instantiate_msg = InstantiateMsg { - name: "Cash Token".to_string(), - symbol: "CASH".to_string(), - decimals: 9, - initial_balances: vec![], - mint: None, - marketing: Some(InstantiateMarketingInfo { - project: Some("Project".to_owned()), - description: Some("Description".to_owned()), - marketing: Some("creator".to_owned()), - logo: Some(Logo::Url("url".to_owned())), - }), - }; - - let info = mock_info("creator", &[]); - - instantiate(deps.as_mut(), mock_env(), info.clone(), instantiate_msg).unwrap(); - - let res = execute( - deps.as_mut(), - mock_env(), - info, - ExecuteMsg::UpdateMarketing { - project: Some("New project".to_owned()), - description: None, - marketing: None, - }, - ) - .unwrap(); - - assert_eq!(res.messages, vec![]); - - assert_eq!( - query_marketing_info(deps.as_ref()).unwrap(), - MarketingInfoResponse { - project: Some("New project".to_owned()), - description: Some("Description".to_owned()), - marketing: Some(Addr::unchecked("creator")), - logo: Some(LogoInfo::Url("url".to_owned())), - } - ); - - let err = query_download_logo(deps.as_ref()).unwrap_err(); - assert!( - matches!(err, StdError::NotFound { .. }), - "Expected StdError::NotFound, received {}", - err - ); - } - - #[test] - fn clear_project() { - let mut deps = mock_dependencies(); - let instantiate_msg = InstantiateMsg { - name: "Cash Token".to_string(), - symbol: "CASH".to_string(), - decimals: 9, - initial_balances: vec![], - mint: None, - marketing: Some(InstantiateMarketingInfo { - project: Some("Project".to_owned()), - description: Some("Description".to_owned()), - marketing: Some("creator".to_owned()), - logo: Some(Logo::Url("url".to_owned())), - }), - }; - - let info = mock_info("creator", &[]); - - instantiate(deps.as_mut(), mock_env(), info.clone(), instantiate_msg).unwrap(); - - let res = execute( - deps.as_mut(), - mock_env(), - info, - ExecuteMsg::UpdateMarketing { - project: Some("".to_owned()), - description: None, - marketing: None, - }, - ) - .unwrap(); - - assert_eq!(res.messages, vec![]); - - assert_eq!( - query_marketing_info(deps.as_ref()).unwrap(), - MarketingInfoResponse { - project: None, - description: Some("Description".to_owned()), - marketing: Some(Addr::unchecked("creator")), - logo: Some(LogoInfo::Url("url".to_owned())), - } - ); - - let err = query_download_logo(deps.as_ref()).unwrap_err(); - assert!( - matches!(err, StdError::NotFound { .. }), - "Expected StdError::NotFound, received {}", - err - ); - } - - #[test] - fn update_description() { - let mut deps = mock_dependencies(); - let instantiate_msg = InstantiateMsg { - name: "Cash Token".to_string(), - symbol: "CASH".to_string(), - decimals: 9, - initial_balances: vec![], - mint: None, - marketing: Some(InstantiateMarketingInfo { - project: Some("Project".to_owned()), - description: Some("Description".to_owned()), - marketing: Some("creator".to_owned()), - logo: Some(Logo::Url("url".to_owned())), - }), - }; - - let info = mock_info("creator", &[]); - - instantiate(deps.as_mut(), mock_env(), info.clone(), instantiate_msg).unwrap(); - - let res = execute( - deps.as_mut(), - mock_env(), - info, - ExecuteMsg::UpdateMarketing { - project: None, - description: Some("Better description".to_owned()), - marketing: None, - }, - ) - .unwrap(); - - assert_eq!(res.messages, vec![]); - - assert_eq!( - query_marketing_info(deps.as_ref()).unwrap(), - MarketingInfoResponse { - project: Some("Project".to_owned()), - description: Some("Better description".to_owned()), - marketing: Some(Addr::unchecked("creator")), - logo: Some(LogoInfo::Url("url".to_owned())), - } - ); - - let err = query_download_logo(deps.as_ref()).unwrap_err(); - assert!( - matches!(err, StdError::NotFound { .. }), - "Expected StdError::NotFound, received {}", - err - ); - } - - #[test] - fn clear_description() { - let mut deps = mock_dependencies(); - let instantiate_msg = InstantiateMsg { - name: "Cash Token".to_string(), - symbol: "CASH".to_string(), - decimals: 9, - initial_balances: vec![], - mint: None, - marketing: Some(InstantiateMarketingInfo { - project: Some("Project".to_owned()), - description: Some("Description".to_owned()), - marketing: Some("creator".to_owned()), - logo: Some(Logo::Url("url".to_owned())), - }), - }; - - let info = mock_info("creator", &[]); - - instantiate(deps.as_mut(), mock_env(), info.clone(), instantiate_msg).unwrap(); - - let res = execute( - deps.as_mut(), - mock_env(), - info, - ExecuteMsg::UpdateMarketing { - project: None, - description: Some("".to_owned()), - marketing: None, - }, - ) - .unwrap(); - - assert_eq!(res.messages, vec![]); - - assert_eq!( - query_marketing_info(deps.as_ref()).unwrap(), - MarketingInfoResponse { - project: Some("Project".to_owned()), - description: None, - marketing: Some(Addr::unchecked("creator")), - logo: Some(LogoInfo::Url("url".to_owned())), - } - ); - - let err = query_download_logo(deps.as_ref()).unwrap_err(); - assert!( - matches!(err, StdError::NotFound { .. }), - "Expected StdError::NotFound, received {}", - err - ); - } - - #[test] - fn update_marketing() { - let mut deps = mock_dependencies(); - let instantiate_msg = InstantiateMsg { - name: "Cash Token".to_string(), - symbol: "CASH".to_string(), - decimals: 9, - initial_balances: vec![], - mint: None, - marketing: Some(InstantiateMarketingInfo { - project: Some("Project".to_owned()), - description: Some("Description".to_owned()), - marketing: Some("creator".to_owned()), - logo: Some(Logo::Url("url".to_owned())), - }), - }; - - let info = mock_info("creator", &[]); - - instantiate(deps.as_mut(), mock_env(), info.clone(), instantiate_msg).unwrap(); - - let res = execute( - deps.as_mut(), - mock_env(), - info, - ExecuteMsg::UpdateMarketing { - project: None, - description: None, - marketing: Some("marketing".to_owned()), - }, - ) - .unwrap(); - - assert_eq!(res.messages, vec![]); - - assert_eq!( - query_marketing_info(deps.as_ref()).unwrap(), - MarketingInfoResponse { - project: Some("Project".to_owned()), - description: Some("Description".to_owned()), - marketing: Some(Addr::unchecked("marketing")), - logo: Some(LogoInfo::Url("url".to_owned())), - } - ); - - let err = query_download_logo(deps.as_ref()).unwrap_err(); - assert!( - matches!(err, StdError::NotFound { .. }), - "Expected StdError::NotFound, received {}", - err - ); - } - - #[test] - fn update_marketing_invalid() { - let mut deps = mock_dependencies(); - let instantiate_msg = InstantiateMsg { - name: "Cash Token".to_string(), - symbol: "CASH".to_string(), - decimals: 9, - initial_balances: vec![], - mint: None, - marketing: Some(InstantiateMarketingInfo { - project: Some("Project".to_owned()), - description: Some("Description".to_owned()), - marketing: Some("creator".to_owned()), - logo: Some(Logo::Url("url".to_owned())), - }), - }; - - let info = mock_info("creator", &[]); - - instantiate(deps.as_mut(), mock_env(), info.clone(), instantiate_msg).unwrap(); - - let err = execute( - deps.as_mut(), - mock_env(), - info, - ExecuteMsg::UpdateMarketing { - project: None, - description: None, - marketing: Some("m".to_owned()), - }, - ) - .unwrap_err(); - - assert!( - matches!(err, ContractError::Std(_)), - "Expected Std error, received: {}", - err - ); - - assert_eq!( - query_marketing_info(deps.as_ref()).unwrap(), - MarketingInfoResponse { - project: Some("Project".to_owned()), - description: Some("Description".to_owned()), - marketing: Some(Addr::unchecked("creator")), - logo: Some(LogoInfo::Url("url".to_owned())), - } - ); - - let err = query_download_logo(deps.as_ref()).unwrap_err(); - assert!( - matches!(err, StdError::NotFound { .. }), - "Expected StdError::NotFound, received {}", - err - ); - } - - #[test] - fn clear_marketing() { - let mut deps = mock_dependencies(); - let instantiate_msg = InstantiateMsg { - name: "Cash Token".to_string(), - symbol: "CASH".to_string(), - decimals: 9, - initial_balances: vec![], - mint: None, - marketing: Some(InstantiateMarketingInfo { - project: Some("Project".to_owned()), - description: Some("Description".to_owned()), - marketing: Some("creator".to_owned()), - logo: Some(Logo::Url("url".to_owned())), - }), - }; - - let info = mock_info("creator", &[]); - - instantiate(deps.as_mut(), mock_env(), info.clone(), instantiate_msg).unwrap(); - - let res = execute( - deps.as_mut(), - mock_env(), - info, - ExecuteMsg::UpdateMarketing { - project: None, - description: None, - marketing: Some("".to_owned()), - }, - ) - .unwrap(); - - assert_eq!(res.messages, vec![]); - - assert_eq!( - query_marketing_info(deps.as_ref()).unwrap(), - MarketingInfoResponse { - project: Some("Project".to_owned()), - description: Some("Description".to_owned()), - marketing: None, - logo: Some(LogoInfo::Url("url".to_owned())), - } - ); - - let err = query_download_logo(deps.as_ref()).unwrap_err(); - assert!( - matches!(err, StdError::NotFound { .. }), - "Expected StdError::NotFound, received {}", - err - ); - } - - #[test] - fn update_logo_url() { - let mut deps = mock_dependencies(); - let instantiate_msg = InstantiateMsg { - name: "Cash Token".to_string(), - symbol: "CASH".to_string(), - decimals: 9, - initial_balances: vec![], - mint: None, - marketing: Some(InstantiateMarketingInfo { - project: Some("Project".to_owned()), - description: Some("Description".to_owned()), - marketing: Some("creator".to_owned()), - logo: Some(Logo::Url("url".to_owned())), - }), - }; - - let info = mock_info("creator", &[]); - - instantiate(deps.as_mut(), mock_env(), info.clone(), instantiate_msg).unwrap(); - - let res = execute( - deps.as_mut(), - mock_env(), - info, - ExecuteMsg::UploadLogo(Logo::Url("new_url".to_owned())), - ) - .unwrap(); - - assert_eq!(res.messages, vec![]); - - assert_eq!( - query_marketing_info(deps.as_ref()).unwrap(), - MarketingInfoResponse { - project: Some("Project".to_owned()), - description: Some("Description".to_owned()), - marketing: Some(Addr::unchecked("creator")), - logo: Some(LogoInfo::Url("new_url".to_owned())), - } - ); - - let err = query_download_logo(deps.as_ref()).unwrap_err(); - assert!( - matches!(err, StdError::NotFound { .. }), - "Expected StdError::NotFound, received {}", - err - ); - } - - #[test] - fn update_logo_png() { - let mut deps = mock_dependencies(); - let instantiate_msg = InstantiateMsg { - name: "Cash Token".to_string(), - symbol: "CASH".to_string(), - decimals: 9, - initial_balances: vec![], - mint: None, - marketing: Some(InstantiateMarketingInfo { - project: Some("Project".to_owned()), - description: Some("Description".to_owned()), - marketing: Some("creator".to_owned()), - logo: Some(Logo::Url("url".to_owned())), - }), - }; - - let info = mock_info("creator", &[]); - - instantiate(deps.as_mut(), mock_env(), info.clone(), instantiate_msg).unwrap(); - - let res = execute( - deps.as_mut(), - mock_env(), - info, - ExecuteMsg::UploadLogo(Logo::Embedded(EmbeddedLogo::Png(PNG_HEADER.into()))), - ) - .unwrap(); - - assert_eq!(res.messages, vec![]); - - assert_eq!( - query_marketing_info(deps.as_ref()).unwrap(), - MarketingInfoResponse { - project: Some("Project".to_owned()), - description: Some("Description".to_owned()), - marketing: Some(Addr::unchecked("creator")), - logo: Some(LogoInfo::Embedded), - } - ); - - assert_eq!( - query_download_logo(deps.as_ref()).unwrap(), - DownloadLogoResponse { - mime_type: "image/png".to_owned(), - data: PNG_HEADER.into(), - } - ); - } - - #[test] - fn update_logo_svg() { - let mut deps = mock_dependencies(); - let instantiate_msg = InstantiateMsg { - name: "Cash Token".to_string(), - symbol: "CASH".to_string(), - decimals: 9, - initial_balances: vec![], - mint: None, - marketing: Some(InstantiateMarketingInfo { - project: Some("Project".to_owned()), - description: Some("Description".to_owned()), - marketing: Some("creator".to_owned()), - logo: Some(Logo::Url("url".to_owned())), - }), - }; - - let info = mock_info("creator", &[]); - - instantiate(deps.as_mut(), mock_env(), info.clone(), instantiate_msg).unwrap(); - - let img = "".as_bytes(); - let res = execute( - deps.as_mut(), - mock_env(), - info, - ExecuteMsg::UploadLogo(Logo::Embedded(EmbeddedLogo::Svg(img.into()))), - ) - .unwrap(); - - assert_eq!(res.messages, vec![]); - - assert_eq!( - query_marketing_info(deps.as_ref()).unwrap(), - MarketingInfoResponse { - project: Some("Project".to_owned()), - description: Some("Description".to_owned()), - marketing: Some(Addr::unchecked("creator")), - logo: Some(LogoInfo::Embedded), - } - ); - - assert_eq!( - query_download_logo(deps.as_ref()).unwrap(), - DownloadLogoResponse { - mime_type: "image/svg+xml".to_owned(), - data: img.into(), - } - ); - } - - #[test] - fn update_logo_png_oversized() { - let mut deps = mock_dependencies(); - let instantiate_msg = InstantiateMsg { - name: "Cash Token".to_string(), - symbol: "CASH".to_string(), - decimals: 9, - initial_balances: vec![], - mint: None, - marketing: Some(InstantiateMarketingInfo { - project: Some("Project".to_owned()), - description: Some("Description".to_owned()), - marketing: Some("creator".to_owned()), - logo: Some(Logo::Url("url".to_owned())), - }), - }; - - let info = mock_info("creator", &[]); - - instantiate(deps.as_mut(), mock_env(), info.clone(), instantiate_msg).unwrap(); - - let img = [&PNG_HEADER[..], &[1; 6000][..]].concat(); - let err = execute( - deps.as_mut(), - mock_env(), - info, - ExecuteMsg::UploadLogo(Logo::Embedded(EmbeddedLogo::Png(img.into()))), - ) - .unwrap_err(); - - assert_eq!(err, ContractError::LogoTooBig {}); - - assert_eq!( - query_marketing_info(deps.as_ref()).unwrap(), - MarketingInfoResponse { - project: Some("Project".to_owned()), - description: Some("Description".to_owned()), - marketing: Some(Addr::unchecked("creator")), - logo: Some(LogoInfo::Url("url".to_owned())), - } - ); - - let err = query_download_logo(deps.as_ref()).unwrap_err(); - assert!( - matches!(err, StdError::NotFound { .. }), - "Expected StdError::NotFound, received {}", - err - ); - } - - #[test] - fn update_logo_svg_oversized() { - let mut deps = mock_dependencies(); - let instantiate_msg = InstantiateMsg { - name: "Cash Token".to_string(), - symbol: "CASH".to_string(), - decimals: 9, - initial_balances: vec![], - mint: None, - marketing: Some(InstantiateMarketingInfo { - project: Some("Project".to_owned()), - description: Some("Description".to_owned()), - marketing: Some("creator".to_owned()), - logo: Some(Logo::Url("url".to_owned())), - }), - }; - - let info = mock_info("creator", &[]); - - instantiate(deps.as_mut(), mock_env(), info.clone(), instantiate_msg).unwrap(); - - let img = [ - "", - std::str::from_utf8(&[b'x'; 6000]).unwrap(), - "", - ] - .concat() - .into_bytes(); - - let err = execute( - deps.as_mut(), - mock_env(), - info, - ExecuteMsg::UploadLogo(Logo::Embedded(EmbeddedLogo::Svg(img.into()))), - ) - .unwrap_err(); - - assert_eq!(err, ContractError::LogoTooBig {}); - - assert_eq!( - query_marketing_info(deps.as_ref()).unwrap(), - MarketingInfoResponse { - project: Some("Project".to_owned()), - description: Some("Description".to_owned()), - marketing: Some(Addr::unchecked("creator")), - logo: Some(LogoInfo::Url("url".to_owned())), - } - ); - - let err = query_download_logo(deps.as_ref()).unwrap_err(); - assert!( - matches!(err, StdError::NotFound { .. }), - "Expected StdError::NotFound, received {}", - err - ); - } - - #[test] - fn update_logo_png_invalid() { - let mut deps = mock_dependencies(); - let instantiate_msg = InstantiateMsg { - name: "Cash Token".to_string(), - symbol: "CASH".to_string(), - decimals: 9, - initial_balances: vec![], - mint: None, - marketing: Some(InstantiateMarketingInfo { - project: Some("Project".to_owned()), - description: Some("Description".to_owned()), - marketing: Some("creator".to_owned()), - logo: Some(Logo::Url("url".to_owned())), - }), - }; - - let info = mock_info("creator", &[]); - - instantiate(deps.as_mut(), mock_env(), info.clone(), instantiate_msg).unwrap(); - - let img = &[1]; - let err = execute( - deps.as_mut(), - mock_env(), - info, - ExecuteMsg::UploadLogo(Logo::Embedded(EmbeddedLogo::Png(img.into()))), - ) - .unwrap_err(); - - assert_eq!(err, ContractError::InvalidPngHeader {}); - - assert_eq!( - query_marketing_info(deps.as_ref()).unwrap(), - MarketingInfoResponse { - project: Some("Project".to_owned()), - description: Some("Description".to_owned()), - marketing: Some(Addr::unchecked("creator")), - logo: Some(LogoInfo::Url("url".to_owned())), - } - ); - - let err = query_download_logo(deps.as_ref()).unwrap_err(); - assert!( - matches!(err, StdError::NotFound { .. }), - "Expected StdError::NotFound, received {}", - err - ); - } - - #[test] - fn update_logo_svg_invalid() { - let mut deps = mock_dependencies(); - let instantiate_msg = InstantiateMsg { - name: "Cash Token".to_string(), - symbol: "CASH".to_string(), - decimals: 9, - initial_balances: vec![], - mint: None, - marketing: Some(InstantiateMarketingInfo { - project: Some("Project".to_owned()), - description: Some("Description".to_owned()), - marketing: Some("creator".to_owned()), - logo: Some(Logo::Url("url".to_owned())), - }), - }; - - let info = mock_info("creator", &[]); - - instantiate(deps.as_mut(), mock_env(), info.clone(), instantiate_msg).unwrap(); - - let img = &[1]; - - let err = execute( - deps.as_mut(), - mock_env(), - info, - ExecuteMsg::UploadLogo(Logo::Embedded(EmbeddedLogo::Svg(img.into()))), - ) - .unwrap_err(); - - assert_eq!(err, ContractError::InvalidXmlPreamble {}); - - assert_eq!( - query_marketing_info(deps.as_ref()).unwrap(), - MarketingInfoResponse { - project: Some("Project".to_owned()), - description: Some("Description".to_owned()), - marketing: Some(Addr::unchecked("creator")), - logo: Some(LogoInfo::Url("url".to_owned())), - } - ); - - let err = query_download_logo(deps.as_ref()).unwrap_err(); - assert!( - matches!(err, StdError::NotFound { .. }), - "Expected StdError::NotFound, received {}", - err - ); - } - } -} diff --git a/cw20/base/src/enumerable.rs b/cw20/base/src/enumerable.rs deleted file mode 100644 index 7f7991c..0000000 --- a/cw20/base/src/enumerable.rs +++ /dev/null @@ -1,210 +0,0 @@ -use cosmwasm_std::{Deps, Order, StdResult}; -use cw20::{AllAccountsResponse, AllAllowancesResponse, AllowanceInfo}; - -use crate::state::{ALLOWANCES, BALANCES}; -use cw_storage_plus::Bound; - -// settings for pagination -const MAX_LIMIT: u32 = 30; -const DEFAULT_LIMIT: u32 = 10; - -pub fn query_all_allowances( - deps: Deps, - owner: String, - start_after: Option, - limit: Option, -) -> StdResult { - let owner_addr = deps.api.addr_validate(&owner)?; - let limit = limit.unwrap_or(DEFAULT_LIMIT).min(MAX_LIMIT) as usize; - let start = start_after.map(|s| Bound::ExclusiveRaw(s.into_bytes())); - - let allowances = ALLOWANCES - .prefix(&owner_addr) - .range(deps.storage, start, None, Order::Ascending) - .take(limit) - .map(|item| { - item.map(|(addr, allow)| AllowanceInfo { - spender: addr.into(), - allowance: allow.allowance, - expires: allow.expires, - }) - }) - .collect::>()?; - Ok(AllAllowancesResponse { allowances }) -} - -pub fn query_all_accounts( - deps: Deps, - start_after: Option, - limit: Option, -) -> StdResult { - let limit = limit.unwrap_or(DEFAULT_LIMIT).min(MAX_LIMIT) as usize; - let start = start_after.map(|s| Bound::ExclusiveRaw(s.into())); - - let accounts = BALANCES - .keys(deps.storage, start, None, Order::Ascending) - .take(limit) - .map(|item| item.map(Into::into)) - .collect::>()?; - - Ok(AllAccountsResponse { accounts }) -} - -#[cfg(test)] -mod tests { - use super::*; - - use cosmwasm_std::testing::{mock_dependencies_with_balance, mock_env, mock_info}; - use cosmwasm_std::{coins, DepsMut, Uint128}; - use cw20::{Cw20Coin, Expiration, TokenInfoResponse}; - - use crate::contract::{execute, instantiate, query_token_info}; - use crate::msg::{ExecuteMsg, InstantiateMsg}; - - // this will set up the instantiation for other tests - fn do_instantiate(mut deps: DepsMut, addr: &str, amount: Uint128) -> TokenInfoResponse { - let instantiate_msg = InstantiateMsg { - name: "Auto Gen".to_string(), - symbol: "AUTO".to_string(), - decimals: 3, - initial_balances: vec![Cw20Coin { - address: addr.into(), - amount, - }], - mint: None, - marketing: None, - }; - let info = mock_info("creator", &[]); - let env = mock_env(); - instantiate(deps.branch(), env, info, instantiate_msg).unwrap(); - query_token_info(deps.as_ref()).unwrap() - } - - #[test] - fn query_all_allowances_works() { - let mut deps = mock_dependencies_with_balance(&coins(2, "token")); - - let owner = String::from("owner"); - // these are in alphabetical order same than insert order - let spender1 = String::from("earlier"); - let spender2 = String::from("later"); - - let info = mock_info(owner.as_ref(), &[]); - let env = mock_env(); - do_instantiate(deps.as_mut(), &owner, Uint128::new(12340000)); - - // no allowance to start - let allowances = query_all_allowances(deps.as_ref(), owner.clone(), None, None).unwrap(); - assert_eq!(allowances.allowances, vec![]); - - // set allowance with height expiration - let allow1 = Uint128::new(7777); - let expires = Expiration::AtHeight(5432); - let msg = ExecuteMsg::IncreaseAllowance { - spender: spender1.clone(), - amount: allow1, - expires: Some(expires), - }; - execute(deps.as_mut(), env.clone(), info.clone(), msg).unwrap(); - - // set allowance with no expiration - let allow2 = Uint128::new(54321); - let msg = ExecuteMsg::IncreaseAllowance { - spender: spender2.clone(), - amount: allow2, - expires: None, - }; - execute(deps.as_mut(), env, info, msg).unwrap(); - - // query list gets 2 - let allowances = query_all_allowances(deps.as_ref(), owner.clone(), None, None).unwrap(); - assert_eq!(allowances.allowances.len(), 2); - - // first one is spender1 (order of CanonicalAddr uncorrelated with String) - let allowances = query_all_allowances(deps.as_ref(), owner.clone(), None, Some(1)).unwrap(); - assert_eq!(allowances.allowances.len(), 1); - let allow = &allowances.allowances[0]; - assert_eq!(&allow.spender, &spender1); - assert_eq!(&allow.expires, &expires); - assert_eq!(&allow.allowance, &allow1); - - // next one is spender2 - let allowances = query_all_allowances( - deps.as_ref(), - owner, - Some(allow.spender.clone()), - Some(10000), - ) - .unwrap(); - assert_eq!(allowances.allowances.len(), 1); - let allow = &allowances.allowances[0]; - assert_eq!(&allow.spender, &spender2); - assert_eq!(&allow.expires, &Expiration::Never {}); - assert_eq!(&allow.allowance, &allow2); - } - - #[test] - fn query_all_accounts_works() { - let mut deps = mock_dependencies_with_balance(&coins(2, "token")); - - // insert order and lexicographical order are different - let acct1 = String::from("acct01"); - let acct2 = String::from("zebra"); - let acct3 = String::from("nice"); - let acct4 = String::from("aaaardvark"); - let expected_order = [acct4.clone(), acct1.clone(), acct3.clone(), acct2.clone()]; - - do_instantiate(deps.as_mut(), &acct1, Uint128::new(12340000)); - - // put money everywhere (to create balanaces) - let info = mock_info(acct1.as_ref(), &[]); - let env = mock_env(); - execute( - deps.as_mut(), - env.clone(), - info.clone(), - ExecuteMsg::Transfer { - recipient: acct2, - amount: Uint128::new(222222), - }, - ) - .unwrap(); - execute( - deps.as_mut(), - env.clone(), - info.clone(), - ExecuteMsg::Transfer { - recipient: acct3, - amount: Uint128::new(333333), - }, - ) - .unwrap(); - execute( - deps.as_mut(), - env, - info, - ExecuteMsg::Transfer { - recipient: acct4, - amount: Uint128::new(444444), - }, - ) - .unwrap(); - - // make sure we get the proper results - let accounts = query_all_accounts(deps.as_ref(), None, None).unwrap(); - assert_eq!(accounts.accounts, expected_order); - - // let's do pagination - let accounts = query_all_accounts(deps.as_ref(), None, Some(2)).unwrap(); - assert_eq!(accounts.accounts, expected_order[0..2].to_vec()); - - let accounts = - query_all_accounts(deps.as_ref(), Some(accounts.accounts[1].clone()), Some(1)).unwrap(); - assert_eq!(accounts.accounts, expected_order[2..3].to_vec()); - - let accounts = - query_all_accounts(deps.as_ref(), Some(accounts.accounts[0].clone()), Some(777)) - .unwrap(); - assert_eq!(accounts.accounts, expected_order[3..].to_vec()); - } -} diff --git a/cw20/base/src/error.rs b/cw20/base/src/error.rs deleted file mode 100644 index 264f375..0000000 --- a/cw20/base/src/error.rs +++ /dev/null @@ -1,35 +0,0 @@ -use cosmwasm_std::StdError; -use thiserror::Error; - -#[derive(Error, Debug, PartialEq)] -pub enum ContractError { - #[error("{0}")] - Std(#[from] StdError), - - #[error("Unauthorized")] - Unauthorized {}, - - #[error("Cannot set to own account")] - CannotSetOwnAccount {}, - - #[error("Invalid zero amount")] - InvalidZeroAmount {}, - - #[error("Allowance is expired")] - Expired {}, - - #[error("No allowance for this account")] - NoAllowance {}, - - #[error("Minting cannot exceed the cap")] - CannotExceedCap {}, - - #[error("Logo binary data exceeds 5KB limit")] - LogoTooBig {}, - - #[error("Invalid xml preamble for SVG")] - InvalidXmlPreamble {}, - - #[error("Invalid png header")] - InvalidPngHeader {}, -} diff --git a/cw20/base/src/lib.rs b/cw20/base/src/lib.rs index 64e8019..b217e0f 100644 --- a/cw20/base/src/lib.rs +++ b/cw20/base/src/lib.rs @@ -1,8 +1,130 @@ -pub mod allowances; -pub mod contract; -pub mod enumerable; -mod error; -pub mod msg; -pub mod state; - -pub use crate::error::ContractError; +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; + +use cosmwasm_std::Empty; +use cw2::set_contract_version; +use cw20:: + +#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug, Default)] +pub struct Trait { + pub display_type: Option, + pub trait_type: String, + pub value: String, +} + +// see: https://ption, + pub description: Option, + pub name: Option, + pub attributes: Option>, + pub background_color: Option, + pub animation_udocs.opensea.io/docs/metadata-standards + #[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug, Default)] + pub struct Metadata { + pub image: Option, + pub image_data: Option, + pub external_url: Orl: Option, + pub youtube_url: Option, +} + +pub type Extension = Option; + +pub type Cw721MetadataContract<'a> = cw721_base::Cw<'a, Extension, Empty>; +pub type ExecuteMsg = cw721_base::ExecuteMsg; + +const CONTRACT_NAME: &str = "crates.io:{{project-name}}"; +const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION"); + +#[cfg(not(feature = "library"))] +pub mod entry { + use super::*; + + use cosmwasm_std::entry_point; + use cosmwasm_std::{Binary, Deps, DepsMut, Env, MessageInfo, Response, StdResult}; + + // This is a simple type to let us handle empty extensions + + // This makes a conscious choice on the various generics used by the contract + #[entry_point] + pub fn instantiate( + deps: DepsMut, + _env: Env, + _info: MessageInfo, + msg: InstantiateMsg, + ) -> StdResult { + set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; + + let info = ContractInfoResponse { + name: msg.name, + symbol: msg.symbol, + }; + Cw721MetadataContract::default() + .contract_info + .save(deps.storage, &info)?; + let minter = deps.api.addr_validate(&msg.minter)?; + Cw721MetadataContract::default() + .minter + .save(deps.storage, &minter)?; + Ok(Response::default()) + } + + #[entry_point] + pub fn execute( + deps: DepsMut, + env: Env, + info: MessageInfo, + msg: ExecuteMsg, + ) -> Result { + Cw721MetadataContract::default().execute(deps, env, info, msg) + } + + #[entry_point] + pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> StdResult { + Cw721MetadataContract::default().query(deps, env, msg) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info}; + use cw721::Cw721Query; + + const CREATOR: &str = "creator"; + + #[test] + fn use_metadata_extension() { + let mut deps = mock_dependencies(); + let contract = Cw721MetadataContract::default(); + + let info = mock_info(CREATOR, &[]); + let init_msg = InstantiateMsg { + name: "SpaceShips".to_string(), + symbol: "SPACE".to_string(), + minter: CREATOR.to_string(), + }; + contract + .instantiate(deps.as_mut(), mock_env(), info.clone(), init_msg) + .unwrap(); + + let token_id = "Enterprise"; + let mint_msg = MintMsg { + token_id: token_id.to_string(), + owner: "john".to_string(), + token_uri: Some("https://starships.example.com/Starship/Enterprise.json".into()), + extension: Some(Metadata { + description: Some("Spaceship with Warp Drive".into()), + name: Some("Starship USS Enterprise".to_string()), + ..Metadata::default() + }), + }; + let exec_msg = ExecuteMsg::Mint(mint_msg.clone()); + contract + .execute(deps.as_mut(), mock_env(), info, exec_msg) + .unwrap(); + + let res = contract.nft_info(deps.as_ref(), token_id.into()).unwrap(); + assert_eq!(res.token_uri, mint_msg.token_uri); + assert_eq!(res.extension, mint_msg.extension); + } +} diff --git a/cw20/base/src/msg.rs b/cw20/base/src/msg.rs deleted file mode 100644 index b234ffd..0000000 --- a/cw20/base/src/msg.rs +++ /dev/null @@ -1,113 +0,0 @@ -use cosmwasm_std::{StdError, StdResult, Uint128}; -use cw20::{Cw20Coin, Logo, MinterResponse}; -use schemars::JsonSchema; -use serde::{Deserialize, Serialize}; - -pub use cw20::Cw20ExecuteMsg as ExecuteMsg; - -#[derive(Serialize, Deserialize, JsonSchema, Debug, Clone, PartialEq)] -pub struct InstantiateMarketingInfo { - pub project: Option, - pub description: Option, - pub marketing: Option, - pub logo: Option, -} - -#[derive(Serialize, Deserialize, JsonSchema, Debug, Clone, PartialEq)] -pub struct InstantiateMsg { - pub name: String, - pub symbol: String, - pub decimals: u8, - pub initial_balances: Vec, - pub mint: Option, - pub marketing: Option, -} - -impl InstantiateMsg { - pub fn get_cap(&self) -> Option { - self.mint.as_ref().and_then(|v| v.cap) - } - - pub fn validate(&self) -> StdResult<()> { - // Check name, symbol, decimals - if !is_valid_name(&self.name) { - return Err(StdError::generic_err( - "Name is not in the expected format (3-50 UTF-8 bytes)", - )); - } - if !is_valid_symbol(&self.symbol) { - return Err(StdError::generic_err( - "Ticker symbol is not in expected format [a-zA-Z\\-]{3,12}", - )); - } - if self.decimals > 18 { - return Err(StdError::generic_err("Decimals must not exceed 18")); - } - Ok(()) - } -} - -fn is_valid_name(name: &str) -> bool { - let bytes = name.as_bytes(); - if bytes.len() < 3 || bytes.len() > 50 { - return false; - } - true -} - -fn is_valid_symbol(symbol: &str) -> bool { - let bytes = symbol.as_bytes(); - if bytes.len() < 3 || bytes.len() > 12 { - return false; - } - for byte in bytes.iter() { - if (*byte != 45) && (*byte < 65 || *byte > 90) && (*byte < 97 || *byte > 122) { - return false; - } - } - true -} - -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] -#[serde(rename_all = "snake_case")] -pub enum QueryMsg { - /// Returns the current balance of the given address, 0 if unset. - /// Return type: BalanceResponse. - Balance { address: String }, - /// Returns metadata on the contract - name, decimals, supply, etc. - /// Return type: TokenInfoResponse. - TokenInfo {}, - /// Only with "mintable" extension. - /// Returns who can mint and the hard cap on maximum tokens after minting. - /// Return type: MinterResponse. - Minter {}, - /// Only with "allowance" extension. - /// Returns how much spender can use from owner account, 0 if unset. - /// Return type: AllowanceResponse. - Allowance { owner: String, spender: String }, - /// Only with "enumerable" extension (and "allowances") - /// Returns all allowances this owner has approved. Supports pagination. - /// Return type: AllAllowancesResponse. - AllAllowances { - owner: String, - start_after: Option, - limit: Option, - }, - /// Only with "enumerable" extension - /// Returns all accounts that have balances. Supports pagination. - /// Return type: AllAccountsResponse. - AllAccounts { - start_after: Option, - limit: Option, - }, - /// Only with "marketing" extension - /// Returns more metadata on the contract to display in the client: - /// - description, logo, project url, etc. - /// Return type: MarketingInfoResponse - MarketingInfo {}, - /// Only with "marketing" extension - /// Downloads the mbeded logo data (if stored on chain). Errors if no logo data ftored for this - /// contract. - /// Return type: DownloadLogoResponse. - DownloadLogo {}, -} diff --git a/cw20/base/src/state.rs b/cw20/base/src/state.rs deleted file mode 100644 index d52f561..0000000 --- a/cw20/base/src/state.rs +++ /dev/null @@ -1,36 +0,0 @@ -use schemars::JsonSchema; -use serde::{Deserialize, Serialize}; - -use cosmwasm_std::{Addr, Uint128}; -use cw_storage_plus::{Item, Map}; - -use cw20::{AllowanceResponse, Logo, MarketingInfoResponse}; - -#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] -#[serde(rename_all = "snake_case")] -pub struct TokenInfo { - pub name: String, - pub symbol: String, - pub decimals: u8, - pub total_supply: Uint128, - pub mint: Option, -} - -#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] -pub struct MinterData { - pub minter: Addr, - /// cap is how many more tokens can be issued by the minter - pub cap: Option, -} - -impl TokenInfo { - pub fn get_cap(&self) -> Option { - self.mint.as_ref().and_then(|v| v.cap) - } -} - -pub const TOKEN_INFO: Item = Item::new("token_info"); -pub const MARKETING_INFO: Item = Item::new("marketing_info"); -pub const LOGO: Item = Item::new("logo"); -pub const BALANCES: Map<&Addr, Uint128> = Map::new("balance"); -pub const ALLOWANCES: Map<(&Addr, &Addr), AllowanceResponse> = Map::new("allowance"); diff --git a/cw721/off-chain-metadata/.cargo/config b/cw721/off-chain-metadata/.cargo/config deleted file mode 100644 index 7d1a066..0000000 --- a/cw721/off-chain-metadata/.cargo/config +++ /dev/null @@ -1,5 +0,0 @@ -[alias] -wasm = "build --release --target wasm32-unknown-unknown" -wasm-debug = "build --target wasm32-unknown-unknown" -unit-test = "test --lib" -schema = "run --example schema" diff --git a/cw721/off-chain-metadata/.circleci/config.yml b/cw721/off-chain-metadata/.circleci/config.yml deleted file mode 100644 index 9b07669..0000000 --- a/cw721/off-chain-metadata/.circleci/config.yml +++ /dev/null @@ -1,61 +0,0 @@ -version: 2.1 - -executors: - builder: - docker: - - image: buildpack-deps:trusty - -jobs: - docker-image: - executor: builder - steps: - - checkout - - setup_remote_docker - docker_layer_caching: true - - run: - name: Build Docker artifact - command: docker build --pull -t "cosmwasm/cw-gitpod-base:${CIRCLE_SHA1}" . - - run: - name: Push application Docker image to docker hub - command: | - if [ "${CIRCLE_BRANCH}" = "master" ]; then - docker tag "cosmwasm/cw-gitpod-base:${CIRCLE_SHA1}" cosmwasm/cw-gitpod-base:latest - docker login --password-stdin -u "$DOCKER_USER" \<<<"$DOCKER_PASS" - docker push cosmwasm/cw-gitpod-base:latest - docker logout - fi - - docker-tagged: - executor: builder - steps: - - checkout - - setup_remote_docker - docker_layer_caching: true - - run: - name: Push application Docker image to docker hub - command: | - docker tag "cosmwasm/cw-gitpod-base:${CIRCLE_SHA1}" "cosmwasm/cw-gitpod-base:${CIRCLE_TAG}" - docker login --password-stdin -u "$DOCKER_USER" \<<<"$DOCKER_PASS" - docker push - docker logout - -workflows: - version: 2 - test-suite: - jobs: - # this is now a slow process... let's only run on master - - docker-image: - filters: - branches: - only: - - master - - docker-tagged: - filters: - tags: - only: - - /^v.*/ - branches: - ignore: - - /.*/ - requires: - - docker-image diff --git a/cw721/off-chain-metadata/.editorconfig b/cw721/off-chain-metadata/.editorconfig deleted file mode 100644 index 3d36f20..0000000 --- a/cw721/off-chain-metadata/.editorconfig +++ /dev/null @@ -1,11 +0,0 @@ -root = true - -[*] -indent_style = space -indent_size = 2 -charset = utf-8 -trim_trailing_whitespace = true -insert_final_newline = true - -[*.rs] -indent_size = 4 diff --git a/cw721/off-chain-metadata/.genignore b/cw721/off-chain-metadata/.genignore deleted file mode 100644 index 4fe5fd0..0000000 --- a/cw721/off-chain-metadata/.genignore +++ /dev/null @@ -1 +0,0 @@ -meta/ diff --git a/cw721/off-chain-metadata/.github/workflows/Basic.yml b/cw721/off-chain-metadata/.github/workflows/Basic.yml deleted file mode 100644 index 6170933..0000000 --- a/cw721/off-chain-metadata/.github/workflows/Basic.yml +++ /dev/null @@ -1,83 +0,0 @@ -# Based on https://github.com/actions-rs/example/blob/master/.github/workflows/quickstart.yml - -on: [push, pull_request] - -name: Basic - -jobs: - - test: - name: Test Suite - runs-on: ubuntu-latest - steps: - - name: Checkout sources - uses: actions/checkout@v2 - - - name: Install stable toolchain - uses: actions-rs/toolchain@v1 - with: - toolchain: stable - target: wasm32-unknown-unknown - override: true - profile: minimal - - - name: Run unit tests - uses: actions-rs/cargo@v1 - with: - command: unit-test - args: --locked - env: - RUST_BACKTRACE: 1 - - - name: Compile WASM contract - uses: actions-rs/cargo@v1 - with: - command: wasm - args: --locked - env: - RUSTFLAGS: "-C link-arg=-s" - - lints: - name: Lints - runs-on: ubuntu-latest - steps: - - name: Checkout sources - uses: actions/checkout@v2 - - - name: Install stable toolchain - uses: actions-rs/toolchain@v1 - with: - toolchain: stable - override: true - profile: minimal - components: rustfmt, clippy - - - name: Run cargo fmt - uses: actions-rs/cargo@v1 - with: - command: fmt - args: --all -- --check - - - name: Run cargo clippy - uses: actions-rs/cargo@v1 - with: - command: clippy - args: -- -D warnings - - - name: Generate schema - uses: actions-rs/cargo@v1 - with: - command: schema - args: --locked - - - name: Verify schema - uses: tj-actions/verify-changed-files@v8 - id: verify-schema - with: - files: schema/.*\.json - - - name: Display changed schemas - if: steps.verify-schema.outputs.files_changed == 'true' - run: | - echo "The schema files are not in sync with the repository. Please, run 'cargo schema' to generate them again and commit the changes." - exit 1 diff --git a/cw721/off-chain-metadata/.gitignore b/cw721/off-chain-metadata/.gitignore deleted file mode 100644 index f9b9a83..0000000 --- a/cw721/off-chain-metadata/.gitignore +++ /dev/null @@ -1,16 +0,0 @@ -# Build results -/target -/artifacts - -# Cargo+Git helper file (https://github.com/rust-lang/cargo/blob/0.44.1/src/cargo/sources/git/utils.rs#L320-L327) -.cargo-ok - -# Text file backups -**/*.rs.bk - -# macOS -.DS_Store - -# IDEs -*.iml -.idea diff --git a/cw721/off-chain-metadata/.gitpod.Dockerfile b/cw721/off-chain-metadata/.gitpod.Dockerfile deleted file mode 100644 index bff8bc5..0000000 --- a/cw721/off-chain-metadata/.gitpod.Dockerfile +++ /dev/null @@ -1,17 +0,0 @@ -### wasmd ### -FROM cosmwasm/wasmd:v0.18.0 as wasmd - -### rust-optimizer ### -FROM cosmwasm/rust-optimizer:0.11.5 as rust-optimizer - -FROM gitpod/workspace-full:latest - -COPY --from=wasmd /usr/bin/wasmd /usr/local/bin/wasmd -COPY --from=wasmd /opt/* /opt/ - -RUN sudo apt-get update \ - && sudo apt-get install -y jq \ - && sudo rm -rf /var/lib/apt/lists/* - -RUN rustup update stable \ - && rustup target add wasm32-unknown-unknown diff --git a/cw721/off-chain-metadata/.gitpod.yml b/cw721/off-chain-metadata/.gitpod.yml deleted file mode 100644 index d03610c..0000000 --- a/cw721/off-chain-metadata/.gitpod.yml +++ /dev/null @@ -1,10 +0,0 @@ -image: cosmwasm/cw-gitpod-base:v0.16 - -vscode: - extensions: - - rust-lang.rust - -tasks: - - name: Dependencies & Build - init: | - cargo build diff --git a/cw721/off-chain-metadata/Cargo.toml b/cw721/off-chain-metadata/Cargo.toml deleted file mode 100644 index 2cb464b..0000000 --- a/cw721/off-chain-metadata/Cargo.toml +++ /dev/null @@ -1,54 +0,0 @@ -[package] -name = "{{project-name}}" -version = "0.1.0" -authors = ["{{authors}}"] -edition = "2018" - -exclude = [ - # Those files are rust-optimizer artifacts. You might want to commit them for convenience but they should not be part of the source code publication. - "contract.wasm", - "hash.txt", -] - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[lib] -crate-type = ["cdylib", "rlib"] - -[profile.release] -opt-level = 3 -debug = false -rpath = false -lto = true -debug-assertions = false -codegen-units = 1 -panic = 'abort' -incremental = false -overflow-checks = true - -[features] -# for more explicit tests, cargo test --features=backtraces -backtraces = ["cosmwasm-std/backtraces"] -# use library feature to disable all instantiate/execute/query exports -library = [] - -[package.metadata.scripts] -optimize = """docker run --rm -v "$(pwd)":/code \ - -e CARGO_TERM_COLOR=always \ - --mount type=volume,source="$(basename "$(pwd)")_cache",target=/code/target \ - --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \ - cosmwasm/rust-optimizer:0.12.5 -""" - -[dependencies] -cosmwasm-std = "1.0.0-beta" -cw-storage-plus = "0.11" -cw-utils = "0.11" -cw2 = "0.11" -cw721 = "0.11" -schemars = "0.8" -serde = { version = "1.0", default-features = false, features = ["derive"] } -thiserror = "1.0" - -[dev-dependencies] -cosmwasm-schema = "1.0.0-beta" diff --git a/cw721/off-chain-metadata/Developing.md b/cw721/off-chain-metadata/Developing.md deleted file mode 100644 index 6aa7cb1..0000000 --- a/cw721/off-chain-metadata/Developing.md +++ /dev/null @@ -1,96 +0,0 @@ -# Developing - -If you have recently created a contract with this template, you probably could use some -help on how to build and test the contract, as well as prepare it for production. This -file attempts to provide a brief overview, assuming you have installed a recent -version of Rust already (eg. 1.51.0+). - -## Prerequisites - -Before starting, make sure you have [rustup](https://rustup.rs/) along with a -recent `rustc` and `cargo` version installed. Currently, we are testing on 1.51.0+. - -And you need to have the `wasm32-unknown-unknown` target installed as well. - -You can check that via: - -```sh -rustc --version -cargo --version -rustup target list --installed -# if wasm32 is not listed above, run this -rustup target add wasm32-unknown-unknown -``` - -## Compiling and running tests - -Now that you created your custom contract, make sure you can compile and run it before -making any changes. Go into the repository and do: - -```sh -# this will produce a wasm build in ./target/wasm32-unknown-unknown/release/YOUR_NAME_HERE.wasm -cargo wasm - -# this runs unit tests with helpful backtraces -RUST_BACKTRACE=1 cargo unit-test - -# auto-generate json schema -cargo schema -``` - -### Understanding the tests - -The main code is in `src/contract.rs` and the unit tests there run in pure rust, -which makes them very quick to execute and give nice output on failures, especially -if you do `RUST_BACKTRACE=1 cargo unit-test`. - -We consider testing critical for anything on a blockchain, and recommend to always keep -the tests up to date. - -## Generating JSON Schema - -While the Wasm calls (`instantiate`, `execute`, `query`) accept JSON, this is not enough -information to use it. We need to expose the schema for the expected messages to the -clients. You can generate this schema by calling `cargo schema`, which will output -4 files in `./schema`, corresponding to the 3 message types the contract accepts, -as well as the internal `State`. - -These files are in standard json-schema format, which should be usable by various -client side tools, either to auto-generate codecs, or just to validate incoming -json wrt. the defined schema. - -## Preparing the Wasm bytecode for production - -Before we upload it to a chain, we need to ensure the smallest output size possible, -as this will be included in the body of a transaction. We also want to have a -reproducible build process, so third parties can verify that the uploaded Wasm -code did indeed come from the claimed rust code. - -To solve both these issues, we have produced `rust-optimizer`, a docker image to -produce an extremely small build output in a consistent manner. The suggest way -to run it is this: - -```sh -docker run --rm -v "$(pwd)":/code \ - --mount type=volume,source="$(basename "$(pwd)")_cache",target=/code/target \ - --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \ - cosmwasm/rust-optimizer:0.11.4 -``` - -We must mount the contract code to `/code`. You can use a absolute path instead -of `$(pwd)` if you don't want to `cd` to the directory first. The other two -volumes are nice for speedup. Mounting `/code/target` in particular is useful -to avoid docker overwriting your local dev files with root permissions. -Note the `/code/target` cache is unique for each contract being compiled to limit -interference, while the registry cache is global. - -This is rather slow compared to local compilations, especially the first compile -of a given contract. The use of the two volume caches is very useful to speed up -following compiles of the same contract. - -This produces an `artifacts` directory with a `PROJECT_NAME.wasm`, as well as -`checksums.txt`, containing the Sha256 hash of the wasm file. -The wasm file is compiled deterministically (anyone else running the same -docker on the same git commit should get the identical file with the same Sha256 hash). -It is also stripped and minimized for upload to a blockchain (we will also -gzip it in the uploading process to make it even smaller). diff --git a/cw721/off-chain-metadata/Importing.md b/cw721/off-chain-metadata/Importing.md deleted file mode 100644 index 7dcec4f..0000000 --- a/cw721/off-chain-metadata/Importing.md +++ /dev/null @@ -1,62 +0,0 @@ -# Importing - -In [Publishing](./Publishing.md), we discussed how you can publish your contract to the world. -This looks at the flip-side, how can you use someone else's contract (which is the same -question as how they will use your contract). Let's go through the various stages. - -## Verifying Artifacts - -Before using remote code, you most certainly want to verify it is honest. - -The simplest audit of the repo is to simply check that the artifacts in the repo -are correct. This involves recompiling the claimed source with the claimed builder -and validating that the locally compiled code (hash) matches the code hash that was -uploaded. This will verify that the source code is the correct preimage. Which allows -one to audit the original (Rust) source code, rather than looking at wasm bytecode. - -We have a script to do this automatic verification steps that can -easily be run by many individuals. Please check out -[`cosmwasm-verify`](https://github.com/CosmWasm/cosmwasm-verify/blob/master/README.md) -to see a simple shell script that does all these steps and easily allows you to verify -any uploaded contract. - -## Reviewing - -Once you have done the quick programatic checks, it is good to give at least a quick -look through the code. A glance at `examples/schema.rs` to make sure it is outputing -all relevant structs from `contract.rs`, and also ensure `src/lib.rs` is just the -default wrapper (nothing funny going on there). After this point, we can dive into -the contract code itself. Check the flows for the execute methods, any invariants and -permission checks that should be there, and a reasonable data storage format. - -You can dig into the contract as far as you want, but it is important to make sure there -are no obvious backdoors at least. - -## Decentralized Verification - -It's not very practical to do a deep code review on every dependency you want to use, -which is a big reason for the popularity of code audits in the blockchain world. We trust -some experts review in lieu of doing the work ourselves. But wouldn't it be nice to do this -in a decentralized manner and peer-review each other's contracts? Bringing in deeper domain -knowledge and saving fees. - -Luckily, there is an amazing project called [crev](https://github.com/crev-dev/cargo-crev/blob/master/cargo-crev/README.md) -that provides `A cryptographically verifiable code review system for the cargo (Rust) package manager`. - -I highly recommend that CosmWasm contract developers get set up with this. At minimum, we -can all add a review on a package that programmatically checked out that the json schemas -and wasm bytecode do match the code, and publish our claim, so we don't all rely on some -central server to say it validated this. As we go on, we can add deeper reviews on standard -packages. - -If you want to use `cargo-crev`, please follow their -[getting started guide](https://github.com/crev-dev/cargo-crev/blob/master/cargo-crev/src/doc/getting_started.md) -and once you have made your own *proof repository* with at least one *trust proof*, -please make a PR to the [`cawesome-wasm`]() repo with a link to your repo and -some public name or pseudonym that people know you by. This allows people who trust you -to also reuse your proofs. - -There is a [standard list of proof repos](https://github.com/crev-dev/cargo-crev/wiki/List-of-Proof-Repositories) -with some strong rust developers in there. This may cover dependencies like `serde` and `snafu` -but will not hit any CosmWasm-related modules, so we look to bootstrap a very focused -review community. diff --git a/cw721/off-chain-metadata/LICENSE b/cw721/off-chain-metadata/LICENSE deleted file mode 100644 index d645695..0000000 --- a/cw721/off-chain-metadata/LICENSE +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/cw721/off-chain-metadata/NOTICE b/cw721/off-chain-metadata/NOTICE deleted file mode 100644 index 216c969..0000000 --- a/cw721/off-chain-metadata/NOTICE +++ /dev/null @@ -1,13 +0,0 @@ -Copyright {{ "now" | date: "%Y" }} {{authors}} - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. diff --git a/cw721/off-chain-metadata/Publishing.md b/cw721/off-chain-metadata/Publishing.md deleted file mode 100644 index df868b9..0000000 --- a/cw721/off-chain-metadata/Publishing.md +++ /dev/null @@ -1,115 +0,0 @@ -# Publishing Contracts - -This is an overview of how to publish the contract's source code in this repo. -We use Cargo's default registry [crates.io](https://crates.io/) for publishing contracts written in Rust. - -## Preparation - -Ensure the `Cargo.toml` file in the repo is properly configured. In particular, you want to -choose a name starting with `cw-`, which will help a lot finding CosmWasm contracts when -searching on crates.io. For the first publication, you will probably want version `0.1.0`. -If you have tested this on a public net already and/or had an audit on the code, -you can start with `1.0.0`, but that should imply some level of stability and confidence. -You will want entries like the following in `Cargo.toml`: - -```toml -name = "cw-escrow" -version = "0.1.0" -description = "Simple CosmWasm contract for an escrow with arbiter and timeout" -repository = "https://github.com/confio/cosmwasm-examples" -``` - -You will also want to add a valid [SPDX license statement](https://spdx.org/licenses/), -so others know the rules for using this crate. You can use any license you wish, -even a commercial license, but we recommend choosing one of the following, unless you have -specific requirements. - -* Permissive: [`Apache-2.0`](https://spdx.org/licenses/Apache-2.0.html#licenseText) or [`MIT`](https://spdx.org/licenses/MIT.html#licenseText) -* Copyleft: [`GPL-3.0-or-later`](https://spdx.org/licenses/GPL-3.0-or-later.html#licenseText) or [`AGPL-3.0-or-later`](https://spdx.org/licenses/AGPL-3.0-or-later.html#licenseText) -* Commercial license: `Commercial` (not sure if this works, I cannot find examples) - -It is also helpful to download the LICENSE text (linked to above) and store this -in a LICENSE file in your repo. Now, you have properly configured your crate for use -in a larger ecosystem. - -### Updating schema - -To allow easy use of the contract, we can publish the schema (`schema/*.json`) together -with the source code. - -```sh -cargo schema -``` - -Ensure you check in all the schema files, and make a git commit with the final state. -This commit will be published and should be tagged. Generally, you will want to -tag with the version (eg. `v0.1.0`), but in the `cosmwasm-examples` repo, we have -multiple contracts and label it like `escrow-0.1.0`. Don't forget a -`git push && git push --tags` - -### Note on build results - -Build results like Wasm bytecode or expected hash don't need to be updated since -the don't belong to the source publication. However, they are excluded from packaging -in `Cargo.toml` which allows you to commit them to your git repository if you like. - -```toml -exclude = ["artifacts"] -``` - -A single source code can be built with multiple different optimizers, so -we should not make any strict assumptions on the tooling that will be used. - -## Publishing - -Now that your package is properly configured and all artifacts are committed, it -is time to share it with the world. -Please refer to the [complete instructions for any questions](https://rurust.github.io/cargo-docs-ru/crates-io.html), -but I will try to give a quick overview of the happy path here. - -### Registry - -You will need an account on [crates.io](https://crates.io) to publish a rust crate. -If you don't have one already, just click on "Log in with GitHub" in the top-right -to quickly set up a free account. Once inside, click on your username (top-right), -then "Account Settings". On the bottom, there is a section called "API Access". -If you don't have this set up already, create a new token and use `cargo login` -to set it up. This will now authenticate you with the `cargo` cli tool and allow -you to publish. - -### Uploading - -Once this is set up, make sure you commit the current state you want to publish. -Then try `cargo publish --dry-run`. If that works well, review the files that -will be published via `cargo package --list`. If you are satisfied, you can now -officially publish it via `cargo publish`. - -Congratulations, your package is public to the world. - -### Sharing - -Once you have published your package, people can now find it by -[searching for "cw-" on crates.io](https://crates.io/search?q=cw). -But that isn't exactly the simplest way. To make things easier and help -keep the ecosystem together, we suggest making a PR to add your package -to the [`cawesome-wasm`](https://github.com/cosmwasm/cawesome-wasm) list. - -### Organizations - -Many times you are writing a contract not as a solo developer, but rather as -part of an organization. You will want to allow colleagues to upload new -versions of the contract to crates.io when you are on holiday. -[These instructions show how]() you can set up your crate to allow multiple maintainers. - -You can add another owner to the crate by specifying their github user. Note, you will -now both have complete control of the crate, and they can remove you: - -`cargo owner --add ethanfrey` - -You can also add an existing github team inside your organization: - -`cargo owner --add github:confio:developers` - -The team will allow anyone who is currently in the team to publish new versions of the crate. -And this is automatically updated when you make changes on github. However, it will not allow -anyone in the team to add or remove other owners. diff --git a/cw721/off-chain-metadata/README.md b/cw721/off-chain-metadata/README.md deleted file mode 100644 index 8734338..0000000 --- a/cw721/off-chain-metadata/README.md +++ /dev/null @@ -1,90 +0,0 @@ -# Archway Network Starter Pack - -This is a template to build smart contracts in Rust to run inside a -[Cosmos SDK](https://github.com/cosmos/cosmos-sdk) module on all chains that enable it. -To understand the framework better, please read the overview in the -[archway repo](https://github.com/archway-network/archway/blob/main/README.md), -and dig into the [archway docs](https://docs.archway.io). - -The below instructions assume you understand the theory and just want to get coding. - -## Creating a new project from a template - -Assuming you have a recent version of rust and cargo (v1.51.0+) installed -(via [rustup](https://rustup.rs/)), -then the following should get you a new repo to start a contract: - -Install [cargo-generate](https://github.com/ashleygwilliams/cargo-generate) and cargo-run-script. -If you didn't install them already, run the following commands: - -```sh -cargo install cargo-generate --features vendored-openssl -cargo install cargo-run-script -``` - -Now, use it to create your new contract. -Go to the folder in which you want to place it and run: - -```sh -cargo generate --git archway-network/archway-templates.git --name PROJECT_NAME default -``` - -You will now have a new folder called `PROJECT_NAME` (I hope you changed that to something else) -containing a simple working contract and build system that you can customize. - -## Create a Repo - -After generating, you have a initialized local git repo, but no commits, and no remote. -Go to a server (eg. github) and create a new upstream repo (called `YOUR-GIT-URL` below). -Then run the following: - -```sh -# this is needed to create a valid Cargo.lock file (see below) -cargo check -git branch -M main -git add . -git commit -m 'Initial Commit' -git remote add origin YOUR-GIT-URL -git push -u origin main -``` - -## CI Support - -We have template configurations for both [GitHub Actions](.github/workflows/Basic.yml) -and [Circle CI](.circleci/config.yml) in the generated project, so you can -get up and running with CI right away. - -One note is that the CI runs all `cargo` commands -with `--locked` to ensure it uses the exact same versions as you have locally. This also means -you must have an up-to-date `Cargo.lock` file, which is not auto-generated. -The first time you set up the project (or after adding any dep), you should ensure the -`Cargo.lock` file is updated, so the CI will test properly. This can be done simply by -running `cargo check` or `cargo unit-test`. - -## Using your project - -Once you have your custom repo, you should check out [Developing](./Developing.md) to explain -more on how to run tests and develop code. Or go through the -[online tutorial](https://docs.archway.io/docs/create/guides/my-first-dapp/start) to get a better feel -of how to develop. - -[Publishing](./Publishing.md) contains useful information on how to publish your contract -to the world, once you are ready to deploy it on a running blockchain. And -[Importing](./Importing.md) contains information about pulling in other contracts or crates -that have been published. - -Please replace this README file with information about your specific project. You can keep -the `Developing.md` and `Publishing.md` files as useful referenced, but please set some -proper description in the README. - -## Gitpod integration - -[Gitpod](https://www.gitpod.io/) container-based development platform will be enabled on your project by default. - -Workspace contains: - -- **rust**: for builds -- [wasmd](https://github.com/CosmWasm/wasmd): for local node setup and client -- **jq**: shell JSON manipulation tool - -Follow [Gitpod Getting Started](https://www.gitpod.io/docs/getting-started) and launch your workspace. diff --git a/cw721/off-chain-metadata/cargo-generate.toml b/cw721/off-chain-metadata/cargo-generate.toml deleted file mode 100644 index b5c5e3c..0000000 --- a/cw721/off-chain-metadata/cargo-generate.toml +++ /dev/null @@ -1,5 +0,0 @@ -[template] -# Files listed here will not be processed by the template engine when a project is generated. -# This is needed when files contains curly brackets as in `v4-cargo-cache-{{ arch }}-{{ checksum "Cargo.lock" }}`. -# The files will be copied 1:1 to the target project. To avoid shipping them completely add them to `.genignore`. -exclude = [".circleci/config.yml"] diff --git a/cw721/off-chain-metadata/examples/schema.rs b/cw721/off-chain-metadata/examples/schema.rs deleted file mode 100644 index 764f1bc..0000000 --- a/cw721/off-chain-metadata/examples/schema.rs +++ /dev/null @@ -1,39 +0,0 @@ -use std::env::current_dir; -use std::fs::create_dir_all; - -use cosmwasm_schema::{export_schema, export_schema_with_title, remove_schemas, schema_for}; - -use cw721::{ - AllNftInfoResponse, ApprovalResponse, ApprovalsResponse, ContractInfoResponse, NftInfoResponse, - NumTokensResponse, OperatorsResponse, OwnerOfResponse, TokensResponse, -}; -use {{crate_name}}::{ExecuteMsg, Extension, InstantiateMsg, MinterResponse, QueryMsg}; - -fn main() { - let mut out_dir = current_dir().unwrap(); - out_dir.push("schema"); - create_dir_all(&out_dir).unwrap(); - remove_schemas(&out_dir).unwrap(); - - export_schema(&schema_for!(InstantiateMsg), &out_dir); - export_schema_with_title(&schema_for!(ExecuteMsg), &out_dir, "ExecuteMsg"); - export_schema(&schema_for!(QueryMsg), &out_dir); - export_schema_with_title( - &schema_for!(AllNftInfoResponse), - &out_dir, - "AllNftInfoResponse", - ); - export_schema(&schema_for!(ApprovalResponse), &out_dir); - export_schema(&schema_for!(ApprovalsResponse), &out_dir); - export_schema(&schema_for!(OperatorsResponse), &out_dir); - export_schema(&schema_for!(ContractInfoResponse), &out_dir); - export_schema(&schema_for!(MinterResponse), &out_dir); - export_schema_with_title( - &schema_for!(NftInfoResponse), - &out_dir, - "NftInfoResponse", - ); - export_schema(&schema_for!(NumTokensResponse), &out_dir); - export_schema(&schema_for!(OwnerOfResponse), &out_dir); - export_schema(&schema_for!(TokensResponse), &out_dir); -} diff --git a/cw721/off-chain-metadata/meta/README.md b/cw721/off-chain-metadata/meta/README.md deleted file mode 100644 index 279d1db..0000000 --- a/cw721/off-chain-metadata/meta/README.md +++ /dev/null @@ -1,16 +0,0 @@ -# The meta folder - -This folder is ignored via the `.genignore` file. It contains meta files -that should not make it into the generated project. - -In particular, it is used for an AppVeyor CI script that runs on `cw-template` -itself (running the cargo-generate script, then testing the generated project). -The `.circleci` and `.github` directories contain scripts destined for any projects created from -this template. - -## Files - -- `appveyor.yml`: The AppVeyor CI configuration -- `test_generate.sh`: A script for generating a project from the template and - runnings builds and tests in it. This works almost like the CI script but - targets local UNIX-like dev environments. diff --git a/cw721/off-chain-metadata/meta/appveyor.yml b/cw721/off-chain-metadata/meta/appveyor.yml deleted file mode 100644 index 00f6d3f..0000000 --- a/cw721/off-chain-metadata/meta/appveyor.yml +++ /dev/null @@ -1,61 +0,0 @@ -# This CI configuration tests the cw-template repository itself, -# not the resulting project. We want to ensure that -# 1. the template to project generation works -# 2. the template files are up to date -# -# We chose Appveyor for this task as it allows us to use an arbitrary config -# location. Furthermore it allows us to ship Circle CI and GitHub Actions configs -# generated for the resulting project. - -image: Ubuntu - -environment: - TOOLCHAIN: 1.51.0 - -services: - - docker - -cache: - - $HOME/.rustup/ -> meta/appveyor.yml - # For details about cargo caching see https://doc.rust-lang.org/cargo/guide/cargo-home.html#caching-the-cargo-home-in-ci - - $HOME/.cargo/bin/ -> meta/appveyor.yml - - $HOME/.cargo/registry/index/ -> meta/appveyor.yml - - $HOME/.cargo/registry/cache/ -> meta/appveyor.yml - - $HOME/.cargo/git/db/ -> meta/appveyor.yml - -install: - - curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- --default-toolchain "$TOOLCHAIN" -y - - source $HOME/.cargo/env - - rustc --version - - cargo --version - - rustup target add wasm32-unknown-unknown - - cargo install --features vendored-openssl cargo-generate || true - -build_script: - # No matter what is currently checked out by the CI (main, other branch, PR merge commit), - # we create a temporary local branch from that point with a constant name, which we need for - # cargo generate. - - git branch current-ci-checkout - - cd .. - - cargo generate --git cw-template --name testgen-ci --branch current-ci-checkout - - cd testgen-ci - - ls -lA - - cargo fmt -- --check - - cargo unit-test - - cargo wasm - - cargo schema - - docker build --pull -t "cosmwasm/cw-gitpod-base:${APPVEYOR_REPO_COMMIT}" . - - \[ "${APPVEYOR_REPO_BRANCH}" = "main" \] && image_tag=latest || image_tag=${APPVEYOR_REPO_TAG_NAME} - - docker tag "cosmwasm/cw-gitpod-base:${APPVEYOR_REPO_COMMIT}" "cosmwasm/cw-gitpod-base:${image_tag}" - -on_success: - # publish docker image - - docker login --password-stdin -u "$DOCKER_USER" <<<"$DOCKER_PASS" - - docker push - - docker logout - -branches: -# whitelist long living branches and tags - only: - # - main - - /v\d+\.\d+\.\d+/ \ No newline at end of file diff --git a/cw721/off-chain-metadata/meta/test_generate.sh b/cw721/off-chain-metadata/meta/test_generate.sh deleted file mode 100755 index b9aaa23..0000000 --- a/cw721/off-chain-metadata/meta/test_generate.sh +++ /dev/null @@ -1,37 +0,0 @@ -#!/bin/bash -set -o errexit -o nounset -o pipefail -command -v shellcheck > /dev/null && shellcheck "$0" - -REPO_ROOT="$(realpath "$(dirname "$0")/..")" - -TMP_DIR=$(mktemp -d "${TMPDIR:-/tmp}/cw-template.XXXXXXXXX") -PROJECT_NAME="testgen-local" - -( - echo "Navigating to $TMP_DIR" - cd "$TMP_DIR" - - GIT_BRANCH=$(git -C "$REPO_ROOT" branch --show-current) - - echo "Generating project from local repository (branch $GIT_BRANCH) ..." - cargo generate --git "$REPO_ROOT" --name "$PROJECT_NAME" --branch "$GIT_BRANCH" - - ( - cd "$PROJECT_NAME" - echo "This is what was generated" - ls -lA - - # Check formatting - echo "Checking formatting ..." - cargo fmt -- --check - - # Debug builds first to fail fast - echo "Running unit tests ..." - cargo unit-test - echo "Creating schema ..." - cargo schema - - echo "Building wasm ..." - cargo wasm - ) -) diff --git a/cw721/off-chain-metadata/rustfmt.toml b/cw721/off-chain-metadata/rustfmt.toml deleted file mode 100644 index 11a85e6..0000000 --- a/cw721/off-chain-metadata/rustfmt.toml +++ /dev/null @@ -1,15 +0,0 @@ -# stable -newline_style = "unix" -hard_tabs = false -tab_spaces = 4 - -# unstable... should we require `rustup run nightly cargo fmt` ? -# or just update the style guide when they are stable? -#fn_single_line = true -#format_code_in_doc_comments = true -#overflow_delimited_expr = true -#reorder_impl_items = true -#struct_field_align_threshold = 20 -#struct_lit_single_line = true -#report_todo = "Always" - diff --git a/cw721/off-chain-metadata/schema/all_nft_info_response.json b/cw721/off-chain-metadata/schema/all_nft_info_response.json deleted file mode 100644 index bfc334b..0000000 --- a/cw721/off-chain-metadata/schema/all_nft_info_response.json +++ /dev/null @@ -1,155 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "AllNftInfoResponse", - "type": "object", - "required": [ - "access", - "info" - ], - "properties": { - "access": { - "description": "Who can transfer the token", - "allOf": [ - { - "$ref": "#/definitions/OwnerOfResponse" - } - ] - }, - "info": { - "description": "Data on the token itself,", - "allOf": [ - { - "$ref": "#/definitions/NftInfoResponse_for_Nullable_Empty" - } - ] - } - }, - "definitions": { - "Approval": { - "type": "object", - "required": [ - "expires", - "spender" - ], - "properties": { - "expires": { - "description": "When the Approval expires (maybe Expiration::never)", - "allOf": [ - { - "$ref": "#/definitions/Expiration" - } - ] - }, - "spender": { - "description": "Account that can transfer/send the token", - "type": "string" - } - } - }, - "Empty": { - "description": "An empty struct that serves as a placeholder in different places, such as contracts that don't set a custom message.\n\nIt is designed to be expressable in correct JSON and JSON Schema but contains no meaningful data. Previously we used enums without cases, but those cannot represented as valid JSON Schema (https://github.com/CosmWasm/cosmwasm/issues/451)", - "type": "object" - }, - "Expiration": { - "description": "Expiration represents a point in time when some event happens. It can compare with a BlockInfo and will return is_expired() == true once the condition is hit (and for every block in the future)", - "oneOf": [ - { - "description": "AtHeight will expire when `env.block.height` >= height", - "type": "object", - "required": [ - "at_height" - ], - "properties": { - "at_height": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 - } - }, - "additionalProperties": false - }, - { - "description": "AtTime will expire when `env.block.time` >= time", - "type": "object", - "required": [ - "at_time" - ], - "properties": { - "at_time": { - "$ref": "#/definitions/Timestamp" - } - }, - "additionalProperties": false - }, - { - "description": "Never will never expire. Used to express the empty variant", - "type": "object", - "required": [ - "never" - ], - "properties": { - "never": { - "type": "object" - } - }, - "additionalProperties": false - } - ] - }, - "NftInfoResponse_for_Nullable_Empty": { - "type": "object", - "properties": { - "extension": { - "description": "You can add any custom metadata here when you extend cw721-base", - "anyOf": [ - { - "$ref": "#/definitions/Empty" - }, - { - "type": "null" - } - ] - }, - "token_uri": { - "description": "Universal resource identifier for this NFT Should point to a JSON file that conforms to the ERC721 Metadata JSON Schema", - "type": [ - "string", - "null" - ] - } - } - }, - "OwnerOfResponse": { - "type": "object", - "required": [ - "approvals", - "owner" - ], - "properties": { - "approvals": { - "description": "If set this address is approved to transfer/send the token as well", - "type": "array", - "items": { - "$ref": "#/definitions/Approval" - } - }, - "owner": { - "description": "Owner of the token", - "type": "string" - } - } - }, - "Timestamp": { - "description": "A point in time in nanosecond precision.\n\nThis type can represent times from 1970-01-01T00:00:00Z to 2554-07-21T23:34:33Z.\n\n## Examples\n\n``` # use cosmwasm_std::Timestamp; let ts = Timestamp::from_nanos(1_000_000_202); assert_eq!(ts.nanos(), 1_000_000_202); assert_eq!(ts.seconds(), 1); assert_eq!(ts.subsec_nanos(), 202);\n\nlet ts = ts.plus_seconds(2); assert_eq!(ts.nanos(), 3_000_000_202); assert_eq!(ts.seconds(), 3); assert_eq!(ts.subsec_nanos(), 202); ```", - "allOf": [ - { - "$ref": "#/definitions/Uint64" - } - ] - }, - "Uint64": { - "description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```", - "type": "string" - } - } -} diff --git a/cw721/off-chain-metadata/schema/approval_response.json b/cw721/off-chain-metadata/schema/approval_response.json deleted file mode 100644 index 4f45b42..0000000 --- a/cw721/off-chain-metadata/schema/approval_response.json +++ /dev/null @@ -1,94 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "ApprovalResponse", - "type": "object", - "required": [ - "approval" - ], - "properties": { - "approval": { - "$ref": "#/definitions/Approval" - } - }, - "definitions": { - "Approval": { - "type": "object", - "required": [ - "expires", - "spender" - ], - "properties": { - "expires": { - "description": "When the Approval expires (maybe Expiration::never)", - "allOf": [ - { - "$ref": "#/definitions/Expiration" - } - ] - }, - "spender": { - "description": "Account that can transfer/send the token", - "type": "string" - } - } - }, - "Expiration": { - "description": "Expiration represents a point in time when some event happens. It can compare with a BlockInfo and will return is_expired() == true once the condition is hit (and for every block in the future)", - "oneOf": [ - { - "description": "AtHeight will expire when `env.block.height` >= height", - "type": "object", - "required": [ - "at_height" - ], - "properties": { - "at_height": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 - } - }, - "additionalProperties": false - }, - { - "description": "AtTime will expire when `env.block.time` >= time", - "type": "object", - "required": [ - "at_time" - ], - "properties": { - "at_time": { - "$ref": "#/definitions/Timestamp" - } - }, - "additionalProperties": false - }, - { - "description": "Never will never expire. Used to express the empty variant", - "type": "object", - "required": [ - "never" - ], - "properties": { - "never": { - "type": "object" - } - }, - "additionalProperties": false - } - ] - }, - "Timestamp": { - "description": "A point in time in nanosecond precision.\n\nThis type can represent times from 1970-01-01T00:00:00Z to 2554-07-21T23:34:33Z.\n\n## Examples\n\n``` # use cosmwasm_std::Timestamp; let ts = Timestamp::from_nanos(1_000_000_202); assert_eq!(ts.nanos(), 1_000_000_202); assert_eq!(ts.seconds(), 1); assert_eq!(ts.subsec_nanos(), 202);\n\nlet ts = ts.plus_seconds(2); assert_eq!(ts.nanos(), 3_000_000_202); assert_eq!(ts.seconds(), 3); assert_eq!(ts.subsec_nanos(), 202); ```", - "allOf": [ - { - "$ref": "#/definitions/Uint64" - } - ] - }, - "Uint64": { - "description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```", - "type": "string" - } - } -} diff --git a/cw721/off-chain-metadata/schema/approvals_response.json b/cw721/off-chain-metadata/schema/approvals_response.json deleted file mode 100644 index 8d8e39e..0000000 --- a/cw721/off-chain-metadata/schema/approvals_response.json +++ /dev/null @@ -1,97 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "ApprovalsResponse", - "type": "object", - "required": [ - "approvals" - ], - "properties": { - "approvals": { - "type": "array", - "items": { - "$ref": "#/definitions/Approval" - } - } - }, - "definitions": { - "Approval": { - "type": "object", - "required": [ - "expires", - "spender" - ], - "properties": { - "expires": { - "description": "When the Approval expires (maybe Expiration::never)", - "allOf": [ - { - "$ref": "#/definitions/Expiration" - } - ] - }, - "spender": { - "description": "Account that can transfer/send the token", - "type": "string" - } - } - }, - "Expiration": { - "description": "Expiration represents a point in time when some event happens. It can compare with a BlockInfo and will return is_expired() == true once the condition is hit (and for every block in the future)", - "oneOf": [ - { - "description": "AtHeight will expire when `env.block.height` >= height", - "type": "object", - "required": [ - "at_height" - ], - "properties": { - "at_height": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 - } - }, - "additionalProperties": false - }, - { - "description": "AtTime will expire when `env.block.time` >= time", - "type": "object", - "required": [ - "at_time" - ], - "properties": { - "at_time": { - "$ref": "#/definitions/Timestamp" - } - }, - "additionalProperties": false - }, - { - "description": "Never will never expire. Used to express the empty variant", - "type": "object", - "required": [ - "never" - ], - "properties": { - "never": { - "type": "object" - } - }, - "additionalProperties": false - } - ] - }, - "Timestamp": { - "description": "A point in time in nanosecond precision.\n\nThis type can represent times from 1970-01-01T00:00:00Z to 2554-07-21T23:34:33Z.\n\n## Examples\n\n``` # use cosmwasm_std::Timestamp; let ts = Timestamp::from_nanos(1_000_000_202); assert_eq!(ts.nanos(), 1_000_000_202); assert_eq!(ts.seconds(), 1); assert_eq!(ts.subsec_nanos(), 202);\n\nlet ts = ts.plus_seconds(2); assert_eq!(ts.nanos(), 3_000_000_202); assert_eq!(ts.seconds(), 3); assert_eq!(ts.subsec_nanos(), 202); ```", - "allOf": [ - { - "$ref": "#/definitions/Uint64" - } - ] - }, - "Uint64": { - "description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```", - "type": "string" - } - } -} diff --git a/cw721/off-chain-metadata/schema/approved_for_all_response.json b/cw721/off-chain-metadata/schema/approved_for_all_response.json deleted file mode 100644 index 453f17b..0000000 --- a/cw721/off-chain-metadata/schema/approved_for_all_response.json +++ /dev/null @@ -1,97 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "ApprovedForAllResponse", - "type": "object", - "required": [ - "operators" - ], - "properties": { - "operators": { - "type": "array", - "items": { - "$ref": "#/definitions/Approval" - } - } - }, - "definitions": { - "Approval": { - "type": "object", - "required": [ - "expires", - "spender" - ], - "properties": { - "expires": { - "description": "When the Approval expires (maybe Expiration::never)", - "allOf": [ - { - "$ref": "#/definitions/Expiration" - } - ] - }, - "spender": { - "description": "Account that can transfer/send the token", - "type": "string" - } - } - }, - "Expiration": { - "description": "Expiration represents a point in time when some event happens. It can compare with a BlockInfo and will return is_expired() == true once the condition is hit (and for every block in the future)", - "oneOf": [ - { - "description": "AtHeight will expire when `env.block.height` >= height", - "type": "object", - "required": [ - "at_height" - ], - "properties": { - "at_height": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 - } - }, - "additionalProperties": false - }, - { - "description": "AtTime will expire when `env.block.time` >= time", - "type": "object", - "required": [ - "at_time" - ], - "properties": { - "at_time": { - "$ref": "#/definitions/Timestamp" - } - }, - "additionalProperties": false - }, - { - "description": "Never will never expire. Used to express the empty variant", - "type": "object", - "required": [ - "never" - ], - "properties": { - "never": { - "type": "object" - } - }, - "additionalProperties": false - } - ] - }, - "Timestamp": { - "description": "A point in time in nanosecond precision.\n\nThis type can represent times from 1970-01-01T00:00:00Z to 2554-07-21T23:34:33Z.\n\n## Examples\n\n``` # use cosmwasm_std::Timestamp; let ts = Timestamp::from_nanos(1_000_000_202); assert_eq!(ts.nanos(), 1_000_000_202); assert_eq!(ts.seconds(), 1); assert_eq!(ts.subsec_nanos(), 202);\n\nlet ts = ts.plus_seconds(2); assert_eq!(ts.nanos(), 3_000_000_202); assert_eq!(ts.seconds(), 3); assert_eq!(ts.subsec_nanos(), 202); ```", - "allOf": [ - { - "$ref": "#/definitions/Uint64" - } - ] - }, - "Uint64": { - "description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```", - "type": "string" - } - } -} diff --git a/cw721/off-chain-metadata/schema/contract_info_response.json b/cw721/off-chain-metadata/schema/contract_info_response.json deleted file mode 100644 index a167125..0000000 --- a/cw721/off-chain-metadata/schema/contract_info_response.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "ContractInfoResponse", - "type": "object", - "required": [ - "name", - "symbol" - ], - "properties": { - "name": { - "type": "string" - }, - "symbol": { - "type": "string" - } - } -} diff --git a/cw721/off-chain-metadata/schema/execute_msg.json b/cw721/off-chain-metadata/schema/execute_msg.json deleted file mode 100644 index 5cdf660..0000000 --- a/cw721/off-chain-metadata/schema/execute_msg.json +++ /dev/null @@ -1,310 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "ExecuteMsg", - "description": "This is like Cw721ExecuteMsg but we add a Mint command for an owner to make this stand-alone. You will likely want to remove mint and use other control logic in any contract that inherits this.", - "oneOf": [ - { - "description": "Transfer is a base message to move a token to another account without triggering actions", - "type": "object", - "required": [ - "transfer_nft" - ], - "properties": { - "transfer_nft": { - "type": "object", - "required": [ - "recipient", - "token_id" - ], - "properties": { - "recipient": { - "type": "string" - }, - "token_id": { - "type": "string" - } - } - } - }, - "additionalProperties": false - }, - { - "description": "Send is a base message to transfer a token to a contract and trigger an action on the receiving contract.", - "type": "object", - "required": [ - "send_nft" - ], - "properties": { - "send_nft": { - "type": "object", - "required": [ - "contract", - "msg", - "token_id" - ], - "properties": { - "contract": { - "type": "string" - }, - "msg": { - "$ref": "#/definitions/Binary" - }, - "token_id": { - "type": "string" - } - } - } - }, - "additionalProperties": false - }, - { - "description": "Allows operator to transfer / send the token from the owner's account. If expiration is set, then this allowance has a time/height limit", - "type": "object", - "required": [ - "approve" - ], - "properties": { - "approve": { - "type": "object", - "required": [ - "spender", - "token_id" - ], - "properties": { - "expires": { - "anyOf": [ - { - "$ref": "#/definitions/Expiration" - }, - { - "type": "null" - } - ] - }, - "spender": { - "type": "string" - }, - "token_id": { - "type": "string" - } - } - } - }, - "additionalProperties": false - }, - { - "description": "Remove previously granted Approval", - "type": "object", - "required": [ - "revoke" - ], - "properties": { - "revoke": { - "type": "object", - "required": [ - "spender", - "token_id" - ], - "properties": { - "spender": { - "type": "string" - }, - "token_id": { - "type": "string" - } - } - } - }, - "additionalProperties": false - }, - { - "description": "Allows operator to transfer / send any token from the owner's account. If expiration is set, then this allowance has a time/height limit", - "type": "object", - "required": [ - "approve_all" - ], - "properties": { - "approve_all": { - "type": "object", - "required": [ - "operator" - ], - "properties": { - "expires": { - "anyOf": [ - { - "$ref": "#/definitions/Expiration" - }, - { - "type": "null" - } - ] - }, - "operator": { - "type": "string" - } - } - } - }, - "additionalProperties": false - }, - { - "description": "Remove previously granted ApproveAll permission", - "type": "object", - "required": [ - "revoke_all" - ], - "properties": { - "revoke_all": { - "type": "object", - "required": [ - "operator" - ], - "properties": { - "operator": { - "type": "string" - } - } - } - }, - "additionalProperties": false - }, - { - "description": "Mint a new NFT, can only be called by the contract minter", - "type": "object", - "required": [ - "mint" - ], - "properties": { - "mint": { - "$ref": "#/definitions/MintMsg_for_Nullable_Empty" - } - }, - "additionalProperties": false - }, - { - "description": "Burn an NFT the sender has access to", - "type": "object", - "required": [ - "burn" - ], - "properties": { - "burn": { - "type": "object", - "required": [ - "token_id" - ], - "properties": { - "token_id": { - "type": "string" - } - } - } - }, - "additionalProperties": false - } - ], - "definitions": { - "Binary": { - "description": "Binary is a wrapper around Vec to add base64 de/serialization with serde. It also adds some helper methods to help encode inline.\n\nThis is only needed as serde-json-{core,wasm} has a horrible encoding for Vec", - "type": "string" - }, - "Empty": { - "description": "An empty struct that serves as a placeholder in different places, such as contracts that don't set a custom message.\n\nIt is designed to be expressable in correct JSON and JSON Schema but contains no meaningful data. Previously we used enums without cases, but those cannot represented as valid JSON Schema (https://github.com/CosmWasm/cosmwasm/issues/451)", - "type": "object" - }, - "Expiration": { - "description": "Expiration represents a point in time when some event happens. It can compare with a BlockInfo and will return is_expired() == true once the condition is hit (and for every block in the future)", - "oneOf": [ - { - "description": "AtHeight will expire when `env.block.height` >= height", - "type": "object", - "required": [ - "at_height" - ], - "properties": { - "at_height": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 - } - }, - "additionalProperties": false - }, - { - "description": "AtTime will expire when `env.block.time` >= time", - "type": "object", - "required": [ - "at_time" - ], - "properties": { - "at_time": { - "$ref": "#/definitions/Timestamp" - } - }, - "additionalProperties": false - }, - { - "description": "Never will never expire. Used to express the empty variant", - "type": "object", - "required": [ - "never" - ], - "properties": { - "never": { - "type": "object" - } - }, - "additionalProperties": false - } - ] - }, - "MintMsg_for_Nullable_Empty": { - "type": "object", - "required": [ - "owner", - "token_id" - ], - "properties": { - "extension": { - "description": "Any custom extension used by this contract", - "anyOf": [ - { - "$ref": "#/definitions/Empty" - }, - { - "type": "null" - } - ] - }, - "owner": { - "description": "The owner of the newly minter NFT", - "type": "string" - }, - "token_id": { - "description": "Unique ID of the NFT", - "type": "string" - }, - "token_uri": { - "description": "Universal resource identifier for this NFT Should point to a JSON file that conforms to the ERC721 Metadata JSON Schema", - "type": [ - "string", - "null" - ] - } - } - }, - "Timestamp": { - "description": "A point in time in nanosecond precision.\n\nThis type can represent times from 1970-01-01T00:00:00Z to 2554-07-21T23:34:33Z.\n\n## Examples\n\n``` # use cosmwasm_std::Timestamp; let ts = Timestamp::from_nanos(1_000_000_202); assert_eq!(ts.nanos(), 1_000_000_202); assert_eq!(ts.seconds(), 1); assert_eq!(ts.subsec_nanos(), 202);\n\nlet ts = ts.plus_seconds(2); assert_eq!(ts.nanos(), 3_000_000_202); assert_eq!(ts.seconds(), 3); assert_eq!(ts.subsec_nanos(), 202); ```", - "allOf": [ - { - "$ref": "#/definitions/Uint64" - } - ] - }, - "Uint64": { - "description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```", - "type": "string" - } - } -} diff --git a/cw721/off-chain-metadata/schema/instantiate_msg.json b/cw721/off-chain-metadata/schema/instantiate_msg.json deleted file mode 100644 index b024c82..0000000 --- a/cw721/off-chain-metadata/schema/instantiate_msg.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "InstantiateMsg", - "type": "object", - "required": [ - "minter", - "name", - "symbol" - ], - "properties": { - "minter": { - "description": "The minter is the only one who can create new NFTs. This is designed for a base NFT that is controlled by an external program or contract. You will likely replace this with custom logic in custom NFTs", - "type": "string" - }, - "name": { - "description": "Name of the NFT contract", - "type": "string" - }, - "symbol": { - "description": "Symbol of the NFT contract", - "type": "string" - } - } -} diff --git a/cw721/off-chain-metadata/schema/minter_response.json b/cw721/off-chain-metadata/schema/minter_response.json deleted file mode 100644 index a20e0d7..0000000 --- a/cw721/off-chain-metadata/schema/minter_response.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "MinterResponse", - "description": "Shows who can mint these tokens", - "type": "object", - "required": [ - "minter" - ], - "properties": { - "minter": { - "type": "string" - } - } -} diff --git a/cw721/off-chain-metadata/schema/nft_info_response.json b/cw721/off-chain-metadata/schema/nft_info_response.json deleted file mode 100644 index e6bf1d4..0000000 --- a/cw721/off-chain-metadata/schema/nft_info_response.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "NftInfoResponse", - "type": "object", - "properties": { - "extension": { - "description": "You can add any custom metadata here when you extend cw721-base", - "anyOf": [ - { - "$ref": "#/definitions/Empty" - }, - { - "type": "null" - } - ] - }, - "token_uri": { - "description": "Universal resource identifier for this NFT Should point to a JSON file that conforms to the ERC721 Metadata JSON Schema", - "type": [ - "string", - "null" - ] - } - }, - "definitions": { - "Empty": { - "description": "An empty struct that serves as a placeholder in different places, such as contracts that don't set a custom message.\n\nIt is designed to be expressable in correct JSON and JSON Schema but contains no meaningful data. Previously we used enums without cases, but those cannot represented as valid JSON Schema (https://github.com/CosmWasm/cosmwasm/issues/451)", - "type": "object" - } - } -} diff --git a/cw721/off-chain-metadata/schema/num_tokens_response.json b/cw721/off-chain-metadata/schema/num_tokens_response.json deleted file mode 100644 index 4647c23..0000000 --- a/cw721/off-chain-metadata/schema/num_tokens_response.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "NumTokensResponse", - "type": "object", - "required": [ - "count" - ], - "properties": { - "count": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 - } - } -} diff --git a/cw721/off-chain-metadata/schema/operators_response.json b/cw721/off-chain-metadata/schema/operators_response.json deleted file mode 100644 index 5370307..0000000 --- a/cw721/off-chain-metadata/schema/operators_response.json +++ /dev/null @@ -1,97 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "OperatorsResponse", - "type": "object", - "required": [ - "operators" - ], - "properties": { - "operators": { - "type": "array", - "items": { - "$ref": "#/definitions/Approval" - } - } - }, - "definitions": { - "Approval": { - "type": "object", - "required": [ - "expires", - "spender" - ], - "properties": { - "expires": { - "description": "When the Approval expires (maybe Expiration::never)", - "allOf": [ - { - "$ref": "#/definitions/Expiration" - } - ] - }, - "spender": { - "description": "Account that can transfer/send the token", - "type": "string" - } - } - }, - "Expiration": { - "description": "Expiration represents a point in time when some event happens. It can compare with a BlockInfo and will return is_expired() == true once the condition is hit (and for every block in the future)", - "oneOf": [ - { - "description": "AtHeight will expire when `env.block.height` >= height", - "type": "object", - "required": [ - "at_height" - ], - "properties": { - "at_height": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 - } - }, - "additionalProperties": false - }, - { - "description": "AtTime will expire when `env.block.time` >= time", - "type": "object", - "required": [ - "at_time" - ], - "properties": { - "at_time": { - "$ref": "#/definitions/Timestamp" - } - }, - "additionalProperties": false - }, - { - "description": "Never will never expire. Used to express the empty variant", - "type": "object", - "required": [ - "never" - ], - "properties": { - "never": { - "type": "object" - } - }, - "additionalProperties": false - } - ] - }, - "Timestamp": { - "description": "A point in time in nanosecond precision.\n\nThis type can represent times from 1970-01-01T00:00:00Z to 2554-07-21T23:34:33Z.\n\n## Examples\n\n``` # use cosmwasm_std::Timestamp; let ts = Timestamp::from_nanos(1_000_000_202); assert_eq!(ts.nanos(), 1_000_000_202); assert_eq!(ts.seconds(), 1); assert_eq!(ts.subsec_nanos(), 202);\n\nlet ts = ts.plus_seconds(2); assert_eq!(ts.nanos(), 3_000_000_202); assert_eq!(ts.seconds(), 3); assert_eq!(ts.subsec_nanos(), 202); ```", - "allOf": [ - { - "$ref": "#/definitions/Uint64" - } - ] - }, - "Uint64": { - "description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```", - "type": "string" - } - } -} diff --git a/cw721/off-chain-metadata/schema/owner_of_response.json b/cw721/off-chain-metadata/schema/owner_of_response.json deleted file mode 100644 index 1258d67..0000000 --- a/cw721/off-chain-metadata/schema/owner_of_response.json +++ /dev/null @@ -1,103 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "OwnerOfResponse", - "type": "object", - "required": [ - "approvals", - "owner" - ], - "properties": { - "approvals": { - "description": "If set this address is approved to transfer/send the token as well", - "type": "array", - "items": { - "$ref": "#/definitions/Approval" - } - }, - "owner": { - "description": "Owner of the token", - "type": "string" - } - }, - "definitions": { - "Approval": { - "type": "object", - "required": [ - "expires", - "spender" - ], - "properties": { - "expires": { - "description": "When the Approval expires (maybe Expiration::never)", - "allOf": [ - { - "$ref": "#/definitions/Expiration" - } - ] - }, - "spender": { - "description": "Account that can transfer/send the token", - "type": "string" - } - } - }, - "Expiration": { - "description": "Expiration represents a point in time when some event happens. It can compare with a BlockInfo and will return is_expired() == true once the condition is hit (and for every block in the future)", - "oneOf": [ - { - "description": "AtHeight will expire when `env.block.height` >= height", - "type": "object", - "required": [ - "at_height" - ], - "properties": { - "at_height": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 - } - }, - "additionalProperties": false - }, - { - "description": "AtTime will expire when `env.block.time` >= time", - "type": "object", - "required": [ - "at_time" - ], - "properties": { - "at_time": { - "$ref": "#/definitions/Timestamp" - } - }, - "additionalProperties": false - }, - { - "description": "Never will never expire. Used to express the empty variant", - "type": "object", - "required": [ - "never" - ], - "properties": { - "never": { - "type": "object" - } - }, - "additionalProperties": false - } - ] - }, - "Timestamp": { - "description": "A point in time in nanosecond precision.\n\nThis type can represent times from 1970-01-01T00:00:00Z to 2554-07-21T23:34:33Z.\n\n## Examples\n\n``` # use cosmwasm_std::Timestamp; let ts = Timestamp::from_nanos(1_000_000_202); assert_eq!(ts.nanos(), 1_000_000_202); assert_eq!(ts.seconds(), 1); assert_eq!(ts.subsec_nanos(), 202);\n\nlet ts = ts.plus_seconds(2); assert_eq!(ts.nanos(), 3_000_000_202); assert_eq!(ts.seconds(), 3); assert_eq!(ts.subsec_nanos(), 202); ```", - "allOf": [ - { - "$ref": "#/definitions/Uint64" - } - ] - }, - "Uint64": { - "description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```", - "type": "string" - } - } -} diff --git a/cw721/off-chain-metadata/schema/query_msg.json b/cw721/off-chain-metadata/schema/query_msg.json deleted file mode 100644 index cd3a956..0000000 --- a/cw721/off-chain-metadata/schema/query_msg.json +++ /dev/null @@ -1,285 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "QueryMsg", - "oneOf": [ - { - "description": "Return the owner of the given token, error if token does not exist Return type: OwnerOfResponse", - "type": "object", - "required": [ - "owner_of" - ], - "properties": { - "owner_of": { - "type": "object", - "required": [ - "token_id" - ], - "properties": { - "include_expired": { - "description": "unset or false will filter out expired approvals, you must set to true to see them", - "type": [ - "boolean", - "null" - ] - }, - "token_id": { - "type": "string" - } - } - } - }, - "additionalProperties": false - }, - { - "description": "Return operator that can access all of the owner's tokens. Return type: `ApprovalResponse`", - "type": "object", - "required": [ - "approval" - ], - "properties": { - "approval": { - "type": "object", - "required": [ - "spender", - "token_id" - ], - "properties": { - "include_expired": { - "type": [ - "boolean", - "null" - ] - }, - "spender": { - "type": "string" - }, - "token_id": { - "type": "string" - } - } - } - }, - "additionalProperties": false - }, - { - "description": "Return approvals that a token has Return type: `ApprovalsResponse`", - "type": "object", - "required": [ - "approvals" - ], - "properties": { - "approvals": { - "type": "object", - "required": [ - "token_id" - ], - "properties": { - "include_expired": { - "type": [ - "boolean", - "null" - ] - }, - "token_id": { - "type": "string" - } - } - } - }, - "additionalProperties": false - }, - { - "description": "List all operators that can access all of the owner's tokens Return type: `OperatorsResponse`", - "type": "object", - "required": [ - "all_operators" - ], - "properties": { - "all_operators": { - "type": "object", - "required": [ - "owner" - ], - "properties": { - "include_expired": { - "description": "unset or false will filter out expired items, you must set to true to see them", - "type": [ - "boolean", - "null" - ] - }, - "limit": { - "type": [ - "integer", - "null" - ], - "format": "uint32", - "minimum": 0.0 - }, - "owner": { - "type": "string" - }, - "start_after": { - "type": [ - "string", - "null" - ] - } - } - } - }, - "additionalProperties": false - }, - { - "description": "Total number of tokens issued", - "type": "object", - "required": [ - "num_tokens" - ], - "properties": { - "num_tokens": { - "type": "object" - } - }, - "additionalProperties": false - }, - { - "description": "With MetaData Extension. Returns top-level metadata about the contract: `ContractInfoResponse`", - "type": "object", - "required": [ - "contract_info" - ], - "properties": { - "contract_info": { - "type": "object" - } - }, - "additionalProperties": false - }, - { - "description": "With MetaData Extension. Returns metadata about one particular token, based on *ERC721 Metadata JSON Schema* but directly from the contract: `NftInfoResponse`", - "type": "object", - "required": [ - "nft_info" - ], - "properties": { - "nft_info": { - "type": "object", - "required": [ - "token_id" - ], - "properties": { - "token_id": { - "type": "string" - } - } - } - }, - "additionalProperties": false - }, - { - "description": "With MetaData Extension. Returns the result of both `NftInfo` and `OwnerOf` as one query as an optimization for clients: `AllNftInfo`", - "type": "object", - "required": [ - "all_nft_info" - ], - "properties": { - "all_nft_info": { - "type": "object", - "required": [ - "token_id" - ], - "properties": { - "include_expired": { - "description": "unset or false will filter out expired approvals, you must set to true to see them", - "type": [ - "boolean", - "null" - ] - }, - "token_id": { - "type": "string" - } - } - } - }, - "additionalProperties": false - }, - { - "description": "With Enumerable extension. Returns all tokens owned by the given address, [] if unset. Return type: TokensResponse.", - "type": "object", - "required": [ - "tokens" - ], - "properties": { - "tokens": { - "type": "object", - "required": [ - "owner" - ], - "properties": { - "limit": { - "type": [ - "integer", - "null" - ], - "format": "uint32", - "minimum": 0.0 - }, - "owner": { - "type": "string" - }, - "start_after": { - "type": [ - "string", - "null" - ] - } - } - } - }, - "additionalProperties": false - }, - { - "description": "With Enumerable extension. Requires pagination. Lists all token_ids controlled by the contract. Return type: TokensResponse.", - "type": "object", - "required": [ - "all_tokens" - ], - "properties": { - "all_tokens": { - "type": "object", - "properties": { - "limit": { - "type": [ - "integer", - "null" - ], - "format": "uint32", - "minimum": 0.0 - }, - "start_after": { - "type": [ - "string", - "null" - ] - } - } - } - }, - "additionalProperties": false - }, - { - "type": "object", - "required": [ - "minter" - ], - "properties": { - "minter": { - "type": "object" - } - }, - "additionalProperties": false - } - ] -} diff --git a/cw721/off-chain-metadata/schema/tokens_response.json b/cw721/off-chain-metadata/schema/tokens_response.json deleted file mode 100644 index b8e3d75..0000000 --- a/cw721/off-chain-metadata/schema/tokens_response.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "TokensResponse", - "type": "object", - "required": [ - "tokens" - ], - "properties": { - "tokens": { - "description": "Contains all token_ids in lexicographical ordering If there are more than `limit`, use `start_from` in future queries to achieve pagination.", - "type": "array", - "items": { - "type": "string" - } - } - } -} diff --git a/cw721/off-chain-metadata/src/error.rs b/cw721/off-chain-metadata/src/error.rs deleted file mode 100644 index db1ceaa..0000000 --- a/cw721/off-chain-metadata/src/error.rs +++ /dev/null @@ -1,20 +0,0 @@ -use cosmwasm_std::StdError; -use thiserror::Error; - -#[derive(Error, Debug, PartialEq)] -pub enum ContractError { - #[error("{0}")] - Std(#[from] StdError), - - #[error("Unauthorized")] - Unauthorized {}, - - #[error("token_id already claimed")] - Claimed {}, - - #[error("Cannot set approval that is already expired")] - Expired {}, - - #[error("Approval not found for: {spender}")] - ApprovalNotFound { spender: String }, -} diff --git a/cw721/off-chain-metadata/src/execute.rs b/cw721/off-chain-metadata/src/execute.rs deleted file mode 100644 index d029332..0000000 --- a/cw721/off-chain-metadata/src/execute.rs +++ /dev/null @@ -1,397 +0,0 @@ -use serde::de::DeserializeOwned; -use serde::Serialize; - -use cosmwasm_std::{Binary, Deps, DepsMut, Env, MessageInfo, Response, StdResult}; - -use cw2::set_contract_version; -use cw721::{ContractInfoResponse, CustomMsg, Cw721Execute, Cw721ReceiveMsg, Expiration}; - -use crate::error::ContractError; -use crate::msg::{ExecuteMsg, InstantiateMsg, MintMsg}; -use crate::state::{Approval, Cw721Contract, TokenInfo}; - -// version info for migration -const CONTRACT_NAME: &str = "crates.io:{{project-name}}"; -const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION"); - -impl<'a, T, C> Cw721Contract<'a, T, C> -where - T: Serialize + DeserializeOwned + Clone, - C: CustomMsg, -{ - pub fn instantiate( - &self, - deps: DepsMut, - _env: Env, - _info: MessageInfo, - msg: InstantiateMsg, - ) -> StdResult> { - set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; - - let info = ContractInfoResponse { - name: msg.name, - symbol: msg.symbol, - }; - self.contract_info.save(deps.storage, &info)?; - let minter = deps.api.addr_validate(&msg.minter)?; - self.minter.save(deps.storage, &minter)?; - Ok(Response::default()) - } - - pub fn execute( - &self, - deps: DepsMut, - env: Env, - info: MessageInfo, - msg: ExecuteMsg, - ) -> Result, ContractError> { - match msg { - ExecuteMsg::Mint(msg) => self.mint(deps, env, info, msg), - ExecuteMsg::Approve { - spender, - token_id, - expires, - } => self.approve(deps, env, info, spender, token_id, expires), - ExecuteMsg::Revoke { spender, token_id } => { - self.revoke(deps, env, info, spender, token_id) - } - ExecuteMsg::ApproveAll { operator, expires } => { - self.approve_all(deps, env, info, operator, expires) - } - ExecuteMsg::RevokeAll { operator } => self.revoke_all(deps, env, info, operator), - ExecuteMsg::TransferNft { - recipient, - token_id, - } => self.transfer_nft(deps, env, info, recipient, token_id), - ExecuteMsg::SendNft { - contract, - token_id, - msg, - } => self.send_nft(deps, env, info, contract, token_id, msg), - ExecuteMsg::Burn { token_id } => self.burn(deps, env, info, token_id), - } - } -} - -// TODO pull this into some sort of trait extension?? -impl<'a, T, C> Cw721Contract<'a, T, C> -where - T: Serialize + DeserializeOwned + Clone, - C: CustomMsg, -{ - pub fn mint( - &self, - deps: DepsMut, - _env: Env, - info: MessageInfo, - msg: MintMsg, - ) -> Result, ContractError> { - let minter = self.minter.load(deps.storage)?; - - if info.sender != minter { - return Err(ContractError::Unauthorized {}); - } - - // create the token - let token = TokenInfo { - owner: deps.api.addr_validate(&msg.owner)?, - approvals: vec![], - token_uri: msg.token_uri, - extension: msg.extension, - }; - self.tokens - .update(deps.storage, &msg.token_id, |old| match old { - Some(_) => Err(ContractError::Claimed {}), - None => Ok(token), - })?; - - self.increment_tokens(deps.storage)?; - - Ok(Response::new() - .add_attribute("action", "mint") - .add_attribute("minter", info.sender) - .add_attribute("token_id", msg.token_id)) - } -} - -impl<'a, T, C> Cw721Execute for Cw721Contract<'a, T, C> -where - T: Serialize + DeserializeOwned + Clone, - C: CustomMsg, -{ - type Err = ContractError; - - fn transfer_nft( - &self, - deps: DepsMut, - env: Env, - info: MessageInfo, - recipient: String, - token_id: String, - ) -> Result, ContractError> { - self._transfer_nft(deps, &env, &info, &recipient, &token_id)?; - - Ok(Response::new() - .add_attribute("action", "transfer_nft") - .add_attribute("sender", info.sender) - .add_attribute("recipient", recipient) - .add_attribute("token_id", token_id)) - } - - fn send_nft( - &self, - deps: DepsMut, - env: Env, - info: MessageInfo, - contract: String, - token_id: String, - msg: Binary, - ) -> Result, ContractError> { - // Transfer token - self._transfer_nft(deps, &env, &info, &contract, &token_id)?; - - let send = Cw721ReceiveMsg { - sender: info.sender.to_string(), - token_id: token_id.clone(), - msg, - }; - - // Send message - Ok(Response::new() - .add_message(send.into_cosmos_msg(contract.clone())?) - .add_attribute("action", "send_nft") - .add_attribute("sender", info.sender) - .add_attribute("recipient", contract) - .add_attribute("token_id", token_id)) - } - - fn approve( - &self, - deps: DepsMut, - env: Env, - info: MessageInfo, - spender: String, - token_id: String, - expires: Option, - ) -> Result, ContractError> { - self._update_approvals(deps, &env, &info, &spender, &token_id, true, expires)?; - - Ok(Response::new() - .add_attribute("action", "approve") - .add_attribute("sender", info.sender) - .add_attribute("spender", spender) - .add_attribute("token_id", token_id)) - } - - fn revoke( - &self, - deps: DepsMut, - env: Env, - info: MessageInfo, - spender: String, - token_id: String, - ) -> Result, ContractError> { - self._update_approvals(deps, &env, &info, &spender, &token_id, false, None)?; - - Ok(Response::new() - .add_attribute("action", "revoke") - .add_attribute("sender", info.sender) - .add_attribute("spender", spender) - .add_attribute("token_id", token_id)) - } - - fn approve_all( - &self, - deps: DepsMut, - env: Env, - info: MessageInfo, - operator: String, - expires: Option, - ) -> Result, ContractError> { - // reject expired data as invalid - let expires = expires.unwrap_or_default(); - if expires.is_expired(&env.block) { - return Err(ContractError::Expired {}); - } - - // set the operator for us - let operator_addr = deps.api.addr_validate(&operator)?; - self.operators - .save(deps.storage, (&info.sender, &operator_addr), &expires)?; - - Ok(Response::new() - .add_attribute("action", "approve_all") - .add_attribute("sender", info.sender) - .add_attribute("operator", operator)) - } - - fn revoke_all( - &self, - deps: DepsMut, - _env: Env, - info: MessageInfo, - operator: String, - ) -> Result, ContractError> { - let operator_addr = deps.api.addr_validate(&operator)?; - self.operators - .remove(deps.storage, (&info.sender, &operator_addr)); - - Ok(Response::new() - .add_attribute("action", "revoke_all") - .add_attribute("sender", info.sender) - .add_attribute("operator", operator)) - } - - fn burn( - &self, - deps: DepsMut, - env: Env, - info: MessageInfo, - token_id: String, - ) -> Result, ContractError> { - let token = self.tokens.load(deps.storage, &token_id)?; - self.check_can_send(deps.as_ref(), &env, &info, &token)?; - - self.tokens.remove(deps.storage, &token_id)?; - self.decrement_tokens(deps.storage)?; - - Ok(Response::new() - .add_attribute("action", "burn") - .add_attribute("sender", info.sender) - .add_attribute("token_id", token_id)) - } -} - -// helpers -impl<'a, T, C> Cw721Contract<'a, T, C> -where - T: Serialize + DeserializeOwned + Clone, - C: CustomMsg, -{ - pub fn _transfer_nft( - &self, - deps: DepsMut, - env: &Env, - info: &MessageInfo, - recipient: &str, - token_id: &str, - ) -> Result, ContractError> { - let mut token = self.tokens.load(deps.storage, token_id)?; - // ensure we have permissions - self.check_can_send(deps.as_ref(), env, info, &token)?; - // set owner and remove existing approvals - token.owner = deps.api.addr_validate(recipient)?; - token.approvals = vec![]; - self.tokens.save(deps.storage, token_id, &token)?; - Ok(token) - } - - #[allow(clippy::too_many_arguments)] - pub fn _update_approvals( - &self, - deps: DepsMut, - env: &Env, - info: &MessageInfo, - spender: &str, - token_id: &str, - // if add == false, remove. if add == true, remove then set with this expiration - add: bool, - expires: Option, - ) -> Result, ContractError> { - let mut token = self.tokens.load(deps.storage, token_id)?; - // ensure we have permissions - self.check_can_approve(deps.as_ref(), env, info, &token)?; - - // update the approval list (remove any for the same spender before adding) - let spender_addr = deps.api.addr_validate(spender)?; - token.approvals = token - .approvals - .into_iter() - .filter(|apr| apr.spender != spender_addr) - .collect(); - - // only difference between approve and revoke - if add { - // reject expired data as invalid - let expires = expires.unwrap_or_default(); - if expires.is_expired(&env.block) { - return Err(ContractError::Expired {}); - } - let approval = Approval { - spender: spender_addr, - expires, - }; - token.approvals.push(approval); - } - - self.tokens.save(deps.storage, token_id, &token)?; - - Ok(token) - } - - /// returns true iff the sender can execute approve or reject on the contract - pub fn check_can_approve( - &self, - deps: Deps, - env: &Env, - info: &MessageInfo, - token: &TokenInfo, - ) -> Result<(), ContractError> { - // owner can approve - if token.owner == info.sender { - return Ok(()); - } - // operator can approve - let op = self - .operators - .may_load(deps.storage, (&token.owner, &info.sender))?; - match op { - Some(ex) => { - if ex.is_expired(&env.block) { - Err(ContractError::Unauthorized {}) - } else { - Ok(()) - } - } - None => Err(ContractError::Unauthorized {}), - } - } - - /// returns true iff the sender can transfer ownership of the token - pub fn check_can_send( - &self, - deps: Deps, - env: &Env, - info: &MessageInfo, - token: &TokenInfo, - ) -> Result<(), ContractError> { - // owner can send - if token.owner == info.sender { - return Ok(()); - } - - // any non-expired token approval can send - if token - .approvals - .iter() - .any(|apr| apr.spender == info.sender && !apr.is_expired(&env.block)) - { - return Ok(()); - } - - // operator can send - let op = self - .operators - .may_load(deps.storage, (&token.owner, &info.sender))?; - match op { - Some(ex) => { - if ex.is_expired(&env.block) { - Err(ContractError::Unauthorized {}) - } else { - Ok(()) - } - } - None => Err(ContractError::Unauthorized {}), - } - } -} diff --git a/cw721/off-chain-metadata/src/helpers.rs b/cw721/off-chain-metadata/src/helpers.rs deleted file mode 100644 index 437132f..0000000 --- a/cw721/off-chain-metadata/src/helpers.rs +++ /dev/null @@ -1,179 +0,0 @@ -use crate::{ExecuteMsg, QueryMsg}; -use cosmwasm_std::{to_binary, Addr, CosmosMsg, QuerierWrapper, StdResult, WasmMsg, WasmQuery}; -use cw721::{ - AllNftInfoResponse, Approval, ApprovalResponse, ApprovalsResponse, ContractInfoResponse, - NftInfoResponse, NumTokensResponse, OperatorsResponse, OwnerOfResponse, TokensResponse, -}; -use serde::de::DeserializeOwned; -use serde::{Deserialize, Serialize}; - -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] -pub struct Cw721Contract(pub Addr); - -#[allow(dead_code)] -impl Cw721Contract { - pub fn addr(&self) -> Addr { - self.0.clone() - } - - pub fn call(&self, msg: ExecuteMsg) -> StdResult { - let msg = to_binary(&msg)?; - Ok(WasmMsg::Execute { - contract_addr: self.addr().into(), - msg, - funds: vec![], - } - .into()) - } - - pub fn query( - &self, - querier: &QuerierWrapper, - req: QueryMsg, - ) -> StdResult { - let query = WasmQuery::Smart { - contract_addr: self.addr().into(), - msg: to_binary(&req)?, - } - .into(); - querier.query(&query) - } - - /*** queries ***/ - - pub fn owner_of>( - &self, - querier: &QuerierWrapper, - token_id: T, - include_expired: bool, - ) -> StdResult { - let req = QueryMsg::OwnerOf { - token_id: token_id.into(), - include_expired: Some(include_expired), - }; - self.query(querier, req) - } - - pub fn approval>( - &self, - querier: &QuerierWrapper, - token_id: T, - spender: T, - include_expired: Option, - ) -> StdResult { - let req = QueryMsg::Approval { - token_id: token_id.into(), - spender: spender.into(), - include_expired, - }; - let res: ApprovalResponse = self.query(querier, req)?; - Ok(res) - } - - pub fn approvals>( - &self, - querier: &QuerierWrapper, - token_id: T, - include_expired: Option, - ) -> StdResult { - let req = QueryMsg::Approvals { - token_id: token_id.into(), - include_expired, - }; - let res: ApprovalsResponse = self.query(querier, req)?; - Ok(res) - } - - pub fn all_operators>( - &self, - querier: &QuerierWrapper, - owner: T, - include_expired: bool, - start_after: Option, - limit: Option, - ) -> StdResult> { - let req = QueryMsg::AllOperators { - owner: owner.into(), - include_expired: Some(include_expired), - start_after, - limit, - }; - let res: OperatorsResponse = self.query(querier, req)?; - Ok(res.operators) - } - - pub fn num_tokens(&self, querier: &QuerierWrapper) -> StdResult { - let req = QueryMsg::NumTokens {}; - let res: NumTokensResponse = self.query(querier, req)?; - Ok(res.count) - } - - /// With metadata extension - pub fn contract_info(&self, querier: &QuerierWrapper) -> StdResult { - let req = QueryMsg::ContractInfo {}; - self.query(querier, req) - } - - /// With metadata extension - pub fn nft_info, U: DeserializeOwned>( - &self, - querier: &QuerierWrapper, - token_id: T, - ) -> StdResult> { - let req = QueryMsg::NftInfo { - token_id: token_id.into(), - }; - self.query(querier, req) - } - - /// With metadata extension - pub fn all_nft_info, U: DeserializeOwned>( - &self, - querier: &QuerierWrapper, - token_id: T, - include_expired: bool, - ) -> StdResult> { - let req = QueryMsg::AllNftInfo { - token_id: token_id.into(), - include_expired: Some(include_expired), - }; - self.query(querier, req) - } - - /// With enumerable extension - pub fn tokens>( - &self, - querier: &QuerierWrapper, - owner: T, - start_after: Option, - limit: Option, - ) -> StdResult { - let req = QueryMsg::Tokens { - owner: owner.into(), - start_after, - limit, - }; - self.query(querier, req) - } - - /// With enumerable extension - pub fn all_tokens( - &self, - querier: &QuerierWrapper, - start_after: Option, - limit: Option, - ) -> StdResult { - let req = QueryMsg::AllTokens { start_after, limit }; - self.query(querier, req) - } - - /// returns true if the contract supports the metadata extension - pub fn has_metadata(&self, querier: &QuerierWrapper) -> bool { - self.contract_info(querier).is_ok() - } - - /// returns true if the contract supports the enumerable extension - pub fn has_enumerable(&self, querier: &QuerierWrapper) -> bool { - self.tokens(querier, self.addr(), None, Some(1)).is_ok() - } -} diff --git a/cw721/off-chain-metadata/src/lib.rs b/cw721/off-chain-metadata/src/lib.rs deleted file mode 100644 index 5028832..0000000 --- a/cw721/off-chain-metadata/src/lib.rs +++ /dev/null @@ -1,53 +0,0 @@ -mod error; -mod execute; -pub mod helpers; -pub mod msg; -mod query; -pub mod state; -mod tests; - -pub use crate::error::ContractError; -pub use crate::msg::{ExecuteMsg, InstantiateMsg, MintMsg, MinterResponse, QueryMsg}; -pub use crate::state::Cw721Contract; - -use cosmwasm_std::Empty; - -// This is a simple type to let us handle empty extensions -pub type Extension = Option; - -#[cfg(not(feature = "library"))] -pub mod entry { - use super::*; - - use cosmwasm_std::entry_point; - use cosmwasm_std::{Binary, Deps, DepsMut, Env, MessageInfo, Response, StdResult}; - - // This makes a conscious choice on the various generics used by the contract - #[entry_point] - pub fn instantiate( - deps: DepsMut, - env: Env, - info: MessageInfo, - msg: InstantiateMsg, - ) -> StdResult { - let contract = Cw721Contract::::default(); - contract.instantiate(deps, env, info, msg) - } - - #[entry_point] - pub fn execute( - deps: DepsMut, - env: Env, - info: MessageInfo, - msg: ExecuteMsg, - ) -> Result { - let contract = Cw721Contract::::default(); - contract.execute(deps, env, info, msg) - } - - #[entry_point] - pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> StdResult { - let contract = Cw721Contract::::default(); - contract.query(deps, env, msg) - } -} diff --git a/cw721/off-chain-metadata/src/msg.rs b/cw721/off-chain-metadata/src/msg.rs deleted file mode 100644 index 6d2994e..0000000 --- a/cw721/off-chain-metadata/src/msg.rs +++ /dev/null @@ -1,154 +0,0 @@ -use schemars::JsonSchema; -use serde::{Deserialize, Serialize}; - -use cosmwasm_std::Binary; -use cw721::Expiration; - -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] -pub struct InstantiateMsg { - /// Name of the NFT contract - pub name: String, - /// Symbol of the NFT contract - pub symbol: String, - - /// The minter is the only one who can create new NFTs. - /// This is designed for a base NFT that is controlled by an external program - /// or contract. You will likely replace this with custom logic in custom NFTs - pub minter: String, -} - -/// This is like Cw721ExecuteMsg but we add a Mint command for an owner -/// to make this stand-alone. You will likely want to remove mint and -/// use other control logic in any contract that inherits this. -#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] -#[serde(rename_all = "snake_case")] -pub enum ExecuteMsg { - /// Transfer is a base message to move a token to another account without triggering actions - TransferNft { recipient: String, token_id: String }, - /// Send is a base message to transfer a token to a contract and trigger an action - /// on the receiving contract. - SendNft { - contract: String, - token_id: String, - msg: Binary, - }, - /// Allows operator to transfer / send the token from the owner's account. - /// If expiration is set, then this allowance has a time/height limit - Approve { - spender: String, - token_id: String, - expires: Option, - }, - /// Remove previously granted Approval - Revoke { spender: String, token_id: String }, - /// Allows operator to transfer / send any token from the owner's account. - /// If expiration is set, then this allowance has a time/height limit - ApproveAll { - operator: String, - expires: Option, - }, - /// Remove previously granted ApproveAll permission - RevokeAll { operator: String }, - - /// Mint a new NFT, can only be called by the contract minter - Mint(MintMsg), - - /// Burn an NFT the sender has access to - Burn { token_id: String }, -} - -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] -pub struct MintMsg { - /// Unique ID of the NFT - pub token_id: String, - /// The owner of the newly minter NFT - pub owner: String, - /// Universal resource identifier for this NFT - /// Should point to a JSON file that conforms to the ERC721 - /// Metadata JSON Schema - pub token_uri: Option, - /// Any custom extension used by this contract - pub extension: T, -} - -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] -#[serde(rename_all = "snake_case")] -pub enum QueryMsg { - /// Return the owner of the given token, error if token does not exist - /// Return type: OwnerOfResponse - OwnerOf { - token_id: String, - /// unset or false will filter out expired approvals, you must set to true to see them - include_expired: Option, - }, - - /// Return operator that can access all of the owner's tokens. - /// Return type: `ApprovalResponse` - Approval { - token_id: String, - spender: String, - include_expired: Option, - }, - - /// Return approvals that a token has - /// Return type: `ApprovalsResponse` - Approvals { - token_id: String, - include_expired: Option, - }, - - /// List all operators that can access all of the owner's tokens - /// Return type: `OperatorsResponse` - AllOperators { - owner: String, - /// unset or false will filter out expired items, you must set to true to see them - include_expired: Option, - start_after: Option, - limit: Option, - }, - /// Total number of tokens issued - NumTokens {}, - - /// With MetaData Extension. - /// Returns top-level metadata about the contract: `ContractInfoResponse` - ContractInfo {}, - /// With MetaData Extension. - /// Returns metadata about one particular token, based on *ERC721 Metadata JSON Schema* - /// but directly from the contract: `NftInfoResponse` - NftInfo { - token_id: String, - }, - /// With MetaData Extension. - /// Returns the result of both `NftInfo` and `OwnerOf` as one query as an optimization - /// for clients: `AllNftInfo` - AllNftInfo { - token_id: String, - /// unset or false will filter out expired approvals, you must set to true to see them - include_expired: Option, - }, - - /// With Enumerable extension. - /// Returns all tokens owned by the given address, [] if unset. - /// Return type: TokensResponse. - Tokens { - owner: String, - start_after: Option, - limit: Option, - }, - /// With Enumerable extension. - /// Requires pagination. Lists all token_ids controlled by the contract. - /// Return type: TokensResponse. - AllTokens { - start_after: Option, - limit: Option, - }, - - // Return the minter - Minter {}, -} - -/// Shows who can mint these tokens -#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] -pub struct MinterResponse { - pub minter: String, -} diff --git a/cw721/off-chain-metadata/src/query.rs b/cw721/off-chain-metadata/src/query.rs deleted file mode 100644 index 885afcd..0000000 --- a/cw721/off-chain-metadata/src/query.rs +++ /dev/null @@ -1,308 +0,0 @@ -use serde::de::DeserializeOwned; -use serde::Serialize; - -use cosmwasm_std::{to_binary, Addr, Binary, BlockInfo, Deps, Env, Order, StdError, StdResult}; - -use cw721::{ - AllNftInfoResponse, ApprovalResponse, ApprovalsResponse, ContractInfoResponse, CustomMsg, - Cw721Query, Expiration, NftInfoResponse, NumTokensResponse, OperatorsResponse, OwnerOfResponse, - TokensResponse, -}; -use cw_storage_plus::Bound; -use cw_utils::maybe_addr; - -use crate::msg::{MinterResponse, QueryMsg}; -use crate::state::{Approval, Cw721Contract, TokenInfo}; - -const DEFAULT_LIMIT: u32 = 10; -const MAX_LIMIT: u32 = 30; - -impl<'a, T, C> Cw721Query for Cw721Contract<'a, T, C> -where - T: Serialize + DeserializeOwned + Clone, - C: CustomMsg, -{ - fn contract_info(&self, deps: Deps) -> StdResult { - self.contract_info.load(deps.storage) - } - - fn num_tokens(&self, deps: Deps) -> StdResult { - let count = self.token_count(deps.storage)?; - Ok(NumTokensResponse { count }) - } - - fn nft_info(&self, deps: Deps, token_id: String) -> StdResult> { - let info = self.tokens.load(deps.storage, &token_id)?; - Ok(NftInfoResponse { - token_uri: info.token_uri, - extension: info.extension, - }) - } - - fn owner_of( - &self, - deps: Deps, - env: Env, - token_id: String, - include_expired: bool, - ) -> StdResult { - let info = self.tokens.load(deps.storage, &token_id)?; - Ok(OwnerOfResponse { - owner: info.owner.to_string(), - approvals: humanize_approvals(&env.block, &info, include_expired), - }) - } - - /// operators returns all operators owner given access to - fn operators( - &self, - deps: Deps, - env: Env, - owner: String, - include_expired: bool, - start_after: Option, - limit: Option, - ) -> StdResult { - let limit = limit.unwrap_or(DEFAULT_LIMIT).min(MAX_LIMIT) as usize; - let start_addr = maybe_addr(deps.api, start_after)?; - let start = start_addr.map(|addr| Bound::exclusive(addr.as_ref())); - - let owner_addr = deps.api.addr_validate(&owner)?; - let res: StdResult> = self - .operators - .prefix(&owner_addr) - .range(deps.storage, start, None, Order::Ascending) - .filter(|r| { - include_expired || r.is_err() || !r.as_ref().unwrap().1.is_expired(&env.block) - }) - .take(limit) - .map(parse_approval) - .collect(); - Ok(OperatorsResponse { operators: res? }) - } - - fn approval( - &self, - deps: Deps, - env: Env, - token_id: String, - spender: String, - include_expired: bool, - ) -> StdResult { - let token = self.tokens.load(deps.storage, &token_id)?; - - // token owner has absolute approval - if token.owner == spender { - let approval = cw721::Approval { - spender: token.owner.to_string(), - expires: Expiration::Never {}, - }; - return Ok(ApprovalResponse { approval }); - } - - let filtered: Vec<_> = token - .approvals - .into_iter() - .filter(|t| t.spender == spender) - .filter(|t| include_expired || !t.is_expired(&env.block)) - .map(|a| cw721::Approval { - spender: a.spender.into_string(), - expires: a.expires, - }) - .collect(); - - if filtered.is_empty() { - return Err(StdError::not_found("Approval not found")); - } - // we expect only one item - let approval = filtered[0].clone(); - - Ok(ApprovalResponse { approval }) - } - - /// approvals returns all approvals owner given access to - fn approvals( - &self, - deps: Deps, - env: Env, - token_id: String, - include_expired: bool, - ) -> StdResult { - let token = self.tokens.load(deps.storage, &token_id)?; - let approvals: Vec<_> = token - .approvals - .into_iter() - .filter(|t| include_expired || !t.is_expired(&env.block)) - .map(|a| cw721::Approval { - spender: a.spender.into_string(), - expires: a.expires, - }) - .collect(); - - Ok(ApprovalsResponse { approvals }) - } - - fn tokens( - &self, - deps: Deps, - owner: String, - start_after: Option, - limit: Option, - ) -> StdResult { - let limit = limit.unwrap_or(DEFAULT_LIMIT).min(MAX_LIMIT) as usize; - let start = start_after.map(Bound::exclusive); - - let owner_addr = deps.api.addr_validate(&owner)?; - let tokens: Vec = self - .tokens - .idx - .owner - .prefix(owner_addr) - .keys(deps.storage, start, None, Order::Ascending) - .take(limit) - .map(|x| x.map(|addr| addr.to_string())) - .collect::>>()?; - - Ok(TokensResponse { tokens }) - } - - fn all_tokens( - &self, - deps: Deps, - start_after: Option, - limit: Option, - ) -> StdResult { - let limit = limit.unwrap_or(DEFAULT_LIMIT).min(MAX_LIMIT) as usize; - let start = start_after.map(Bound::exclusive); - - let tokens: StdResult> = self - .tokens - .range(deps.storage, start, None, Order::Ascending) - .take(limit) - .map(|item| item.map(|(k, _)| k)) - .collect(); - - Ok(TokensResponse { tokens: tokens? }) - } - - fn all_nft_info( - &self, - deps: Deps, - env: Env, - token_id: String, - include_expired: bool, - ) -> StdResult> { - let info = self.tokens.load(deps.storage, &token_id)?; - Ok(AllNftInfoResponse { - access: OwnerOfResponse { - owner: info.owner.to_string(), - approvals: humanize_approvals(&env.block, &info, include_expired), - }, - info: NftInfoResponse { - token_uri: info.token_uri, - extension: info.extension, - }, - }) - } -} - -impl<'a, T, C> Cw721Contract<'a, T, C> -where - T: Serialize + DeserializeOwned + Clone, - C: CustomMsg, -{ - pub fn minter(&self, deps: Deps) -> StdResult { - let minter_addr = self.minter.load(deps.storage)?; - Ok(MinterResponse { - minter: minter_addr.to_string(), - }) - } - - pub fn query(&self, deps: Deps, env: Env, msg: QueryMsg) -> StdResult { - match msg { - QueryMsg::Minter {} => to_binary(&self.minter(deps)?), - QueryMsg::ContractInfo {} => to_binary(&self.contract_info(deps)?), - QueryMsg::NftInfo { token_id } => to_binary(&self.nft_info(deps, token_id)?), - QueryMsg::OwnerOf { - token_id, - include_expired, - } => { - to_binary(&self.owner_of(deps, env, token_id, include_expired.unwrap_or(false))?) - } - QueryMsg::AllNftInfo { - token_id, - include_expired, - } => to_binary(&self.all_nft_info( - deps, - env, - token_id, - include_expired.unwrap_or(false), - )?), - QueryMsg::AllOperators { - owner, - include_expired, - start_after, - limit, - } => to_binary(&self.operators( - deps, - env, - owner, - include_expired.unwrap_or(false), - start_after, - limit, - )?), - QueryMsg::NumTokens {} => to_binary(&self.num_tokens(deps)?), - QueryMsg::Tokens { - owner, - start_after, - limit, - } => to_binary(&self.tokens(deps, owner, start_after, limit)?), - QueryMsg::AllTokens { start_after, limit } => { - to_binary(&self.all_tokens(deps, start_after, limit)?) - } - QueryMsg::Approval { - token_id, - spender, - include_expired, - } => to_binary(&self.approval( - deps, - env, - token_id, - spender, - include_expired.unwrap_or(false), - )?), - QueryMsg::Approvals { - token_id, - include_expired, - } => { - to_binary(&self.approvals(deps, env, token_id, include_expired.unwrap_or(false))?) - } - } - } -} - -fn parse_approval(item: StdResult<(Addr, Expiration)>) -> StdResult { - item.map(|(spender, expires)| cw721::Approval { - spender: spender.to_string(), - expires, - }) -} - -fn humanize_approvals( - block: &BlockInfo, - info: &TokenInfo, - include_expired: bool, -) -> Vec { - info.approvals - .iter() - .filter(|apr| include_expired || !apr.is_expired(block)) - .map(humanize_approval) - .collect() -} - -fn humanize_approval(approval: &Approval) -> cw721::Approval { - cw721::Approval { - spender: approval.spender.to_string(), - expires: approval.expires, - } -} diff --git a/cw721/off-chain-metadata/src/state.rs b/cw721/off-chain-metadata/src/state.rs deleted file mode 100644 index 37af500..0000000 --- a/cw721/off-chain-metadata/src/state.rs +++ /dev/null @@ -1,140 +0,0 @@ -use schemars::JsonSchema; -use serde::de::DeserializeOwned; -use serde::{Deserialize, Serialize}; -use std::marker::PhantomData; - -use cosmwasm_std::{Addr, BlockInfo, StdResult, Storage}; - -use cw721::{ContractInfoResponse, CustomMsg, Cw721, Expiration}; -use cw_storage_plus::{Index, IndexList, IndexedMap, Item, Map, MultiIndex}; - -pub struct Cw721Contract<'a, T, C> -where - T: Serialize + DeserializeOwned + Clone, -{ - pub contract_info: Item<'a, ContractInfoResponse>, - pub minter: Item<'a, Addr>, - pub token_count: Item<'a, u64>, - /// Stored as (granter, operator) giving operator full control over granter's account - pub operators: Map<'a, (&'a Addr, &'a Addr), Expiration>, - pub tokens: IndexedMap<'a, &'a str, TokenInfo, TokenIndexes<'a, T>>, - - pub(crate) _custom_response: PhantomData, -} - -// This is a signal, the implementations are in other files -impl<'a, T, C> Cw721 for Cw721Contract<'a, T, C> -where - T: Serialize + DeserializeOwned + Clone, - C: CustomMsg, -{ -} - -impl Default for Cw721Contract<'static, T, C> -where - T: Serialize + DeserializeOwned + Clone, -{ - fn default() -> Self { - Self::new( - "nft_info", - "minter", - "num_tokens", - "operators", - "tokens", - "tokens__owner", - ) - } -} - -impl<'a, T, C> Cw721Contract<'a, T, C> -where - T: Serialize + DeserializeOwned + Clone, -{ - fn new( - contract_key: &'a str, - minter_key: &'a str, - token_count_key: &'a str, - operator_key: &'a str, - tokens_key: &'a str, - tokens_owner_key: &'a str, - ) -> Self { - let indexes = TokenIndexes { - owner: MultiIndex::new(token_owner_idx, tokens_key, tokens_owner_key), - }; - Self { - contract_info: Item::new(contract_key), - minter: Item::new(minter_key), - token_count: Item::new(token_count_key), - operators: Map::new(operator_key), - tokens: IndexedMap::new(tokens_key, indexes), - _custom_response: PhantomData, - } - } - - pub fn token_count(&self, storage: &dyn Storage) -> StdResult { - Ok(self.token_count.may_load(storage)?.unwrap_or_default()) - } - - pub fn increment_tokens(&self, storage: &mut dyn Storage) -> StdResult { - let val = self.token_count(storage)? + 1; - self.token_count.save(storage, &val)?; - Ok(val) - } - - pub fn decrement_tokens(&self, storage: &mut dyn Storage) -> StdResult { - let val = self.token_count(storage)? - 1; - self.token_count.save(storage, &val)?; - Ok(val) - } -} - -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] -pub struct TokenInfo { - /// The owner of the newly minted NFT - pub owner: Addr, - /// Approvals are stored here, as we clear them all upon transfer and cannot accumulate much - pub approvals: Vec, - - /// Universal resource identifier for this NFT - /// Should point to a JSON file that conforms to the ERC721 - /// Metadata JSON Schema - pub token_uri: Option, - - /// You can add any custom metadata here when you extend cw721-base - pub extension: T, -} - -#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] -pub struct Approval { - /// Account that can transfer/send the token - pub spender: Addr, - /// When the Approval expires (maybe Expiration::never) - pub expires: Expiration, -} - -impl Approval { - pub fn is_expired(&self, block: &BlockInfo) -> bool { - self.expires.is_expired(block) - } -} - -pub struct TokenIndexes<'a, T> -where - T: Serialize + DeserializeOwned + Clone, -{ - pub owner: MultiIndex<'a, Addr, TokenInfo, Addr>, -} - -impl<'a, T> IndexList> for TokenIndexes<'a, T> -where - T: Serialize + DeserializeOwned + Clone, -{ - fn get_indexes(&'_ self) -> Box>> + '_> { - let v: Vec<&dyn Index>> = vec![&self.owner]; - Box::new(v.into_iter()) - } -} - -pub fn token_owner_idx(d: &TokenInfo) -> Addr { - d.owner.clone() -} diff --git a/cw721/off-chain-metadata/src/tests.rs b/cw721/off-chain-metadata/src/tests.rs deleted file mode 100644 index 2b84024..0000000 --- a/cw721/off-chain-metadata/src/tests.rs +++ /dev/null @@ -1,751 +0,0 @@ -#![cfg(test)] -use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info}; -use cosmwasm_std::{from_binary, to_binary, CosmosMsg, DepsMut, Empty, Response, WasmMsg}; - -use cw721::{ - Approval, ApprovalResponse, ContractInfoResponse, Cw721Query, Cw721ReceiveMsg, Expiration, - NftInfoResponse, OperatorsResponse, OwnerOfResponse, -}; - -use crate::{ - ContractError, Cw721Contract, ExecuteMsg, Extension, InstantiateMsg, MintMsg, QueryMsg, -}; - -const MINTER: &str = "merlin"; -const CONTRACT_NAME: &str = "Magic Power"; -const SYMBOL: &str = "MGK"; - -fn setup_contract(deps: DepsMut<'_>) -> Cw721Contract<'static, Extension, Empty> { - let contract = Cw721Contract::default(); - let msg = InstantiateMsg { - name: CONTRACT_NAME.to_string(), - symbol: SYMBOL.to_string(), - minter: String::from(MINTER), - }; - let info = mock_info("creator", &[]); - let res = contract.instantiate(deps, mock_env(), info, msg).unwrap(); - assert_eq!(0, res.messages.len()); - contract -} - -#[test] -fn proper_instantiation() { - let mut deps = mock_dependencies(); - let contract = Cw721Contract::::default(); - - let msg = InstantiateMsg { - name: CONTRACT_NAME.to_string(), - symbol: SYMBOL.to_string(), - minter: String::from(MINTER), - }; - let info = mock_info("creator", &[]); - - // we can just call .unwrap() to assert this was a success - let res = contract - .instantiate(deps.as_mut(), mock_env(), info, msg) - .unwrap(); - assert_eq!(0, res.messages.len()); - - // it worked, let's query the state - let res = contract.minter(deps.as_ref()).unwrap(); - assert_eq!(MINTER, res.minter); - let info = contract.contract_info(deps.as_ref()).unwrap(); - assert_eq!( - info, - ContractInfoResponse { - name: CONTRACT_NAME.to_string(), - symbol: SYMBOL.to_string(), - } - ); - - let count = contract.num_tokens(deps.as_ref()).unwrap(); - assert_eq!(0, count.count); - - // list the token_ids - let tokens = contract.all_tokens(deps.as_ref(), None, None).unwrap(); - assert_eq!(0, tokens.tokens.len()); -} - -#[test] -fn minting() { - let mut deps = mock_dependencies(); - let contract = setup_contract(deps.as_mut()); - - let token_id = "petrify".to_string(); - let token_uri = "https://www.merriam-webster.com/dictionary/petrify".to_string(); - - let mint_msg = ExecuteMsg::Mint(MintMsg:: { - token_id: token_id.clone(), - owner: String::from("medusa"), - token_uri: Some(token_uri.clone()), - extension: None, - }); - - // random cannot mint - let random = mock_info("random", &[]); - let err = contract - .execute(deps.as_mut(), mock_env(), random, mint_msg.clone()) - .unwrap_err(); - assert_eq!(err, ContractError::Unauthorized {}); - - // minter can mint - let allowed = mock_info(MINTER, &[]); - let _ = contract - .execute(deps.as_mut(), mock_env(), allowed, mint_msg) - .unwrap(); - - // ensure num tokens increases - let count = contract.num_tokens(deps.as_ref()).unwrap(); - assert_eq!(1, count.count); - - // unknown nft returns error - let _ = contract - .nft_info(deps.as_ref(), "unknown".to_string()) - .unwrap_err(); - - // this nft info is correct - let info = contract.nft_info(deps.as_ref(), token_id.clone()).unwrap(); - assert_eq!( - info, - NftInfoResponse:: { - token_uri: Some(token_uri), - extension: None, - } - ); - - // owner info is correct - let owner = contract - .owner_of(deps.as_ref(), mock_env(), token_id.clone(), true) - .unwrap(); - assert_eq!( - owner, - OwnerOfResponse { - owner: String::from("medusa"), - approvals: vec![], - } - ); - - // Cannot mint same token_id again - let mint_msg2 = ExecuteMsg::Mint(MintMsg:: { - token_id: token_id.clone(), - owner: String::from("hercules"), - token_uri: None, - extension: None, - }); - - let allowed = mock_info(MINTER, &[]); - let err = contract - .execute(deps.as_mut(), mock_env(), allowed, mint_msg2) - .unwrap_err(); - assert_eq!(err, ContractError::Claimed {}); - - // list the token_ids - let tokens = contract.all_tokens(deps.as_ref(), None, None).unwrap(); - assert_eq!(1, tokens.tokens.len()); - assert_eq!(vec![token_id], tokens.tokens); -} - -#[test] -fn burning() { - let mut deps = mock_dependencies(); - let contract = setup_contract(deps.as_mut()); - - let token_id = "petrify".to_string(); - let token_uri = "https://www.merriam-webster.com/dictionary/petrify".to_string(); - - let mint_msg = ExecuteMsg::Mint(MintMsg:: { - token_id: token_id.clone(), - owner: MINTER.to_string(), - token_uri: Some(token_uri), - extension: None, - }); - - let burn_msg = ExecuteMsg::Burn { token_id }; - - // mint some NFT - let allowed = mock_info(MINTER, &[]); - let _ = contract - .execute(deps.as_mut(), mock_env(), allowed.clone(), mint_msg) - .unwrap(); - - // random not allowed to burn - let random = mock_info("random", &[]); - let err = contract - .execute(deps.as_mut(), mock_env(), random, burn_msg.clone()) - .unwrap_err(); - - assert_eq!(err, ContractError::Unauthorized {}); - - let _ = contract - .execute(deps.as_mut(), mock_env(), allowed, burn_msg) - .unwrap(); - - // ensure num tokens decreases - let count = contract.num_tokens(deps.as_ref()).unwrap(); - assert_eq!(0, count.count); - - // trying to get nft returns error - let _ = contract - .nft_info(deps.as_ref(), "petrify".to_string()) - .unwrap_err(); - - // list the token_ids - let tokens = contract.all_tokens(deps.as_ref(), None, None).unwrap(); - assert!(tokens.tokens.is_empty()); -} - -#[test] -fn transferring_nft() { - let mut deps = mock_dependencies(); - let contract = setup_contract(deps.as_mut()); - - // Mint a token - let token_id = "melt".to_string(); - let token_uri = "https://www.merriam-webster.com/dictionary/melt".to_string(); - - let mint_msg = ExecuteMsg::Mint(MintMsg:: { - token_id: token_id.clone(), - owner: String::from("venus"), - token_uri: Some(token_uri), - extension: None, - }); - - let minter = mock_info(MINTER, &[]); - contract - .execute(deps.as_mut(), mock_env(), minter, mint_msg) - .unwrap(); - - // random cannot transfer - let random = mock_info("random", &[]); - let transfer_msg = ExecuteMsg::TransferNft { - recipient: String::from("random"), - token_id: token_id.clone(), - }; - - let err = contract - .execute(deps.as_mut(), mock_env(), random, transfer_msg) - .unwrap_err(); - assert_eq!(err, ContractError::Unauthorized {}); - - // owner can - let random = mock_info("venus", &[]); - let transfer_msg = ExecuteMsg::TransferNft { - recipient: String::from("random"), - token_id: token_id.clone(), - }; - - let res = contract - .execute(deps.as_mut(), mock_env(), random, transfer_msg) - .unwrap(); - - assert_eq!( - res, - Response::new() - .add_attribute("action", "transfer_nft") - .add_attribute("sender", "venus") - .add_attribute("recipient", "random") - .add_attribute("token_id", token_id) - ); -} - -#[test] -fn sending_nft() { - let mut deps = mock_dependencies(); - let contract = setup_contract(deps.as_mut()); - - // Mint a token - let token_id = "melt".to_string(); - let token_uri = "https://www.merriam-webster.com/dictionary/melt".to_string(); - - let mint_msg = ExecuteMsg::Mint(MintMsg:: { - token_id: token_id.clone(), - owner: String::from("venus"), - token_uri: Some(token_uri), - extension: None, - }); - - let minter = mock_info(MINTER, &[]); - contract - .execute(deps.as_mut(), mock_env(), minter, mint_msg) - .unwrap(); - - let msg = to_binary("You now have the melting power").unwrap(); - let target = String::from("another_contract"); - let send_msg = ExecuteMsg::SendNft { - contract: target.clone(), - token_id: token_id.clone(), - msg: msg.clone(), - }; - - let random = mock_info("random", &[]); - let err = contract - .execute(deps.as_mut(), mock_env(), random, send_msg.clone()) - .unwrap_err(); - assert_eq!(err, ContractError::Unauthorized {}); - - // but owner can - let random = mock_info("venus", &[]); - let res = contract - .execute(deps.as_mut(), mock_env(), random, send_msg) - .unwrap(); - - let payload = Cw721ReceiveMsg { - sender: String::from("venus"), - token_id: token_id.clone(), - msg, - }; - let expected = payload.into_cosmos_msg(target.clone()).unwrap(); - // ensure expected serializes as we think it should - match &expected { - CosmosMsg::Wasm(WasmMsg::Execute { contract_addr, .. }) => { - assert_eq!(contract_addr, &target) - } - m => panic!("Unexpected message type: {:?}", m), - } - // and make sure this is the request sent by the contract - assert_eq!( - res, - Response::new() - .add_message(expected) - .add_attribute("action", "send_nft") - .add_attribute("sender", "venus") - .add_attribute("recipient", "another_contract") - .add_attribute("token_id", token_id) - ); -} - -#[test] -fn approving_revoking() { - let mut deps = mock_dependencies(); - let contract = setup_contract(deps.as_mut()); - - // Mint a token - let token_id = "grow".to_string(); - let token_uri = "https://www.merriam-webster.com/dictionary/grow".to_string(); - - let mint_msg = ExecuteMsg::Mint(MintMsg:: { - token_id: token_id.clone(), - owner: String::from("demeter"), - token_uri: Some(token_uri), - extension: None, - }); - - let minter = mock_info(MINTER, &[]); - contract - .execute(deps.as_mut(), mock_env(), minter, mint_msg) - .unwrap(); - - // token owner shows in approval query - let res = contract - .approval( - deps.as_ref(), - mock_env(), - token_id.clone(), - String::from("demeter"), - false, - ) - .unwrap(); - assert_eq!( - res, - ApprovalResponse { - approval: Approval { - spender: String::from("demeter"), - expires: Expiration::Never {} - } - } - ); - - // Give random transferring power - let approve_msg = ExecuteMsg::Approve { - spender: String::from("random"), - token_id: token_id.clone(), - expires: None, - }; - let owner = mock_info("demeter", &[]); - let res = contract - .execute(deps.as_mut(), mock_env(), owner, approve_msg) - .unwrap(); - assert_eq!( - res, - Response::new() - .add_attribute("action", "approve") - .add_attribute("sender", "demeter") - .add_attribute("spender", "random") - .add_attribute("token_id", token_id.clone()) - ); - - // test approval query - let res = contract - .approval( - deps.as_ref(), - mock_env(), - token_id.clone(), - String::from("random"), - true, - ) - .unwrap(); - assert_eq!( - res, - ApprovalResponse { - approval: Approval { - spender: String::from("random"), - expires: Expiration::Never {} - } - } - ); - - // random can now transfer - let random = mock_info("random", &[]); - let transfer_msg = ExecuteMsg::TransferNft { - recipient: String::from("person"), - token_id: token_id.clone(), - }; - contract - .execute(deps.as_mut(), mock_env(), random, transfer_msg) - .unwrap(); - - // Approvals are removed / cleared - let query_msg = QueryMsg::OwnerOf { - token_id: token_id.clone(), - include_expired: None, - }; - let res: OwnerOfResponse = from_binary( - &contract - .query(deps.as_ref(), mock_env(), query_msg.clone()) - .unwrap(), - ) - .unwrap(); - assert_eq!( - res, - OwnerOfResponse { - owner: String::from("person"), - approvals: vec![], - } - ); - - // Approve, revoke, and check for empty, to test revoke - let approve_msg = ExecuteMsg::Approve { - spender: String::from("random"), - token_id: token_id.clone(), - expires: None, - }; - let owner = mock_info("person", &[]); - contract - .execute(deps.as_mut(), mock_env(), owner.clone(), approve_msg) - .unwrap(); - - let revoke_msg = ExecuteMsg::Revoke { - spender: String::from("random"), - token_id, - }; - contract - .execute(deps.as_mut(), mock_env(), owner, revoke_msg) - .unwrap(); - - // Approvals are now removed / cleared - let res: OwnerOfResponse = from_binary( - &contract - .query(deps.as_ref(), mock_env(), query_msg) - .unwrap(), - ) - .unwrap(); - assert_eq!( - res, - OwnerOfResponse { - owner: String::from("person"), - approvals: vec![], - } - ); -} - -#[test] -fn approving_all_revoking_all() { - let mut deps = mock_dependencies(); - let contract = setup_contract(deps.as_mut()); - - // Mint a couple tokens (from the same owner) - let token_id1 = "grow1".to_string(); - let token_uri1 = "https://www.merriam-webster.com/dictionary/grow1".to_string(); - - let token_id2 = "grow2".to_string(); - let token_uri2 = "https://www.merriam-webster.com/dictionary/grow2".to_string(); - - let mint_msg1 = ExecuteMsg::Mint(MintMsg:: { - token_id: token_id1.clone(), - owner: String::from("demeter"), - token_uri: Some(token_uri1), - extension: None, - }); - - let minter = mock_info(MINTER, &[]); - contract - .execute(deps.as_mut(), mock_env(), minter.clone(), mint_msg1) - .unwrap(); - - let mint_msg2 = ExecuteMsg::Mint(MintMsg:: { - token_id: token_id2.clone(), - owner: String::from("demeter"), - token_uri: Some(token_uri2), - extension: None, - }); - - contract - .execute(deps.as_mut(), mock_env(), minter, mint_msg2) - .unwrap(); - - // paginate the token_ids - let tokens = contract.all_tokens(deps.as_ref(), None, Some(1)).unwrap(); - assert_eq!(1, tokens.tokens.len()); - assert_eq!(vec![token_id1.clone()], tokens.tokens); - let tokens = contract - .all_tokens(deps.as_ref(), Some(token_id1.clone()), Some(3)) - .unwrap(); - assert_eq!(1, tokens.tokens.len()); - assert_eq!(vec![token_id2.clone()], tokens.tokens); - - // demeter gives random full (operator) power over her tokens - let approve_all_msg = ExecuteMsg::ApproveAll { - operator: String::from("random"), - expires: None, - }; - let owner = mock_info("demeter", &[]); - let res = contract - .execute(deps.as_mut(), mock_env(), owner, approve_all_msg) - .unwrap(); - assert_eq!( - res, - Response::new() - .add_attribute("action", "approve_all") - .add_attribute("sender", "demeter") - .add_attribute("operator", "random") - ); - - // random can now transfer - let random = mock_info("random", &[]); - let transfer_msg = ExecuteMsg::TransferNft { - recipient: String::from("person"), - token_id: token_id1, - }; - contract - .execute(deps.as_mut(), mock_env(), random.clone(), transfer_msg) - .unwrap(); - - // random can now send - let inner_msg = WasmMsg::Execute { - contract_addr: "another_contract".into(), - msg: to_binary("You now also have the growing power").unwrap(), - funds: vec![], - }; - let msg: CosmosMsg = CosmosMsg::Wasm(inner_msg); - - let send_msg = ExecuteMsg::SendNft { - contract: String::from("another_contract"), - token_id: token_id2, - msg: to_binary(&msg).unwrap(), - }; - contract - .execute(deps.as_mut(), mock_env(), random, send_msg) - .unwrap(); - - // Approve_all, revoke_all, and check for empty, to test revoke_all - let approve_all_msg = ExecuteMsg::ApproveAll { - operator: String::from("operator"), - expires: None, - }; - // person is now the owner of the tokens - let owner = mock_info("person", &[]); - contract - .execute(deps.as_mut(), mock_env(), owner, approve_all_msg) - .unwrap(); - - let res = contract - .operators( - deps.as_ref(), - mock_env(), - String::from("person"), - true, - None, - None, - ) - .unwrap(); - assert_eq!( - res, - OperatorsResponse { - operators: vec![cw721::Approval { - spender: String::from("operator"), - expires: Expiration::Never {} - }] - } - ); - - // second approval - let buddy_expires = Expiration::AtHeight(1234567); - let approve_all_msg = ExecuteMsg::ApproveAll { - operator: String::from("buddy"), - expires: Some(buddy_expires), - }; - let owner = mock_info("person", &[]); - contract - .execute(deps.as_mut(), mock_env(), owner.clone(), approve_all_msg) - .unwrap(); - - // and paginate queries - let res = contract - .operators( - deps.as_ref(), - mock_env(), - String::from("person"), - true, - None, - Some(1), - ) - .unwrap(); - assert_eq!( - res, - OperatorsResponse { - operators: vec![cw721::Approval { - spender: String::from("buddy"), - expires: buddy_expires, - }] - } - ); - let res = contract - .operators( - deps.as_ref(), - mock_env(), - String::from("person"), - true, - Some(String::from("buddy")), - Some(2), - ) - .unwrap(); - assert_eq!( - res, - OperatorsResponse { - operators: vec![cw721::Approval { - spender: String::from("operator"), - expires: Expiration::Never {} - }] - } - ); - - let revoke_all_msg = ExecuteMsg::RevokeAll { - operator: String::from("operator"), - }; - contract - .execute(deps.as_mut(), mock_env(), owner, revoke_all_msg) - .unwrap(); - - // Approvals are removed / cleared without affecting others - let res = contract - .operators( - deps.as_ref(), - mock_env(), - String::from("person"), - false, - None, - None, - ) - .unwrap(); - assert_eq!( - res, - OperatorsResponse { - operators: vec![cw721::Approval { - spender: String::from("buddy"), - expires: buddy_expires, - }] - } - ); - - // ensure the filter works (nothing should be here - let mut late_env = mock_env(); - late_env.block.height = 1234568; //expired - let res = contract - .operators( - deps.as_ref(), - late_env, - String::from("person"), - false, - None, - None, - ) - .unwrap(); - assert_eq!(0, res.operators.len()); -} - -#[test] -fn query_tokens_by_owner() { - let mut deps = mock_dependencies(); - let contract = setup_contract(deps.as_mut()); - let minter = mock_info(MINTER, &[]); - - // Mint a couple tokens (from the same owner) - let token_id1 = "grow1".to_string(); - let demeter = String::from("Demeter"); - let token_id2 = "grow2".to_string(); - let ceres = String::from("Ceres"); - let token_id3 = "sing".to_string(); - - let mint_msg = ExecuteMsg::Mint(MintMsg:: { - token_id: token_id1.clone(), - owner: demeter.clone(), - token_uri: None, - extension: None, - }); - contract - .execute(deps.as_mut(), mock_env(), minter.clone(), mint_msg) - .unwrap(); - - let mint_msg = ExecuteMsg::Mint(MintMsg:: { - token_id: token_id2.clone(), - owner: ceres.clone(), - token_uri: None, - extension: None, - }); - contract - .execute(deps.as_mut(), mock_env(), minter.clone(), mint_msg) - .unwrap(); - - let mint_msg = ExecuteMsg::Mint(MintMsg:: { - token_id: token_id3.clone(), - owner: demeter.clone(), - token_uri: None, - extension: None, - }); - contract - .execute(deps.as_mut(), mock_env(), minter, mint_msg) - .unwrap(); - - // get all tokens in order: - let expected = vec![token_id1.clone(), token_id2.clone(), token_id3.clone()]; - let tokens = contract.all_tokens(deps.as_ref(), None, None).unwrap(); - assert_eq!(&expected, &tokens.tokens); - // paginate - let tokens = contract.all_tokens(deps.as_ref(), None, Some(2)).unwrap(); - assert_eq!(&expected[..2], &tokens.tokens[..]); - let tokens = contract - .all_tokens(deps.as_ref(), Some(expected[1].clone()), None) - .unwrap(); - assert_eq!(&expected[2..], &tokens.tokens[..]); - - // get by owner - let by_ceres = vec![token_id2]; - let by_demeter = vec![token_id1, token_id3]; - // all tokens by owner - let tokens = contract - .tokens(deps.as_ref(), demeter.clone(), None, None) - .unwrap(); - assert_eq!(&by_demeter, &tokens.tokens); - let tokens = contract.tokens(deps.as_ref(), ceres, None, None).unwrap(); - assert_eq!(&by_ceres, &tokens.tokens); - - // paginate for demeter - let tokens = contract - .tokens(deps.as_ref(), demeter.clone(), None, Some(1)) - .unwrap(); - assert_eq!(&by_demeter[..1], &tokens.tokens[..]); - let tokens = contract - .tokens(deps.as_ref(), demeter, Some(by_demeter[0].clone()), Some(3)) - .unwrap(); - assert_eq!(&by_demeter[1..], &tokens.tokens[..]); -} From 2b962f7c62b0702e98f023461ff6cd645d598f55 Mon Sep 17 00:00:00 2001 From: Georges Chouchani Date: Wed, 29 Jun 2022 11:33:40 +0300 Subject: [PATCH 02/65] changed readme to add all new contracts including escrow --- README.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 6064145..9635f14 100644 --- a/README.md +++ b/README.md @@ -2,10 +2,13 @@ Archway Smart Contract template projects used by the [Archway Developer CLI](https://github.com/archway-network/archway-cli). -## List of templates +## List of templatesa - [Default](./default): a blank slate project -- [Increment](./increment): a simple smart contract that increments and resets a counter +- [Increment](./increment): a simple smart contrct that increments and resets a counter +- [CW20-base](./cw20/base): the base smart contract for the CW20 Fungible Tokens standard +- [CW20-escrow](./cw20/escrow): a smart contract representing an escrow for depositing and withdrawing CW20 tokens. +- [CW721-on-chain-metdata](./cw721/on-chain-metadata/): the CW721 standard smart contract with an extension to store NFT metadata on chain. ## Creating a new project from a template From 268314e5a5ef45fc8bc3db220a0c11c8f08e14bd Mon Sep 17 00:00:00 2001 From: Georges Chouchani Date: Wed, 29 Jun 2022 11:38:22 +0300 Subject: [PATCH 03/65] updated dependencies on cw721 template --- cw721/on-chain-metadata/Cargo.toml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cw721/on-chain-metadata/Cargo.toml b/cw721/on-chain-metadata/Cargo.toml index 1bf98d7..3761030 100644 --- a/cw721/on-chain-metadata/Cargo.toml +++ b/cw721/on-chain-metadata/Cargo.toml @@ -41,10 +41,10 @@ optimize = """docker run --rm -v "$(pwd)":/code \ [dependencies] cosmwasm-std = "1.0.0-beta" -cw2 = "0.11" -cw721 = "0.11" -cw721-base = { version = "0.11", features = ["library"] } -schemars = "0.8" +cw2 = "0.13.4" +cw721 = "0.13.2" +cw721-base = { version = "0.13.2", features = ["library"] } +schemars = "0.8.10" serde = { version = "1.0", default-features = false, features = ["derive"] } thiserror = "1.0" From 11bd6293b2164593e62e0ed0eef29435ead406f3 Mon Sep 17 00:00:00 2001 From: Georges Chouchani Date: Fri, 1 Jul 2022 17:16:24 +0300 Subject: [PATCH 04/65] simplification of cw20 base --- cw20/base/.cargo/config | 1 - cw20/base/.genignore | 1 - cw20/base/.github/workflows/Basic.yml | 24 +- cw20/base/.gitignore | 1 - cw20/base/Cargo.toml | 27 +- cw20/base/Developing.md | 14 +- cw20/base/NOTICE | 2 +- cw20/base/Publishing.md | 2 +- cw20/base/README.md | 44 +- cw20/base/examples/schema.rs | 11 +- cw20/base/meta/README.md | 16 - cw20/base/meta/appveyor.yml | 61 --- cw20/base/meta/test_generate.sh | 37 -- cw20/base/schema/all_accounts_response.json | 16 - cw20/base/schema/all_allowances_response.json | 99 ---- cw20/base/schema/allowance_response.json | 81 ---- cw20/base/schema/balance_response.json | 19 - cw20/base/schema/count_response.json | 14 + cw20/base/schema/cw20_execute_msg.json | 442 ------------------ cw20/base/schema/execute_msg.json | 39 ++ cw20/base/schema/instantiate_msg.json | 184 +------- cw20/base/schema/query_msg.json | 154 +----- cw20/base/schema/state.json | 24 + cw20/base/schema/token_info_response.json | 33 -- cw20/base/src/lib.rs | 127 ++--- 25 files changed, 199 insertions(+), 1274 deletions(-) delete mode 100644 cw20/base/.genignore delete mode 100644 cw20/base/meta/README.md delete mode 100644 cw20/base/meta/appveyor.yml delete mode 100755 cw20/base/meta/test_generate.sh delete mode 100644 cw20/base/schema/all_accounts_response.json delete mode 100644 cw20/base/schema/all_allowances_response.json delete mode 100644 cw20/base/schema/allowance_response.json delete mode 100644 cw20/base/schema/balance_response.json create mode 100644 cw20/base/schema/count_response.json delete mode 100644 cw20/base/schema/cw20_execute_msg.json create mode 100644 cw20/base/schema/execute_msg.json create mode 100644 cw20/base/schema/state.json delete mode 100644 cw20/base/schema/token_info_response.json diff --git a/cw20/base/.cargo/config b/cw20/base/.cargo/config index 7d1a066..336b618 100644 --- a/cw20/base/.cargo/config +++ b/cw20/base/.cargo/config @@ -1,5 +1,4 @@ [alias] wasm = "build --release --target wasm32-unknown-unknown" -wasm-debug = "build --target wasm32-unknown-unknown" unit-test = "test --lib" schema = "run --example schema" diff --git a/cw20/base/.genignore b/cw20/base/.genignore deleted file mode 100644 index 4fe5fd0..0000000 --- a/cw20/base/.genignore +++ /dev/null @@ -1 +0,0 @@ -meta/ diff --git a/cw20/base/.github/workflows/Basic.yml b/cw20/base/.github/workflows/Basic.yml index 6170933..0aa4193 100644 --- a/cw20/base/.github/workflows/Basic.yml +++ b/cw20/base/.github/workflows/Basic.yml @@ -16,10 +16,10 @@ jobs: - name: Install stable toolchain uses: actions-rs/toolchain@v1 with: - toolchain: stable + profile: minimal + toolchain: 1.58.1 target: wasm32-unknown-unknown override: true - profile: minimal - name: Run unit tests uses: actions-rs/cargo@v1 @@ -47,9 +47,9 @@ jobs: - name: Install stable toolchain uses: actions-rs/toolchain@v1 with: - toolchain: stable - override: true profile: minimal + toolchain: 1.58.1 + override: true components: rustfmt, clippy - name: Run cargo fmt @@ -64,20 +64,12 @@ jobs: command: clippy args: -- -D warnings - - name: Generate schema + - name: Generate Schema uses: actions-rs/cargo@v1 with: command: schema args: --locked - - name: Verify schema - uses: tj-actions/verify-changed-files@v8 - id: verify-schema - with: - files: schema/.*\.json - - - name: Display changed schemas - if: steps.verify-schema.outputs.files_changed == 'true' - run: | - echo "The schema files are not in sync with the repository. Please, run 'cargo schema' to generate them again and commit the changes." - exit 1 + - name: Schema Changes + # fails if any changes not committed + run: git diff --exit-code schema diff --git a/cw20/base/.gitignore b/cw20/base/.gitignore index f9b9a83..dfdaaa6 100644 --- a/cw20/base/.gitignore +++ b/cw20/base/.gitignore @@ -1,6 +1,5 @@ # Build results /target -/artifacts # Cargo+Git helper file (https://github.com/rust-lang/cargo/blob/0.44.1/src/cargo/sources/git/utils.rs#L320-L327) .cargo-ok diff --git a/cw20/base/Cargo.toml b/cw20/base/Cargo.toml index dc07e42..9cb6fc7 100644 --- a/cw20/base/Cargo.toml +++ b/cw20/base/Cargo.toml @@ -6,7 +6,8 @@ edition = "2018" exclude = [ # Those files are rust-optimizer artifacts. You might want to commit them for convenience but they should not be part of the source code publication. - "artifacts/*", + "contract.wasm", + "hash.txt", ] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -33,22 +34,22 @@ library = [] [package.metadata.scripts] optimize = """docker run --rm -v "$(pwd)":/code \ - -e CARGO_TERM_COLOR=always \ --mount type=volume,source="$(basename "$(pwd)")_cache",target=/code/target \ --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \ - cosmwasm/rust-optimizer:0.12.5 + cosmwasm/rust-optimizer:0.12.6 """ [dependencies] -cosmwasm-std = "1.0.0-beta" -cosmwasm-storage = "1.0.0-beta" -cw-storage-plus = "0.12" -cw0 = "0.10" -cw2 = "0.12" -cw20 = "0.12" -schemars = "0.8" -serde = { version = "1.0", default-features = false, features = ["derive"] } -thiserror = "1.0" +cosmwasm-std = "1.0.0" +cosmwasm-storage = "1.0.0" +cw-storage-plus = "0.13.2" +cw2 = "0.13.2" +cw20 = "0.13.4" +cw20-base = "0.13.2" +schemars = "0.8.8" +serde = { version = "1.0.137", default-features = false, features = ["derive"] } +thiserror = { version = "1.0.31" } [dev-dependencies] -cosmwasm-schema = "1.0.0-beta" +cosmwasm-schema = "1.0.0" +cw-multi-test = "0.13.2" diff --git a/cw20/base/Developing.md b/cw20/base/Developing.md index 6aa7cb1..e9f6f01 100644 --- a/cw20/base/Developing.md +++ b/cw20/base/Developing.md @@ -3,12 +3,12 @@ If you have recently created a contract with this template, you probably could use some help on how to build and test the contract, as well as prepare it for production. This file attempts to provide a brief overview, assuming you have installed a recent -version of Rust already (eg. 1.51.0+). +version of Rust already (eg. 1.58.1+). ## Prerequisites Before starting, make sure you have [rustup](https://rustup.rs/) along with a -recent `rustc` and `cargo` version installed. Currently, we are testing on 1.51.0+. +recent `rustc` and `cargo` version installed. Currently, we are testing on 1.58.1+. And you need to have the `wasm32-unknown-unknown` target installed as well. @@ -74,7 +74,15 @@ to run it is this: docker run --rm -v "$(pwd)":/code \ --mount type=volume,source="$(basename "$(pwd)")_cache",target=/code/target \ --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \ - cosmwasm/rust-optimizer:0.11.4 + cosmwasm/rust-optimizer:0.12.4 +``` + +Or, If you're on an arm64 machine, you should use a docker image built with arm64. +```sh +docker run --rm -v "$(pwd)":/code \ + --mount type=volume,source="$(basename "$(pwd)")_cache",target=/code/target \ + --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \ + cosmwasm/rust-optimizer-arm64:0.12.4 ``` We must mount the contract code to `/code`. You can use a absolute path instead diff --git a/cw20/base/NOTICE b/cw20/base/NOTICE index 216c969..ba84db2 100644 --- a/cw20/base/NOTICE +++ b/cw20/base/NOTICE @@ -1,4 +1,4 @@ -Copyright {{ "now" | date: "%Y" }} {{authors}} +Copyright 2022 georgeschouchani Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/cw20/base/Publishing.md b/cw20/base/Publishing.md index df868b9..c94f867 100644 --- a/cw20/base/Publishing.md +++ b/cw20/base/Publishing.md @@ -50,7 +50,7 @@ multiple contracts and label it like `escrow-0.1.0`. Don't forget a ### Note on build results Build results like Wasm bytecode or expected hash don't need to be updated since -the don't belong to the source publication. However, they are excluded from packaging +they don't belong to the source publication. However, they are excluded from packaging in `Cargo.toml` which allows you to commit them to your git repository if you like. ```toml diff --git a/cw20/base/README.md b/cw20/base/README.md index 8734338..954383a 100644 --- a/cw20/base/README.md +++ b/cw20/base/README.md @@ -1,21 +1,20 @@ -# Archway Network Starter Pack +# CosmWasm Starter Pack This is a template to build smart contracts in Rust to run inside a [Cosmos SDK](https://github.com/cosmos/cosmos-sdk) module on all chains that enable it. To understand the framework better, please read the overview in the -[archway repo](https://github.com/archway-network/archway/blob/main/README.md), -and dig into the [archway docs](https://docs.archway.io). +[cosmwasm repo](https://github.com/CosmWasm/cosmwasm/blob/master/README.md), +and dig into the [cosmwasm docs](https://www.cosmwasm.com). +This assumes you understand the theory and just want to get coding. -The below instructions assume you understand the theory and just want to get coding. +## Creating a new repo from template -## Creating a new project from a template - -Assuming you have a recent version of rust and cargo (v1.51.0+) installed +Assuming you have a recent version of rust and cargo (v1.58.1+) installed (via [rustup](https://rustup.rs/)), then the following should get you a new repo to start a contract: Install [cargo-generate](https://github.com/ashleygwilliams/cargo-generate) and cargo-run-script. -If you didn't install them already, run the following commands: +Unless you did that before, run this line now: ```sh cargo install cargo-generate --features vendored-openssl @@ -25,8 +24,25 @@ cargo install cargo-run-script Now, use it to create your new contract. Go to the folder in which you want to place it and run: + +**Latest: 1.0.0-beta6** + +```sh +cargo generate --git https://github.com/CosmWasm/cw-template.git --name PROJECT_NAME +```` + +**Older Version** + +Pass version as branch flag: + +```sh +cargo generate --git https://github.com/CosmWasm/cw-template.git --branch --name PROJECT_NAME +```` + +Example: + ```sh -cargo generate --git archway-network/archway-templates.git --name PROJECT_NAME default +cargo generate --git https://github.com/CosmWasm/cw-template.git --branch 0.16 --name PROJECT_NAME ``` You will now have a new folder called `PROJECT_NAME` (I hope you changed that to something else) @@ -65,7 +81,7 @@ running `cargo check` or `cargo unit-test`. Once you have your custom repo, you should check out [Developing](./Developing.md) to explain more on how to run tests and develop code. Or go through the -[online tutorial](https://docs.archway.io/docs/create/guides/my-first-dapp/start) to get a better feel +[online tutorial](https://docs.cosmwasm.com/) to get a better feel of how to develop. [Publishing](./Publishing.md) contains useful information on how to publish your contract @@ -82,9 +98,9 @@ proper description in the README. [Gitpod](https://www.gitpod.io/) container-based development platform will be enabled on your project by default. Workspace contains: - -- **rust**: for builds -- [wasmd](https://github.com/CosmWasm/wasmd): for local node setup and client -- **jq**: shell JSON manipulation tool + - **rust**: for builds + - [wasmd](https://github.com/CosmWasm/wasmd): for local node setup and client + - **jq**: shell JSON manipulation tool Follow [Gitpod Getting Started](https://www.gitpod.io/docs/getting-started) and launch your workspace. + diff --git a/cw20/base/examples/schema.rs b/cw20/base/examples/schema.rs index c13d8b6..92e9d8e 100644 --- a/cw20/base/examples/schema.rs +++ b/cw20/base/examples/schema.rs @@ -3,11 +3,7 @@ use std::fs::create_dir_all; use cosmwasm_schema::{export_schema, remove_schemas, schema_for}; -use cw20::{ - AllAccountsResponse, AllAllowancesResponse, AllowanceResponse, BalanceResponse, - TokenInfoResponse, -}; -use {{crate_name}}::msg::{ExecuteMsg, InstantiateMsg, QueryMsg}; +use cw20_base::msg::{ExecuteMsg, InstantiateMsg, QueryMsg}; fn main() { let mut out_dir = current_dir().unwrap(); @@ -18,9 +14,4 @@ fn main() { export_schema(&schema_for!(InstantiateMsg), &out_dir); export_schema(&schema_for!(ExecuteMsg), &out_dir); export_schema(&schema_for!(QueryMsg), &out_dir); - export_schema(&schema_for!(AllowanceResponse), &out_dir); - export_schema(&schema_for!(BalanceResponse), &out_dir); - export_schema(&schema_for!(TokenInfoResponse), &out_dir); - export_schema(&schema_for!(AllAllowancesResponse), &out_dir); - export_schema(&schema_for!(AllAccountsResponse), &out_dir); } diff --git a/cw20/base/meta/README.md b/cw20/base/meta/README.md deleted file mode 100644 index 279d1db..0000000 --- a/cw20/base/meta/README.md +++ /dev/null @@ -1,16 +0,0 @@ -# The meta folder - -This folder is ignored via the `.genignore` file. It contains meta files -that should not make it into the generated project. - -In particular, it is used for an AppVeyor CI script that runs on `cw-template` -itself (running the cargo-generate script, then testing the generated project). -The `.circleci` and `.github` directories contain scripts destined for any projects created from -this template. - -## Files - -- `appveyor.yml`: The AppVeyor CI configuration -- `test_generate.sh`: A script for generating a project from the template and - runnings builds and tests in it. This works almost like the CI script but - targets local UNIX-like dev environments. diff --git a/cw20/base/meta/appveyor.yml b/cw20/base/meta/appveyor.yml deleted file mode 100644 index 00f6d3f..0000000 --- a/cw20/base/meta/appveyor.yml +++ /dev/null @@ -1,61 +0,0 @@ -# This CI configuration tests the cw-template repository itself, -# not the resulting project. We want to ensure that -# 1. the template to project generation works -# 2. the template files are up to date -# -# We chose Appveyor for this task as it allows us to use an arbitrary config -# location. Furthermore it allows us to ship Circle CI and GitHub Actions configs -# generated for the resulting project. - -image: Ubuntu - -environment: - TOOLCHAIN: 1.51.0 - -services: - - docker - -cache: - - $HOME/.rustup/ -> meta/appveyor.yml - # For details about cargo caching see https://doc.rust-lang.org/cargo/guide/cargo-home.html#caching-the-cargo-home-in-ci - - $HOME/.cargo/bin/ -> meta/appveyor.yml - - $HOME/.cargo/registry/index/ -> meta/appveyor.yml - - $HOME/.cargo/registry/cache/ -> meta/appveyor.yml - - $HOME/.cargo/git/db/ -> meta/appveyor.yml - -install: - - curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- --default-toolchain "$TOOLCHAIN" -y - - source $HOME/.cargo/env - - rustc --version - - cargo --version - - rustup target add wasm32-unknown-unknown - - cargo install --features vendored-openssl cargo-generate || true - -build_script: - # No matter what is currently checked out by the CI (main, other branch, PR merge commit), - # we create a temporary local branch from that point with a constant name, which we need for - # cargo generate. - - git branch current-ci-checkout - - cd .. - - cargo generate --git cw-template --name testgen-ci --branch current-ci-checkout - - cd testgen-ci - - ls -lA - - cargo fmt -- --check - - cargo unit-test - - cargo wasm - - cargo schema - - docker build --pull -t "cosmwasm/cw-gitpod-base:${APPVEYOR_REPO_COMMIT}" . - - \[ "${APPVEYOR_REPO_BRANCH}" = "main" \] && image_tag=latest || image_tag=${APPVEYOR_REPO_TAG_NAME} - - docker tag "cosmwasm/cw-gitpod-base:${APPVEYOR_REPO_COMMIT}" "cosmwasm/cw-gitpod-base:${image_tag}" - -on_success: - # publish docker image - - docker login --password-stdin -u "$DOCKER_USER" <<<"$DOCKER_PASS" - - docker push - - docker logout - -branches: -# whitelist long living branches and tags - only: - # - main - - /v\d+\.\d+\.\d+/ \ No newline at end of file diff --git a/cw20/base/meta/test_generate.sh b/cw20/base/meta/test_generate.sh deleted file mode 100755 index b9aaa23..0000000 --- a/cw20/base/meta/test_generate.sh +++ /dev/null @@ -1,37 +0,0 @@ -#!/bin/bash -set -o errexit -o nounset -o pipefail -command -v shellcheck > /dev/null && shellcheck "$0" - -REPO_ROOT="$(realpath "$(dirname "$0")/..")" - -TMP_DIR=$(mktemp -d "${TMPDIR:-/tmp}/cw-template.XXXXXXXXX") -PROJECT_NAME="testgen-local" - -( - echo "Navigating to $TMP_DIR" - cd "$TMP_DIR" - - GIT_BRANCH=$(git -C "$REPO_ROOT" branch --show-current) - - echo "Generating project from local repository (branch $GIT_BRANCH) ..." - cargo generate --git "$REPO_ROOT" --name "$PROJECT_NAME" --branch "$GIT_BRANCH" - - ( - cd "$PROJECT_NAME" - echo "This is what was generated" - ls -lA - - # Check formatting - echo "Checking formatting ..." - cargo fmt -- --check - - # Debug builds first to fail fast - echo "Running unit tests ..." - cargo unit-test - echo "Creating schema ..." - cargo schema - - echo "Building wasm ..." - cargo wasm - ) -) diff --git a/cw20/base/schema/all_accounts_response.json b/cw20/base/schema/all_accounts_response.json deleted file mode 100644 index cea50fb..0000000 --- a/cw20/base/schema/all_accounts_response.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "AllAccountsResponse", - "type": "object", - "required": [ - "accounts" - ], - "properties": { - "accounts": { - "type": "array", - "items": { - "type": "string" - } - } - } -} diff --git a/cw20/base/schema/all_allowances_response.json b/cw20/base/schema/all_allowances_response.json deleted file mode 100644 index a8a11a5..0000000 --- a/cw20/base/schema/all_allowances_response.json +++ /dev/null @@ -1,99 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "AllAllowancesResponse", - "type": "object", - "required": [ - "allowances" - ], - "properties": { - "allowances": { - "type": "array", - "items": { - "$ref": "#/definitions/AllowanceInfo" - } - } - }, - "definitions": { - "AllowanceInfo": { - "type": "object", - "required": [ - "allowance", - "expires", - "spender" - ], - "properties": { - "allowance": { - "$ref": "#/definitions/Uint128" - }, - "expires": { - "$ref": "#/definitions/Expiration" - }, - "spender": { - "type": "string" - } - } - }, - "Expiration": { - "description": "Expiration represents a point in time when some event happens. It can compare with a BlockInfo and will return is_expired() == true once the condition is hit (and for every block in the future)", - "anyOf": [ - { - "description": "AtHeight will expire when `env.block.height` >= height", - "type": "object", - "required": [ - "at_height" - ], - "properties": { - "at_height": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 - } - }, - "additionalProperties": false - }, - { - "description": "AtTime will expire when `env.block.time` >= time", - "type": "object", - "required": [ - "at_time" - ], - "properties": { - "at_time": { - "$ref": "#/definitions/Timestamp" - } - }, - "additionalProperties": false - }, - { - "description": "Never will never expire. Used to express the empty variant", - "type": "object", - "required": [ - "never" - ], - "properties": { - "never": { - "type": "object" - } - }, - "additionalProperties": false - } - ] - }, - "Timestamp": { - "description": "A point in time in nanosecond precision.\n\nThis type can represent times from 1970-01-01T00:00:00Z to 2554-07-21T23:34:33Z.\n\n## Examples\n\n``` # use cosmwasm_std::Timestamp; let ts = Timestamp::from_nanos(1_000_000_202); assert_eq!(ts.nanos(), 1_000_000_202); assert_eq!(ts.seconds(), 1); assert_eq!(ts.subsec_nanos(), 202);\n\nlet ts = ts.plus_seconds(2); assert_eq!(ts.nanos(), 3_000_000_202); assert_eq!(ts.seconds(), 3); assert_eq!(ts.subsec_nanos(), 202); ```", - "allOf": [ - { - "$ref": "#/definitions/Uint64" - } - ] - }, - "Uint128": { - "description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```", - "type": "string" - }, - "Uint64": { - "description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```", - "type": "string" - } - } -} diff --git a/cw20/base/schema/allowance_response.json b/cw20/base/schema/allowance_response.json deleted file mode 100644 index 71b49ad..0000000 --- a/cw20/base/schema/allowance_response.json +++ /dev/null @@ -1,81 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "AllowanceResponse", - "type": "object", - "required": [ - "allowance", - "expires" - ], - "properties": { - "allowance": { - "$ref": "#/definitions/Uint128" - }, - "expires": { - "$ref": "#/definitions/Expiration" - } - }, - "definitions": { - "Expiration": { - "description": "Expiration represents a point in time when some event happens. It can compare with a BlockInfo and will return is_expired() == true once the condition is hit (and for every block in the future)", - "anyOf": [ - { - "description": "AtHeight will expire when `env.block.height` >= height", - "type": "object", - "required": [ - "at_height" - ], - "properties": { - "at_height": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 - } - }, - "additionalProperties": false - }, - { - "description": "AtTime will expire when `env.block.time` >= time", - "type": "object", - "required": [ - "at_time" - ], - "properties": { - "at_time": { - "$ref": "#/definitions/Timestamp" - } - }, - "additionalProperties": false - }, - { - "description": "Never will never expire. Used to express the empty variant", - "type": "object", - "required": [ - "never" - ], - "properties": { - "never": { - "type": "object" - } - }, - "additionalProperties": false - } - ] - }, - "Timestamp": { - "description": "A point in time in nanosecond precision.\n\nThis type can represent times from 1970-01-01T00:00:00Z to 2554-07-21T23:34:33Z.\n\n## Examples\n\n``` # use cosmwasm_std::Timestamp; let ts = Timestamp::from_nanos(1_000_000_202); assert_eq!(ts.nanos(), 1_000_000_202); assert_eq!(ts.seconds(), 1); assert_eq!(ts.subsec_nanos(), 202);\n\nlet ts = ts.plus_seconds(2); assert_eq!(ts.nanos(), 3_000_000_202); assert_eq!(ts.seconds(), 3); assert_eq!(ts.subsec_nanos(), 202); ```", - "allOf": [ - { - "$ref": "#/definitions/Uint64" - } - ] - }, - "Uint128": { - "description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```", - "type": "string" - }, - "Uint64": { - "description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```", - "type": "string" - } - } -} diff --git a/cw20/base/schema/balance_response.json b/cw20/base/schema/balance_response.json deleted file mode 100644 index 4e1a0be..0000000 --- a/cw20/base/schema/balance_response.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "BalanceResponse", - "type": "object", - "required": [ - "balance" - ], - "properties": { - "balance": { - "$ref": "#/definitions/Uint128" - } - }, - "definitions": { - "Uint128": { - "description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```", - "type": "string" - } - } -} diff --git a/cw20/base/schema/count_response.json b/cw20/base/schema/count_response.json new file mode 100644 index 0000000..fa1e81f --- /dev/null +++ b/cw20/base/schema/count_response.json @@ -0,0 +1,14 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "CountResponse", + "type": "object", + "required": [ + "count" + ], + "properties": { + "count": { + "type": "integer", + "format": "int32" + } + } +} diff --git a/cw20/base/schema/cw20_execute_msg.json b/cw20/base/schema/cw20_execute_msg.json deleted file mode 100644 index 4dd7b8a..0000000 --- a/cw20/base/schema/cw20_execute_msg.json +++ /dev/null @@ -1,442 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "Cw20ExecuteMsg", - "anyOf": [ - { - "description": "Transfer is a base message to move tokens to another account without triggering actions", - "type": "object", - "required": [ - "transfer" - ], - "properties": { - "transfer": { - "type": "object", - "required": [ - "amount", - "recipient" - ], - "properties": { - "amount": { - "$ref": "#/definitions/Uint128" - }, - "recipient": { - "type": "string" - } - } - } - }, - "additionalProperties": false - }, - { - "description": "Burn is a base message to destroy tokens forever", - "type": "object", - "required": [ - "burn" - ], - "properties": { - "burn": { - "type": "object", - "required": [ - "amount" - ], - "properties": { - "amount": { - "$ref": "#/definitions/Uint128" - } - } - } - }, - "additionalProperties": false - }, - { - "description": "Send is a base message to transfer tokens to a contract and trigger an action on the receiving contract.", - "type": "object", - "required": [ - "send" - ], - "properties": { - "send": { - "type": "object", - "required": [ - "amount", - "contract", - "msg" - ], - "properties": { - "amount": { - "$ref": "#/definitions/Uint128" - }, - "contract": { - "type": "string" - }, - "msg": { - "$ref": "#/definitions/Binary" - } - } - } - }, - "additionalProperties": false - }, - { - "description": "Only with \"approval\" extension. Allows spender to access an additional amount tokens from the owner's (env.sender) account. If expires is Some(), overwrites current allowance expiration with this one.", - "type": "object", - "required": [ - "increase_allowance" - ], - "properties": { - "increase_allowance": { - "type": "object", - "required": [ - "amount", - "spender" - ], - "properties": { - "amount": { - "$ref": "#/definitions/Uint128" - }, - "expires": { - "anyOf": [ - { - "$ref": "#/definitions/Expiration" - }, - { - "type": "null" - } - ] - }, - "spender": { - "type": "string" - } - } - } - }, - "additionalProperties": false - }, - { - "description": "Only with \"approval\" extension. Lowers the spender's access of tokens from the owner's (env.sender) account by amount. If expires is Some(), overwrites current allowance expiration with this one.", - "type": "object", - "required": [ - "decrease_allowance" - ], - "properties": { - "decrease_allowance": { - "type": "object", - "required": [ - "amount", - "spender" - ], - "properties": { - "amount": { - "$ref": "#/definitions/Uint128" - }, - "expires": { - "anyOf": [ - { - "$ref": "#/definitions/Expiration" - }, - { - "type": "null" - } - ] - }, - "spender": { - "type": "string" - } - } - } - }, - "additionalProperties": false - }, - { - "description": "Only with \"approval\" extension. Transfers amount tokens from owner -> recipient if `env.sender` has sufficient pre-approval.", - "type": "object", - "required": [ - "transfer_from" - ], - "properties": { - "transfer_from": { - "type": "object", - "required": [ - "amount", - "owner", - "recipient" - ], - "properties": { - "amount": { - "$ref": "#/definitions/Uint128" - }, - "owner": { - "type": "string" - }, - "recipient": { - "type": "string" - } - } - } - }, - "additionalProperties": false - }, - { - "description": "Only with \"approval\" extension. Sends amount tokens from owner -> contract if `env.sender` has sufficient pre-approval.", - "type": "object", - "required": [ - "send_from" - ], - "properties": { - "send_from": { - "type": "object", - "required": [ - "amount", - "contract", - "msg", - "owner" - ], - "properties": { - "amount": { - "$ref": "#/definitions/Uint128" - }, - "contract": { - "type": "string" - }, - "msg": { - "$ref": "#/definitions/Binary" - }, - "owner": { - "type": "string" - } - } - } - }, - "additionalProperties": false - }, - { - "description": "Only with \"approval\" extension. Destroys tokens forever", - "type": "object", - "required": [ - "burn_from" - ], - "properties": { - "burn_from": { - "type": "object", - "required": [ - "amount", - "owner" - ], - "properties": { - "amount": { - "$ref": "#/definitions/Uint128" - }, - "owner": { - "type": "string" - } - } - } - }, - "additionalProperties": false - }, - { - "description": "Only with the \"mintable\" extension. If authorized, creates amount new tokens and adds to the recipient balance.", - "type": "object", - "required": [ - "mint" - ], - "properties": { - "mint": { - "type": "object", - "required": [ - "amount", - "recipient" - ], - "properties": { - "amount": { - "$ref": "#/definitions/Uint128" - }, - "recipient": { - "type": "string" - } - } - } - }, - "additionalProperties": false - }, - { - "description": "Only with the \"marketing\" extension. If authorized, updates marketing metadata. Setting None/null for any of these will leave it unchanged. Setting Some(\"\") will clear this field on the contract storage", - "type": "object", - "required": [ - "update_marketing" - ], - "properties": { - "update_marketing": { - "type": "object", - "properties": { - "description": { - "description": "A longer description of the token and it's utility. Designed for tooltips or such", - "type": [ - "string", - "null" - ] - }, - "marketing": { - "description": "The address (if any) who can update this data structure", - "type": [ - "string", - "null" - ] - }, - "project": { - "description": "A URL pointing to the project behind this token.", - "type": [ - "string", - "null" - ] - } - } - } - }, - "additionalProperties": false - }, - { - "description": "If set as the \"marketing\" role on the contract, upload a new URL, SVG, or PNG for the token", - "type": "object", - "required": [ - "upload_logo" - ], - "properties": { - "upload_logo": { - "$ref": "#/definitions/Logo" - } - }, - "additionalProperties": false - } - ], - "definitions": { - "Binary": { - "description": "Binary is a wrapper around Vec to add base64 de/serialization with serde. It also adds some helper methods to help encode inline.\n\nThis is only needed as serde-json-{core,wasm} has a horrible encoding for Vec", - "type": "string" - }, - "EmbeddedLogo": { - "description": "This is used to store the logo on the blockchain in an accepted format. Enforce maximum size of 5KB on all variants.", - "anyOf": [ - { - "description": "Store the Logo as an SVG file. The content must conform to the spec at https://en.wikipedia.org/wiki/Scalable_Vector_Graphics (The contract should do some light-weight sanity-check validation)", - "type": "object", - "required": [ - "svg" - ], - "properties": { - "svg": { - "$ref": "#/definitions/Binary" - } - }, - "additionalProperties": false - }, - { - "description": "Store the Logo as a PNG file. This will likely only support up to 64x64 or so within the 5KB limit.", - "type": "object", - "required": [ - "png" - ], - "properties": { - "png": { - "$ref": "#/definitions/Binary" - } - }, - "additionalProperties": false - } - ] - }, - "Expiration": { - "description": "Expiration represents a point in time when some event happens. It can compare with a BlockInfo and will return is_expired() == true once the condition is hit (and for every block in the future)", - "anyOf": [ - { - "description": "AtHeight will expire when `env.block.height` >= height", - "type": "object", - "required": [ - "at_height" - ], - "properties": { - "at_height": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 - } - }, - "additionalProperties": false - }, - { - "description": "AtTime will expire when `env.block.time` >= time", - "type": "object", - "required": [ - "at_time" - ], - "properties": { - "at_time": { - "$ref": "#/definitions/Timestamp" - } - }, - "additionalProperties": false - }, - { - "description": "Never will never expire. Used to express the empty variant", - "type": "object", - "required": [ - "never" - ], - "properties": { - "never": { - "type": "object" - } - }, - "additionalProperties": false - } - ] - }, - "Logo": { - "description": "This is used for uploading logo data, or setting it in InstantiateData", - "anyOf": [ - { - "description": "A reference to an externally hosted logo. Must be a valid HTTP or HTTPS URL.", - "type": "object", - "required": [ - "url" - ], - "properties": { - "url": { - "type": "string" - } - }, - "additionalProperties": false - }, - { - "description": "Logo content stored on the blockchain. Enforce maximum size of 5KB on all variants", - "type": "object", - "required": [ - "embedded" - ], - "properties": { - "embedded": { - "$ref": "#/definitions/EmbeddedLogo" - } - }, - "additionalProperties": false - } - ] - }, - "Timestamp": { - "description": "A point in time in nanosecond precision.\n\nThis type can represent times from 1970-01-01T00:00:00Z to 2554-07-21T23:34:33Z.\n\n## Examples\n\n``` # use cosmwasm_std::Timestamp; let ts = Timestamp::from_nanos(1_000_000_202); assert_eq!(ts.nanos(), 1_000_000_202); assert_eq!(ts.seconds(), 1); assert_eq!(ts.subsec_nanos(), 202);\n\nlet ts = ts.plus_seconds(2); assert_eq!(ts.nanos(), 3_000_000_202); assert_eq!(ts.seconds(), 3); assert_eq!(ts.subsec_nanos(), 202); ```", - "allOf": [ - { - "$ref": "#/definitions/Uint64" - } - ] - }, - "Uint128": { - "description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```", - "type": "string" - }, - "Uint64": { - "description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```", - "type": "string" - } - } -} diff --git a/cw20/base/schema/execute_msg.json b/cw20/base/schema/execute_msg.json new file mode 100644 index 0000000..6fa0a75 --- /dev/null +++ b/cw20/base/schema/execute_msg.json @@ -0,0 +1,39 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "ExecuteMsg", + "anyOf": [ + { + "type": "object", + "required": [ + "increment" + ], + "properties": { + "increment": { + "type": "object" + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": [ + "reset" + ], + "properties": { + "reset": { + "type": "object", + "required": [ + "count" + ], + "properties": { + "count": { + "type": "integer", + "format": "int32" + } + } + } + }, + "additionalProperties": false + } + ] +} diff --git a/cw20/base/schema/instantiate_msg.json b/cw20/base/schema/instantiate_msg.json index c8a3fca..e794ec1 100644 --- a/cw20/base/schema/instantiate_msg.json +++ b/cw20/base/schema/instantiate_msg.json @@ -3,190 +3,12 @@ "title": "InstantiateMsg", "type": "object", "required": [ - "decimals", - "initial_balances", - "name", - "symbol" + "count" ], "properties": { - "decimals": { + "count": { "type": "integer", - "format": "uint8", - "minimum": 0.0 - }, - "initial_balances": { - "type": "array", - "items": { - "$ref": "#/definitions/Cw20Coin" - } - }, - "marketing": { - "anyOf": [ - { - "$ref": "#/definitions/InstantiateMarketingInfo" - }, - { - "type": "null" - } - ] - }, - "mint": { - "anyOf": [ - { - "$ref": "#/definitions/MinterResponse" - }, - { - "type": "null" - } - ] - }, - "name": { - "type": "string" - }, - "symbol": { - "type": "string" - } - }, - "definitions": { - "Binary": { - "description": "Binary is a wrapper around Vec to add base64 de/serialization with serde. It also adds some helper methods to help encode inline.\n\nThis is only needed as serde-json-{core,wasm} has a horrible encoding for Vec", - "type": "string" - }, - "Cw20Coin": { - "type": "object", - "required": [ - "address", - "amount" - ], - "properties": { - "address": { - "type": "string" - }, - "amount": { - "$ref": "#/definitions/Uint128" - } - } - }, - "EmbeddedLogo": { - "description": "This is used to store the logo on the blockchain in an accepted format. Enforce maximum size of 5KB on all variants.", - "anyOf": [ - { - "description": "Store the Logo as an SVG file. The content must conform to the spec at https://en.wikipedia.org/wiki/Scalable_Vector_Graphics (The contract should do some light-weight sanity-check validation)", - "type": "object", - "required": [ - "svg" - ], - "properties": { - "svg": { - "$ref": "#/definitions/Binary" - } - }, - "additionalProperties": false - }, - { - "description": "Store the Logo as a PNG file. This will likely only support up to 64x64 or so within the 5KB limit.", - "type": "object", - "required": [ - "png" - ], - "properties": { - "png": { - "$ref": "#/definitions/Binary" - } - }, - "additionalProperties": false - } - ] - }, - "InstantiateMarketingInfo": { - "type": "object", - "properties": { - "description": { - "type": [ - "string", - "null" - ] - }, - "logo": { - "anyOf": [ - { - "$ref": "#/definitions/Logo" - }, - { - "type": "null" - } - ] - }, - "marketing": { - "type": [ - "string", - "null" - ] - }, - "project": { - "type": [ - "string", - "null" - ] - } - } - }, - "Logo": { - "description": "This is used for uploading logo data, or setting it in InstantiateData", - "anyOf": [ - { - "description": "A reference to an externally hosted logo. Must be a valid HTTP or HTTPS URL.", - "type": "object", - "required": [ - "url" - ], - "properties": { - "url": { - "type": "string" - } - }, - "additionalProperties": false - }, - { - "description": "Logo content stored on the blockchain. Enforce maximum size of 5KB on all variants", - "type": "object", - "required": [ - "embedded" - ], - "properties": { - "embedded": { - "$ref": "#/definitions/EmbeddedLogo" - } - }, - "additionalProperties": false - } - ] - }, - "MinterResponse": { - "type": "object", - "required": [ - "minter" - ], - "properties": { - "cap": { - "description": "cap is a hard cap on total supply that can be achieved by minting. Note that this refers to total_supply. If None, there is unlimited cap.", - "anyOf": [ - { - "$ref": "#/definitions/Uint128" - }, - { - "type": "null" - } - ] - }, - "minter": { - "type": "string" - } - } - }, - "Uint128": { - "description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```", - "type": "string" + "format": "int32" } } } diff --git a/cw20/base/schema/query_msg.json b/cw20/base/schema/query_msg.json index 60aac9e..be0245b 100644 --- a/cw20/base/schema/query_msg.json +++ b/cw20/base/schema/query_msg.json @@ -3,162 +3,12 @@ "title": "QueryMsg", "anyOf": [ { - "description": "Returns the current balance of the given address, 0 if unset. Return type: BalanceResponse.", "type": "object", "required": [ - "balance" + "get_count" ], "properties": { - "balance": { - "type": "object", - "required": [ - "address" - ], - "properties": { - "address": { - "type": "string" - } - } - } - }, - "additionalProperties": false - }, - { - "description": "Returns metadata on the contract - name, decimals, supply, etc. Return type: TokenInfoResponse.", - "type": "object", - "required": [ - "token_info" - ], - "properties": { - "token_info": { - "type": "object" - } - }, - "additionalProperties": false - }, - { - "description": "Only with \"mintable\" extension. Returns who can mint and the hard cap on maximum tokens after minting. Return type: MinterResponse.", - "type": "object", - "required": [ - "minter" - ], - "properties": { - "minter": { - "type": "object" - } - }, - "additionalProperties": false - }, - { - "description": "Only with \"allowance\" extension. Returns how much spender can use from owner account, 0 if unset. Return type: AllowanceResponse.", - "type": "object", - "required": [ - "allowance" - ], - "properties": { - "allowance": { - "type": "object", - "required": [ - "owner", - "spender" - ], - "properties": { - "owner": { - "type": "string" - }, - "spender": { - "type": "string" - } - } - } - }, - "additionalProperties": false - }, - { - "description": "Only with \"enumerable\" extension (and \"allowances\") Returns all allowances this owner has approved. Supports pagination. Return type: AllAllowancesResponse.", - "type": "object", - "required": [ - "all_allowances" - ], - "properties": { - "all_allowances": { - "type": "object", - "required": [ - "owner" - ], - "properties": { - "limit": { - "type": [ - "integer", - "null" - ], - "format": "uint32", - "minimum": 0.0 - }, - "owner": { - "type": "string" - }, - "start_after": { - "type": [ - "string", - "null" - ] - } - } - } - }, - "additionalProperties": false - }, - { - "description": "Only with \"enumerable\" extension Returns all accounts that have balances. Supports pagination. Return type: AllAccountsResponse.", - "type": "object", - "required": [ - "all_accounts" - ], - "properties": { - "all_accounts": { - "type": "object", - "properties": { - "limit": { - "type": [ - "integer", - "null" - ], - "format": "uint32", - "minimum": 0.0 - }, - "start_after": { - "type": [ - "string", - "null" - ] - } - } - } - }, - "additionalProperties": false - }, - { - "description": "Only with \"marketing\" extension Returns more metadata on the contract to display in the client: - description, logo, project url, etc. Return type: MarketingInfoResponse", - "type": "object", - "required": [ - "marketing_info" - ], - "properties": { - "marketing_info": { - "type": "object" - } - }, - "additionalProperties": false - }, - { - "description": "Only with \"marketing\" extension Downloads the mbeded logo data (if stored on chain). Errors if no logo data ftored for this contract. Return type: DownloadLogoResponse.", - "type": "object", - "required": [ - "download_logo" - ], - "properties": { - "download_logo": { + "get_count": { "type": "object" } }, diff --git a/cw20/base/schema/state.json b/cw20/base/schema/state.json new file mode 100644 index 0000000..e18725d --- /dev/null +++ b/cw20/base/schema/state.json @@ -0,0 +1,24 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "State", + "type": "object", + "required": [ + "count", + "owner" + ], + "properties": { + "count": { + "type": "integer", + "format": "int32" + }, + "owner": { + "$ref": "#/definitions/Addr" + } + }, + "definitions": { + "Addr": { + "description": "A human readable address.\n\nIn Cosmos, this is typically bech32 encoded. But for multi-chain smart contracts no assumptions should be made other than being UTF-8 encoded and of reasonable length.\n\nThis type represents a validated address. It can be created in the following ways 1. Use `Addr::unchecked(input)` 2. Use `let checked: Addr = deps.api.addr_validate(input)?` 3. Use `let checked: Addr = deps.api.addr_humanize(canonical_addr)?` 4. Deserialize from JSON. This must only be done from JSON that was validated before such as a contract's state. `Addr` must not be used in messages sent by the user because this would result in unvalidated instances.\n\nThis type is immutable. If you really need to mutate it (Really? Are you sure?), create a mutable copy using `let mut mutable = Addr::to_string()` and operate on that `String` instance.", + "type": "string" + } + } +} diff --git a/cw20/base/schema/token_info_response.json b/cw20/base/schema/token_info_response.json deleted file mode 100644 index 9920c84..0000000 --- a/cw20/base/schema/token_info_response.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "TokenInfoResponse", - "type": "object", - "required": [ - "decimals", - "name", - "symbol", - "total_supply" - ], - "properties": { - "decimals": { - "type": "integer", - "format": "uint8", - "minimum": 0.0 - }, - "name": { - "type": "string" - }, - "symbol": { - "type": "string" - }, - "total_supply": { - "$ref": "#/definitions/Uint128" - } - }, - "definitions": { - "Uint128": { - "description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```", - "type": "string" - } - } -} diff --git a/cw20/base/src/lib.rs b/cw20/base/src/lib.rs index b217e0f..a8fd802 100644 --- a/cw20/base/src/lib.rs +++ b/cw20/base/src/lib.rs @@ -1,35 +1,14 @@ -use schemars::JsonSchema; -use serde::{Deserialize, Serialize}; -use cosmwasm_std::Empty; + use cw2::set_contract_version; -use cw20:: -#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug, Default)] -pub struct Trait { - pub display_type: Option, - pub trait_type: String, - pub value: String, -} +pub use cw20_base::msg::{ExecuteMsg,InstantiateMsg,QueryMsg}; +pub use cw20_base::contract::{instantiate as instantiateCw20, execute as executeCw20, query as queryCw20}; + + -// see: https://ption, - pub description: Option, - pub name: Option, - pub attributes: Option>, - pub background_color: Option, - pub animation_udocs.opensea.io/docs/metadata-standards - #[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug, Default)] - pub struct Metadata { - pub image: Option, - pub image_data: Option, - pub external_url: Orl: Option, - pub youtube_url: Option, -} -pub type Extension = Option; -pub type Cw721MetadataContract<'a> = cw721_base::Cw<'a, Extension, Empty>; -pub type ExecuteMsg = cw721_base::ExecuteMsg; const CONTRACT_NAME: &str = "crates.io:{{project-name}}"; const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION"); @@ -40,6 +19,7 @@ pub mod entry { use cosmwasm_std::entry_point; use cosmwasm_std::{Binary, Deps, DepsMut, Env, MessageInfo, Response, StdResult}; + use cw20_base::ContractError; // This is a simple type to let us handle empty extensions @@ -47,23 +27,12 @@ pub mod entry { #[entry_point] pub fn instantiate( deps: DepsMut, - _env: Env, - _info: MessageInfo, + env: Env, + info: MessageInfo, msg: InstantiateMsg, ) -> StdResult { set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; - - let info = ContractInfoResponse { - name: msg.name, - symbol: msg.symbol, - }; - Cw721MetadataContract::default() - .contract_info - .save(deps.storage, &info)?; - let minter = deps.api.addr_validate(&msg.minter)?; - Cw721MetadataContract::default() - .minter - .save(deps.storage, &minter)?; + instantiateCw20(deps, env, info, msg).unwrap(); Ok(Response::default()) } @@ -74,57 +43,63 @@ pub mod entry { info: MessageInfo, msg: ExecuteMsg, ) -> Result { - Cw721MetadataContract::default().execute(deps, env, info, msg) + executeCw20(deps, env, info, msg) } #[entry_point] pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> StdResult { - Cw721MetadataContract::default().query(deps, env, msg) + queryCw20(deps, env, msg) } } #[cfg(test)] mod tests { - use super::*; + use crate::entry::instantiate; - use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info}; - use cw721::Cw721Query; + use super::*; + use cosmwasm_std::{testing::{mock_dependencies, mock_env, mock_info}, Deps}; + use cw20::{Cw20Coin, TokenInfoResponse}; + use cosmwasm_std::Uint128; + use cw20_base::contract::{query_token_info, query_balance}; const CREATOR: &str = "creator"; + fn get_balance>(deps: Deps, address: T) -> Uint128 { + query_balance(deps, address.into()).unwrap().balance + } #[test] - fn use_metadata_extension() { + fn basic() { let mut deps = mock_dependencies(); - let contract = Cw721MetadataContract::default(); - - let info = mock_info(CREATOR, &[]); - let init_msg = InstantiateMsg { - name: "SpaceShips".to_string(), - symbol: "SPACE".to_string(), - minter: CREATOR.to_string(), - }; - contract - .instantiate(deps.as_mut(), mock_env(), info.clone(), init_msg) - .unwrap(); - - let token_id = "Enterprise"; - let mint_msg = MintMsg { - token_id: token_id.to_string(), - owner: "john".to_string(), - token_uri: Some("https://starships.example.com/Starship/Enterprise.json".into()), - extension: Some(Metadata { - description: Some("Spaceship with Warp Drive".into()), - name: Some("Starship USS Enterprise".to_string()), - ..Metadata::default() - }), + let amount = Uint128::from(11223344u128); + let instantiate_msg = InstantiateMsg { + name: "Cash Token".to_string(), + symbol: "CASH".to_string(), + decimals: 9, + initial_balances: vec![Cw20Coin { + address: String::from("addr0000"), + amount, + }], + mint: None, + marketing: None, }; - let exec_msg = ExecuteMsg::Mint(mint_msg.clone()); - contract - .execute(deps.as_mut(), mock_env(), info, exec_msg) - .unwrap(); - - let res = contract.nft_info(deps.as_ref(), token_id.into()).unwrap(); - assert_eq!(res.token_uri, mint_msg.token_uri); - assert_eq!(res.extension, mint_msg.extension); + let info = mock_info("creator", &[]); + let env = mock_env(); + let res = instantiate(deps.as_mut(), env, info, instantiate_msg).unwrap(); + assert_eq!(0, res.messages.len()); + + assert_eq!( + query_token_info(deps.as_ref()).unwrap(), + TokenInfoResponse { + name: "Cash Token".to_string(), + symbol: "CASH".to_string(), + decimals: 9, + total_supply: amount, + } + ); + assert_eq!( + get_balance(deps.as_ref(), "addr0000"), + Uint128::new(11223344) + ); } } + From 891517b8c369ccb81be185a96267736532b6a84b Mon Sep 17 00:00:00 2001 From: Georges Chouchani Date: Tue, 5 Jul 2022 18:24:17 +0300 Subject: [PATCH 05/65] changes completed especially in readme --- .gitignore | 2 ++ README.md | 6 +++--- cw20/base/.gitignore | 2 +- cw20/base/NOTICE | 2 +- cw20/base/README.md | 44 ++++++++++++++------------------------------ 5 files changed, 21 insertions(+), 35 deletions(-) diff --git a/.gitignore b/.gitignore index 088ba6b..6a0375b 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,5 @@ Cargo.lock # These are backup files generated by rustfmt **/*.rs.bk + +.idea \ No newline at end of file diff --git a/README.md b/README.md index 9635f14..47cc610 100644 --- a/README.md +++ b/README.md @@ -2,12 +2,12 @@ Archway Smart Contract template projects used by the [Archway Developer CLI](https://github.com/archway-network/archway-cli). -## List of templatesa +## List of templates - [Default](./default): a blank slate project - [Increment](./increment): a simple smart contrct that increments and resets a counter -- [CW20-base](./cw20/base): the base smart contract for the CW20 Fungible Tokens standard -- [CW20-escrow](./cw20/escrow): a smart contract representing an escrow for depositing and withdrawing CW20 tokens. +- [CW20-base](./cw20/base): the base smart contract for the CW20 Fungible Tokens standard +- [CW20-escrow](./cw20/escrow): a smart contract representing an escrow for depositing and withdrawing CW20 tokens. - [CW721-on-chain-metdata](./cw721/on-chain-metadata/): the CW721 standard smart contract with an extension to store NFT metadata on chain. ## Creating a new project from a template diff --git a/cw20/base/.gitignore b/cw20/base/.gitignore index dfdaaa6..73211d4 100644 --- a/cw20/base/.gitignore +++ b/cw20/base/.gitignore @@ -1,6 +1,6 @@ # Build results /target - +/artifacts # Cargo+Git helper file (https://github.com/rust-lang/cargo/blob/0.44.1/src/cargo/sources/git/utils.rs#L320-L327) .cargo-ok diff --git a/cw20/base/NOTICE b/cw20/base/NOTICE index ba84db2..216c969 100644 --- a/cw20/base/NOTICE +++ b/cw20/base/NOTICE @@ -1,4 +1,4 @@ -Copyright 2022 georgeschouchani +Copyright {{ "now" | date: "%Y" }} {{authors}} Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/cw20/base/README.md b/cw20/base/README.md index 954383a..8734338 100644 --- a/cw20/base/README.md +++ b/cw20/base/README.md @@ -1,20 +1,21 @@ -# CosmWasm Starter Pack +# Archway Network Starter Pack This is a template to build smart contracts in Rust to run inside a [Cosmos SDK](https://github.com/cosmos/cosmos-sdk) module on all chains that enable it. To understand the framework better, please read the overview in the -[cosmwasm repo](https://github.com/CosmWasm/cosmwasm/blob/master/README.md), -and dig into the [cosmwasm docs](https://www.cosmwasm.com). -This assumes you understand the theory and just want to get coding. +[archway repo](https://github.com/archway-network/archway/blob/main/README.md), +and dig into the [archway docs](https://docs.archway.io). -## Creating a new repo from template +The below instructions assume you understand the theory and just want to get coding. -Assuming you have a recent version of rust and cargo (v1.58.1+) installed +## Creating a new project from a template + +Assuming you have a recent version of rust and cargo (v1.51.0+) installed (via [rustup](https://rustup.rs/)), then the following should get you a new repo to start a contract: Install [cargo-generate](https://github.com/ashleygwilliams/cargo-generate) and cargo-run-script. -Unless you did that before, run this line now: +If you didn't install them already, run the following commands: ```sh cargo install cargo-generate --features vendored-openssl @@ -24,25 +25,8 @@ cargo install cargo-run-script Now, use it to create your new contract. Go to the folder in which you want to place it and run: - -**Latest: 1.0.0-beta6** - -```sh -cargo generate --git https://github.com/CosmWasm/cw-template.git --name PROJECT_NAME -```` - -**Older Version** - -Pass version as branch flag: - -```sh -cargo generate --git https://github.com/CosmWasm/cw-template.git --branch --name PROJECT_NAME -```` - -Example: - ```sh -cargo generate --git https://github.com/CosmWasm/cw-template.git --branch 0.16 --name PROJECT_NAME +cargo generate --git archway-network/archway-templates.git --name PROJECT_NAME default ``` You will now have a new folder called `PROJECT_NAME` (I hope you changed that to something else) @@ -81,7 +65,7 @@ running `cargo check` or `cargo unit-test`. Once you have your custom repo, you should check out [Developing](./Developing.md) to explain more on how to run tests and develop code. Or go through the -[online tutorial](https://docs.cosmwasm.com/) to get a better feel +[online tutorial](https://docs.archway.io/docs/create/guides/my-first-dapp/start) to get a better feel of how to develop. [Publishing](./Publishing.md) contains useful information on how to publish your contract @@ -98,9 +82,9 @@ proper description in the README. [Gitpod](https://www.gitpod.io/) container-based development platform will be enabled on your project by default. Workspace contains: - - **rust**: for builds - - [wasmd](https://github.com/CosmWasm/wasmd): for local node setup and client - - **jq**: shell JSON manipulation tool -Follow [Gitpod Getting Started](https://www.gitpod.io/docs/getting-started) and launch your workspace. +- **rust**: for builds +- [wasmd](https://github.com/CosmWasm/wasmd): for local node setup and client +- **jq**: shell JSON manipulation tool +Follow [Gitpod Getting Started](https://www.gitpod.io/docs/getting-started) and launch your workspace. From c3d841efc7ecc89815fccd39c6226e5bbffa8905 Mon Sep 17 00:00:00 2001 From: Georges Chouchani Date: Thu, 7 Jul 2022 18:09:11 +0300 Subject: [PATCH 06/65] resolve issues with idea --- .idea/.gitignore | 8 -------- .idea/archway-templates.iml | 8 -------- .idea/modules.xml | 8 -------- .idea/vcs.xml | 6 ------ 4 files changed, 30 deletions(-) delete mode 100644 .idea/.gitignore delete mode 100644 .idea/archway-templates.iml delete mode 100644 .idea/modules.xml delete mode 100644 .idea/vcs.xml diff --git a/.idea/.gitignore b/.idea/.gitignore deleted file mode 100644 index 13566b8..0000000 --- a/.idea/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml -# Editor-based HTTP Client requests -/httpRequests/ -# Datasource local storage ignored files -/dataSources/ -/dataSources.local.xml diff --git a/.idea/archway-templates.iml b/.idea/archway-templates.iml deleted file mode 100644 index bc2cd87..0000000 --- a/.idea/archway-templates.iml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index 064e119..0000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 94a25f7..0000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file From 99bb5a1fa8475871d3b0d2f601408415b8a1e63c Mon Sep 17 00:00:00 2001 From: Georges Chouchani Date: Thu, 7 Jul 2022 18:12:25 +0300 Subject: [PATCH 07/65] removed schema from base --- cw20/base/schema/count_response.json | 14 ---------- cw20/base/schema/execute_msg.json | 39 --------------------------- cw20/base/schema/instantiate_msg.json | 14 ---------- cw20/base/schema/query_msg.json | 18 ------------- cw20/base/schema/state.json | 24 ----------------- 5 files changed, 109 deletions(-) delete mode 100644 cw20/base/schema/count_response.json delete mode 100644 cw20/base/schema/execute_msg.json delete mode 100644 cw20/base/schema/instantiate_msg.json delete mode 100644 cw20/base/schema/query_msg.json delete mode 100644 cw20/base/schema/state.json diff --git a/cw20/base/schema/count_response.json b/cw20/base/schema/count_response.json deleted file mode 100644 index fa1e81f..0000000 --- a/cw20/base/schema/count_response.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "CountResponse", - "type": "object", - "required": [ - "count" - ], - "properties": { - "count": { - "type": "integer", - "format": "int32" - } - } -} diff --git a/cw20/base/schema/execute_msg.json b/cw20/base/schema/execute_msg.json deleted file mode 100644 index 6fa0a75..0000000 --- a/cw20/base/schema/execute_msg.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "ExecuteMsg", - "anyOf": [ - { - "type": "object", - "required": [ - "increment" - ], - "properties": { - "increment": { - "type": "object" - } - }, - "additionalProperties": false - }, - { - "type": "object", - "required": [ - "reset" - ], - "properties": { - "reset": { - "type": "object", - "required": [ - "count" - ], - "properties": { - "count": { - "type": "integer", - "format": "int32" - } - } - } - }, - "additionalProperties": false - } - ] -} diff --git a/cw20/base/schema/instantiate_msg.json b/cw20/base/schema/instantiate_msg.json deleted file mode 100644 index e794ec1..0000000 --- a/cw20/base/schema/instantiate_msg.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "InstantiateMsg", - "type": "object", - "required": [ - "count" - ], - "properties": { - "count": { - "type": "integer", - "format": "int32" - } - } -} diff --git a/cw20/base/schema/query_msg.json b/cw20/base/schema/query_msg.json deleted file mode 100644 index be0245b..0000000 --- a/cw20/base/schema/query_msg.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "QueryMsg", - "anyOf": [ - { - "type": "object", - "required": [ - "get_count" - ], - "properties": { - "get_count": { - "type": "object" - } - }, - "additionalProperties": false - } - ] -} diff --git a/cw20/base/schema/state.json b/cw20/base/schema/state.json deleted file mode 100644 index e18725d..0000000 --- a/cw20/base/schema/state.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "State", - "type": "object", - "required": [ - "count", - "owner" - ], - "properties": { - "count": { - "type": "integer", - "format": "int32" - }, - "owner": { - "$ref": "#/definitions/Addr" - } - }, - "definitions": { - "Addr": { - "description": "A human readable address.\n\nIn Cosmos, this is typically bech32 encoded. But for multi-chain smart contracts no assumptions should be made other than being UTF-8 encoded and of reasonable length.\n\nThis type represents a validated address. It can be created in the following ways 1. Use `Addr::unchecked(input)` 2. Use `let checked: Addr = deps.api.addr_validate(input)?` 3. Use `let checked: Addr = deps.api.addr_humanize(canonical_addr)?` 4. Deserialize from JSON. This must only be done from JSON that was validated before such as a contract's state. `Addr` must not be used in messages sent by the user because this would result in unvalidated instances.\n\nThis type is immutable. If you really need to mutate it (Really? Are you sure?), create a mutable copy using `let mut mutable = Addr::to_string()` and operate on that `String` instance.", - "type": "string" - } - } -} From 5d9544ad1b67c6c98edd293745804f3999ef94ef Mon Sep 17 00:00:00 2001 From: Georges Chouchani Date: Fri, 8 Jul 2022 13:22:33 +0300 Subject: [PATCH 08/65] fix test_generate --- .github/scripts/test_generate.sh | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/scripts/test_generate.sh b/.github/scripts/test_generate.sh index 834ecc5..1ce4925 100755 --- a/.github/scripts/test_generate.sh +++ b/.github/scripts/test_generate.sh @@ -2,7 +2,6 @@ set -u -o errexit -o nounset -o pipefail command -v shellcheck > /dev/null && shellcheck "$0" -REPO_ROOT="$(realpath "$(dirname "$0")/../..")" TMP_DIR=$(mktemp -d "${TMPDIR:-/tmp}/XXXXXXXXX") echo "Navigating to $TMP_DIR" @@ -15,10 +14,10 @@ function test-template() { echo "# Testing template $TEMPLATE" echo "#######################################" ( - GIT_BRANCH=$(git -C "$REPO_ROOT" branch --show-current) + GIT_BRANCH=$(git -C "$GITHUB_SERVER_URL/$GITHUB_REPOSITORY" branch --show-current) echo "Generating project from local repository (branch $GIT_BRANCH) ..." - cargo generate --git "$REPO_ROOT" --name "$PROJECT_NAME" --branch "$GIT_BRANCH" "$TEMPLATE" + cargo generate --git "$GITHUB_SERVER_URL/$GITHUB_REPOSITORY" --name "$PROJECT_NAME" --branch "$GIT_BRANCH" "$TEMPLATE" ( cd "$PROJECT_NAME" From b41f72efb72b6cc240b6c8b1abcae227fb4ba816 Mon Sep 17 00:00:00 2001 From: Georges Chouchani Date: Fri, 8 Jul 2022 13:29:21 +0300 Subject: [PATCH 09/65] change testing --- .github/scripts/test_generate.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/scripts/test_generate.sh b/.github/scripts/test_generate.sh index 1ce4925..c069463 100755 --- a/.github/scripts/test_generate.sh +++ b/.github/scripts/test_generate.sh @@ -43,7 +43,7 @@ function test-template() { ) } -find "$REPO_ROOT" -name Cargo.toml -exec dirname {} \; | while read -r TEMPLATE; do - test-template "${TEMPLATE//$REPO_ROOT\//}" +find "$GITHUB_SERVER_URL/$GITHUB_REPOSITORY" -name Cargo.toml -exec dirname {} \; | while read -r TEMPLATE; do + test-template "${TEMPLATE//$GITHUB_SERVER_URL/$GITHUB_REPOSITORY\//}" echo done From ce3c7ddc9e1c6cd6caed2a86b75f390c2788143e Mon Sep 17 00:00:00 2001 From: Georges Chouchani Date: Fri, 8 Jul 2022 13:36:55 +0300 Subject: [PATCH 10/65] extra changes --- .github/scripts/test_generate.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/scripts/test_generate.sh b/.github/scripts/test_generate.sh index c069463..592fb1b 100755 --- a/.github/scripts/test_generate.sh +++ b/.github/scripts/test_generate.sh @@ -2,6 +2,7 @@ set -u -o errexit -o nounset -o pipefail command -v shellcheck > /dev/null && shellcheck "$0" +REPO_ROOT="$(realpath "$(dirname "$0")/../..")" TMP_DIR=$(mktemp -d "${TMPDIR:-/tmp}/XXXXXXXXX") echo "Navigating to $TMP_DIR" @@ -43,7 +44,7 @@ function test-template() { ) } -find "$GITHUB_SERVER_URL/$GITHUB_REPOSITORY" -name Cargo.toml -exec dirname {} \; | while read -r TEMPLATE; do - test-template "${TEMPLATE//$GITHUB_SERVER_URL/$GITHUB_REPOSITORY\//}" +find "$REPO_ROOT" -name Cargo.toml -exec dirname {} \; | while read -r TEMPLATE; do + test-template "${TEMPLATE//$REPO_ROOT\//}" echo done From 3e14c081c39739f7c423c49795fc405e48ea8709 Mon Sep 17 00:00:00 2001 From: Georges Chouchani Date: Fri, 8 Jul 2022 14:01:50 +0300 Subject: [PATCH 11/65] cjange git branch --- .github/scripts/test_generate.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/scripts/test_generate.sh b/.github/scripts/test_generate.sh index 592fb1b..d56d91c 100755 --- a/.github/scripts/test_generate.sh +++ b/.github/scripts/test_generate.sh @@ -15,7 +15,7 @@ function test-template() { echo "# Testing template $TEMPLATE" echo "#######################################" ( - GIT_BRANCH=$(git -C "$GITHUB_SERVER_URL/$GITHUB_REPOSITORY" branch --show-current) + GIT_BRANCH=$(git -C "$REPO_ROOT" branch --show-current) echo "Generating project from local repository (branch $GIT_BRANCH) ..." cargo generate --git "$GITHUB_SERVER_URL/$GITHUB_REPOSITORY" --name "$PROJECT_NAME" --branch "$GIT_BRANCH" "$TEMPLATE" From 1560efc8299baa957f493af67c3d1358b4e95c48 Mon Sep 17 00:00:00 2001 From: Georges Chouchani Date: Fri, 8 Jul 2022 14:14:36 +0300 Subject: [PATCH 12/65] echo of template root --- .github/scripts/test_generate.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/scripts/test_generate.sh b/.github/scripts/test_generate.sh index d56d91c..d9ae5fa 100755 --- a/.github/scripts/test_generate.sh +++ b/.github/scripts/test_generate.sh @@ -14,6 +14,7 @@ function test-template() { echo "#######################################" echo "# Testing template $TEMPLATE" echo "#######################################" + echo "$REPO_ROOT" ( GIT_BRANCH=$(git -C "$REPO_ROOT" branch --show-current) From 78f1cfae0ffd2475e9f3ac09102939a1f10ab5cb Mon Sep 17 00:00:00 2001 From: Georges Chouchani Date: Fri, 8 Jul 2022 14:24:16 +0300 Subject: [PATCH 13/65] ff --- .github/scripts/test_generate.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/scripts/test_generate.sh b/.github/scripts/test_generate.sh index d9ae5fa..592fb1b 100755 --- a/.github/scripts/test_generate.sh +++ b/.github/scripts/test_generate.sh @@ -14,9 +14,8 @@ function test-template() { echo "#######################################" echo "# Testing template $TEMPLATE" echo "#######################################" - echo "$REPO_ROOT" ( - GIT_BRANCH=$(git -C "$REPO_ROOT" branch --show-current) + GIT_BRANCH=$(git -C "$GITHUB_SERVER_URL/$GITHUB_REPOSITORY" branch --show-current) echo "Generating project from local repository (branch $GIT_BRANCH) ..." cargo generate --git "$GITHUB_SERVER_URL/$GITHUB_REPOSITORY" --name "$PROJECT_NAME" --branch "$GIT_BRANCH" "$TEMPLATE" From 31bb4fa9aa8c4d6de519b70a2034a6da81ae75f0 Mon Sep 17 00:00:00 2001 From: Georges Chouchani Date: Mon, 11 Jul 2022 12:13:07 +0300 Subject: [PATCH 14/65] change to repo root in test_generate.sh --- .github/scripts/test_generate.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/scripts/test_generate.sh b/.github/scripts/test_generate.sh index 592fb1b..d56d91c 100755 --- a/.github/scripts/test_generate.sh +++ b/.github/scripts/test_generate.sh @@ -15,7 +15,7 @@ function test-template() { echo "# Testing template $TEMPLATE" echo "#######################################" ( - GIT_BRANCH=$(git -C "$GITHUB_SERVER_URL/$GITHUB_REPOSITORY" branch --show-current) + GIT_BRANCH=$(git -C "$REPO_ROOT" branch --show-current) echo "Generating project from local repository (branch $GIT_BRANCH) ..." cargo generate --git "$GITHUB_SERVER_URL/$GITHUB_REPOSITORY" --name "$PROJECT_NAME" --branch "$GIT_BRANCH" "$TEMPLATE" From daca01916bc2ecb4339631d0c4022dd547239834 Mon Sep 17 00:00:00 2001 From: Georges Chouchani Date: Mon, 11 Jul 2022 12:19:47 +0300 Subject: [PATCH 15/65] added tmate session after failure to debug error --- .github/workflows/check.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 3918dc9..c40d57b 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -25,3 +25,7 @@ jobs: - name: Test all templates run: ${{ github.workspace }}/.github/scripts/test_generate.sh + - name: Setup tmate session + if: ${{ failure() }} + uses: mxschmitt/action-tmate@v3 + From d2c49ab932b24ce810790577e1fe99e58d73fcef Mon Sep 17 00:00:00 2001 From: Georges Chouchani Date: Mon, 11 Jul 2022 12:32:10 +0300 Subject: [PATCH 16/65] change in repo test generate --- .github/scripts/test_generate.sh | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/scripts/test_generate.sh b/.github/scripts/test_generate.sh index d56d91c..50a44ca 100755 --- a/.github/scripts/test_generate.sh +++ b/.github/scripts/test_generate.sh @@ -1,4 +1,3 @@ -#!/bin/bash set -u -o errexit -o nounset -o pipefail command -v shellcheck > /dev/null && shellcheck "$0" @@ -18,7 +17,7 @@ function test-template() { GIT_BRANCH=$(git -C "$REPO_ROOT" branch --show-current) echo "Generating project from local repository (branch $GIT_BRANCH) ..." - cargo generate --git "$GITHUB_SERVER_URL/$GITHUB_REPOSITORY" --name "$PROJECT_NAME" --branch "$GIT_BRANCH" "$TEMPLATE" + cargo generate --git "$REPO_ROOT" --name "$PROJECT_NAME" --branch "$GIT_BRANCH" "$TEMPLATE" ( cd "$PROJECT_NAME" @@ -47,4 +46,4 @@ function test-template() { find "$REPO_ROOT" -name Cargo.toml -exec dirname {} \; | while read -r TEMPLATE; do test-template "${TEMPLATE//$REPO_ROOT\//}" echo -done +done \ No newline at end of file From b3304492dee1ca78c68d8734edd75d0b18993f82 Mon Sep 17 00:00:00 2001 From: Georges Chouchani Date: Mon, 11 Jul 2022 12:32:33 +0300 Subject: [PATCH 17/65] removed tmate session --- .github/workflows/check.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index c40d57b..68b21bf 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -25,7 +25,5 @@ jobs: - name: Test all templates run: ${{ github.workspace }}/.github/scripts/test_generate.sh - - name: Setup tmate session - if: ${{ failure() }} - uses: mxschmitt/action-tmate@v3 + From b29505ede2757752f47218fb16c9abcec2dcd5bc Mon Sep 17 00:00:00 2001 From: Georges Chouchani Date: Mon, 11 Jul 2022 12:49:13 +0300 Subject: [PATCH 18/65] added top comment --- .github/scripts/test_generate.sh | 2 ++ .github/workflows/check.yml | 4 +--- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/scripts/test_generate.sh b/.github/scripts/test_generate.sh index 50a44ca..4a484af 100755 --- a/.github/scripts/test_generate.sh +++ b/.github/scripts/test_generate.sh @@ -1,3 +1,5 @@ +#!/bin/bash + set -u -o errexit -o nounset -o pipefail command -v shellcheck > /dev/null && shellcheck "$0" diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 68b21bf..b4cbebb 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -24,6 +24,4 @@ jobs: args: cargo-generate --features vendored-openssl - name: Test all templates - run: ${{ github.workspace }}/.github/scripts/test_generate.sh - - + run: ${{ github.workspace }}/.github/scripts/test_generate.sh \ No newline at end of file From e4733a8be2e267c48f67eb42dfa5fc937ae572ba Mon Sep 17 00:00:00 2001 From: Georges Chouchani Date: Mon, 11 Jul 2022 13:12:09 +0300 Subject: [PATCH 19/65] fixing testing in test_generate.sh --- .github/scripts/test_generate.sh | 1 - cw20/base/src/lib.rs | 24 +++++++++--------------- 2 files changed, 9 insertions(+), 16 deletions(-) diff --git a/.github/scripts/test_generate.sh b/.github/scripts/test_generate.sh index 4a484af..4339601 100755 --- a/.github/scripts/test_generate.sh +++ b/.github/scripts/test_generate.sh @@ -1,5 +1,4 @@ #!/bin/bash - set -u -o errexit -o nounset -o pipefail command -v shellcheck > /dev/null && shellcheck "$0" diff --git a/cw20/base/src/lib.rs b/cw20/base/src/lib.rs index a8fd802..4e7678a 100644 --- a/cw20/base/src/lib.rs +++ b/cw20/base/src/lib.rs @@ -1,15 +1,8 @@ - - use cw2::set_contract_version; -pub use cw20_base::msg::{ExecuteMsg,InstantiateMsg,QueryMsg}; -pub use cw20_base::contract::{instantiate as instantiateCw20, execute as executeCw20, query as queryCw20}; - - - - - - +pub use cw20_base::contract::{execute as executeCw20, instantiate as instantiateCw20, query as queryCw20, +}; +pub use cw20_base::msg::{ExecuteMsg, InstantiateMsg, QueryMsg}; const CONTRACT_NAME: &str = "crates.io:{{project-name}}"; const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION"); @@ -58,10 +51,12 @@ mod tests { use super::*; - use cosmwasm_std::{testing::{mock_dependencies, mock_env, mock_info}, Deps}; + use cosmwasm_std::{ + testing::{mock_dependencies, mock_env, mock_info}, + Deps, + }; use cw20::{Cw20Coin, TokenInfoResponse}; - use cosmwasm_std::Uint128; - use cw20_base::contract::{query_token_info, query_balance}; + use cw20_base::contract::{query_balance, query_token_info}; const CREATOR: &str = "creator"; fn get_balance>(deps: Deps, address: T) -> Uint128 { @@ -101,5 +96,4 @@ mod tests { Uint128::new(11223344) ); } -} - +} \ No newline at end of file From f03f8ba5f0619bde6596868ed2c6daed1bd69074 Mon Sep 17 00:00:00 2001 From: Georges Chouchani Date: Mon, 11 Jul 2022 13:23:53 +0300 Subject: [PATCH 20/65] fixed extra differences --- cw20/base/src/lib.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/cw20/base/src/lib.rs b/cw20/base/src/lib.rs index 4e7678a..377d7af 100644 --- a/cw20/base/src/lib.rs +++ b/cw20/base/src/lib.rs @@ -1,6 +1,7 @@ use cw2::set_contract_version; -pub use cw20_base::contract::{execute as executeCw20, instantiate as instantiateCw20, query as queryCw20, +pub use cw20_base::contract::{ + execute as executeCw20, instantiate as instantiateCw20, query as queryCw20, }; pub use cw20_base::msg::{ExecuteMsg, InstantiateMsg, QueryMsg}; const CONTRACT_NAME: &str = "crates.io:{{project-name}}"; @@ -52,9 +53,9 @@ mod tests { use super::*; use cosmwasm_std::{ - testing::{mock_dependencies, mock_env, mock_info}, - Deps, - }; + testing::{mock_dependencies, mock_env, mock_info}, + Deps, + }; use cw20::{Cw20Coin, TokenInfoResponse}; use cw20_base::contract::{query_balance, query_token_info}; const CREATOR: &str = "creator"; From b75231a1612e5277a174a4d80e3e48e0b4c40811 Mon Sep 17 00:00:00 2001 From: Georges Chouchani Date: Mon, 11 Jul 2022 13:39:01 +0300 Subject: [PATCH 21/65] added extra end line --- cw20/base/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cw20/base/src/lib.rs b/cw20/base/src/lib.rs index 377d7af..0cd3d84 100644 --- a/cw20/base/src/lib.rs +++ b/cw20/base/src/lib.rs @@ -97,4 +97,4 @@ mod tests { Uint128::new(11223344) ); } -} \ No newline at end of file +} From 8a3936add2d2956c6d9d2e41d9a3bf7e694a1b37 Mon Sep 17 00:00:00 2001 From: Georges Chouchani Date: Mon, 11 Jul 2022 13:50:21 +0300 Subject: [PATCH 22/65] added Uint128 import --- cw20/base/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cw20/base/src/lib.rs b/cw20/base/src/lib.rs index 0cd3d84..a3c44aa 100644 --- a/cw20/base/src/lib.rs +++ b/cw20/base/src/lib.rs @@ -53,7 +53,7 @@ mod tests { use super::*; use cosmwasm_std::{ - testing::{mock_dependencies, mock_env, mock_info}, + testing::{mock_dependencies, mock_env, mock_info, Uint128}, Deps, }; use cw20::{Cw20Coin, TokenInfoResponse}; From f8aac0c4debc3868f1e4c7e1f4c95a3f10d983b8 Mon Sep 17 00:00:00 2001 From: Georges Chouchani Date: Mon, 11 Jul 2022 14:05:23 +0300 Subject: [PATCH 23/65] fixed Uint128 import --- cw20/base/src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cw20/base/src/lib.rs b/cw20/base/src/lib.rs index a3c44aa..76f7b35 100644 --- a/cw20/base/src/lib.rs +++ b/cw20/base/src/lib.rs @@ -53,8 +53,9 @@ mod tests { use super::*; use cosmwasm_std::{ - testing::{mock_dependencies, mock_env, mock_info, Uint128}, + testing::{mock_dependencies, mock_env, mock_info}, Deps, + Uint128 }; use cw20::{Cw20Coin, TokenInfoResponse}; use cw20_base::contract::{query_balance, query_token_info}; From f2fbe4dd3bbc1bdee2050928e7805731eb0a9dcf Mon Sep 17 00:00:00 2001 From: Georges Chouchani Date: Mon, 11 Jul 2022 14:17:06 +0300 Subject: [PATCH 24/65] fixed space --- cw20/base/src/lib.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cw20/base/src/lib.rs b/cw20/base/src/lib.rs index 76f7b35..551f1ca 100644 --- a/cw20/base/src/lib.rs +++ b/cw20/base/src/lib.rs @@ -54,8 +54,7 @@ mod tests { use cosmwasm_std::{ testing::{mock_dependencies, mock_env, mock_info}, - Deps, - Uint128 + Deps, Uint128 }; use cw20::{Cw20Coin, TokenInfoResponse}; use cw20_base::contract::{query_balance, query_token_info}; From f10d7f1aaa80db03d8be47be3e4ed3ed831003b7 Mon Sep 17 00:00:00 2001 From: Georges Chouchani Date: Mon, 11 Jul 2022 14:35:49 +0300 Subject: [PATCH 25/65] fixed comma --- cw20/base/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cw20/base/src/lib.rs b/cw20/base/src/lib.rs index 551f1ca..92ac8b2 100644 --- a/cw20/base/src/lib.rs +++ b/cw20/base/src/lib.rs @@ -54,7 +54,7 @@ mod tests { use cosmwasm_std::{ testing::{mock_dependencies, mock_env, mock_info}, - Deps, Uint128 + Deps, Uint128, }; use cw20::{Cw20Coin, TokenInfoResponse}; use cw20_base::contract::{query_balance, query_token_info}; From bd742c6dda04a3bbe11af48f2ee121a796230d17 Mon Sep 17 00:00:00 2001 From: Georges Chouchani Date: Mon, 11 Jul 2022 14:58:17 +0300 Subject: [PATCH 26/65] change schema to template name --- cw20/base/examples/schema.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cw20/base/examples/schema.rs b/cw20/base/examples/schema.rs index 92e9d8e..24d5770 100644 --- a/cw20/base/examples/schema.rs +++ b/cw20/base/examples/schema.rs @@ -3,7 +3,7 @@ use std::fs::create_dir_all; use cosmwasm_schema::{export_schema, remove_schemas, schema_for}; -use cw20_base::msg::{ExecuteMsg, InstantiateMsg, QueryMsg}; +use {{crate_name}}::msg::{ExecuteMsg, InstantiateMsg, QueryMsg}; fn main() { let mut out_dir = current_dir().unwrap(); From 639cc6ec77534ab1d960bb0c6cc89913db7c678e Mon Sep 17 00:00:00 2001 From: Georges Chouchani Date: Mon, 11 Jul 2022 15:15:15 +0300 Subject: [PATCH 27/65] remove schema run from .cargo --- cw20/base/.cargo/config | 1 - 1 file changed, 1 deletion(-) diff --git a/cw20/base/.cargo/config b/cw20/base/.cargo/config index 336b618..f31de6c 100644 --- a/cw20/base/.cargo/config +++ b/cw20/base/.cargo/config @@ -1,4 +1,3 @@ [alias] wasm = "build --release --target wasm32-unknown-unknown" unit-test = "test --lib" -schema = "run --example schema" From c80c49def7bae73bf738d5113ee148deaa6632a5 Mon Sep 17 00:00:00 2001 From: Georges Chouchani Date: Mon, 11 Jul 2022 15:25:51 +0300 Subject: [PATCH 28/65] removed schema test from test_generate --- .github/scripts/test_generate.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/scripts/test_generate.sh b/.github/scripts/test_generate.sh index 4339601..463af71 100755 --- a/.github/scripts/test_generate.sh +++ b/.github/scripts/test_generate.sh @@ -35,8 +35,6 @@ function test-template() { # Debug builds first to fail fast echo "Running unit tests ..." cargo unit-test - echo "Creating schema ..." - cargo schema echo "Building wasm ..." cargo wasm From 623ab7dd62af36eaaf17e0e1c48e151f3f0521ff Mon Sep 17 00:00:00 2001 From: Georges Chouchani Date: Mon, 11 Jul 2022 15:50:21 +0300 Subject: [PATCH 29/65] add updates to rust with script --- .github/scripts/test_generate.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/scripts/test_generate.sh b/.github/scripts/test_generate.sh index 463af71..1cd0a23 100755 --- a/.github/scripts/test_generate.sh +++ b/.github/scripts/test_generate.sh @@ -16,7 +16,8 @@ function test-template() { echo "#######################################" ( GIT_BRANCH=$(git -C "$REPO_ROOT" branch --show-current) - + echo "Updating rust and cargo ..." + rustup update echo "Generating project from local repository (branch $GIT_BRANCH) ..." cargo generate --git "$REPO_ROOT" --name "$PROJECT_NAME" --branch "$GIT_BRANCH" "$TEMPLATE" From 8d6662a9a31536eb5dea5fa6d040610ba1b56a56 Mon Sep 17 00:00:00 2001 From: Georges Chouchani Date: Mon, 11 Jul 2022 16:16:12 +0300 Subject: [PATCH 30/65] changed name of cw20-base to cw20-base-lib --- cw20/{base => base-lib}/.cargo/config | 0 cw20/{base => base-lib}/.circleci/config.yml | 0 cw20/{base => base-lib}/.editorconfig | 0 cw20/{base => base-lib}/.github/workflows/Basic.yml | 0 cw20/{base => base-lib}/.gitignore | 0 cw20/{base => base-lib}/.gitpod.Dockerfile | 0 cw20/{base => base-lib}/.gitpod.yml | 0 cw20/{base => base-lib}/Cargo.toml | 0 cw20/{base => base-lib}/Developing.md | 0 cw20/{base => base-lib}/Importing.md | 0 cw20/{base => base-lib}/LICENSE | 0 cw20/{base => base-lib}/NOTICE | 0 cw20/{base => base-lib}/Publishing.md | 0 cw20/{base => base-lib}/README.md | 0 cw20/{base => base-lib}/cargo-generate.toml | 0 cw20/{base => base-lib}/examples/schema.rs | 0 cw20/{base => base-lib}/rustfmt.toml | 0 cw20/{base => base-lib}/src/lib.rs | 0 18 files changed, 0 insertions(+), 0 deletions(-) rename cw20/{base => base-lib}/.cargo/config (100%) rename cw20/{base => base-lib}/.circleci/config.yml (100%) rename cw20/{base => base-lib}/.editorconfig (100%) rename cw20/{base => base-lib}/.github/workflows/Basic.yml (100%) rename cw20/{base => base-lib}/.gitignore (100%) rename cw20/{base => base-lib}/.gitpod.Dockerfile (100%) rename cw20/{base => base-lib}/.gitpod.yml (100%) rename cw20/{base => base-lib}/Cargo.toml (100%) rename cw20/{base => base-lib}/Developing.md (100%) rename cw20/{base => base-lib}/Importing.md (100%) rename cw20/{base => base-lib}/LICENSE (100%) rename cw20/{base => base-lib}/NOTICE (100%) rename cw20/{base => base-lib}/Publishing.md (100%) rename cw20/{base => base-lib}/README.md (100%) rename cw20/{base => base-lib}/cargo-generate.toml (100%) rename cw20/{base => base-lib}/examples/schema.rs (100%) rename cw20/{base => base-lib}/rustfmt.toml (100%) rename cw20/{base => base-lib}/src/lib.rs (100%) diff --git a/cw20/base/.cargo/config b/cw20/base-lib/.cargo/config similarity index 100% rename from cw20/base/.cargo/config rename to cw20/base-lib/.cargo/config diff --git a/cw20/base/.circleci/config.yml b/cw20/base-lib/.circleci/config.yml similarity index 100% rename from cw20/base/.circleci/config.yml rename to cw20/base-lib/.circleci/config.yml diff --git a/cw20/base/.editorconfig b/cw20/base-lib/.editorconfig similarity index 100% rename from cw20/base/.editorconfig rename to cw20/base-lib/.editorconfig diff --git a/cw20/base/.github/workflows/Basic.yml b/cw20/base-lib/.github/workflows/Basic.yml similarity index 100% rename from cw20/base/.github/workflows/Basic.yml rename to cw20/base-lib/.github/workflows/Basic.yml diff --git a/cw20/base/.gitignore b/cw20/base-lib/.gitignore similarity index 100% rename from cw20/base/.gitignore rename to cw20/base-lib/.gitignore diff --git a/cw20/base/.gitpod.Dockerfile b/cw20/base-lib/.gitpod.Dockerfile similarity index 100% rename from cw20/base/.gitpod.Dockerfile rename to cw20/base-lib/.gitpod.Dockerfile diff --git a/cw20/base/.gitpod.yml b/cw20/base-lib/.gitpod.yml similarity index 100% rename from cw20/base/.gitpod.yml rename to cw20/base-lib/.gitpod.yml diff --git a/cw20/base/Cargo.toml b/cw20/base-lib/Cargo.toml similarity index 100% rename from cw20/base/Cargo.toml rename to cw20/base-lib/Cargo.toml diff --git a/cw20/base/Developing.md b/cw20/base-lib/Developing.md similarity index 100% rename from cw20/base/Developing.md rename to cw20/base-lib/Developing.md diff --git a/cw20/base/Importing.md b/cw20/base-lib/Importing.md similarity index 100% rename from cw20/base/Importing.md rename to cw20/base-lib/Importing.md diff --git a/cw20/base/LICENSE b/cw20/base-lib/LICENSE similarity index 100% rename from cw20/base/LICENSE rename to cw20/base-lib/LICENSE diff --git a/cw20/base/NOTICE b/cw20/base-lib/NOTICE similarity index 100% rename from cw20/base/NOTICE rename to cw20/base-lib/NOTICE diff --git a/cw20/base/Publishing.md b/cw20/base-lib/Publishing.md similarity index 100% rename from cw20/base/Publishing.md rename to cw20/base-lib/Publishing.md diff --git a/cw20/base/README.md b/cw20/base-lib/README.md similarity index 100% rename from cw20/base/README.md rename to cw20/base-lib/README.md diff --git a/cw20/base/cargo-generate.toml b/cw20/base-lib/cargo-generate.toml similarity index 100% rename from cw20/base/cargo-generate.toml rename to cw20/base-lib/cargo-generate.toml diff --git a/cw20/base/examples/schema.rs b/cw20/base-lib/examples/schema.rs similarity index 100% rename from cw20/base/examples/schema.rs rename to cw20/base-lib/examples/schema.rs diff --git a/cw20/base/rustfmt.toml b/cw20/base-lib/rustfmt.toml similarity index 100% rename from cw20/base/rustfmt.toml rename to cw20/base-lib/rustfmt.toml diff --git a/cw20/base/src/lib.rs b/cw20/base-lib/src/lib.rs similarity index 100% rename from cw20/base/src/lib.rs rename to cw20/base-lib/src/lib.rs From aab3c2d4f876b9bbb436bca575ac4eb57eedd893 Mon Sep 17 00:00:00 2001 From: Georges Chouchani Date: Mon, 11 Jul 2022 16:49:16 +0300 Subject: [PATCH 31/65] change dependency of version --- cw20/base-lib/.cargo/config | 3 +++ cw20/base-lib/.gitignore | 21 +++++++++------------ cw20/base-lib/Cargo.toml | 6 +++--- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/cw20/base-lib/.cargo/config b/cw20/base-lib/.cargo/config index f31de6c..46a96a8 100644 --- a/cw20/base-lib/.cargo/config +++ b/cw20/base-lib/.cargo/config @@ -1,3 +1,6 @@ [alias] wasm = "build --release --target wasm32-unknown-unknown" +wasm-debug = "build --target wasm32-unknown-unknown" unit-test = "test --lib" +schema = "run --example schema" + diff --git a/cw20/base-lib/.gitignore b/cw20/base-lib/.gitignore index 73211d4..6a0375b 100644 --- a/cw20/base-lib/.gitignore +++ b/cw20/base-lib/.gitignore @@ -1,15 +1,12 @@ -# Build results -/target -/artifacts -# Cargo+Git helper file (https://github.com/rust-lang/cargo/blob/0.44.1/src/cargo/sources/git/utils.rs#L320-L327) -.cargo-ok +# Generated by Cargo +# will have compiled files and executables +/target/ -# Text file backups -**/*.rs.bk +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html +Cargo.lock -# macOS -.DS_Store +# These are backup files generated by rustfmt +**/*.rs.bk -# IDEs -*.iml -.idea +.idea \ No newline at end of file diff --git a/cw20/base-lib/Cargo.toml b/cw20/base-lib/Cargo.toml index 9cb6fc7..95c6388 100644 --- a/cw20/base-lib/Cargo.toml +++ b/cw20/base-lib/Cargo.toml @@ -42,10 +42,10 @@ optimize = """docker run --rm -v "$(pwd)":/code \ [dependencies] cosmwasm-std = "1.0.0" cosmwasm-storage = "1.0.0" -cw-storage-plus = "0.13.2" -cw2 = "0.13.2" +cw-storage-plus = "0.13.4" +cw2 = "0.13.4" cw20 = "0.13.4" -cw20-base = "0.13.2" +cw20-base = "0.13.4" schemars = "0.8.8" serde = { version = "1.0.137", default-features = false, features = ["derive"] } thiserror = { version = "1.0.31" } From 03ecc169a11809da5022e5e4462c9c008596854d Mon Sep 17 00:00:00 2001 From: Georges Chouchani Date: Wed, 13 Jul 2022 13:43:21 +0300 Subject: [PATCH 32/65] change in check to remove pull-request test --- .github/workflows/check.yml | 2 +- cw20/base-lib/examples/schema.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index b4cbebb..aa1338b 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -1,4 +1,4 @@ -on: [push, pull_request] +on: [push] name: Check Templates diff --git a/cw20/base-lib/examples/schema.rs b/cw20/base-lib/examples/schema.rs index 24d5770..850b639 100644 --- a/cw20/base-lib/examples/schema.rs +++ b/cw20/base-lib/examples/schema.rs @@ -11,7 +11,7 @@ fn main() { create_dir_all(&out_dir).unwrap(); remove_schemas(&out_dir).unwrap(); - export_schema(&schema_for!(InstantiateMsg), &out_dir); + export_schema(&sxchema_for!(InstantiateMsg), &out_dir); export_schema(&schema_for!(ExecuteMsg), &out_dir); export_schema(&schema_for!(QueryMsg), &out_dir); } From 10e4eae234739701e9afa7605bd4cce28ff960c0 Mon Sep 17 00:00:00 2001 From: Georges Chouchani Date: Thu, 4 Aug 2022 14:17:05 +0300 Subject: [PATCH 33/65] fixed library entry point issue --- cw20/{base-lib => base}/.cargo/config | 0 cw20/{base-lib => base}/.circleci/config.yml | 0 cw20/{base-lib => base}/.editorconfig | 0 cw20/{base-lib => base}/.github/workflows/Basic.yml | 0 cw20/{base-lib => base}/.gitignore | 0 cw20/{base-lib => base}/.gitpod.Dockerfile | 0 cw20/{base-lib => base}/.gitpod.yml | 0 cw20/{base-lib => base}/Cargo.toml | 2 +- cw20/{base-lib => base}/Developing.md | 0 cw20/{base-lib => base}/Importing.md | 0 cw20/{base-lib => base}/LICENSE | 0 cw20/{base-lib => base}/NOTICE | 0 cw20/{base-lib => base}/Publishing.md | 0 cw20/{base-lib => base}/README.md | 0 cw20/{base-lib => base}/cargo-generate.toml | 0 cw20/{base-lib => base}/examples/schema.rs | 0 cw20/{base-lib => base}/rustfmt.toml | 0 cw20/{base-lib => base}/src/lib.rs | 0 18 files changed, 1 insertion(+), 1 deletion(-) rename cw20/{base-lib => base}/.cargo/config (100%) rename cw20/{base-lib => base}/.circleci/config.yml (100%) rename cw20/{base-lib => base}/.editorconfig (100%) rename cw20/{base-lib => base}/.github/workflows/Basic.yml (100%) rename cw20/{base-lib => base}/.gitignore (100%) rename cw20/{base-lib => base}/.gitpod.Dockerfile (100%) rename cw20/{base-lib => base}/.gitpod.yml (100%) rename cw20/{base-lib => base}/Cargo.toml (95%) rename cw20/{base-lib => base}/Developing.md (100%) rename cw20/{base-lib => base}/Importing.md (100%) rename cw20/{base-lib => base}/LICENSE (100%) rename cw20/{base-lib => base}/NOTICE (100%) rename cw20/{base-lib => base}/Publishing.md (100%) rename cw20/{base-lib => base}/README.md (100%) rename cw20/{base-lib => base}/cargo-generate.toml (100%) rename cw20/{base-lib => base}/examples/schema.rs (100%) rename cw20/{base-lib => base}/rustfmt.toml (100%) rename cw20/{base-lib => base}/src/lib.rs (100%) diff --git a/cw20/base-lib/.cargo/config b/cw20/base/.cargo/config similarity index 100% rename from cw20/base-lib/.cargo/config rename to cw20/base/.cargo/config diff --git a/cw20/base-lib/.circleci/config.yml b/cw20/base/.circleci/config.yml similarity index 100% rename from cw20/base-lib/.circleci/config.yml rename to cw20/base/.circleci/config.yml diff --git a/cw20/base-lib/.editorconfig b/cw20/base/.editorconfig similarity index 100% rename from cw20/base-lib/.editorconfig rename to cw20/base/.editorconfig diff --git a/cw20/base-lib/.github/workflows/Basic.yml b/cw20/base/.github/workflows/Basic.yml similarity index 100% rename from cw20/base-lib/.github/workflows/Basic.yml rename to cw20/base/.github/workflows/Basic.yml diff --git a/cw20/base-lib/.gitignore b/cw20/base/.gitignore similarity index 100% rename from cw20/base-lib/.gitignore rename to cw20/base/.gitignore diff --git a/cw20/base-lib/.gitpod.Dockerfile b/cw20/base/.gitpod.Dockerfile similarity index 100% rename from cw20/base-lib/.gitpod.Dockerfile rename to cw20/base/.gitpod.Dockerfile diff --git a/cw20/base-lib/.gitpod.yml b/cw20/base/.gitpod.yml similarity index 100% rename from cw20/base-lib/.gitpod.yml rename to cw20/base/.gitpod.yml diff --git a/cw20/base-lib/Cargo.toml b/cw20/base/Cargo.toml similarity index 95% rename from cw20/base-lib/Cargo.toml rename to cw20/base/Cargo.toml index 95c6388..2452550 100644 --- a/cw20/base-lib/Cargo.toml +++ b/cw20/base/Cargo.toml @@ -45,7 +45,7 @@ cosmwasm-storage = "1.0.0" cw-storage-plus = "0.13.4" cw2 = "0.13.4" cw20 = "0.13.4" -cw20-base = "0.13.4" +cw20-base = { version = "0.13.4", features = ["library"] } schemars = "0.8.8" serde = { version = "1.0.137", default-features = false, features = ["derive"] } thiserror = { version = "1.0.31" } diff --git a/cw20/base-lib/Developing.md b/cw20/base/Developing.md similarity index 100% rename from cw20/base-lib/Developing.md rename to cw20/base/Developing.md diff --git a/cw20/base-lib/Importing.md b/cw20/base/Importing.md similarity index 100% rename from cw20/base-lib/Importing.md rename to cw20/base/Importing.md diff --git a/cw20/base-lib/LICENSE b/cw20/base/LICENSE similarity index 100% rename from cw20/base-lib/LICENSE rename to cw20/base/LICENSE diff --git a/cw20/base-lib/NOTICE b/cw20/base/NOTICE similarity index 100% rename from cw20/base-lib/NOTICE rename to cw20/base/NOTICE diff --git a/cw20/base-lib/Publishing.md b/cw20/base/Publishing.md similarity index 100% rename from cw20/base-lib/Publishing.md rename to cw20/base/Publishing.md diff --git a/cw20/base-lib/README.md b/cw20/base/README.md similarity index 100% rename from cw20/base-lib/README.md rename to cw20/base/README.md diff --git a/cw20/base-lib/cargo-generate.toml b/cw20/base/cargo-generate.toml similarity index 100% rename from cw20/base-lib/cargo-generate.toml rename to cw20/base/cargo-generate.toml diff --git a/cw20/base-lib/examples/schema.rs b/cw20/base/examples/schema.rs similarity index 100% rename from cw20/base-lib/examples/schema.rs rename to cw20/base/examples/schema.rs diff --git a/cw20/base-lib/rustfmt.toml b/cw20/base/rustfmt.toml similarity index 100% rename from cw20/base-lib/rustfmt.toml rename to cw20/base/rustfmt.toml diff --git a/cw20/base-lib/src/lib.rs b/cw20/base/src/lib.rs similarity index 100% rename from cw20/base-lib/src/lib.rs rename to cw20/base/src/lib.rs From ed67eb4b752c684cec4c111e80405e85bdb795a7 Mon Sep 17 00:00:00 2001 From: Georges Chouchani Date: Thu, 4 Aug 2022 14:33:56 +0300 Subject: [PATCH 34/65] fixed issues from PR comment and testing --- .github/scripts/test_generate.sh | 6 +++--- .github/workflows/check.yml | 2 +- cw20/base/examples/schema.rs | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/scripts/test_generate.sh b/.github/scripts/test_generate.sh index 1cd0a23..d02ec07 100755 --- a/.github/scripts/test_generate.sh +++ b/.github/scripts/test_generate.sh @@ -16,8 +16,7 @@ function test-template() { echo "#######################################" ( GIT_BRANCH=$(git -C "$REPO_ROOT" branch --show-current) - echo "Updating rust and cargo ..." - rustup update + echo "Generating project from local repository (branch $GIT_BRANCH) ..." cargo generate --git "$REPO_ROOT" --name "$PROJECT_NAME" --branch "$GIT_BRANCH" "$TEMPLATE" @@ -36,7 +35,8 @@ function test-template() { # Debug builds first to fail fast echo "Running unit tests ..." cargo unit-test - + echo "Creating schema ..." + cargo schema echo "Building wasm ..." cargo wasm ) diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index aa1338b..b4cbebb 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -1,4 +1,4 @@ -on: [push] +on: [push, pull_request] name: Check Templates diff --git a/cw20/base/examples/schema.rs b/cw20/base/examples/schema.rs index 850b639..92e9d8e 100644 --- a/cw20/base/examples/schema.rs +++ b/cw20/base/examples/schema.rs @@ -3,7 +3,7 @@ use std::fs::create_dir_all; use cosmwasm_schema::{export_schema, remove_schemas, schema_for}; -use {{crate_name}}::msg::{ExecuteMsg, InstantiateMsg, QueryMsg}; +use cw20_base::msg::{ExecuteMsg, InstantiateMsg, QueryMsg}; fn main() { let mut out_dir = current_dir().unwrap(); @@ -11,7 +11,7 @@ fn main() { create_dir_all(&out_dir).unwrap(); remove_schemas(&out_dir).unwrap(); - export_schema(&sxchema_for!(InstantiateMsg), &out_dir); + export_schema(&schema_for!(InstantiateMsg), &out_dir); export_schema(&schema_for!(ExecuteMsg), &out_dir); export_schema(&schema_for!(QueryMsg), &out_dir); } From 44cc1d0fb4b969039e1e7b1531c81f44df98a275 Mon Sep 17 00:00:00 2001 From: Georges Chouchani Date: Thu, 4 Aug 2022 15:22:33 +0300 Subject: [PATCH 35/65] fixed test_generate script and schema crate name issue --- .github/scripts/test_generate.sh | 2 +- cw20/base/examples/schema.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/scripts/test_generate.sh b/.github/scripts/test_generate.sh index d02ec07..80a8798 100755 --- a/.github/scripts/test_generate.sh +++ b/.github/scripts/test_generate.sh @@ -10,7 +10,7 @@ cd "$TMP_DIR" function test-template() { TEMPLATE="${1}" - PROJECT_NAME="${TEMPLATE//\//-}" + PROJECT_NAME="${TEMPLATE//\//-//$RANDOM}" echo "#######################################" echo "# Testing template $TEMPLATE" echo "#######################################" diff --git a/cw20/base/examples/schema.rs b/cw20/base/examples/schema.rs index 92e9d8e..af0a927 100644 --- a/cw20/base/examples/schema.rs +++ b/cw20/base/examples/schema.rs @@ -3,7 +3,7 @@ use std::fs::create_dir_all; use cosmwasm_schema::{export_schema, remove_schemas, schema_for}; -use cw20_base::msg::{ExecuteMsg, InstantiateMsg, QueryMsg}; +use {{crate_name}}::{ExecuteMsg, InstantiateMsg, QueryMsg}; fn main() { let mut out_dir = current_dir().unwrap(); From d8cd4e0c8accc454c0e6a69474d90058eff7e323 Mon Sep 17 00:00:00 2001 From: Georges Chouchani Date: Thu, 4 Aug 2022 15:30:52 +0300 Subject: [PATCH 36/65] fixed test generate --- .github/scripts/test_generate.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/scripts/test_generate.sh b/.github/scripts/test_generate.sh index 80a8798..d02ec07 100755 --- a/.github/scripts/test_generate.sh +++ b/.github/scripts/test_generate.sh @@ -10,7 +10,7 @@ cd "$TMP_DIR" function test-template() { TEMPLATE="${1}" - PROJECT_NAME="${TEMPLATE//\//-//$RANDOM}" + PROJECT_NAME="${TEMPLATE//\//-}" echo "#######################################" echo "# Testing template $TEMPLATE" echo "#######################################" From badb95af4278b1361f0e140d8829525ded203a3c Mon Sep 17 00:00:00 2001 From: Georges Chouchani Date: Mon, 8 Aug 2022 13:38:42 +0300 Subject: [PATCH 37/65] fix PR issues --- cw20/base/.github/workflows/Basic.yml | 12 ++++++++++++ cw20/base/.gitignore | 2 +- cw20/base/Cargo.toml | 9 +++++---- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/cw20/base/.github/workflows/Basic.yml b/cw20/base/.github/workflows/Basic.yml index 0aa4193..240ddd8 100644 --- a/cw20/base/.github/workflows/Basic.yml +++ b/cw20/base/.github/workflows/Basic.yml @@ -37,6 +37,18 @@ jobs: env: RUSTFLAGS: "-C link-arg=-s" + - name: Verify schema + uses: tj-actions/verify-changed-files@v8 + id: verify-schema + with: + files: schema/.*\.json + + - name: Display changed schemas + if: steps.verify-schema.outputs.files_changed == 'true' + run: | + echo "The schema files are not in sync with the repository. Please, run 'cargo schema' to generate them again and commit the changes." + exit 1 + lints: name: Lints runs-on: ubuntu-latest diff --git a/cw20/base/.gitignore b/cw20/base/.gitignore index 6a0375b..4f19b76 100644 --- a/cw20/base/.gitignore +++ b/cw20/base/.gitignore @@ -1,7 +1,7 @@ # Generated by Cargo # will have compiled files and executables /target/ - +/artifacts # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html Cargo.lock diff --git a/cw20/base/Cargo.toml b/cw20/base/Cargo.toml index 2452550..f3488bf 100644 --- a/cw20/base/Cargo.toml +++ b/cw20/base/Cargo.toml @@ -8,6 +8,7 @@ exclude = [ # Those files are rust-optimizer artifacts. You might want to commit them for convenience but they should not be part of the source code publication. "contract.wasm", "hash.txt", + "artifacts/*" ] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -42,10 +43,10 @@ optimize = """docker run --rm -v "$(pwd)":/code \ [dependencies] cosmwasm-std = "1.0.0" cosmwasm-storage = "1.0.0" -cw-storage-plus = "0.13.4" -cw2 = "0.13.4" -cw20 = "0.13.4" -cw20-base = { version = "0.13.4", features = ["library"] } +cw-storage-plus = "^0.13.0" +cw2 = "^0.13.0" +cw20 = "^0.13.0" +cw20-base = { version = "^0.13.0", features = ["library"] } schemars = "0.8.8" serde = { version = "1.0.137", default-features = false, features = ["derive"] } thiserror = { version = "1.0.31" } From 32a977dd08ae52609dca03476dc21d07bf6ae444 Mon Sep 17 00:00:00 2001 From: Georges Chouchani Date: Mon, 8 Aug 2022 13:59:07 +0300 Subject: [PATCH 38/65] changed template name in workflow --- .github/scripts/test_generate.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/scripts/test_generate.sh b/.github/scripts/test_generate.sh index d02ec07..96235cc 100755 --- a/.github/scripts/test_generate.sh +++ b/.github/scripts/test_generate.sh @@ -10,7 +10,7 @@ cd "$TMP_DIR" function test-template() { TEMPLATE="${1}" - PROJECT_NAME="${TEMPLATE//\//-}" + PROJECT_NAME="cw-test" echo "#######################################" echo "# Testing template $TEMPLATE" echo "#######################################" From 4c9c2c2ac2bb253de54be8eb1ed554ca93e2bb0a Mon Sep 17 00:00:00 2001 From: Georges Chouchani Date: Mon, 8 Aug 2022 14:45:35 +0300 Subject: [PATCH 39/65] added Random generator for project_name --- .github/scripts/test_generate.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/scripts/test_generate.sh b/.github/scripts/test_generate.sh index 96235cc..12171b2 100755 --- a/.github/scripts/test_generate.sh +++ b/.github/scripts/test_generate.sh @@ -10,7 +10,7 @@ cd "$TMP_DIR" function test-template() { TEMPLATE="${1}" - PROJECT_NAME="cw-test" + PROJECT_NAME="$RANDOM" echo "#######################################" echo "# Testing template $TEMPLATE" echo "#######################################" From 2b2e5ad804a7785ca1d93589381b57e376dec9ad Mon Sep 17 00:00:00 2001 From: Georges Chouchani Date: Mon, 8 Aug 2022 14:57:42 +0300 Subject: [PATCH 40/65] changed name to not start with digit --- .github/scripts/test_generate.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/scripts/test_generate.sh b/.github/scripts/test_generate.sh index 12171b2..ae1865b 100755 --- a/.github/scripts/test_generate.sh +++ b/.github/scripts/test_generate.sh @@ -10,7 +10,7 @@ cd "$TMP_DIR" function test-template() { TEMPLATE="${1}" - PROJECT_NAME="$RANDOM" + PROJECT_NAME="$TEMPLATE/$RANDOM" echo "#######################################" echo "# Testing template $TEMPLATE" echo "#######################################" From b92a7c803bcd0977870332827af24369557afd41 Mon Sep 17 00:00:00 2001 From: Georges Chouchani Date: Mon, 8 Aug 2022 15:15:05 +0300 Subject: [PATCH 41/65] replaced slash with dash to fit name --- .github/scripts/test_generate.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/scripts/test_generate.sh b/.github/scripts/test_generate.sh index ae1865b..1105715 100755 --- a/.github/scripts/test_generate.sh +++ b/.github/scripts/test_generate.sh @@ -10,7 +10,7 @@ cd "$TMP_DIR" function test-template() { TEMPLATE="${1}" - PROJECT_NAME="$TEMPLATE/$RANDOM" + PROJECT_NAME="$TEMPLATE-$RANDOM" echo "#######################################" echo "# Testing template $TEMPLATE" echo "#######################################" From ca871d3744b48e376ae889abdc05eec6e0668572 Mon Sep 17 00:00:00 2001 From: Georges Chouchani Date: Mon, 8 Aug 2022 15:23:06 +0300 Subject: [PATCH 42/65] final changes: --- .github/scripts/test_generate.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/scripts/test_generate.sh b/.github/scripts/test_generate.sh index 1105715..c3c58bc 100755 --- a/.github/scripts/test_generate.sh +++ b/.github/scripts/test_generate.sh @@ -10,7 +10,7 @@ cd "$TMP_DIR" function test-template() { TEMPLATE="${1}" - PROJECT_NAME="$TEMPLATE-$RANDOM" + PROJECT_NAME="test-$RANDOM" echo "#######################################" echo "# Testing template $TEMPLATE" echo "#######################################" From 0b47285cbdbc74423aa0897ddf259d1106f4fe74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Augusto=20Elesb=C3=A3o?= Date: Mon, 8 Aug 2022 15:05:25 +0200 Subject: [PATCH 43/65] Add pull_request checks back again --- .github/workflows/check.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index aa1338b..3918dc9 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -1,4 +1,4 @@ -on: [push] +on: [push, pull_request] name: Check Templates @@ -24,4 +24,4 @@ jobs: args: cargo-generate --features vendored-openssl - name: Test all templates - run: ${{ github.workspace }}/.github/scripts/test_generate.sh \ No newline at end of file + run: ${{ github.workspace }}/.github/scripts/test_generate.sh From 692b542be4fdc5dc5f992be4e716aaed30bd4eb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Augusto=20Elesb=C3=A3o?= Date: Mon, 8 Aug 2022 15:10:54 +0200 Subject: [PATCH 44/65] Use template path as project name for debugging --- .github/scripts/test_generate.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/scripts/test_generate.sh b/.github/scripts/test_generate.sh index c3c58bc..8b69ef4 100755 --- a/.github/scripts/test_generate.sh +++ b/.github/scripts/test_generate.sh @@ -10,10 +10,12 @@ cd "$TMP_DIR" function test-template() { TEMPLATE="${1}" - PROJECT_NAME="test-$RANDOM" + PROJECT_NAME="${TEMPLATE//\//-}-$RANDOM" + echo "#######################################" echo "# Testing template $TEMPLATE" echo "#######################################" + ( GIT_BRANCH=$(git -C "$REPO_ROOT" branch --show-current) @@ -46,4 +48,4 @@ function test-template() { find "$REPO_ROOT" -name Cargo.toml -exec dirname {} \; | while read -r TEMPLATE; do test-template "${TEMPLATE//$REPO_ROOT\//}" echo -done \ No newline at end of file +done From f0681b261b1213460c4b5fdcfbfd709932a32891 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Augusto=20Elesb=C3=A3o?= Date: Mon, 8 Aug 2022 15:25:36 +0200 Subject: [PATCH 45/65] Fix builds triggered by the pull_request event --- .github/scripts/test_generate.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/scripts/test_generate.sh b/.github/scripts/test_generate.sh index 8b69ef4..934a733 100755 --- a/.github/scripts/test_generate.sh +++ b/.github/scripts/test_generate.sh @@ -17,7 +17,7 @@ function test-template() { echo "#######################################" ( - GIT_BRANCH=$(git -C "$REPO_ROOT" branch --show-current) + GIT_BRANCH="${GITHUB_REF:-$(git -C "$REPO_ROOT" branch --show-current)}" echo "Generating project from local repository (branch $GIT_BRANCH) ..." cargo generate --git "$REPO_ROOT" --name "$PROJECT_NAME" --branch "$GIT_BRANCH" "$TEMPLATE" From b614ea801037973151b09f768710d3be29cd5734 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Augusto=20Elesb=C3=A3o?= Date: Mon, 8 Aug 2022 15:33:26 +0200 Subject: [PATCH 46/65] Try using GITHUB_REF_NAME for build --- .github/scripts/test_generate.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/scripts/test_generate.sh b/.github/scripts/test_generate.sh index 934a733..68be6ff 100755 --- a/.github/scripts/test_generate.sh +++ b/.github/scripts/test_generate.sh @@ -17,7 +17,7 @@ function test-template() { echo "#######################################" ( - GIT_BRANCH="${GITHUB_REF:-$(git -C "$REPO_ROOT" branch --show-current)}" + GIT_BRANCH="${GITHUB_REF_NAME:-$(git -C "$REPO_ROOT" branch --show-current)}" echo "Generating project from local repository (branch $GIT_BRANCH) ..." cargo generate --git "$REPO_ROOT" --name "$PROJECT_NAME" --branch "$GIT_BRANCH" "$TEMPLATE" From f26e98f5053d17c12e68ec0661d516670b6cb2d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Augusto=20Elesb=C3=A3o?= Date: Mon, 8 Aug 2022 15:46:32 +0200 Subject: [PATCH 47/65] Specifying a branch name is unnecessary for CI --- .github/scripts/test_generate.sh | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/scripts/test_generate.sh b/.github/scripts/test_generate.sh index 68be6ff..bf94881 100755 --- a/.github/scripts/test_generate.sh +++ b/.github/scripts/test_generate.sh @@ -17,10 +17,8 @@ function test-template() { echo "#######################################" ( - GIT_BRANCH="${GITHUB_REF_NAME:-$(git -C "$REPO_ROOT" branch --show-current)}" - - echo "Generating project from local repository (branch $GIT_BRANCH) ..." - cargo generate --git "$REPO_ROOT" --name "$PROJECT_NAME" --branch "$GIT_BRANCH" "$TEMPLATE" + echo "Generating project from local repository..." + cargo generate --git "$REPO_ROOT" --name "$PROJECT_NAME" "$TEMPLATE" ( cd "$PROJECT_NAME" From bd268ed797e838cbbc29d7a2477ec22ee18180d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Augusto=20Elesb=C3=A3o?= Date: Mon, 8 Aug 2022 17:07:14 +0200 Subject: [PATCH 48/65] Use `--path` for `cargo generate` tests --- .github/scripts/test_generate.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/scripts/test_generate.sh b/.github/scripts/test_generate.sh index bf94881..7c62494 100755 --- a/.github/scripts/test_generate.sh +++ b/.github/scripts/test_generate.sh @@ -18,7 +18,7 @@ function test-template() { ( echo "Generating project from local repository..." - cargo generate --git "$REPO_ROOT" --name "$PROJECT_NAME" "$TEMPLATE" + cargo generate --path "$REPO_ROOT" --name "$PROJECT_NAME" "$TEMPLATE" ( cd "$PROJECT_NAME" From d5ff3f6daa6a0b8cf9f616adba4213ecb7f42451 Mon Sep 17 00:00:00 2001 From: Georges Chouchani Date: Tue, 9 Aug 2022 15:06:47 +0300 Subject: [PATCH 49/65] fixed git diff issue in github workflow --- cw20/base/.github/workflows/Basic.yml | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/cw20/base/.github/workflows/Basic.yml b/cw20/base/.github/workflows/Basic.yml index 240ddd8..879341a 100644 --- a/cw20/base/.github/workflows/Basic.yml +++ b/cw20/base/.github/workflows/Basic.yml @@ -29,15 +29,7 @@ jobs: env: RUST_BACKTRACE: 1 - - name: Compile WASM contract - uses: actions-rs/cargo@v1 - with: - command: wasm - args: --locked - env: - RUSTFLAGS: "-C link-arg=-s" - - - name: Verify schema + - name: Verify Schema uses: tj-actions/verify-changed-files@v8 id: verify-schema with: @@ -49,6 +41,16 @@ jobs: echo "The schema files are not in sync with the repository. Please, run 'cargo schema' to generate them again and commit the changes." exit 1 + - name: Compile WASM contract + uses: actions-rs/cargo@v1 + with: + command: wasm + args: --locked + env: + RUSTFLAGS: "-C link-arg=-s" + + + lints: name: Lints runs-on: ubuntu-latest From 158ca44e79a8b4c835f025f24eb9eee28092c8fd Mon Sep 17 00:00:00 2001 From: Georges Chouchani Date: Tue, 9 Aug 2022 15:40:25 +0300 Subject: [PATCH 50/65] fixed linter error in workflow --- cw721/on-chain-metadata/Cargo.toml | 8 ++++---- cw721/on-chain-metadata/examples/schema.rs | 4 +++- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/cw721/on-chain-metadata/Cargo.toml b/cw721/on-chain-metadata/Cargo.toml index 3761030..cdcbaa7 100644 --- a/cw721/on-chain-metadata/Cargo.toml +++ b/cw721/on-chain-metadata/Cargo.toml @@ -41,10 +41,10 @@ optimize = """docker run --rm -v "$(pwd)":/code \ [dependencies] cosmwasm-std = "1.0.0-beta" -cw2 = "0.13.4" -cw721 = "0.13.2" -cw721-base = { version = "0.13.2", features = ["library"] } -schemars = "0.8.10" +cw2 = "^0.13.0" +cw721 = "^0.13.0" +cw721-base = { version = "^0.13.0", features = ["library"] } +schemars = "^0.8.0" serde = { version = "1.0", default-features = false, features = ["derive"] } thiserror = "1.0" diff --git a/cw721/on-chain-metadata/examples/schema.rs b/cw721/on-chain-metadata/examples/schema.rs index 0516b42..043b355 100644 --- a/cw721/on-chain-metadata/examples/schema.rs +++ b/cw721/on-chain-metadata/examples/schema.rs @@ -7,7 +7,9 @@ use cw721::{ AllNftInfoResponse, ApprovalResponse, ApprovalsResponse, ContractInfoResponse, NftInfoResponse, NumTokensResponse, OperatorsResponse, OwnerOfResponse, TokensResponse, }; -use {{crate_name}}::{ExecuteMsg, Extension, InstantiateMsg, MinterResponse, QueryMsg}; +use {{crate_name}}::{ + ExecuteMsg, Extension, InstantiateMsg, MinterResponse, QueryMsg +}; fn main() { let mut out_dir = current_dir().unwrap(); From fbe34c8f60d75b2e7216f36b7783ea2133e1c47d Mon Sep 17 00:00:00 2001 From: Georges Chouchani Date: Tue, 9 Aug 2022 15:49:29 +0300 Subject: [PATCH 51/65] fixed comma linter issue --- cw721/on-chain-metadata/examples/schema.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cw721/on-chain-metadata/examples/schema.rs b/cw721/on-chain-metadata/examples/schema.rs index 043b355..13f5b62 100644 --- a/cw721/on-chain-metadata/examples/schema.rs +++ b/cw721/on-chain-metadata/examples/schema.rs @@ -8,7 +8,7 @@ use cw721::{ NumTokensResponse, OperatorsResponse, OwnerOfResponse, TokensResponse, }; use {{crate_name}}::{ - ExecuteMsg, Extension, InstantiateMsg, MinterResponse, QueryMsg + ExecuteMsg, Extension, InstantiateMsg, MinterResponse, QueryMsg, }; fn main() { From 7546b5b0a9e6b79808f5b85afbbd2728af01b08c Mon Sep 17 00:00:00 2001 From: Georges Chouchani Date: Tue, 9 Aug 2022 16:02:22 +0300 Subject: [PATCH 52/65] fixed crate name issue in escrow --- cw20/escrow/Cargo.toml | 18 +++++++++--------- cw20/escrow/examples/schema.rs | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/cw20/escrow/Cargo.toml b/cw20/escrow/Cargo.toml index 64823f5..8117fd8 100644 --- a/cw20/escrow/Cargo.toml +++ b/cw20/escrow/Cargo.toml @@ -18,16 +18,16 @@ backtraces = ["cosmwasm-std/backtraces"] library = [] [dependencies] -cw-utils = "0.13.2" -cw2 = "0.13.2" -cw20 = "0.13.2" +cw-utils = "^0.13.0" +cw2 = "^0.13.0" +cw20 = "^0.13.0" cosmwasm-std = "1.0.0-beta8" -cw-storage-plus = "0.13.2" -schemars = "0.8.8" -serde = { version = "1.0.137", default-features = false, features = ["derive"] } -thiserror = "1.0.31" +cw-storage-plus = "^0.13.0" +schemars = "^0.8.0" +serde = { version = "^1.0.0", default-features = false, features = ["derive"] } +thiserror = "^1.0.0" [dev-dependencies] cosmwasm-schema = "1.0.0-beta8" -cw-multi-test = "0.13.2" -cw20-base = { version = "0.13.2", features = ["library"] } +cw-multi-test = "^0.13.0" +cw20-base = { version = "^0.13.0", features = ["library"] } diff --git a/cw20/escrow/examples/schema.rs b/cw20/escrow/examples/schema.rs index e290178..aa320cd 100644 --- a/cw20/escrow/examples/schema.rs +++ b/cw20/escrow/examples/schema.rs @@ -3,7 +3,7 @@ use std::fs::create_dir_all; use cosmwasm_schema::{export_schema, remove_schemas, schema_for}; -use cw20_escrow::msg::{ +use {{crate_name}}::{ DetailsResponse, ExecuteMsg, InstantiateMsg, ListResponse, QueryMsg, ReceiveMsg, }; From a5226ae335fa13bf9a0826fd58a9c9ce7c822fd2 Mon Sep 17 00:00:00 2001 From: Georges Chouchani Date: Tue, 9 Aug 2022 16:14:45 +0300 Subject: [PATCH 53/65] change import of msgs for escrow --- cw20/escrow/examples/schema.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cw20/escrow/examples/schema.rs b/cw20/escrow/examples/schema.rs index aa320cd..4911e0f 100644 --- a/cw20/escrow/examples/schema.rs +++ b/cw20/escrow/examples/schema.rs @@ -3,7 +3,7 @@ use std::fs::create_dir_all; use cosmwasm_schema::{export_schema, remove_schemas, schema_for}; -use {{crate_name}}::{ +use {{crate_name}}::msg::{ DetailsResponse, ExecuteMsg, InstantiateMsg, ListResponse, QueryMsg, ReceiveMsg, }; From 2813ac952ca39e517b78f62b27d399ce2973ffdf Mon Sep 17 00:00:00 2001 From: Georges Chouchani Date: Thu, 11 Aug 2022 18:03:08 +0300 Subject: [PATCH 54/65] fixed workflow diff issue --- cw20/base/.github/workflows/Basic.yml | 24 ++++++++++++------------ cw20/base/rustfmt.toml | 1 - 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/cw20/base/.github/workflows/Basic.yml b/cw20/base/.github/workflows/Basic.yml index 879341a..1e99a2a 100644 --- a/cw20/base/.github/workflows/Basic.yml +++ b/cw20/base/.github/workflows/Basic.yml @@ -29,18 +29,6 @@ jobs: env: RUST_BACKTRACE: 1 - - name: Verify Schema - uses: tj-actions/verify-changed-files@v8 - id: verify-schema - with: - files: schema/.*\.json - - - name: Display changed schemas - if: steps.verify-schema.outputs.files_changed == 'true' - run: | - echo "The schema files are not in sync with the repository. Please, run 'cargo schema' to generate them again and commit the changes." - exit 1 - - name: Compile WASM contract uses: actions-rs/cargo@v1 with: @@ -84,6 +72,18 @@ jobs: command: schema args: --locked + - name: Verify Schema + uses: tj-actions/verify-changed-files@v8 + id: verify-schema + with: + files: schema/.*\.json + + - name: Display changed schemas + if: steps.verify-schema.outputs.files_changed == 'true' + run: | + echo "The schema files are not in sync with the repository. Please, run 'cargo schema' to generate them again and commit the changes." + exit 1 + - name: Schema Changes # fails if any changes not committed run: git diff --exit-code schema diff --git a/cw20/base/rustfmt.toml b/cw20/base/rustfmt.toml index 11a85e6..6918e22 100644 --- a/cw20/base/rustfmt.toml +++ b/cw20/base/rustfmt.toml @@ -12,4 +12,3 @@ tab_spaces = 4 #struct_field_align_threshold = 20 #struct_lit_single_line = true #report_todo = "Always" - From e9d529492468f6d7faf8496d62947fa57efe533b Mon Sep 17 00:00:00 2001 From: Georges Chouchani Date: Thu, 11 Aug 2022 18:25:54 +0300 Subject: [PATCH 55/65] deriving as well: --- cw721/on-chain-metadata/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cw721/on-chain-metadata/src/lib.rs b/cw721/on-chain-metadata/src/lib.rs index 40e2440..25eea22 100644 --- a/cw721/on-chain-metadata/src/lib.rs +++ b/cw721/on-chain-metadata/src/lib.rs @@ -6,7 +6,7 @@ use cw2::set_contract_version; use cw721::ContractInfoResponse; pub use cw721_base::{ContractError, InstantiateMsg, MintMsg, MinterResponse, QueryMsg}; -#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug, Default)] +#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, JsonSchema, Debug, Default)] pub struct Trait { pub display_type: Option, pub trait_type: String, From 0dba2ecea9464614c60a4cdd4bc0de53db59b575 Mon Sep 17 00:00:00 2001 From: Georges Chouchani Date: Thu, 11 Aug 2022 18:27:43 +0300 Subject: [PATCH 56/65] deriving as well: --- cw721/on-chain-metadata/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cw721/on-chain-metadata/src/lib.rs b/cw721/on-chain-metadata/src/lib.rs index 25eea22..be478c1 100644 --- a/cw721/on-chain-metadata/src/lib.rs +++ b/cw721/on-chain-metadata/src/lib.rs @@ -14,7 +14,7 @@ pub struct Trait { } // see: https://docs.opensea.io/docs/metadata-standards -#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug, Default)] +#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, JsonSchema, Debug, Default)] pub struct Metadata { pub image: Option, pub image_data: Option, From 839a04d77678491bbf64320c4603b5e4fb7abffe Mon Sep 17 00:00:00 2001 From: Georges Chouchani Date: Mon, 15 Aug 2022 14:49:24 +0300 Subject: [PATCH 57/65] added Eq next to partialEq --- cw20/escrow/src/msg.rs | 12 ++++++------ default/src/msg.rs | 8 ++++---- increment/src/msg.rs | 8 ++++---- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/cw20/escrow/src/msg.rs b/cw20/escrow/src/msg.rs index 6c328fc..1d4cd98 100644 --- a/cw20/escrow/src/msg.rs +++ b/cw20/escrow/src/msg.rs @@ -5,10 +5,10 @@ use cosmwasm_std::{Addr, Api, Coin, StdResult}; use cw20::{Cw20Coin, Cw20ReceiveMsg}; -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] pub struct InstantiateMsg {} -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] #[serde(rename_all = "snake_case")] pub enum ExecuteMsg { Create(CreateMsg), @@ -37,7 +37,7 @@ pub enum ExecuteMsg { Receive(Cw20ReceiveMsg), } -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] #[serde(rename_all = "snake_case")] pub enum ReceiveMsg { Create(CreateMsg), @@ -47,7 +47,7 @@ pub enum ReceiveMsg { }, } -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] pub struct CreateMsg { /// id is a human-readable name for the escrow to use later /// 3-20 bytes of utf-8 text @@ -100,13 +100,13 @@ pub enum QueryMsg { Details { id: String }, } -#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] +#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, JsonSchema, Debug)] pub struct ListResponse { /// list all registered ids pub escrows: Vec, } -#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] +#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, JsonSchema, Debug)] pub struct DetailsResponse { /// id of this escrow pub id: String, diff --git a/default/src/msg.rs b/default/src/msg.rs index 6e4dd2e..1012a29 100644 --- a/default/src/msg.rs +++ b/default/src/msg.rs @@ -1,23 +1,23 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] pub struct InstantiateMsg {} -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] #[serde(rename_all = "snake_case")] pub enum ExecuteMsg { Dummy {}, } -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] #[serde(rename_all = "snake_case")] pub enum QueryMsg { Hello {}, } // We define a custom struct for each query response -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] pub struct HelloResponse { pub msg: String, } diff --git a/increment/src/msg.rs b/increment/src/msg.rs index 4cec36d..0ca3ed4 100644 --- a/increment/src/msg.rs +++ b/increment/src/msg.rs @@ -1,19 +1,19 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] pub struct InstantiateMsg { pub count: i32, } -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] #[serde(rename_all = "snake_case")] pub enum ExecuteMsg { Increment {}, Reset { count: i32 }, } -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] #[serde(rename_all = "snake_case")] pub enum QueryMsg { // GetCount returns the current count as a json-encoded number @@ -21,7 +21,7 @@ pub enum QueryMsg { } // We define a custom struct for each query response -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] pub struct CountResponse { pub count: i32, } From ee80f5e658a8317791b00c0d61272a2e24cc8024 Mon Sep 17 00:00:00 2001 From: Georges Chouchani Date: Mon, 15 Aug 2022 15:00:59 +0300 Subject: [PATCH 58/65] added Eq in state --- default/src/state.rs | 2 +- increment/src/state.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/default/src/state.rs b/default/src/state.rs index bc116fa..48cf02f 100644 --- a/default/src/state.rs +++ b/default/src/state.rs @@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize}; use cosmwasm_std::Addr; use cw_storage_plus::Item; -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] pub struct State { pub owner: Addr, } diff --git a/increment/src/state.rs b/increment/src/state.rs index 1b426f9..bad9202 100644 --- a/increment/src/state.rs +++ b/increment/src/state.rs @@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize}; use cosmwasm_std::Addr; use cw_storage_plus::Item; -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] pub struct State { pub count: i32, pub owner: Addr, From 37826f3dc608f876e7766a667b18d1f31c0a459f Mon Sep 17 00:00:00 2001 From: Georges Chouchani Date: Mon, 15 Aug 2022 15:14:14 +0300 Subject: [PATCH 59/65] removed Eq from escrow --- cw20/escrow/src/msg.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/cw20/escrow/src/msg.rs b/cw20/escrow/src/msg.rs index 1d4cd98..6c328fc 100644 --- a/cw20/escrow/src/msg.rs +++ b/cw20/escrow/src/msg.rs @@ -5,10 +5,10 @@ use cosmwasm_std::{Addr, Api, Coin, StdResult}; use cw20::{Cw20Coin, Cw20ReceiveMsg}; -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] pub struct InstantiateMsg {} -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] #[serde(rename_all = "snake_case")] pub enum ExecuteMsg { Create(CreateMsg), @@ -37,7 +37,7 @@ pub enum ExecuteMsg { Receive(Cw20ReceiveMsg), } -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] #[serde(rename_all = "snake_case")] pub enum ReceiveMsg { Create(CreateMsg), @@ -47,7 +47,7 @@ pub enum ReceiveMsg { }, } -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] pub struct CreateMsg { /// id is a human-readable name for the escrow to use later /// 3-20 bytes of utf-8 text @@ -100,13 +100,13 @@ pub enum QueryMsg { Details { id: String }, } -#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, JsonSchema, Debug)] +#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] pub struct ListResponse { /// list all registered ids pub escrows: Vec, } -#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, JsonSchema, Debug)] +#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] pub struct DetailsResponse { /// id of this escrow pub id: String, From 43acf428b10b997536ad1ded115131b6cfa3628f Mon Sep 17 00:00:00 2001 From: Georges Chouchani Date: Mon, 15 Aug 2022 16:49:33 +0300 Subject: [PATCH 60/65] added clippy configs --- clippy.toml | 1 + 1 file changed, 1 insertion(+) create mode 100644 clippy.toml diff --git a/clippy.toml b/clippy.toml new file mode 100644 index 0000000..d4b2a55 --- /dev/null +++ b/clippy.toml @@ -0,0 +1 @@ +derive_partial_eq_without_eq = true \ No newline at end of file From 61e2dd3ecd9e6889638d3a7e8867ab713c9f7801 Mon Sep 17 00:00:00 2001 From: Georges Chouchani Date: Wed, 17 Aug 2022 16:10:56 +0300 Subject: [PATCH 61/65] added clippy to each template seperately --- clippy.toml => cw20/base/clippy.toml | 0 cw20/escrow/clippy.toml | 1 + cw721/on-chain-metadata/clippy.toml | 1 + default/clippy.toml | 1 + increment/clippy.toml | 1 + 5 files changed, 4 insertions(+) rename clippy.toml => cw20/base/clippy.toml (100%) create mode 100644 cw20/escrow/clippy.toml create mode 100644 cw721/on-chain-metadata/clippy.toml create mode 100644 default/clippy.toml create mode 100644 increment/clippy.toml diff --git a/clippy.toml b/cw20/base/clippy.toml similarity index 100% rename from clippy.toml rename to cw20/base/clippy.toml diff --git a/cw20/escrow/clippy.toml b/cw20/escrow/clippy.toml new file mode 100644 index 0000000..d4b2a55 --- /dev/null +++ b/cw20/escrow/clippy.toml @@ -0,0 +1 @@ +derive_partial_eq_without_eq = true \ No newline at end of file diff --git a/cw721/on-chain-metadata/clippy.toml b/cw721/on-chain-metadata/clippy.toml new file mode 100644 index 0000000..d4b2a55 --- /dev/null +++ b/cw721/on-chain-metadata/clippy.toml @@ -0,0 +1 @@ +derive_partial_eq_without_eq = true \ No newline at end of file diff --git a/default/clippy.toml b/default/clippy.toml new file mode 100644 index 0000000..d4b2a55 --- /dev/null +++ b/default/clippy.toml @@ -0,0 +1 @@ +derive_partial_eq_without_eq = true \ No newline at end of file diff --git a/increment/clippy.toml b/increment/clippy.toml new file mode 100644 index 0000000..d4b2a55 --- /dev/null +++ b/increment/clippy.toml @@ -0,0 +1 @@ +derive_partial_eq_without_eq = true \ No newline at end of file From a415331537fa94b5495091cc15c2698cba1e7dd4 Mon Sep 17 00:00:00 2001 From: Georges Chouchani Date: Thu, 18 Aug 2022 13:10:58 +0300 Subject: [PATCH 62/65] added clippy as component in stable toolchain --- .github/workflows/check.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 3918dc9..71df1f4 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -16,6 +16,8 @@ jobs: target: wasm32-unknown-unknown override: true profile: minimal + components: clippy + - name: Install cargo-generate uses: actions-rs/cargo@v1 From d93e2667c8e1ada5a4ab291d75bd9c0690c41f78 Mon Sep 17 00:00:00 2001 From: Georges Chouchani Date: Thu, 18 Aug 2022 13:34:53 +0300 Subject: [PATCH 63/65] remove clippy files --- cw20/base/clippy.toml | 1 - cw20/escrow/clippy.toml | 1 - cw721/on-chain-metadata/clippy.toml | 1 - default/clippy.toml | 1 - increment/clippy.toml | 1 - 5 files changed, 5 deletions(-) delete mode 100644 cw20/base/clippy.toml delete mode 100644 cw20/escrow/clippy.toml delete mode 100644 cw721/on-chain-metadata/clippy.toml delete mode 100644 default/clippy.toml delete mode 100644 increment/clippy.toml diff --git a/cw20/base/clippy.toml b/cw20/base/clippy.toml deleted file mode 100644 index d4b2a55..0000000 --- a/cw20/base/clippy.toml +++ /dev/null @@ -1 +0,0 @@ -derive_partial_eq_without_eq = true \ No newline at end of file diff --git a/cw20/escrow/clippy.toml b/cw20/escrow/clippy.toml deleted file mode 100644 index d4b2a55..0000000 --- a/cw20/escrow/clippy.toml +++ /dev/null @@ -1 +0,0 @@ -derive_partial_eq_without_eq = true \ No newline at end of file diff --git a/cw721/on-chain-metadata/clippy.toml b/cw721/on-chain-metadata/clippy.toml deleted file mode 100644 index d4b2a55..0000000 --- a/cw721/on-chain-metadata/clippy.toml +++ /dev/null @@ -1 +0,0 @@ -derive_partial_eq_without_eq = true \ No newline at end of file diff --git a/default/clippy.toml b/default/clippy.toml deleted file mode 100644 index d4b2a55..0000000 --- a/default/clippy.toml +++ /dev/null @@ -1 +0,0 @@ -derive_partial_eq_without_eq = true \ No newline at end of file diff --git a/increment/clippy.toml b/increment/clippy.toml deleted file mode 100644 index d4b2a55..0000000 --- a/increment/clippy.toml +++ /dev/null @@ -1 +0,0 @@ -derive_partial_eq_without_eq = true \ No newline at end of file From 66d6dee32613241caa0108db494a25cfd8d1ca1c Mon Sep 17 00:00:00 2001 From: Georges Chouchani Date: Thu, 18 Aug 2022 13:56:18 +0300 Subject: [PATCH 64/65] added clippy to escrow only --- cw20/escrow/clippy.toml | 1 + 1 file changed, 1 insertion(+) create mode 100644 cw20/escrow/clippy.toml diff --git a/cw20/escrow/clippy.toml b/cw20/escrow/clippy.toml new file mode 100644 index 0000000..397d43d --- /dev/null +++ b/cw20/escrow/clippy.toml @@ -0,0 +1 @@ +derive-partial-eq-without-eq = true \ No newline at end of file From 412182271aa5a407da4b942a11e59bf1ee22144e Mon Sep 17 00:00:00 2001 From: Georges Chouchani Date: Thu, 18 Aug 2022 14:10:18 +0300 Subject: [PATCH 65/65] added eq only for escrow --- cw20/escrow/clippy.toml | 1 - cw20/escrow/src/msg.rs | 14 +++++++------- cw20/escrow/src/state.rs | 4 ++-- 3 files changed, 9 insertions(+), 10 deletions(-) delete mode 100644 cw20/escrow/clippy.toml diff --git a/cw20/escrow/clippy.toml b/cw20/escrow/clippy.toml deleted file mode 100644 index 397d43d..0000000 --- a/cw20/escrow/clippy.toml +++ /dev/null @@ -1 +0,0 @@ -derive-partial-eq-without-eq = true \ No newline at end of file diff --git a/cw20/escrow/src/msg.rs b/cw20/escrow/src/msg.rs index 6c328fc..4a66856 100644 --- a/cw20/escrow/src/msg.rs +++ b/cw20/escrow/src/msg.rs @@ -5,10 +5,10 @@ use cosmwasm_std::{Addr, Api, Coin, StdResult}; use cw20::{Cw20Coin, Cw20ReceiveMsg}; -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] pub struct InstantiateMsg {} -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] #[serde(rename_all = "snake_case")] pub enum ExecuteMsg { Create(CreateMsg), @@ -37,7 +37,7 @@ pub enum ExecuteMsg { Receive(Cw20ReceiveMsg), } -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] #[serde(rename_all = "snake_case")] pub enum ReceiveMsg { Create(CreateMsg), @@ -47,7 +47,7 @@ pub enum ReceiveMsg { }, } -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] pub struct CreateMsg { /// id is a human-readable name for the escrow to use later /// 3-20 bytes of utf-8 text @@ -90,7 +90,7 @@ pub fn is_valid_name(name: &str) -> bool { true } -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] #[serde(rename_all = "snake_case")] pub enum QueryMsg { /// Show all open escrows. Return type is ListResponse. @@ -100,13 +100,13 @@ pub enum QueryMsg { Details { id: String }, } -#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] +#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, JsonSchema, Debug)] pub struct ListResponse { /// list all registered ids pub escrows: Vec, } -#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] +#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, JsonSchema, Debug)] pub struct DetailsResponse { /// id of this escrow pub id: String, diff --git a/cw20/escrow/src/state.rs b/cw20/escrow/src/state.rs index 28d56e9..1bcb8b3 100644 --- a/cw20/escrow/src/state.rs +++ b/cw20/escrow/src/state.rs @@ -6,7 +6,7 @@ use cw_storage_plus::Map; use cw20::{Balance, Cw20CoinVerified}; -#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug, Default)] +#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, JsonSchema, Debug, Default)] pub struct GenericBalance { pub native: Vec, pub cw20: Vec, @@ -47,7 +47,7 @@ impl GenericBalance { } } -#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] +#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, JsonSchema, Debug)] pub struct Escrow { /// arbiter can decide to approve or refund the escrow pub arbiter: Addr,