diff --git a/.circleci/config.yml b/.circleci/config.yml index 13506eb4e..a0520236c 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -16,6 +16,7 @@ workflows: - contract_cw20_ics20 - contract_cw20_staking - contract_cw721_base + - contract_cw1155_base - package_controllers - package_cw0 - package_cw1 @@ -24,6 +25,7 @@ workflows: - package_cw4 - package_cw20 - package_cw721 + - package_cw1155 - package_multi_test - package_storage_plus - lint @@ -509,6 +511,42 @@ jobs: - target key: cargocache-cw721-base-rust:1.51.0-{{ checksum "~/project/Cargo.lock" }} + contract_cw1155_base: + docker: + - image: rust:1.51.0 + working_directory: ~/project/contracts/cw1155-base + steps: + - checkout: + path: ~/project + - run: + name: Version information + command: rustc --version; cargo --version; rustup --version + - restore_cache: + keys: + - cargocache-cw1155-base-rust:1.51.0-{{ checksum "~/project/Cargo.lock" }} + - run: + name: Unit Tests + environment: + RUST_BACKTRACE: 1 + command: cargo unit-test --locked + - run: + name: Build and run schema generator + command: cargo schema --locked + - run: + name: Ensure checked-in schemas are up-to-date + command: | + CHANGES_IN_REPO=$(git status --porcelain) + if [[ -n "$CHANGES_IN_REPO" ]]; then + echo "Repository is dirty. Showing 'git status' and 'git --no-pager diff' for debugging now:" + git status && git --no-pager diff + exit 1 + fi + - save_cache: + paths: + - /usr/local/cargo/registry + - target + key: cargocache-cw1155-base-rust:1.51.0-{{ checksum "~/project/Cargo.lock" }} + package_controllers: docker: - image: rust:1.51.0 @@ -770,6 +808,44 @@ jobs: - target key: cargocache-v2-cw721:1.51.0-{{ checksum "~/project/Cargo.lock" }} + + package_cw1155: + docker: + - image: rust:1.51.0 + working_directory: ~/project/packages/cw1155 + steps: + - checkout: + path: ~/project + - run: + name: Version information + command: rustc --version; cargo --version; rustup --version; rustup target list --installed + - restore_cache: + keys: + - cargocache-v2-cw1155:1.51.0-{{ checksum "~/project/Cargo.lock" }} + - run: + name: Build library for native target + command: cargo build --locked + - run: + name: Run unit tests + command: cargo test --locked + - run: + name: Build and run schema generator + command: cargo schema --locked + - run: + name: Ensure schemas are up-to-date + command: | + CHANGES_IN_REPO=$(git status --porcelain) + if [[ -n "$CHANGES_IN_REPO" ]]; then + echo "Repository is dirty. Showing 'git status' and 'git --no-pager diff' for debugging now:" + git status && git --no-pager diff + exit 1 + fi + - save_cache: + paths: + - /usr/local/cargo/registry + - target + key: cargocache-v2-cw1155:1.51.0-{{ checksum "~/project/Cargo.lock" }} + lint: docker: - image: rust:1.51.0 @@ -833,7 +909,7 @@ jobs: # Uses --debug for compilation speed # FIXME: Change when `check_contract` (part of `cosmwasm-0.14.0`) is published #command: cargo install --debug --features iterator --example check_contract -- cosmwasm-vm - command: cargo install --debug --features iterator --git https://github.com/CosmWasm/cosmwasm --tag=v0.14.0-beta1 --example check_contract -- cosmwasm-vm + command: cargo install --debug --features iterator --git https://github.com/CosmWasm/cosmwasm --tag=v0.14.0-beta2 --example check_contract -- cosmwasm-vm - save_cache: paths: - /usr/local/cargo/registry diff --git a/Cargo.lock b/Cargo.lock index 1ebd139fa..c168dc23b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -87,9 +87,9 @@ checksum = "9f6b64db6932c7e49332728e3a6bd82c6b7e16016607d20923b537c3bc4c0d5f" [[package]] name = "cosmwasm-crypto" -version = "0.14.0-beta1" +version = "0.14.0-beta2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcdb840c68257bc4a44896b4f671f1970f150babd68d9a8ad873a9828c15d09b" +checksum = "3f347f7f854748171728d50d82d8f1ecf90e5567ae7a2679457773f83279a91c" dependencies = [ "digest 0.9.0", "ed25519-zebra", @@ -100,18 +100,18 @@ dependencies = [ [[package]] name = "cosmwasm-derive" -version = "0.14.0-beta1" +version = "0.14.0-beta2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e9c8eb7f9e3295d52d79aadbede09ffe69b9fa6450ff1a89db3b37476e2afe7" +checksum = "26f20e355bc852cd34d4654c7e2e9749708d7666ecb895b09011f3bf0ebf4fac" dependencies = [ "syn", ] [[package]] name = "cosmwasm-schema" -version = "0.14.0-beta1" +version = "0.14.0-beta2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0de1d9d68e85bb6d95bb2a76b0017f700ecb053e4b35b3f644fe3eca41bad98" +checksum = "aba58f05df7c54f6c2c62e7d598de6aa8cd2be51a88f892999033e6302fa7f57" dependencies = [ "schemars", "serde_json", @@ -119,9 +119,9 @@ dependencies = [ [[package]] name = "cosmwasm-std" -version = "0.14.0-beta1" +version = "0.14.0-beta2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f27fdd729c143cb4f973a5bb5cd16f277d72a49c3d72d0266a3da25df76d5466" +checksum = "235b90e9f9185ae479a79c1f54fa793f07ff49bcbeed26636f6dd0e3acb6e20a" dependencies = [ "base64", "cosmwasm-crypto", @@ -408,12 +408,9 @@ version = "0.6.0-alpha3" dependencies = [ "cosmwasm-schema", "cosmwasm-std", - "cw-multi-test", "cw-storage-plus", "cw0", "cw2", - "cw20", - "cw20-base", "cw3", "schemars", "serde", @@ -534,6 +531,12 @@ dependencies = [ "generic-array 0.14.4", ] +[[package]] +name = "dyn-clone" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee2626afccd7561a06cf1367e2950c4718ea04565e20fb5029b6c7d8ad09abcf" + [[package]] name = "ecdsa" version = "0.10.2" @@ -786,10 +789,11 @@ checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" [[package]] name = "schemars" -version = "0.7.6" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be77ed66abed6954aabf6a3e31a84706bedbf93750d267e92ef4a6d90bbd6a61" +checksum = "8a24475737c47c5a97cd0858d09db5b0c01ade85d671ee569cd1a5a2c0c80a44" dependencies = [ + "dyn-clone", "schemars_derive", "serde", "serde_json", @@ -797,9 +801,9 @@ dependencies = [ [[package]] name = "schemars_derive" -version = "0.7.6" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11af7a475c9ee266cfaa9e303a47c830ebe072bf3101ab907a7b7b9d816fa01d" +checksum = "c5f0ccbfe5a97322d90f8b19604fa5b99dd8223540eb6e36c99a9125303e4c00" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 3b0b7747a..7990e6df8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -53,6 +53,10 @@ incremental = false codegen-units = 1 incremental = false +[profile.release.package.cw1155-base] +codegen-units = 1 +incremental = false + [profile.release] rpath = false lto = true diff --git a/contracts/cw1-subkeys/Cargo.toml b/contracts/cw1-subkeys/Cargo.toml index 13eb81e57..1e67b7dc0 100644 --- a/contracts/cw1-subkeys/Cargo.toml +++ b/contracts/cw1-subkeys/Cargo.toml @@ -22,11 +22,11 @@ cw0 = { path = "../../packages/cw0", version = "0.6.0-alpha3" } cw1 = { path = "../../packages/cw1", version = "0.6.0-alpha3" } cw2 = { path = "../../packages/cw2", version = "0.6.0-alpha3" } cw1-whitelist = { path = "../cw1-whitelist", version = "0.6.0-alpha3", features = ["library"] } -cosmwasm-std = { version = "0.14.0-beta1", features = ["iterator", "staking"] } +cosmwasm-std = { version = "0.14.0-beta2", features = ["iterator", "staking"] } cw-storage-plus = { path = "../../packages/storage-plus", version = "0.6.0-alpha3", features = ["iterator"] } -schemars = "0.7" +schemars = "0.8.1" serde = { version = "1.0.103", default-features = false, features = ["derive"] } thiserror = { version = "1.0.20" } [dev-dependencies] -cosmwasm-schema = { version = "0.14.0-beta1" } +cosmwasm-schema = { version = "0.14.0-beta2" } diff --git a/contracts/cw1-subkeys/schema/admin_list_response.json b/contracts/cw1-subkeys/schema/admin_list_response.json index 4173be545..bc20467c3 100644 --- a/contracts/cw1-subkeys/schema/admin_list_response.json +++ b/contracts/cw1-subkeys/schema/admin_list_response.json @@ -10,16 +10,11 @@ "admins": { "type": "array", "items": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } }, "mutable": { "type": "boolean" } - }, - "definitions": { - "HumanAddr": { - "type": "string" - } } } diff --git a/contracts/cw1-subkeys/schema/all_allowances_response.json b/contracts/cw1-subkeys/schema/all_allowances_response.json index 0a2ed7c3e..c859f53b3 100644 --- a/contracts/cw1-subkeys/schema/all_allowances_response.json +++ b/contracts/cw1-subkeys/schema/all_allowances_response.json @@ -29,7 +29,7 @@ "$ref": "#/definitions/Expiration" }, "spender": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } }, @@ -63,7 +63,8 @@ "format": "uint64", "minimum": 0.0 } - } + }, + "additionalProperties": false }, { "description": "AtTime will expire when `env.block.time` >= time", @@ -77,7 +78,8 @@ "format": "uint64", "minimum": 0.0 } - } + }, + "additionalProperties": false }, { "description": "Never will never expire. Used to express the empty variant", @@ -89,13 +91,11 @@ "never": { "type": "object" } - } + }, + "additionalProperties": false } ] }, - "HumanAddr": { - "type": "string" - }, "NativeBalance": { "type": "array", "items": { diff --git a/contracts/cw1-subkeys/schema/allowance.json b/contracts/cw1-subkeys/schema/allowance.json index 63b7ec766..f5f9fac31 100644 --- a/contracts/cw1-subkeys/schema/allowance.json +++ b/contracts/cw1-subkeys/schema/allowance.json @@ -45,7 +45,8 @@ "format": "uint64", "minimum": 0.0 } - } + }, + "additionalProperties": false }, { "description": "AtTime will expire when `env.block.time` >= time", @@ -59,7 +60,8 @@ "format": "uint64", "minimum": 0.0 } - } + }, + "additionalProperties": false }, { "description": "Never will never expire. Used to express the empty variant", @@ -71,7 +73,8 @@ "never": { "type": "object" } - } + }, + "additionalProperties": false } ] }, diff --git a/contracts/cw1-subkeys/schema/execute_msg.json b/contracts/cw1-subkeys/schema/execute_msg.json index af5f7b056..2f0e7f64e 100644 --- a/contracts/cw1-subkeys/schema/execute_msg.json +++ b/contracts/cw1-subkeys/schema/execute_msg.json @@ -23,7 +23,8 @@ } } } - } + }, + "additionalProperties": false }, { "description": "Freeze will make a mutable contract immutable, must be called by an admin", @@ -35,7 +36,8 @@ "freeze": { "type": "object" } - } + }, + "additionalProperties": false }, { "description": "UpdateAdmins will change the admin set of the contract, must be called by an existing admin, and only works if the contract is mutable", @@ -53,12 +55,13 @@ "admins": { "type": "array", "items": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } } - } + }, + "additionalProperties": false }, { "description": "Add an allowance to a given subkey (subkey must not be admin)", @@ -88,11 +91,12 @@ ] }, "spender": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "Decreases an allowance for a given subkey (subkey must not be admin)", @@ -122,11 +126,12 @@ ] }, "spender": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false }, { "type": "object", @@ -145,11 +150,12 @@ "$ref": "#/definitions/Permissions" }, "spender": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false } ], "definitions": { @@ -177,11 +183,12 @@ } }, "to_address": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false } ] }, @@ -215,7 +222,8 @@ "bank": { "$ref": "#/definitions/BankMsg" } - } + }, + "additionalProperties": false }, { "type": "object", @@ -226,7 +234,8 @@ "custom": { "$ref": "#/definitions/Empty" } - } + }, + "additionalProperties": false }, { "type": "object", @@ -237,7 +246,8 @@ "staking": { "$ref": "#/definitions/StakingMsg" } - } + }, + "additionalProperties": false }, { "type": "object", @@ -248,7 +258,8 @@ "wasm": { "$ref": "#/definitions/WasmMsg" } - } + }, + "additionalProperties": false } ] }, @@ -271,7 +282,8 @@ "format": "uint64", "minimum": 0.0 } - } + }, + "additionalProperties": false }, { "description": "AtTime will expire when `env.block.time` >= time", @@ -285,7 +297,8 @@ "format": "uint64", "minimum": 0.0 } - } + }, + "additionalProperties": false }, { "description": "Never will never expire. Used to express the empty variant", @@ -297,13 +310,11 @@ "never": { "type": "object" } - } + }, + "additionalProperties": false } ] }, - "HumanAddr": { - "type": "string" - }, "Permissions": { "type": "object", "required": [ @@ -348,11 +359,12 @@ "$ref": "#/definitions/Coin" }, "validator": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "This is translated to a [MsgUndelegate](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L112-L121). `delegator_address` is automatically filled with the current contract's address.", @@ -372,11 +384,12 @@ "$ref": "#/definitions/Coin" }, "validator": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "This is translated to a [MsgSetWithdrawAddress](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/distribution/v1beta1/tx.proto#L29-L37) followed by a [MsgWithdrawDelegatorReward](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/distribution/v1beta1/tx.proto#L42-L50). `delegator_address` is automatically filled with the current contract's address.", @@ -393,21 +406,18 @@ "properties": { "recipient": { "description": "this is the \"withdraw address\", the one that should receive the rewards if None, then use delegator address", - "anyOf": [ - { - "$ref": "#/definitions/HumanAddr" - }, - { - "type": "null" - } + "type": [ + "string", + "null" ] }, "validator": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "This is translated to a [MsgBeginRedelegate](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L95-L105). `delegator_address` is automatically filled with the current contract's address.", @@ -428,14 +438,15 @@ "$ref": "#/definitions/Coin" }, "dst_validator": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "src_validator": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false } ] }, @@ -461,7 +472,7 @@ ], "properties": { "contract_addr": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "msg": { "description": "msg is the json-encoded ExecuteMsg struct (as raw Binary)", @@ -479,7 +490,8 @@ } } } - } + }, + "additionalProperties": false }, { "description": "Instantiates a new contracts from previously uploaded Wasm code.\n\nThis is translated to a [MsgInstantiateContract](https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto#L47-L61). `sender` is automatically filled with the current contract's address.", @@ -522,7 +534,8 @@ } } } - } + }, + "additionalProperties": false }, { "description": "Migrates a given contracts to use new wasm code. Passes a MigrateMsg to allow us to customize behavior.\n\nOnly the contract admin (as defined in wasmd), if any, is able to make this call.\n\nThis is translated to a [MsgMigrateContract](https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto#L86-L96). `sender` is automatically filled with the current contract's address.", @@ -540,7 +553,7 @@ ], "properties": { "contract_addr": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "msg": { "description": "msg is the json-encoded MigrateMsg struct that will be passed to the new code", @@ -558,7 +571,8 @@ } } } - } + }, + "additionalProperties": false } ] } diff --git a/contracts/cw1-subkeys/schema/instantiate_msg.json b/contracts/cw1-subkeys/schema/instantiate_msg.json index 56d597219..fdcd684aa 100644 --- a/contracts/cw1-subkeys/schema/instantiate_msg.json +++ b/contracts/cw1-subkeys/schema/instantiate_msg.json @@ -10,16 +10,11 @@ "admins": { "type": "array", "items": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } }, "mutable": { "type": "boolean" } - }, - "definitions": { - "HumanAddr": { - "type": "string" - } } } diff --git a/contracts/cw1-subkeys/schema/query_msg.json b/contracts/cw1-subkeys/schema/query_msg.json index ba69b9e73..cc9f52e86 100644 --- a/contracts/cw1-subkeys/schema/query_msg.json +++ b/contracts/cw1-subkeys/schema/query_msg.json @@ -12,7 +12,8 @@ "admin_list": { "type": "object" } - } + }, + "additionalProperties": false }, { "description": "Get the current allowance for the given subkey (how much it can spend) Returns crate::state::Allowance", @@ -28,11 +29,12 @@ ], "properties": { "spender": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "Get the current permissions for the given subkey (how much it can spend) Returns PermissionsInfo", @@ -48,11 +50,12 @@ ], "properties": { "spender": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "Checks permissions of the caller on this proxy. If CanExecute returns true then a call to `Execute` with the same message, before any further state changes, should also succeed.", @@ -72,11 +75,12 @@ "$ref": "#/definitions/CosmosMsg_for_Empty" }, "sender": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "Gets all Allowances for this contract Returns AllAllowancesResponse", @@ -97,18 +101,15 @@ "minimum": 0.0 }, "start_after": { - "anyOf": [ - { - "$ref": "#/definitions/HumanAddr" - }, - { - "type": "null" - } + "type": [ + "string", + "null" ] } } } - } + }, + "additionalProperties": false }, { "description": "Gets all Permissions for this contract Returns AllPermissionsResponse", @@ -129,18 +130,15 @@ "minimum": 0.0 }, "start_after": { - "anyOf": [ - { - "$ref": "#/definitions/HumanAddr" - }, - { - "type": "null" - } + "type": [ + "string", + "null" ] } } } - } + }, + "additionalProperties": false } ], "definitions": { @@ -168,11 +166,12 @@ } }, "to_address": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false } ] }, @@ -206,7 +205,8 @@ "bank": { "$ref": "#/definitions/BankMsg" } - } + }, + "additionalProperties": false }, { "type": "object", @@ -217,7 +217,8 @@ "custom": { "$ref": "#/definitions/Empty" } - } + }, + "additionalProperties": false }, { "type": "object", @@ -228,7 +229,8 @@ "staking": { "$ref": "#/definitions/StakingMsg" } - } + }, + "additionalProperties": false }, { "type": "object", @@ -239,7 +241,8 @@ "wasm": { "$ref": "#/definitions/WasmMsg" } - } + }, + "additionalProperties": false } ] }, @@ -247,9 +250,6 @@ "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" }, - "HumanAddr": { - "type": "string" - }, "StakingMsg": { "description": "The message types of the staking module.\n\nSee https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto", "anyOf": [ @@ -271,11 +271,12 @@ "$ref": "#/definitions/Coin" }, "validator": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "This is translated to a [MsgUndelegate](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L112-L121). `delegator_address` is automatically filled with the current contract's address.", @@ -295,11 +296,12 @@ "$ref": "#/definitions/Coin" }, "validator": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "This is translated to a [MsgSetWithdrawAddress](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/distribution/v1beta1/tx.proto#L29-L37) followed by a [MsgWithdrawDelegatorReward](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/distribution/v1beta1/tx.proto#L42-L50). `delegator_address` is automatically filled with the current contract's address.", @@ -316,21 +318,18 @@ "properties": { "recipient": { "description": "this is the \"withdraw address\", the one that should receive the rewards if None, then use delegator address", - "anyOf": [ - { - "$ref": "#/definitions/HumanAddr" - }, - { - "type": "null" - } + "type": [ + "string", + "null" ] }, "validator": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "This is translated to a [MsgBeginRedelegate](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L95-L105). `delegator_address` is automatically filled with the current contract's address.", @@ -351,14 +350,15 @@ "$ref": "#/definitions/Coin" }, "dst_validator": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "src_validator": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false } ] }, @@ -384,7 +384,7 @@ ], "properties": { "contract_addr": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "msg": { "description": "msg is the json-encoded ExecuteMsg struct (as raw Binary)", @@ -402,7 +402,8 @@ } } } - } + }, + "additionalProperties": false }, { "description": "Instantiates a new contracts from previously uploaded Wasm code.\n\nThis is translated to a [MsgInstantiateContract](https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto#L47-L61). `sender` is automatically filled with the current contract's address.", @@ -445,7 +446,8 @@ } } } - } + }, + "additionalProperties": false }, { "description": "Migrates a given contracts to use new wasm code. Passes a MigrateMsg to allow us to customize behavior.\n\nOnly the contract admin (as defined in wasmd), if any, is able to make this call.\n\nThis is translated to a [MsgMigrateContract](https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto#L86-L96). `sender` is automatically filled with the current contract's address.", @@ -463,7 +465,7 @@ ], "properties": { "contract_addr": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "msg": { "description": "msg is the json-encoded MigrateMsg struct that will be passed to the new code", @@ -481,7 +483,8 @@ } } } - } + }, + "additionalProperties": false } ] } diff --git a/contracts/cw1-subkeys/src/contract.rs b/contracts/cw1-subkeys/src/contract.rs index baea313a3..ddfcd1485 100644 --- a/contracts/cw1-subkeys/src/contract.rs +++ b/contracts/cw1-subkeys/src/contract.rs @@ -5,10 +5,10 @@ use std::ops::{AddAssign, Sub}; #[cfg(not(feature = "library"))] use cosmwasm_std::entry_point; use cosmwasm_std::{ - attr, to_binary, BankMsg, Binary, CanonicalAddr, Coin, CosmosMsg, Deps, DepsMut, Empty, Env, - HumanAddr, MessageInfo, Order, Response, StakingMsg, StdError, StdResult, + attr, to_binary, BankMsg, Binary, Coin, CosmosMsg, Deps, DepsMut, Empty, Env, MessageInfo, + Order, Response, StakingMsg, StdError, StdResult, }; -use cw0::{maybe_canonical, Expiration}; +use cw0::Expiration; use cw1::CanExecuteResponse; use cw1_whitelist::{ contract::{ @@ -19,6 +19,7 @@ use cw1_whitelist::{ state::ADMIN_LIST, }; use cw2::set_contract_version; +use cw_storage_plus::Bound; use crate::error::ContractError; use crate::msg::{ @@ -26,7 +27,6 @@ use crate::msg::{ QueryMsg, }; use crate::state::{Allowance, Permissions, ALLOWANCES, PERMISSIONS}; -use cw_storage_plus::Bound; // version info for migration info const CONTRACT_NAME: &str = "crates.io:cw1-subkeys"; @@ -84,9 +84,8 @@ where T: Clone + fmt::Debug + PartialEq + JsonSchema, { let cfg = ADMIN_LIST.load(deps.storage)?; - let owner_raw = &deps.api.canonical_address(&info.sender)?; // this is the admin behavior (same as cw1-whitelist) - if cfg.is_admin(owner_raw) { + if cfg.is_admin(info.sender.as_ref()) { let res = Response { messages: msgs, attributes: vec![attr("action", "execute"), attr("owner", info.sender)], @@ -97,7 +96,7 @@ where for msg in &msgs { match msg { CosmosMsg::Staking(staking_msg) => { - let perm = PERMISSIONS.may_load(deps.storage, &owner_raw)?; + let perm = PERMISSIONS.may_load(deps.storage, &info.sender)?; let perm = perm.ok_or(ContractError::NotAllowed {})?; check_staking_permissions(staking_msg, perm)?; } @@ -105,11 +104,12 @@ where to_address: _, amount, }) => { - let allow = ALLOWANCES.may_load(deps.storage, &owner_raw)?; - let mut allowance = allow.ok_or(ContractError::NoAllowance {})?; - // Decrease allowance - allowance.balance = allowance.balance.sub(amount.clone())?; - ALLOWANCES.save(deps.storage, &owner_raw, &allowance)?; + ALLOWANCES.update::<_, ContractError>(deps.storage, &info.sender, |allow| { + let mut allowance = allow.ok_or(ContractError::NoAllowance {})?; + // Decrease allowance + allowance.balance = allowance.balance.sub(amount.clone())?; + Ok(allowance) + })?; } _ => { return Err(ContractError::MessageTypeRejected {}); @@ -161,7 +161,7 @@ pub fn execute_increase_allowance( deps: DepsMut, _env: Env, info: MessageInfo, - spender: HumanAddr, + spender: String, amount: Coin, expires: Option, ) -> Result, ContractError> @@ -169,17 +169,16 @@ where T: Clone + fmt::Debug + PartialEq + JsonSchema, { let cfg = ADMIN_LIST.load(deps.storage)?; - let spender_raw = &deps.api.canonical_address(&spender)?; - let owner_raw = &deps.api.canonical_address(&info.sender)?; - - if !cfg.is_admin(&owner_raw) { + if !cfg.is_admin(info.sender.as_ref()) { return Err(ContractError::Unauthorized {}); } - if spender_raw == owner_raw { + + let spender_addr = deps.api.addr_validate(&spender)?; + if info.sender == spender_addr { return Err(ContractError::CannotSetOwnAccount {}); } - ALLOWANCES.update::<_, StdError>(deps.storage, &spender_raw, |allow| { + ALLOWANCES.update::<_, StdError>(deps.storage, &spender_addr, |allow| { let mut allowance = allow.unwrap_or_default(); if let Some(exp) = expires { allowance.expires = exp; @@ -207,7 +206,7 @@ pub fn execute_decrease_allowance( deps: DepsMut, _env: Env, info: MessageInfo, - spender: HumanAddr, + spender: String, amount: Coin, expires: Option, ) -> Result, ContractError> @@ -215,27 +214,27 @@ where T: Clone + fmt::Debug + PartialEq + JsonSchema, { let cfg = ADMIN_LIST.load(deps.storage)?; - let spender_raw = &deps.api.canonical_address(&spender)?; - let owner_raw = &deps.api.canonical_address(&info.sender)?; - - if !cfg.is_admin(&owner_raw) { + if !cfg.is_admin(info.sender.as_ref()) { return Err(ContractError::Unauthorized {}); } - if spender_raw == owner_raw { + + let spender_addr = deps.api.addr_validate(&spender)?; + if info.sender == spender_addr { return Err(ContractError::CannotSetOwnAccount {}); } - let allowance = ALLOWANCES.update::<_, ContractError>(deps.storage, &spender_raw, |allow| { - // Fail fast - let mut allowance = allow.ok_or(ContractError::NoAllowance {})?; - if let Some(exp) = expires { - allowance.expires = exp; - } - allowance.balance = allowance.balance.sub_saturating(amount.clone())?; // Tolerates underflows (amount bigger than balance), but fails if there are no tokens at all for the denom (report potential errors) - Ok(allowance) - })?; + let allowance = + ALLOWANCES.update::<_, ContractError>(deps.storage, &spender_addr, |allow| { + // Fail fast + let mut allowance = allow.ok_or(ContractError::NoAllowance {})?; + if let Some(exp) = expires { + allowance.expires = exp; + } + allowance.balance = allowance.balance.sub_saturating(amount.clone())?; // Tolerates underflows (amount bigger than balance), but fails if there are no tokens at all for the denom (report potential errors) + Ok(allowance) + })?; if allowance.balance.is_empty() { - ALLOWANCES.remove(deps.storage, &spender_raw); + ALLOWANCES.remove(deps.storage, &spender_addr); } let res = Response { @@ -243,7 +242,7 @@ where messages: vec![], attributes: vec![ attr("action", "decrease_allowance"), - attr("owner", deps.api.human_address(owner_raw)?), + attr("owner", info.sender), attr("spender", spender), attr("denomination", amount.denom), attr("amount", amount.amount), @@ -257,30 +256,29 @@ pub fn execute_set_permissions( deps: DepsMut, _env: Env, info: MessageInfo, - spender: HumanAddr, + spender: String, perm: Permissions, ) -> Result, ContractError> where T: Clone + fmt::Debug + PartialEq + JsonSchema, { let cfg = ADMIN_LIST.load(deps.storage)?; - let spender_raw = &deps.api.canonical_address(&spender)?; - let owner_raw = &deps.api.canonical_address(&info.sender)?; - - if !cfg.is_admin(&owner_raw) { + if !cfg.is_admin(info.sender.as_ref()) { return Err(ContractError::Unauthorized {}); } - if spender_raw == owner_raw { + + let spender_addr = deps.api.addr_validate(&spender)?; + if info.sender == spender_addr { return Err(ContractError::CannotSetOwnAccount {}); } - PERMISSIONS.save(deps.storage, &spender_raw, &perm)?; + PERMISSIONS.save(deps.storage, &spender_addr, &perm)?; let res = Response { submessages: vec![], messages: vec![], attributes: vec![ attr("action", "set_permissions"), - attr("owner", deps.api.human_address(owner_raw)?), + attr("owner", info.sender), attr("spender", spender), attr("permissions", perm), ], @@ -306,44 +304,42 @@ pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult { } // if the subkey has no allowance, return an empty struct (not an error) -pub fn query_allowance(deps: Deps, spender: HumanAddr) -> StdResult { - let subkey = deps.api.canonical_address(&spender)?; +pub fn query_allowance(deps: Deps, spender: String) -> StdResult { + // we can use unchecked here as it is a query - bad value means a miss, we never write it + let spender = deps.api.addr_validate(&spender)?; let allow = ALLOWANCES - .may_load(deps.storage, &subkey)? + .may_load(deps.storage, &spender)? .unwrap_or_default(); Ok(allow) } // if the subkey has no permissions, return an empty struct (not an error) -pub fn query_permissions(deps: Deps, spender: HumanAddr) -> StdResult { - let subkey = deps.api.canonical_address(&spender)?; +pub fn query_permissions(deps: Deps, spender: String) -> StdResult { + let spender = deps.api.addr_validate(&spender)?; let permissions = PERMISSIONS - .may_load(deps.storage, &subkey)? + .may_load(deps.storage, &spender)? .unwrap_or_default(); Ok(permissions) } -fn query_can_execute( - deps: Deps, - sender: HumanAddr, - msg: CosmosMsg, -) -> StdResult { +fn query_can_execute(deps: Deps, sender: String, msg: CosmosMsg) -> StdResult { Ok(CanExecuteResponse { can_execute: can_execute(deps, sender, msg)?, }) } // this can just return booleans and the query_can_execute wrapper creates the struct once, not on every path -fn can_execute(deps: Deps, sender: HumanAddr, msg: CosmosMsg) -> StdResult { - let owner_raw = deps.api.canonical_address(&sender)?; +fn can_execute(deps: Deps, sender: String, msg: CosmosMsg) -> StdResult { let cfg = ADMIN_LIST.load(deps.storage)?; - if cfg.is_admin(&owner_raw) { + if cfg.is_admin(&sender) { return Ok(true); } + + let sender = deps.api.addr_validate(&sender)?; match msg { CosmosMsg::Bank(BankMsg::Send { amount, .. }) => { // now we check if there is enough allowance for this message - let allowance = ALLOWANCES.may_load(deps.storage, &owner_raw)?; + let allowance = ALLOWANCES.may_load(deps.storage, &sender)?; match allowance { // if there is an allowance, we subtract the requested amount to ensure it is covered (error on underflow) Some(allow) => Ok(allow.balance.sub(amount).is_ok()), @@ -351,7 +347,7 @@ fn can_execute(deps: Deps, sender: HumanAddr, msg: CosmosMsg) -> StdResult } } CosmosMsg::Staking(staking_msg) => { - let perm_opt = PERMISSIONS.may_load(deps.storage, &owner_raw)?; + let perm_opt = PERMISSIONS.may_load(deps.storage, &sender)?; match perm_opt { Some(permission) => Ok(check_staking_permissions(&staking_msg, permission).is_ok()), None => Ok(false), @@ -371,21 +367,20 @@ fn calc_limit(request: Option) -> usize { // return a list of all allowances here pub fn query_all_allowances( deps: Deps, - start_after: Option, + start_after: Option, limit: Option, ) -> StdResult { let limit = calc_limit(limit); - let canon = maybe_canonical(deps.api, start_after)?; - let start = canon.map(Bound::exclusive); + // we use raw addresses here.... + let start = start_after.map(Bound::exclusive); - let api = &deps.api; let res: StdResult> = ALLOWANCES .range(deps.storage, start, None, Order::Ascending) .take(limit) .map(|item| { item.and_then(|(k, allow)| { Ok(AllowanceInfo { - spender: api.human_address(&CanonicalAddr::from(k))?, + spender: String::from_utf8(k)?, balance: allow.balance, expires: allow.expires, }) @@ -398,21 +393,19 @@ pub fn query_all_allowances( // return a list of all permissions here pub fn query_all_permissions( deps: Deps, - start_after: Option, + start_after: Option, limit: Option, ) -> StdResult { let limit = calc_limit(limit); - let canon = maybe_canonical(deps.api, start_after)?; - let start = canon.map(Bound::exclusive); + let start = start_after.map(Bound::exclusive); - let api = &deps.api; let res: StdResult> = PERMISSIONS .range(deps.storage, start, None, Order::Ascending) .take(limit) .map(|item| { item.and_then(|(k, perm)| { Ok(PermissionsInfo { - spender: api.human_address(&CanonicalAddr::from(k))?, + spender: String::from_utf8(k)?, permissions: perm, }) }) @@ -424,7 +417,7 @@ pub fn query_all_permissions( #[cfg(test)] mod tests { use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info}; - use cosmwasm_std::{coin, coins, Api, StakingMsg}; + use cosmwasm_std::{coin, coins, Addr, StakingMsg}; use cw0::NativeBalance; use cw1_whitelist::msg::AdminListResponse; @@ -438,23 +431,23 @@ mod tests { fn setup_test_case( mut deps: DepsMut, info: &MessageInfo, - admins: &[HumanAddr], - spenders: &[HumanAddr], + admins: &[&str], + spenders: &[&str], allowances: &[Coin], expirations: &[Expiration], ) { // Instantiate a contract with admins let instantiate_msg = InstantiateMsg { - admins: admins.to_vec(), + admins: admins.into_iter().map(|x| x.to_string()).collect(), mutable: true, }; instantiate(deps.branch(), mock_env(), info.clone(), instantiate_msg).unwrap(); // Add subkeys with initial allowances - for (spender, expiration) in spenders.iter().zip(expirations) { + for (spender, expiration) in spenders.into_iter().zip(expirations) { for amount in allowances { let msg = ExecuteMsg::IncreaseAllowance { - spender: spender.clone(), + spender: spender.to_string(), amount: amount.clone(), expires: Some(expiration.clone()), }; @@ -467,12 +460,12 @@ mod tests { fn get_contract_version_works() { let mut deps = mock_dependencies(&[]); - let owner = HumanAddr::from("admin0001"); - let admins = vec![owner.clone(), HumanAddr::from("admin0002")]; + let owner = "admin0001"; + let admins = vec![owner, "admin0002"]; - let spender1 = HumanAddr::from("spender0001"); - let spender2 = HumanAddr::from("spender0002"); - let initial_spenders = vec![spender1.clone(), spender2.clone()]; + let spender1 = "spender0001"; + let spender2 = "spender0002"; + let initial_spenders = vec![spender1, spender2]; // Same allowances for all spenders, for simplicity let denom1 = "token1"; @@ -507,13 +500,13 @@ mod tests { fn query_allowance_works() { let mut deps = mock_dependencies(&[]); - let owner = HumanAddr::from("admin0001"); - let admins = vec![owner.clone(), HumanAddr::from("admin0002")]; + let owner = "admin0001"; + let admins = vec![owner.clone(), "admin0002"]; - let spender1 = HumanAddr::from("spender0001"); - let spender2 = HumanAddr::from("spender0002"); - let spender3 = HumanAddr::from("spender0003"); - let initial_spenders = vec![spender1.clone(), spender2.clone()]; + let spender1 = "spender0001"; + let spender2 = "spender0002"; + let spender3 = "spender0003"; + let initial_spenders = vec![spender1, spender2]; // Same allowances for all spenders, for simplicity let denom1 = "token1"; @@ -536,7 +529,7 @@ mod tests { ); // Check allowances work for accounts with balances - let allowance = query_allowance(deps.as_ref(), spender1.clone()).unwrap(); + let allowance = query_allowance(deps.as_ref(), spender1.to_string()).unwrap(); assert_eq!( allowance, Allowance { @@ -544,7 +537,7 @@ mod tests { expires: expires_never.clone(), } ); - let allowance = query_allowance(deps.as_ref(), spender2.clone()).unwrap(); + let allowance = query_allowance(deps.as_ref(), spender2.to_string()).unwrap(); assert_eq!( allowance, Allowance { @@ -554,7 +547,7 @@ mod tests { ); // Check allowances work for accounts with no balance - let allowance = query_allowance(deps.as_ref(), spender3.clone()).unwrap(); + let allowance = query_allowance(deps.as_ref(), spender3.to_string()).unwrap(); assert_eq!(allowance, Allowance::default(),); } @@ -562,13 +555,13 @@ mod tests { fn query_all_allowances_works() { let mut deps = mock_dependencies(&[]); - let owner = HumanAddr::from("admin0001"); - let admins = vec![owner.clone(), HumanAddr::from("admin0002")]; + let owner = "admin0001"; + let admins = vec![owner.clone(), "admin0002"]; - let spender1 = HumanAddr::from("spender0001"); - let spender2 = HumanAddr::from("spender0002"); - let spender3 = HumanAddr::from("spender0003"); - let initial_spenders = vec![spender1.clone(), spender2.clone(), spender3.clone()]; + let spender1 = "spender0001"; + let spender2 = "spender0002"; + let spender3 = "spender0003"; + let initial_spenders = vec![spender1, spender2, spender3]; // Same allowances for all spenders, for simplicity let initial_allowances = coins(1234, "mytoken"); @@ -597,7 +590,7 @@ mod tests { assert_eq!( allowances[0], AllowanceInfo { - spender: spender2, + spender: spender1.into(), balance: NativeBalance(initial_allowances.clone()), expires: Expiration::Never {}, } @@ -605,23 +598,23 @@ mod tests { assert_eq!( allowances[1], AllowanceInfo { - spender: spender3.clone(), + spender: spender2.to_string(), balance: NativeBalance(initial_allowances.clone()), - expires: expires_later, + expires: Expiration::Never {}, } ); // now continue from after the last one - let allowances = query_all_allowances(deps.as_ref(), Some(spender3), Some(2)) + let allowances = query_all_allowances(deps.as_ref(), Some(spender2.into()), Some(2)) .unwrap() .allowances; assert_eq!(1, allowances.len()); assert_eq!( allowances[0], AllowanceInfo { - spender: spender1, + spender: spender3.into(), balance: NativeBalance(initial_allowances.clone()), - expires: Expiration::Never {}, + expires: expires_later, } ); } @@ -630,15 +623,15 @@ mod tests { fn query_permissions_works() { let mut deps = mock_dependencies(&[]); - let owner = HumanAddr::from("admin0001"); - let admins = vec![owner.clone()]; + let owner = "admin0001"; + let admins = vec![owner.to_string()]; // spender1 has every permission to stake - let spender1 = HumanAddr::from("spender0001"); + let spender1 = "spender0001"; // spender2 do not have permission - let spender2 = HumanAddr::from("spender0002"); + let spender2 = "spender0002"; // non existent spender - let spender3 = HumanAddr::from("spender0003"); + let spender3 = "spender0003"; let god_mode = Permissions { delegate: true, @@ -656,22 +649,22 @@ mod tests { instantiate(deps.as_mut(), mock_env(), info.clone(), instantiate_msg).unwrap(); let setup_perm_msg1 = ExecuteMsg::SetPermissions { - spender: spender1.clone(), + spender: spender1.to_string(), permissions: god_mode, }; execute(deps.as_mut(), mock_env(), info.clone(), setup_perm_msg1).unwrap(); let setup_perm_msg2 = ExecuteMsg::SetPermissions { - spender: spender2.clone(), + spender: spender2.to_string(), // default is no permission permissions: Default::default(), }; execute(deps.as_mut(), mock_env(), info, setup_perm_msg2).unwrap(); - let permissions = query_permissions(deps.as_ref(), spender1.clone()).unwrap(); + let permissions = query_permissions(deps.as_ref(), spender1.to_string()).unwrap(); assert_eq!(permissions, god_mode); - let permissions = query_permissions(deps.as_ref(), spender2.clone()).unwrap(); + let permissions = query_permissions(deps.as_ref(), spender2.to_string()).unwrap(); assert_eq!( permissions, Permissions { @@ -683,7 +676,7 @@ mod tests { ); // no permission is set. should return false - let permissions = query_permissions(deps.as_ref(), spender3.clone()).unwrap(); + let permissions = query_permissions(deps.as_ref(), spender3.to_string()).unwrap(); assert_eq!( permissions, Permissions { @@ -701,12 +694,12 @@ mod tests { fn query_all_permissions_works() { let mut deps = mock_dependencies(&[]); - let owner = HumanAddr::from("admin0001"); - let admins = vec![owner.clone(), HumanAddr::from("admin0002")]; + let owner = "admin0001"; + let admins = vec![owner.to_string(), "admin0002".to_string()]; - let spender1 = HumanAddr::from("spender0001"); - let spender2 = HumanAddr::from("spender0002"); - let spender3 = HumanAddr::from("spender0003"); + let spender1 = "spender0001"; + let spender2 = "spender0002"; + let spender3 = "spender0003"; let god_mode = Permissions { delegate: true, @@ -732,19 +725,19 @@ mod tests { instantiate(deps.as_mut(), mock_env(), info.clone(), instantiate_msg).unwrap(); let setup_perm_msg1 = ExecuteMsg::SetPermissions { - spender: spender1.clone(), + spender: spender1.to_string(), permissions: god_mode, }; execute(deps.as_mut(), mock_env(), info.clone(), setup_perm_msg1).unwrap(); let setup_perm_msg2 = ExecuteMsg::SetPermissions { - spender: spender2.clone(), + spender: spender2.to_string(), permissions: noob_mode, }; execute(deps.as_mut(), mock_env(), info.clone(), setup_perm_msg2).unwrap(); let setup_perm_msg3 = ExecuteMsg::SetPermissions { - spender: spender3.clone(), + spender: spender3.to_string(), permissions: noob_mode, }; execute(deps.as_mut(), mock_env(), info, setup_perm_msg3).unwrap(); @@ -757,28 +750,28 @@ mod tests { assert_eq!( permissions[0], PermissionsInfo { - spender: spender2, - permissions: noob_mode, + spender: spender1.into(), + permissions: god_mode, } ); assert_eq!( permissions[1], PermissionsInfo { - spender: spender3.clone(), + spender: spender2.to_string(), permissions: noob_mode, } ); // now continue from after the last one - let permissions = query_all_permissions(deps.as_ref(), Some(spender3), Some(2)) + let permissions = query_all_permissions(deps.as_ref(), Some(spender2.into()), Some(2)) .unwrap() .permissions; assert_eq!(1, permissions.len()); assert_eq!( permissions[0], PermissionsInfo { - spender: spender1, - permissions: god_mode, + spender: spender3.into(), + permissions: noob_mode, } ); } @@ -787,9 +780,9 @@ mod tests { fn update_admins_and_query() { let mut deps = mock_dependencies(&[]); - let owner = HumanAddr::from("admin0001"); - let admin2 = HumanAddr::from("admin0002"); - let admin3 = HumanAddr::from("admin0003"); + let owner = "admin0001"; + let admin2 = "admin0002"; + let admin3 = "admin0003"; let initial_admins = vec![owner.clone(), admin2.clone()]; let info = mock_info(owner.clone(), &[]); @@ -807,13 +800,13 @@ mod tests { assert_eq!( config, AdminListResponse { - admins: initial_admins.clone(), + admins: initial_admins.iter().map(|x| x.to_string()).collect(), mutable: true, } ); // Add a third (new) admin - let new_admins = vec![owner.clone(), admin2.clone(), admin3.clone()]; + let new_admins = vec![owner.to_string(), admin2.to_string(), admin3.to_string()]; let msg = ExecuteMsg::UpdateAdmins { admins: new_admins.clone(), }; @@ -832,7 +825,7 @@ mod tests { // Set admin3 as the only admin let msg = ExecuteMsg::UpdateAdmins { - admins: vec![admin3.clone()], + admins: vec![admin3.to_string()], }; execute(deps.as_mut(), mock_env(), info.clone(), msg).unwrap(); @@ -842,14 +835,14 @@ mod tests { assert_eq!( config, AdminListResponse { - admins: vec![admin3.clone()], + admins: vec![admin3.to_string()], mutable: true, } ); // Try to add owner back let msg = ExecuteMsg::UpdateAdmins { - admins: vec![admin3.clone(), owner.clone()], + admins: vec![admin3.to_string(), owner.to_string()], }; let res = execute(deps.as_mut(), mock_env(), info, msg); @@ -857,10 +850,10 @@ mod tests { assert!(res.is_err()); // Connect as admin3 - let info = mock_info(admin3.clone(), &[]); + let info = mock_info(admin3, &[]); // Add owner back let msg = ExecuteMsg::UpdateAdmins { - admins: vec![admin3.clone(), owner.clone()], + admins: vec![admin3.to_string(), owner.to_string()], }; execute(deps.as_mut(), mock_env(), info, msg).unwrap(); @@ -870,7 +863,7 @@ mod tests { assert_eq!( config, AdminListResponse { - admins: vec![admin3, owner], + admins: vec![admin3.to_string(), owner.to_string()], mutable: true, } ); @@ -880,14 +873,14 @@ mod tests { fn increase_allowances() { let mut deps = mock_dependencies(&[]); - let owner = HumanAddr::from("admin0001"); - let admins = vec![owner.clone(), HumanAddr::from("admin0002")]; + let owner = "admin0001"; + let admins = vec![owner.clone(), "admin0002"]; - let spender1 = HumanAddr::from("spender0001"); - let spender2 = HumanAddr::from("spender0002"); - let spender3 = HumanAddr::from("spender0003"); - let spender4 = HumanAddr::from("spender0004"); - let initial_spenders = vec![spender1.clone(), spender2.clone()]; + let spender1 = "spender0001"; + let spender2 = "spender0002"; + let spender3 = "spender0003"; + let spender4 = "spender0004"; + let initial_spenders = vec![spender1, spender2]; // Same allowances for all spenders, for simplicity let denom1 = "token1"; @@ -920,14 +913,14 @@ mod tests { // Add to spender1 account (expires = None) => don't change Expiration let msg = ExecuteMsg::IncreaseAllowance { - spender: spender1.clone(), + spender: spender1.to_string(), amount: allow1.clone(), expires: None, }; execute(deps.as_mut(), mock_env(), info.clone(), msg).unwrap(); // Verify - let allowance = query_allowance(deps.as_ref(), spender1.clone()).unwrap(); + let allowance = query_allowance(deps.as_ref(), spender1.to_string()).unwrap(); assert_eq!( allowance, Allowance { @@ -938,14 +931,14 @@ mod tests { // Add to spender2 account (expires = Some) let msg = ExecuteMsg::IncreaseAllowance { - spender: spender2.clone(), + spender: spender2.to_string(), amount: allow3.clone(), expires: Some(expires_height.clone()), }; execute(deps.as_mut(), mock_env(), info.clone(), msg).unwrap(); // Verify - let allowance = query_allowance(deps.as_ref(), spender2.clone()).unwrap(); + let allowance = query_allowance(deps.as_ref(), spender2.to_string()).unwrap(); assert_eq!( allowance, Allowance { @@ -956,14 +949,14 @@ mod tests { // Add to spender3 (new account) (expires = None) => default Expiration::Never let msg = ExecuteMsg::IncreaseAllowance { - spender: spender3.clone(), + spender: spender3.to_string(), amount: allow1.clone(), expires: None, }; execute(deps.as_mut(), mock_env(), info.clone(), msg).unwrap(); // Verify - let allowance = query_allowance(deps.as_ref(), spender3.clone()).unwrap(); + let allowance = query_allowance(deps.as_ref(), spender3.to_string()).unwrap(); assert_eq!( allowance, Allowance { @@ -974,14 +967,14 @@ mod tests { // Add to spender4 (new account) (expires = Some) let msg = ExecuteMsg::IncreaseAllowance { - spender: spender4.clone(), + spender: spender4.into(), amount: allow2.clone(), expires: Some(expires_time.clone()), }; execute(deps.as_mut(), mock_env(), info, msg).unwrap(); // Verify - let allowance = query_allowance(deps.as_ref(), spender4.clone()).unwrap(); + let allowance = query_allowance(deps.as_ref(), spender4.into()).unwrap(); assert_eq!( allowance, Allowance { @@ -995,12 +988,12 @@ mod tests { fn decrease_allowances() { let mut deps = mock_dependencies(&[]); - let owner = HumanAddr::from("admin0001"); - let admins = vec![owner.clone(), HumanAddr::from("admin0002")]; + let owner = "admin0001"; + let admins = vec![owner.clone(), "admin0002"]; - let spender1 = HumanAddr::from("spender0001"); - let spender2 = HumanAddr::from("spender0002"); - let initial_spenders = vec![spender1.clone(), spender2.clone()]; + let spender1 = "spender0001"; + let spender2 = "spender0002"; + let initial_spenders = vec![spender1, spender2]; // Same allowances for all spenders, for simplicity let denom1 = "token1"; @@ -1033,7 +1026,7 @@ mod tests { // Subtract from spender1 (existing) account (has none of that denom) let msg = ExecuteMsg::DecreaseAllowance { - spender: spender1.clone(), + spender: spender1.to_string(), amount: allow3.clone(), expires: None, }; @@ -1042,7 +1035,7 @@ mod tests { // Verify assert!(res.is_err()); // Verify everything stays the same for that spender - let allowance = query_allowance(deps.as_ref(), spender1.clone()).unwrap(); + let allowance = query_allowance(deps.as_ref(), spender1.to_string()).unwrap(); assert_eq!( allowance, Allowance { @@ -1053,14 +1046,14 @@ mod tests { // Subtract from spender2 (existing) account (brings denom to 0, other denoms left) let msg = ExecuteMsg::DecreaseAllowance { - spender: spender2.clone(), + spender: spender2.to_string(), amount: allow2.clone(), expires: None, }; execute(deps.as_mut(), mock_env(), info.clone(), msg).unwrap(); // Verify - let allowance = query_allowance(deps.as_ref(), spender2.clone()).unwrap(); + let allowance = query_allowance(deps.as_ref(), spender2.to_string()).unwrap(); assert_eq!( allowance, Allowance { @@ -1071,14 +1064,14 @@ mod tests { // Subtract from spender1 (existing) account (brings denom to > 0) let msg = ExecuteMsg::DecreaseAllowance { - spender: spender1.clone(), + spender: spender1.to_string(), amount: coin(amount1 / 2, denom1), expires: None, }; execute(deps.as_mut(), mock_env(), info.clone(), msg).unwrap(); // Verify - let allowance = query_allowance(deps.as_ref(), spender1.clone()).unwrap(); + let allowance = query_allowance(deps.as_ref(), spender1.to_string()).unwrap(); assert_eq!( allowance, Allowance { @@ -1092,19 +1085,19 @@ mod tests { // Subtract from spender2 (existing) account (brings denom to 0, no other denoms left => should delete Allowance) let msg = ExecuteMsg::DecreaseAllowance { - spender: spender2.clone(), + spender: spender2.to_string(), amount: allow1.clone(), expires: None, }; execute(deps.as_mut(), mock_env(), info.clone(), msg).unwrap(); // Verify - let allowance = query_allowance(deps.as_ref(), spender2.clone()).unwrap(); + let allowance = query_allowance(deps.as_ref(), spender2.to_string()).unwrap(); assert_eq!(allowance, Allowance::default()); // Subtract from spender2 (empty) account (should error) let msg = ExecuteMsg::DecreaseAllowance { - spender: spender2.clone(), + spender: spender2.to_string(), amount: allow1.clone(), expires: None, }; @@ -1115,14 +1108,14 @@ mod tests { // Subtract from spender1 (existing) account (underflows denom => should delete denom) let msg = ExecuteMsg::DecreaseAllowance { - spender: spender1.clone(), + spender: spender1.to_string(), amount: coin(amount1 * 10, denom1), expires: None, }; execute(deps.as_mut(), mock_env(), info, msg).unwrap(); // Verify - let allowance = query_allowance(deps.as_ref(), spender1.clone()).unwrap(); + let allowance = query_allowance(deps.as_ref(), spender1.to_string()).unwrap(); assert_eq!( allowance, Allowance { @@ -1136,12 +1129,12 @@ mod tests { fn execute_checks() { let mut deps = mock_dependencies(&[]); - let owner = HumanAddr::from("admin0001"); - let admins = vec![owner.clone(), HumanAddr::from("admin0002")]; + let owner = "admin0001"; + let admins = vec![owner.clone(), "admin0002"]; - let spender1 = HumanAddr::from("spender0001"); - let spender2 = HumanAddr::from("spender0002"); - let initial_spenders = vec![spender1.clone()]; + let spender1 = "spender0001"; + let spender2 = "spender0002"; + let initial_spenders = vec![spender1]; let denom1 = "token1"; let amount1 = 1111; @@ -1163,7 +1156,7 @@ mod tests { // Create Send message let msgs = vec![BankMsg::Send { - to_address: spender2.clone(), + to_address: spender2.to_string(), amount: coins(1000, "token1"), } .into()]; @@ -1181,15 +1174,15 @@ mod tests { assert_eq!(res.messages, msgs); assert_eq!( res.attributes, - vec![attr("action", "execute"), attr("owner", spender1.clone())] + vec![ + attr("action", "execute"), + attr("owner", spender1.to_string()) + ] ); // And then cannot (not enough funds anymore) let err = execute(deps.as_mut(), mock_env(), info, execute_msg.clone()).unwrap_err(); - assert!(matches!( - err, - ContractError::Std(StdError::Underflow { .. }) - )); + assert!(matches!(err, ContractError::Std(StdError::Overflow { .. }))); // Owner / admins can do anything (at the contract level) let info = mock_info(&owner.clone(), &[]); @@ -1224,13 +1217,13 @@ mod tests { fn staking_permission_checks() { let mut deps = mock_dependencies(&[]); - let owner = HumanAddr::from("admin0001"); - let admins = vec![owner.clone()]; + let owner = "admin0001"; + let admins = vec![owner.to_string()]; // spender1 has every permission to stake - let spender1 = HumanAddr::from("spender0001"); + let spender1 = "spender0001"; // spender2 do not have permission - let spender2 = HumanAddr::from("spender0002"); + let spender2 = "spender0002"; let denom = "token1"; let amount = 10000; let coin1 = coin(amount, denom); @@ -1251,13 +1244,13 @@ mod tests { instantiate(deps.as_mut(), mock_env(), info.clone(), instantiate_msg).unwrap(); let setup_perm_msg1 = ExecuteMsg::SetPermissions { - spender: spender1.clone(), + spender: spender1.to_string(), permissions: god_mode, }; execute(deps.as_mut(), mock_env(), info.clone(), setup_perm_msg1).unwrap(); let setup_perm_msg2 = ExecuteMsg::SetPermissions { - spender: spender2.clone(), + spender: spender2.to_string(), // default is no permission permissions: Default::default(), }; @@ -1265,23 +1258,23 @@ mod tests { execute(deps.as_mut(), mock_env(), info.clone(), setup_perm_msg2).unwrap(); let msg_delegate = vec![StakingMsg::Delegate { - validator: HumanAddr::from("validator1"), + validator: "validator1".into(), amount: coin1.clone(), } .into()]; let msg_redelegate = vec![StakingMsg::Redelegate { - src_validator: HumanAddr::from("validator1"), - dst_validator: HumanAddr::from("validator2"), + src_validator: "validator1".into(), + dst_validator: "validator2".into(), amount: coin1.clone(), } .into()]; let msg_undelegate = vec![StakingMsg::Undelegate { - validator: HumanAddr::from("validator1"), + validator: "validator1".into(), amount: coin1.clone(), } .into()]; let msg_withdraw = vec![StakingMsg::Withdraw { - validator: HumanAddr::from("validator1"), + validator: "validator1".into(), recipient: None, } .into()]; @@ -1318,9 +1311,9 @@ mod tests { } // test mixed permissions - let spender3 = HumanAddr::from("spender0003"); + let spender3 = "spender0003"; let setup_perm_msg3 = ExecuteMsg::SetPermissions { - spender: spender3.clone(), + spender: spender3.to_string(), permissions: Permissions { delegate: false, redelegate: true, @@ -1374,12 +1367,12 @@ mod tests { fn permissions_allowances_independent() { let mut deps = mock_dependencies(&[]); - let owner = HumanAddr::from("admin0001"); - let admins = vec![owner.clone()]; + let owner = "admin0001"; + let admins = vec![owner.to_string()]; // spender1 has every permission to stake - let spender1 = HumanAddr::from("spender0001"); - let spender2 = HumanAddr::from("spender0002"); + let spender1 = "spender0001"; + let spender2 = "spender0002"; let denom = "token1"; let amount = 10000; let coin = coin(amount, denom); @@ -1405,40 +1398,40 @@ mod tests { // setup permission and then allowance and check if changed let setup_perm_msg = ExecuteMsg::SetPermissions { - spender: spender1.clone(), + spender: spender1.to_string(), permissions: perm, }; execute(deps.as_mut(), mock_env(), info.clone(), setup_perm_msg).unwrap(); let setup_allowance_msg = ExecuteMsg::IncreaseAllowance { - spender: spender1.clone(), + spender: spender1.to_string(), amount: coin.clone(), expires: None, }; execute(deps.as_mut(), mock_env(), info.clone(), setup_allowance_msg).unwrap(); - let res_perm = query_permissions(deps.as_ref(), spender1.clone()).unwrap(); + let res_perm = query_permissions(deps.as_ref(), spender1.to_string()).unwrap(); assert_eq!(perm, res_perm); - let res_allow = query_allowance(deps.as_ref(), spender1.clone()).unwrap(); + let res_allow = query_allowance(deps.as_ref(), spender1.to_string()).unwrap(); assert_eq!(allow, res_allow); // setup allowance and then permission and check if changed let setup_allowance_msg = ExecuteMsg::IncreaseAllowance { - spender: spender2.clone(), + spender: spender2.to_string(), amount: coin.clone(), expires: None, }; execute(deps.as_mut(), mock_env(), info.clone(), setup_allowance_msg).unwrap(); let setup_perm_msg = ExecuteMsg::SetPermissions { - spender: spender2.clone(), + spender: spender2.to_string(), permissions: perm, }; execute(deps.as_mut(), mock_env(), info, setup_perm_msg).unwrap(); - let res_perm = query_permissions(deps.as_ref(), spender2.clone()).unwrap(); + let res_perm = query_permissions(deps.as_ref(), spender2.to_string()).unwrap(); assert_eq!(perm, res_perm); - let res_allow = query_allowance(deps.as_ref(), spender2.clone()).unwrap(); + let res_allow = query_allowance(deps.as_ref(), spender2.to_string()).unwrap(); assert_eq!(allow, res_allow); } @@ -1446,17 +1439,17 @@ mod tests { fn can_execute_query_works() { let mut deps = mock_dependencies(&[]); - let owner = HumanAddr::from("admin007"); - let spender = HumanAddr::from("spender808"); - let anyone = HumanAddr::from("anyone"); + let owner = "admin007"; + let spender = "spender808"; + let anyone = "anyone"; let info = mock_info(owner.clone(), &[]); // spender has allowance of 55000 ushell setup_test_case( deps.as_mut(), &info, - &[owner.clone()], - &[spender.clone()], + &[owner], + &[spender], &coins(55000, "ushell"), &[Expiration::Never {}], ); @@ -1468,62 +1461,84 @@ mod tests { withdraw: false, }; - let spender_raw = &deps.api.canonical_address(&spender).unwrap(); - let _ = PERMISSIONS.save(&mut deps.storage, &spender_raw, &perm); + let spender_addr = Addr::unchecked(spender); + let _ = PERMISSIONS.save(&mut deps.storage, &spender_addr, &perm); // let us make some queries... different msg types by owner and by other let send_msg = CosmosMsg::Bank(BankMsg::Send { - to_address: anyone.clone(), + to_address: anyone.to_string(), amount: coins(12345, "ushell"), }); let send_msg_large = CosmosMsg::Bank(BankMsg::Send { - to_address: anyone.clone(), + to_address: anyone.to_string(), amount: coins(1234567, "ushell"), }); let staking_delegate_msg = CosmosMsg::Staking(StakingMsg::Delegate { - validator: anyone.clone(), + validator: anyone.to_string(), amount: coin(70000, "ureef"), }); let staking_withdraw_msg = CosmosMsg::Staking(StakingMsg::Withdraw { - validator: anyone.clone(), + validator: anyone.to_string(), recipient: None, }); // owner can send big or small - let res = query_can_execute(deps.as_ref(), owner.clone(), send_msg.clone()).unwrap(); + let res = query_can_execute(deps.as_ref(), owner.to_string(), send_msg.clone()).unwrap(); assert_eq!(res.can_execute, true); - let res = query_can_execute(deps.as_ref(), owner.clone(), send_msg_large.clone()).unwrap(); + let res = + query_can_execute(deps.as_ref(), owner.to_string(), send_msg_large.clone()).unwrap(); assert_eq!(res.can_execute, true); // owner can stake - let res = - query_can_execute(deps.as_ref(), owner.clone(), staking_delegate_msg.clone()).unwrap(); + let res = query_can_execute( + deps.as_ref(), + owner.to_string(), + staking_delegate_msg.clone(), + ) + .unwrap(); assert_eq!(res.can_execute, true); // spender can send small - let res = query_can_execute(deps.as_ref(), spender.clone(), send_msg.clone()).unwrap(); + let res = query_can_execute(deps.as_ref(), spender.to_string(), send_msg.clone()).unwrap(); assert_eq!(res.can_execute, true); // not too big let res = - query_can_execute(deps.as_ref(), spender.clone(), send_msg_large.clone()).unwrap(); + query_can_execute(deps.as_ref(), spender.to_string(), send_msg_large.clone()).unwrap(); assert_eq!(res.can_execute, false); // spender can send staking msgs if permissioned - let res = query_can_execute(deps.as_ref(), spender.clone(), staking_delegate_msg.clone()) - .unwrap(); + let res = query_can_execute( + deps.as_ref(), + spender.to_string(), + staking_delegate_msg.clone(), + ) + .unwrap(); assert_eq!(res.can_execute, true); - let res = query_can_execute(deps.as_ref(), spender.clone(), staking_withdraw_msg.clone()) - .unwrap(); + let res = query_can_execute( + deps.as_ref(), + spender.to_string(), + staking_withdraw_msg.clone(), + ) + .unwrap(); assert_eq!(res.can_execute, false); // random person cannot do anything - let res = query_can_execute(deps.as_ref(), anyone.clone(), send_msg.clone()).unwrap(); - assert_eq!(res.can_execute, false); - let res = query_can_execute(deps.as_ref(), anyone.clone(), send_msg_large.clone()).unwrap(); + let res = query_can_execute(deps.as_ref(), anyone.to_string(), send_msg.clone()).unwrap(); assert_eq!(res.can_execute, false); let res = - query_can_execute(deps.as_ref(), anyone.clone(), staking_delegate_msg.clone()).unwrap(); + query_can_execute(deps.as_ref(), anyone.to_string(), send_msg_large.clone()).unwrap(); assert_eq!(res.can_execute, false); - let res = - query_can_execute(deps.as_ref(), anyone.clone(), staking_withdraw_msg.clone()).unwrap(); + let res = query_can_execute( + deps.as_ref(), + anyone.to_string(), + staking_delegate_msg.clone(), + ) + .unwrap(); + assert_eq!(res.can_execute, false); + let res = query_can_execute( + deps.as_ref(), + anyone.to_string(), + staking_withdraw_msg.clone(), + ) + .unwrap(); assert_eq!(res.can_execute, false); } } diff --git a/contracts/cw1-subkeys/src/msg.rs b/contracts/cw1-subkeys/src/msg.rs index 10fbb4ba8..1e4bd55b0 100644 --- a/contracts/cw1-subkeys/src/msg.rs +++ b/contracts/cw1-subkeys/src/msg.rs @@ -2,7 +2,7 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use std::fmt; -use cosmwasm_std::{Coin, CosmosMsg, Empty, HumanAddr}; +use cosmwasm_std::{Coin, CosmosMsg, Empty}; use cw0::{Expiration, NativeBalance}; use crate::state::Permissions; @@ -21,24 +21,24 @@ where Freeze {}, /// UpdateAdmins will change the admin set of the contract, must be called by an existing admin, /// and only works if the contract is mutable - UpdateAdmins { admins: Vec }, + UpdateAdmins { admins: Vec }, /// Add an allowance to a given subkey (subkey must not be admin) IncreaseAllowance { - spender: HumanAddr, + spender: String, amount: Coin, expires: Option, }, /// Decreases an allowance for a given subkey (subkey must not be admin) DecreaseAllowance { - spender: HumanAddr, + spender: String, amount: Coin, expires: Option, }, // Setups up permissions for a given subkey. SetPermissions { - spender: HumanAddr, + spender: String, permissions: Permissions, }, } @@ -54,27 +54,24 @@ where AdminList {}, /// Get the current allowance for the given subkey (how much it can spend) /// Returns crate::state::Allowance - Allowance { spender: HumanAddr }, + Allowance { spender: String }, /// Get the current permissions for the given subkey (how much it can spend) /// Returns PermissionsInfo - Permissions { spender: HumanAddr }, + Permissions { spender: String }, /// Checks permissions of the caller on this proxy. /// If CanExecute returns true then a call to `Execute` with the same message, /// before any further state changes, should also succeed. - CanExecute { - sender: HumanAddr, - msg: CosmosMsg, - }, + CanExecute { sender: String, msg: CosmosMsg }, /// Gets all Allowances for this contract /// Returns AllAllowancesResponse AllAllowances { - start_after: Option, + start_after: Option, limit: Option, }, /// Gets all Permissions for this contract /// Returns AllPermissionsResponse AllPermissions { - start_after: Option, + start_after: Option, limit: Option, }, } @@ -86,14 +83,14 @@ pub struct AllAllowancesResponse { #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] pub struct AllowanceInfo { - pub spender: HumanAddr, + pub spender: String, pub balance: NativeBalance, pub expires: Expiration, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] pub struct PermissionsInfo { - pub spender: HumanAddr, + pub spender: String, pub permissions: Permissions, } diff --git a/contracts/cw1-subkeys/src/state.rs b/contracts/cw1-subkeys/src/state.rs index 9169a88f8..3fe457ceb 100644 --- a/contracts/cw1-subkeys/src/state.rs +++ b/contracts/cw1-subkeys/src/state.rs @@ -1,11 +1,11 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; +use std::fmt; +use cosmwasm_std::Addr; use cw0::{Expiration, NativeBalance}; use cw_storage_plus::Map; -use std::fmt; - // Permissions struct defines users message execution permissions. // Could have implemented permissions for each cosmos module(StakingPermissions, GovPermissions etc...) // But that meant a lot of code for each module. Keeping the permissions inside one struct is more @@ -34,5 +34,5 @@ pub struct Allowance { pub expires: Expiration, } -pub const PERMISSIONS: Map<&[u8], Permissions> = Map::new("permissions"); -pub const ALLOWANCES: Map<&[u8], Allowance> = Map::new("allowances"); +pub const PERMISSIONS: Map<&Addr, Permissions> = Map::new("permissions"); +pub const ALLOWANCES: Map<&Addr, Allowance> = Map::new("allowances"); diff --git a/contracts/cw1-whitelist/Cargo.toml b/contracts/cw1-whitelist/Cargo.toml index 9119021df..e9fc1c040 100644 --- a/contracts/cw1-whitelist/Cargo.toml +++ b/contracts/cw1-whitelist/Cargo.toml @@ -21,11 +21,11 @@ library = [] cw0 = { path = "../../packages/cw0", version = "0.6.0-alpha3" } cw1 = { path = "../../packages/cw1", version = "0.6.0-alpha3" } cw2 = { path = "../../packages/cw2", version = "0.6.0-alpha3" } -cosmwasm-std = { version = "0.14.0-beta1", features = ["iterator"] } +cosmwasm-std = { version = "0.14.0-beta2", features = ["iterator"] } cw-storage-plus = { path = "../../packages/storage-plus", version = "0.6.0-alpha3", features = ["iterator"] } -schemars = "0.7" +schemars = "0.8.1" serde = { version = "1.0.103", default-features = false, features = ["derive"] } thiserror = { version = "1.0.20" } [dev-dependencies] -cosmwasm-schema = { version = "0.14.0-beta1" } +cosmwasm-schema = { version = "0.14.0-beta2" } diff --git a/contracts/cw1-whitelist/schema/admin_list_response.json b/contracts/cw1-whitelist/schema/admin_list_response.json index 4173be545..bc20467c3 100644 --- a/contracts/cw1-whitelist/schema/admin_list_response.json +++ b/contracts/cw1-whitelist/schema/admin_list_response.json @@ -10,16 +10,11 @@ "admins": { "type": "array", "items": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } }, "mutable": { "type": "boolean" } - }, - "definitions": { - "HumanAddr": { - "type": "string" - } } } diff --git a/contracts/cw1-whitelist/schema/execute_msg.json b/contracts/cw1-whitelist/schema/execute_msg.json index 2cba3fec7..de5c43334 100644 --- a/contracts/cw1-whitelist/schema/execute_msg.json +++ b/contracts/cw1-whitelist/schema/execute_msg.json @@ -23,7 +23,8 @@ } } } - } + }, + "additionalProperties": false }, { "description": "Freeze will make a mutable contract immutable, must be called by an admin", @@ -35,7 +36,8 @@ "freeze": { "type": "object" } - } + }, + "additionalProperties": false }, { "description": "UpdateAdmins will change the admin set of the contract, must be called by an existing admin, and only works if the contract is mutable", @@ -53,12 +55,13 @@ "admins": { "type": "array", "items": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } } - } + }, + "additionalProperties": false } ], "definitions": { @@ -86,11 +89,12 @@ } }, "to_address": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false } ] }, @@ -124,7 +128,8 @@ "bank": { "$ref": "#/definitions/BankMsg" } - } + }, + "additionalProperties": false }, { "type": "object", @@ -135,7 +140,8 @@ "custom": { "$ref": "#/definitions/Empty" } - } + }, + "additionalProperties": false }, { "type": "object", @@ -146,7 +152,8 @@ "staking": { "$ref": "#/definitions/StakingMsg" } - } + }, + "additionalProperties": false }, { "type": "object", @@ -157,7 +164,8 @@ "wasm": { "$ref": "#/definitions/WasmMsg" } - } + }, + "additionalProperties": false } ] }, @@ -165,9 +173,6 @@ "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" }, - "HumanAddr": { - "type": "string" - }, "StakingMsg": { "description": "The message types of the staking module.\n\nSee https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto", "anyOf": [ @@ -189,11 +194,12 @@ "$ref": "#/definitions/Coin" }, "validator": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "This is translated to a [MsgUndelegate](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L112-L121). `delegator_address` is automatically filled with the current contract's address.", @@ -213,11 +219,12 @@ "$ref": "#/definitions/Coin" }, "validator": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "This is translated to a [MsgSetWithdrawAddress](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/distribution/v1beta1/tx.proto#L29-L37) followed by a [MsgWithdrawDelegatorReward](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/distribution/v1beta1/tx.proto#L42-L50). `delegator_address` is automatically filled with the current contract's address.", @@ -234,21 +241,18 @@ "properties": { "recipient": { "description": "this is the \"withdraw address\", the one that should receive the rewards if None, then use delegator address", - "anyOf": [ - { - "$ref": "#/definitions/HumanAddr" - }, - { - "type": "null" - } + "type": [ + "string", + "null" ] }, "validator": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "This is translated to a [MsgBeginRedelegate](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L95-L105). `delegator_address` is automatically filled with the current contract's address.", @@ -269,14 +273,15 @@ "$ref": "#/definitions/Coin" }, "dst_validator": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "src_validator": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false } ] }, @@ -302,7 +307,7 @@ ], "properties": { "contract_addr": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "msg": { "description": "msg is the json-encoded ExecuteMsg struct (as raw Binary)", @@ -320,7 +325,8 @@ } } } - } + }, + "additionalProperties": false }, { "description": "Instantiates a new contracts from previously uploaded Wasm code.\n\nThis is translated to a [MsgInstantiateContract](https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto#L47-L61). `sender` is automatically filled with the current contract's address.", @@ -363,7 +369,8 @@ } } } - } + }, + "additionalProperties": false }, { "description": "Migrates a given contracts to use new wasm code. Passes a MigrateMsg to allow us to customize behavior.\n\nOnly the contract admin (as defined in wasmd), if any, is able to make this call.\n\nThis is translated to a [MsgMigrateContract](https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto#L86-L96). `sender` is automatically filled with the current contract's address.", @@ -381,7 +388,7 @@ ], "properties": { "contract_addr": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "msg": { "description": "msg is the json-encoded MigrateMsg struct that will be passed to the new code", @@ -399,7 +406,8 @@ } } } - } + }, + "additionalProperties": false } ] } diff --git a/contracts/cw1-whitelist/schema/instantiate_msg.json b/contracts/cw1-whitelist/schema/instantiate_msg.json index 56d597219..fdcd684aa 100644 --- a/contracts/cw1-whitelist/schema/instantiate_msg.json +++ b/contracts/cw1-whitelist/schema/instantiate_msg.json @@ -10,16 +10,11 @@ "admins": { "type": "array", "items": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } }, "mutable": { "type": "boolean" } - }, - "definitions": { - "HumanAddr": { - "type": "string" - } } } diff --git a/contracts/cw1-whitelist/schema/query_msg.json b/contracts/cw1-whitelist/schema/query_msg.json index 1302f04fc..36fb75908 100644 --- a/contracts/cw1-whitelist/schema/query_msg.json +++ b/contracts/cw1-whitelist/schema/query_msg.json @@ -12,7 +12,8 @@ "admin_list": { "type": "object" } - } + }, + "additionalProperties": false }, { "description": "Checks permissions of the caller on this proxy. If CanExecute returns true then a call to `Execute` with the same message, before any further state changes, should also succeed.", @@ -32,11 +33,12 @@ "$ref": "#/definitions/CosmosMsg_for_Empty" }, "sender": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false } ], "definitions": { @@ -64,11 +66,12 @@ } }, "to_address": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false } ] }, @@ -102,7 +105,8 @@ "bank": { "$ref": "#/definitions/BankMsg" } - } + }, + "additionalProperties": false }, { "type": "object", @@ -113,7 +117,8 @@ "custom": { "$ref": "#/definitions/Empty" } - } + }, + "additionalProperties": false }, { "type": "object", @@ -124,7 +129,8 @@ "staking": { "$ref": "#/definitions/StakingMsg" } - } + }, + "additionalProperties": false }, { "type": "object", @@ -135,7 +141,8 @@ "wasm": { "$ref": "#/definitions/WasmMsg" } - } + }, + "additionalProperties": false } ] }, @@ -143,9 +150,6 @@ "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" }, - "HumanAddr": { - "type": "string" - }, "StakingMsg": { "description": "The message types of the staking module.\n\nSee https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto", "anyOf": [ @@ -167,11 +171,12 @@ "$ref": "#/definitions/Coin" }, "validator": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "This is translated to a [MsgUndelegate](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L112-L121). `delegator_address` is automatically filled with the current contract's address.", @@ -191,11 +196,12 @@ "$ref": "#/definitions/Coin" }, "validator": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "This is translated to a [MsgSetWithdrawAddress](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/distribution/v1beta1/tx.proto#L29-L37) followed by a [MsgWithdrawDelegatorReward](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/distribution/v1beta1/tx.proto#L42-L50). `delegator_address` is automatically filled with the current contract's address.", @@ -212,21 +218,18 @@ "properties": { "recipient": { "description": "this is the \"withdraw address\", the one that should receive the rewards if None, then use delegator address", - "anyOf": [ - { - "$ref": "#/definitions/HumanAddr" - }, - { - "type": "null" - } + "type": [ + "string", + "null" ] }, "validator": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "This is translated to a [MsgBeginRedelegate](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L95-L105). `delegator_address` is automatically filled with the current contract's address.", @@ -247,14 +250,15 @@ "$ref": "#/definitions/Coin" }, "dst_validator": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "src_validator": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false } ] }, @@ -280,7 +284,7 @@ ], "properties": { "contract_addr": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "msg": { "description": "msg is the json-encoded ExecuteMsg struct (as raw Binary)", @@ -298,7 +302,8 @@ } } } - } + }, + "additionalProperties": false }, { "description": "Instantiates a new contracts from previously uploaded Wasm code.\n\nThis is translated to a [MsgInstantiateContract](https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto#L47-L61). `sender` is automatically filled with the current contract's address.", @@ -341,7 +346,8 @@ } } } - } + }, + "additionalProperties": false }, { "description": "Migrates a given contracts to use new wasm code. Passes a MigrateMsg to allow us to customize behavior.\n\nOnly the contract admin (as defined in wasmd), if any, is able to make this call.\n\nThis is translated to a [MsgMigrateContract](https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto#L86-L96). `sender` is automatically filled with the current contract's address.", @@ -359,7 +365,7 @@ ], "properties": { "contract_addr": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "msg": { "description": "msg is the json-encoded MigrateMsg struct that will be passed to the new code", @@ -377,7 +383,8 @@ } } } - } + }, + "additionalProperties": false } ] } diff --git a/contracts/cw1-whitelist/src/contract.rs b/contracts/cw1-whitelist/src/contract.rs index 3b9b6b2fe..be2790473 100644 --- a/contracts/cw1-whitelist/src/contract.rs +++ b/contracts/cw1-whitelist/src/contract.rs @@ -4,8 +4,8 @@ use std::fmt; #[cfg(not(feature = "library"))] use cosmwasm_std::entry_point; use cosmwasm_std::{ - attr, to_binary, Api, Binary, CanonicalAddr, CosmosMsg, Deps, DepsMut, Empty, Env, HumanAddr, - MessageInfo, Response, StdResult, + attr, to_binary, Addr, Api, Binary, CosmosMsg, Deps, DepsMut, Empty, Env, MessageInfo, + Response, StdResult, }; use cw1::CanExecuteResponse; @@ -28,22 +28,15 @@ pub fn instantiate( ) -> StdResult { set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; let cfg = AdminList { - admins: map_canonical(deps.api, &msg.admins)?, + admins: map_validate(deps.api, &msg.admins)?, mutable: msg.mutable, }; ADMIN_LIST.save(deps.storage, &cfg)?; Ok(Response::default()) } -pub fn map_canonical(api: &dyn Api, admins: &[HumanAddr]) -> StdResult> { - admins - .iter() - .map(|addr| api.canonical_address(addr)) - .collect() -} - -fn map_human(api: &dyn Api, admins: &[CanonicalAddr]) -> StdResult> { - admins.iter().map(|addr| api.human_address(addr)).collect() +pub fn map_validate(api: &dyn Api, admins: &[String]) -> StdResult> { + admins.iter().map(|addr| api.addr_validate(&addr)).collect() } #[cfg_attr(not(feature = "library"), entry_point)] @@ -71,7 +64,7 @@ pub fn execute_execute( where T: Clone + fmt::Debug + PartialEq + JsonSchema, { - if !can_execute(deps.as_ref(), &info.sender)? { + if !can_execute(deps.as_ref(), info.sender.as_ref())? { Err(ContractError::Unauthorized {}) } else { let res = Response { @@ -89,7 +82,7 @@ pub fn execute_freeze( info: MessageInfo, ) -> Result { let mut cfg = ADMIN_LIST.load(deps.storage)?; - if !cfg.can_modify(&deps.api.canonical_address(&info.sender)?) { + if !cfg.can_modify(info.sender.as_ref()) { Err(ContractError::Unauthorized {}) } else { cfg.mutable = false; @@ -107,13 +100,13 @@ pub fn execute_update_admins( deps: DepsMut, _env: Env, info: MessageInfo, - admins: Vec, + admins: Vec, ) -> Result { let mut cfg = ADMIN_LIST.load(deps.storage)?; - if !cfg.can_modify(&deps.api.canonical_address(&info.sender)?) { + if !cfg.can_modify(info.sender.as_ref()) { Err(ContractError::Unauthorized {}) } else { - cfg.admins = map_canonical(deps.api, &admins)?; + cfg.admins = map_validate(deps.api, &admins)?; ADMIN_LIST.save(deps.storage, &cfg)?; let res = Response { @@ -124,9 +117,9 @@ pub fn execute_update_admins( } } -fn can_execute(deps: Deps, sender: &HumanAddr) -> StdResult { +fn can_execute(deps: Deps, sender: &str) -> StdResult { let cfg = ADMIN_LIST.load(deps.storage)?; - let can = cfg.is_admin(&deps.api.canonical_address(sender)?); + let can = cfg.is_admin(sender.as_ref()); Ok(can) } @@ -141,14 +134,14 @@ pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult { pub fn query_admin_list(deps: Deps) -> StdResult { let cfg = ADMIN_LIST.load(deps.storage)?; Ok(AdminListResponse { - admins: map_human(deps.api, &cfg.admins)?, + admins: cfg.admins.into_iter().map(|a| a.into()).collect(), mutable: cfg.mutable, }) } pub fn query_can_execute( deps: Deps, - sender: HumanAddr, + sender: String, _msg: CosmosMsg, ) -> StdResult { Ok(CanExecuteResponse { @@ -166,15 +159,15 @@ mod tests { fn instantiate_and_modify_config() { let mut deps = mock_dependencies(&[]); - let alice = HumanAddr::from("alice"); - let bob = HumanAddr::from("bob"); - let carl = HumanAddr::from("carl"); + let alice = "alice"; + let bob = "bob"; + let carl = "carl"; - let anyone = HumanAddr::from("anyone"); + let anyone = "anyone"; // instantiate the contract let instantiate_msg = InstantiateMsg { - admins: vec![alice.clone(), bob.clone(), carl.clone()], + admins: vec![alice.to_string(), bob.to_string(), carl.to_string()], mutable: true, }; let info = mock_info(&anyone, &[]); @@ -182,14 +175,14 @@ mod tests { // ensure expected config let expected = AdminListResponse { - admins: vec![alice.clone(), bob.clone(), carl.clone()], + admins: vec![alice.to_string(), bob.to_string(), carl.to_string()], mutable: true, }; assert_eq!(query_admin_list(deps.as_ref()).unwrap(), expected); // anyone cannot modify the contract let msg = ExecuteMsg::UpdateAdmins { - admins: vec![anyone.clone()], + admins: vec![anyone.to_string()], }; let info = mock_info(&anyone, &[]); let err = execute(deps.as_mut(), mock_env(), info, msg).unwrap_err(); @@ -197,14 +190,14 @@ mod tests { // but alice can kick out carl let msg = ExecuteMsg::UpdateAdmins { - admins: vec![alice.clone(), bob.clone()], + admins: vec![alice.to_string(), bob.to_string()], }; let info = mock_info(&alice, &[]); execute(deps.as_mut(), mock_env(), info, msg).unwrap(); // ensure expected config let expected = AdminListResponse { - admins: vec![alice.clone(), bob.clone()], + admins: vec![alice.to_string(), bob.to_string()], mutable: true, }; assert_eq!(query_admin_list(deps.as_ref()).unwrap(), expected); @@ -218,14 +211,14 @@ mod tests { let info = mock_info(&bob, &[]); execute(deps.as_mut(), mock_env(), info, ExecuteMsg::Freeze {}).unwrap(); let expected = AdminListResponse { - admins: vec![alice.clone(), bob.clone()], + admins: vec![alice.to_string(), bob.to_string()], mutable: false, }; assert_eq!(query_admin_list(deps.as_ref()).unwrap(), expected); // and now alice cannot change it again let msg = ExecuteMsg::UpdateAdmins { - admins: vec![alice.clone()], + admins: vec![alice.to_string()], }; let info = mock_info(&alice, &[]); let err = execute(deps.as_mut(), mock_env(), info, msg).unwrap_err(); @@ -236,13 +229,13 @@ mod tests { fn execute_messages_has_proper_permissions() { let mut deps = mock_dependencies(&[]); - let alice = HumanAddr::from("alice"); - let bob = HumanAddr::from("bob"); - let carl = HumanAddr::from("carl"); + let alice = "alice"; + let bob = "bob"; + let carl = "carl"; // instantiate the contract let instantiate_msg = InstantiateMsg { - admins: vec![alice.clone(), carl.clone()], + admins: vec![alice.to_string(), carl.to_string()], mutable: false, }; let info = mock_info(&bob, &[]); @@ -251,12 +244,12 @@ mod tests { let freeze: ExecuteMsg = ExecuteMsg::Freeze {}; let msgs = vec![ BankMsg::Send { - to_address: bob.clone(), + to_address: bob.to_string(), amount: coins(10000, "DAI"), } .into(), WasmMsg::Execute { - contract_addr: HumanAddr::from("some contract"), + contract_addr: "some contract".into(), msg: to_binary(&freeze).unwrap(), send: vec![], } @@ -282,14 +275,14 @@ mod tests { fn can_execute_query_works() { let mut deps = mock_dependencies(&[]); - let alice = HumanAddr::from("alice"); - let bob = HumanAddr::from("bob"); + let alice = "alice"; + let bob = "bob"; - let anyone = HumanAddr::from("anyone"); + let anyone = "anyone"; // instantiate the contract let instantiate_msg = InstantiateMsg { - admins: vec![alice.clone(), bob.clone()], + admins: vec![alice.to_string(), bob.to_string()], mutable: false, }; let info = mock_info(&anyone, &[]); @@ -297,28 +290,29 @@ mod tests { // let us make some queries... different msg types by owner and by other let send_msg = CosmosMsg::Bank(BankMsg::Send { - to_address: anyone.clone(), + to_address: anyone.to_string(), amount: coins(12345, "ushell"), }); let staking_msg = CosmosMsg::Staking(StakingMsg::Delegate { - validator: anyone.clone(), + validator: anyone.to_string(), amount: coin(70000, "ureef"), }); // owner can send - let res = query_can_execute(deps.as_ref(), alice.clone(), send_msg.clone()).unwrap(); + let res = query_can_execute(deps.as_ref(), alice.to_string(), send_msg.clone()).unwrap(); assert_eq!(res.can_execute, true); // owner can stake - let res = query_can_execute(deps.as_ref(), bob.clone(), staking_msg.clone()).unwrap(); + let res = query_can_execute(deps.as_ref(), bob.to_string(), staking_msg.clone()).unwrap(); assert_eq!(res.can_execute, true); // anyone cannot send - let res = query_can_execute(deps.as_ref(), anyone.clone(), send_msg.clone()).unwrap(); + let res = query_can_execute(deps.as_ref(), anyone.to_string(), send_msg.clone()).unwrap(); assert_eq!(res.can_execute, false); // anyone cannot stake - let res = query_can_execute(deps.as_ref(), anyone.clone(), staking_msg.clone()).unwrap(); + let res = + query_can_execute(deps.as_ref(), anyone.to_string(), staking_msg.clone()).unwrap(); assert_eq!(res.can_execute, false); } } diff --git a/contracts/cw1-whitelist/src/msg.rs b/contracts/cw1-whitelist/src/msg.rs index 43568236b..0eeed3d2c 100644 --- a/contracts/cw1-whitelist/src/msg.rs +++ b/contracts/cw1-whitelist/src/msg.rs @@ -2,11 +2,11 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use std::fmt; -use cosmwasm_std::{CosmosMsg, Empty, HumanAddr}; +use cosmwasm_std::{CosmosMsg, Empty}; #[derive(Serialize, Deserialize, JsonSchema)] pub struct InstantiateMsg { - pub admins: Vec, + pub admins: Vec, pub mutable: bool, } @@ -24,7 +24,7 @@ where Freeze {}, /// UpdateAdmins will change the admin set of the contract, must be called by an existing admin, /// and only works if the contract is mutable - UpdateAdmins { admins: Vec }, + UpdateAdmins { admins: Vec }, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] @@ -38,14 +38,11 @@ where /// Checks permissions of the caller on this proxy. /// If CanExecute returns true then a call to `Execute` with the same message, /// before any further state changes, should also succeed. - CanExecute { - sender: HumanAddr, - msg: CosmosMsg, - }, + CanExecute { sender: String, msg: CosmosMsg }, } #[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] pub struct AdminListResponse { - pub admins: Vec, + pub admins: Vec, pub mutable: bool, } diff --git a/contracts/cw1-whitelist/src/state.rs b/contracts/cw1-whitelist/src/state.rs index 508c6a473..239d29a21 100644 --- a/contracts/cw1-whitelist/src/state.rs +++ b/contracts/cw1-whitelist/src/state.rs @@ -1,23 +1,23 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -use cosmwasm_std::CanonicalAddr; +use cosmwasm_std::Addr; use cw_storage_plus::Item; #[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug, Default)] pub struct AdminList { - pub admins: Vec, + pub admins: Vec, pub mutable: bool, } impl AdminList { /// returns true if the address is a registered admin - pub fn is_admin(&self, addr: &CanonicalAddr) -> bool { - self.admins.iter().any(|a| a == addr) + pub fn is_admin(&self, addr: &str) -> bool { + self.admins.iter().any(|a| a.as_ref() == addr) } /// returns true if the address is a registered admin and the config is mutable - pub fn can_modify(&self, addr: &CanonicalAddr) -> bool { + pub fn can_modify(&self, addr: &str) -> bool { self.mutable && self.is_admin(addr) } } @@ -27,47 +27,42 @@ pub const ADMIN_LIST: Item = Item::new("admin_list"); #[cfg(test)] mod tests { use super::*; - use cosmwasm_std::testing::MockApi; - use cosmwasm_std::{Api, HumanAddr}; #[test] fn is_admin() { - let api = MockApi::default(); let admins: Vec<_> = vec!["bob", "paul", "john"] .into_iter() - .map(|name| api.canonical_address(&HumanAddr::from(name)).unwrap()) + .map(Addr::unchecked) .collect(); let config = AdminList { admins: admins.clone(), mutable: false, }; - assert!(config.is_admin(&admins[0])); - assert!(config.is_admin(&admins[2])); - let other = api.canonical_address(&HumanAddr::from("other")).unwrap(); - assert!(!config.is_admin(&other)); + assert!(config.is_admin(admins[0].as_ref())); + assert!(config.is_admin(admins[2].as_ref())); + assert!(!config.is_admin("other")); } #[test] fn can_modify() { - let api = MockApi::default(); - let alice = api.canonical_address(&HumanAddr::from("alice")).unwrap(); - let bob = api.canonical_address(&HumanAddr::from("bob")).unwrap(); + let alice = Addr::unchecked("alice"); + let bob = Addr::unchecked("bob"); // admin can modify mutable contract let config = AdminList { admins: vec![bob.clone()], mutable: true, }; - assert!(!config.can_modify(&alice)); - assert!(config.can_modify(&bob)); + assert!(!config.can_modify(alice.as_ref())); + assert!(config.can_modify(bob.as_ref())); // no one can modify an immutable contract let config = AdminList { admins: vec![alice.clone()], mutable: false, }; - assert!(!config.can_modify(&alice)); - assert!(!config.can_modify(&bob)); + assert!(!config.can_modify(alice.as_ref())); + assert!(!config.can_modify(bob.as_ref())); } } diff --git a/contracts/cw1155-base/.cargo/config b/contracts/cw1155-base/.cargo/config new file mode 100644 index 000000000..7d1a066c8 --- /dev/null +++ b/contracts/cw1155-base/.cargo/config @@ -0,0 +1,5 @@ +[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/contracts/cw1155-base/Cargo.toml b/contracts/cw1155-base/Cargo.toml index 4ee4d88eb..b235997c4 100644 --- a/contracts/cw1155-base/Cargo.toml +++ b/contracts/cw1155-base/Cargo.toml @@ -22,8 +22,8 @@ cw0 = { path = "../../packages/cw0", version = "0.6.0-alpha3" } cw2 = { path = "../../packages/cw2", version = "0.6.0-alpha3" } cw1155 = { path = "../../packages/cw1155", version = "0.6.0-alpha3" } cw-storage-plus = { path = "../../packages/storage-plus", version = "0.6.0-alpha3" , features = ["iterator"]} -cosmwasm-std = { version = "0.14.0-beta1", features = ["iterator"] } -schemars = "0.7" +cosmwasm-std = { version = "0.14.0-beta2", features = ["iterator"] } +schemars = "0.8.1" serde = { version = "1.0.103", default-features = false, features = ["derive"] } thiserror = { version = "1.0.20" } diff --git a/contracts/cw1155-base/examples/schema.rs b/contracts/cw1155-base/examples/schema.rs new file mode 100644 index 000000000..de4b260f9 --- /dev/null +++ b/contracts/cw1155-base/examples/schema.rs @@ -0,0 +1,27 @@ +use std::env::current_dir; +use std::fs::create_dir_all; + +use cosmwasm_schema::{export_schema, remove_schemas, schema_for}; + +use cw1155; +use cw1155_base::InstantiateMsg; + +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(&schema_for!(cw1155::Cw1155ExecuteMsg), &out_dir); + export_schema(&schema_for!(cw1155::Cw1155QueryMsg), &out_dir); + export_schema(&schema_for!(cw1155::Cw1155ReceiveMsg), &out_dir); + export_schema(&schema_for!(cw1155::Cw1155BatchReceiveMsg), &out_dir); + export_schema(&schema_for!(cw1155::BalanceResponse), &out_dir); + export_schema(&schema_for!(cw1155::BatchBalanceResponse), &out_dir); + export_schema(&schema_for!(cw1155::ApprovedForAllResponse), &out_dir); + export_schema(&schema_for!(cw1155::IsApprovedForAllResponse), &out_dir); + export_schema(&schema_for!(cw1155::TokenInfoResponse), &out_dir); + export_schema(&schema_for!(cw1155::TokensResponse), &out_dir); +} diff --git a/contracts/cw1155-base/schema/approved_for_all_response.json b/contracts/cw1155-base/schema/approved_for_all_response.json new file mode 100644 index 000000000..ce7407ba5 --- /dev/null +++ b/contracts/cw1155-base/schema/approved_for_all_response.json @@ -0,0 +1,87 @@ +{ + "$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)", + "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": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + }, + "additionalProperties": false + }, + { + "description": "Never will never expire. Used to express the empty variant", + "type": "object", + "required": [ + "never" + ], + "properties": { + "never": { + "type": "object" + } + }, + "additionalProperties": false + } + ] + } + } +} diff --git a/contracts/cw1155-base/schema/balance_response.json b/contracts/cw1155-base/schema/balance_response.json new file mode 100644 index 000000000..efa5d6ce0 --- /dev/null +++ b/contracts/cw1155-base/schema/balance_response.json @@ -0,0 +1,18 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "BalanceResponse", + "type": "object", + "required": [ + "balance" + ], + "properties": { + "balance": { + "$ref": "#/definitions/Uint128" + } + }, + "definitions": { + "Uint128": { + "type": "string" + } + } +} diff --git a/contracts/cw1155-base/schema/batch_balance_response.json b/contracts/cw1155-base/schema/batch_balance_response.json new file mode 100644 index 000000000..138cc4a43 --- /dev/null +++ b/contracts/cw1155-base/schema/batch_balance_response.json @@ -0,0 +1,21 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "BatchBalanceResponse", + "type": "object", + "required": [ + "balances" + ], + "properties": { + "balances": { + "type": "array", + "items": { + "$ref": "#/definitions/Uint128" + } + } + }, + "definitions": { + "Uint128": { + "type": "string" + } + } +} diff --git a/contracts/cw1155-base/schema/cw1155_batch_receive_msg.json b/contracts/cw1155-base/schema/cw1155_batch_receive_msg.json new file mode 100644 index 000000000..e4541af6c --- /dev/null +++ b/contracts/cw1155-base/schema/cw1155_batch_receive_msg.json @@ -0,0 +1,50 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Cw1155BatchReceiveMsg", + "description": "Cw1155BatchReceiveMsg should be de/serialized under `BatchReceive()` variant in a ExecuteMsg", + "type": "object", + "required": [ + "batch", + "msg", + "operator" + ], + "properties": { + "batch": { + "type": "array", + "items": { + "type": "array", + "items": [ + { + "type": "string" + }, + { + "$ref": "#/definitions/Uint128" + } + ], + "maxItems": 2, + "minItems": 2 + } + }, + "from": { + "type": [ + "string", + "null" + ] + }, + "msg": { + "$ref": "#/definitions/Binary" + }, + "operator": { + "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" + }, + "Uint128": { + "type": "string" + } + } +} diff --git a/contracts/cw1155-base/schema/cw1155_execute_msg.json b/contracts/cw1155-base/schema/cw1155_execute_msg.json new file mode 100644 index 000000000..4da6ba57b --- /dev/null +++ b/contracts/cw1155-base/schema/cw1155_execute_msg.json @@ -0,0 +1,372 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Cw1155ExecuteMsg", + "anyOf": [ + { + "description": "SendFrom is a base message to move tokens, if `env.sender` is the owner or has sufficient pre-approval.", + "type": "object", + "required": [ + "send_from" + ], + "properties": { + "send_from": { + "type": "object", + "required": [ + "from", + "to", + "token_id", + "value" + ], + "properties": { + "from": { + "type": "string" + }, + "msg": { + "description": "`None` means don't call the receiver interface", + "anyOf": [ + { + "$ref": "#/definitions/Binary" + }, + { + "type": "null" + } + ] + }, + "to": { + "description": "If `to` is not contract, `msg` should be `None`", + "type": "string" + }, + "token_id": { + "type": "string" + }, + "value": { + "$ref": "#/definitions/Uint128" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "BatchSendFrom is a base message to move multiple types of tokens in batch, if `env.sender` is the owner or has sufficient pre-approval.", + "type": "object", + "required": [ + "batch_send_from" + ], + "properties": { + "batch_send_from": { + "type": "object", + "required": [ + "batch", + "from", + "to" + ], + "properties": { + "batch": { + "type": "array", + "items": { + "type": "array", + "items": [ + { + "type": "string" + }, + { + "$ref": "#/definitions/Uint128" + } + ], + "maxItems": 2, + "minItems": 2 + } + }, + "from": { + "type": "string" + }, + "msg": { + "description": "`None` means don't call the receiver interface", + "anyOf": [ + { + "$ref": "#/definitions/Binary" + }, + { + "type": "null" + } + ] + }, + "to": { + "description": "if `to` is not contract, `msg` should be `None`", + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "Mint is a base message to mint tokens.", + "type": "object", + "required": [ + "mint" + ], + "properties": { + "mint": { + "type": "object", + "required": [ + "to", + "token_id", + "value" + ], + "properties": { + "msg": { + "description": "`None` means don't call the receiver interface", + "anyOf": [ + { + "$ref": "#/definitions/Binary" + }, + { + "type": "null" + } + ] + }, + "to": { + "description": "If `to` is not contract, `msg` should be `None`", + "type": "string" + }, + "token_id": { + "type": "string" + }, + "value": { + "$ref": "#/definitions/Uint128" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "BatchMint is a base message to mint multiple types of tokens in batch.", + "type": "object", + "required": [ + "batch_mint" + ], + "properties": { + "batch_mint": { + "type": "object", + "required": [ + "batch", + "to" + ], + "properties": { + "batch": { + "type": "array", + "items": { + "type": "array", + "items": [ + { + "type": "string" + }, + { + "$ref": "#/definitions/Uint128" + } + ], + "maxItems": 2, + "minItems": 2 + } + }, + "msg": { + "description": "`None` means don't call the receiver interface", + "anyOf": [ + { + "$ref": "#/definitions/Binary" + }, + { + "type": "null" + } + ] + }, + "to": { + "description": "If `to` is not contract, `msg` should be `None`", + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "Burn is a base message to burn tokens.", + "type": "object", + "required": [ + "burn" + ], + "properties": { + "burn": { + "type": "object", + "required": [ + "from", + "token_id", + "value" + ], + "properties": { + "from": { + "type": "string" + }, + "token_id": { + "type": "string" + }, + "value": { + "$ref": "#/definitions/Uint128" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "BatchBurn is a base message to burn multiple types of tokens in batch.", + "type": "object", + "required": [ + "batch_burn" + ], + "properties": { + "batch_burn": { + "type": "object", + "required": [ + "batch", + "from" + ], + "properties": { + "batch": { + "type": "array", + "items": { + "type": "array", + "items": [ + { + "type": "string" + }, + { + "$ref": "#/definitions/Uint128" + } + ], + "maxItems": 2, + "minItems": 2 + } + }, + "from": { + "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 + } + ], + "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" + }, + "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": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + }, + "additionalProperties": false + }, + { + "description": "Never will never expire. Used to express the empty variant", + "type": "object", + "required": [ + "never" + ], + "properties": { + "never": { + "type": "object" + } + }, + "additionalProperties": false + } + ] + }, + "Uint128": { + "type": "string" + } + } +} diff --git a/contracts/cw1155-base/schema/cw1155_query_msg.json b/contracts/cw1155-base/schema/cw1155_query_msg.json new file mode 100644 index 000000000..33537818c --- /dev/null +++ b/contracts/cw1155-base/schema/cw1155_query_msg.json @@ -0,0 +1,211 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Cw1155QueryMsg", + "anyOf": [ + { + "description": "Returns the current balance of the given address, 0 if unset. Return type: BalanceResponse.", + "type": "object", + "required": [ + "balance" + ], + "properties": { + "balance": { + "type": "object", + "required": [ + "owner", + "token_id" + ], + "properties": { + "owner": { + "type": "string" + }, + "token_id": { + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "Returns the current balance of the given address for a batch of tokens, 0 if unset. Return type: BatchBalanceResponse.", + "type": "object", + "required": [ + "batch_balance" + ], + "properties": { + "batch_balance": { + "type": "object", + "required": [ + "owner", + "token_ids" + ], + "properties": { + "owner": { + "type": "string" + }, + "token_ids": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + }, + "additionalProperties": false + }, + { + "description": "List all operators that can access all of the owner's tokens. Return type: ApprovedForAllResponse.", + "type": "object", + "required": [ + "approved_for_all" + ], + "properties": { + "approved_for_all": { + "type": "object", + "required": [ + "owner" + ], + "properties": { + "include_expired": { + "description": "unset or false will filter out expired approvals, 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": "Query approved status `owner` granted to `operator`. Return type: IsApprovedForAllResponse", + "type": "object", + "required": [ + "is_approved_for_all" + ], + "properties": { + "is_approved_for_all": { + "type": "object", + "required": [ + "operator", + "owner" + ], + "properties": { + "operator": { + "type": "string" + }, + "owner": { + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "With MetaData Extension. Query metadata of token Return type: TokenInfoResponse.", + "type": "object", + "required": [ + "token_info" + ], + "properties": { + "token_info": { + "type": "object", + "required": [ + "token_id" + ], + "properties": { + "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 + } + ] +} diff --git a/contracts/cw1155-base/schema/cw1155_receive_msg.json b/contracts/cw1155-base/schema/cw1155_receive_msg.json new file mode 100644 index 000000000..4879dbb34 --- /dev/null +++ b/contracts/cw1155-base/schema/cw1155_receive_msg.json @@ -0,0 +1,43 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Cw1155ReceiveMsg", + "description": "Cw1155ReceiveMsg should be de/serialized under `Receive()` variant in a ExecuteMsg", + "type": "object", + "required": [ + "amount", + "msg", + "operator", + "token_id" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Uint128" + }, + "from": { + "description": "The account that the token transfered from", + "type": [ + "string", + "null" + ] + }, + "msg": { + "$ref": "#/definitions/Binary" + }, + "operator": { + "description": "The account that executed the send message", + "type": "string" + }, + "token_id": { + "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" + }, + "Uint128": { + "type": "string" + } + } +} diff --git a/contracts/cw1155-base/schema/instantiate_msg.json b/contracts/cw1155-base/schema/instantiate_msg.json new file mode 100644 index 000000000..3f5eaf0ce --- /dev/null +++ b/contracts/cw1155-base/schema/instantiate_msg.json @@ -0,0 +1,14 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "InstantiateMsg", + "type": "object", + "required": [ + "minter" + ], + "properties": { + "minter": { + "description": "The minter is the only one who can create new tokens. This is designed for a base token platform that is controlled by an external program or contract.", + "type": "string" + } + } +} diff --git a/contracts/cw1155-base/schema/is_approved_for_all_response.json b/contracts/cw1155-base/schema/is_approved_for_all_response.json new file mode 100644 index 000000000..e3af7a983 --- /dev/null +++ b/contracts/cw1155-base/schema/is_approved_for_all_response.json @@ -0,0 +1,13 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "IsApprovedForAllResponse", + "type": "object", + "required": [ + "approved" + ], + "properties": { + "approved": { + "type": "boolean" + } + } +} diff --git a/contracts/cw1155-base/schema/token_info_response.json b/contracts/cw1155-base/schema/token_info_response.json new file mode 100644 index 000000000..a94af98e3 --- /dev/null +++ b/contracts/cw1155-base/schema/token_info_response.json @@ -0,0 +1,14 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "TokenInfoResponse", + "type": "object", + "required": [ + "url" + ], + "properties": { + "url": { + "description": "Should be a url point to a json file", + "type": "string" + } + } +} diff --git a/contracts/cw1155-base/schema/tokens_response.json b/contracts/cw1155-base/schema/tokens_response.json new file mode 100644 index 000000000..b8e3d75b5 --- /dev/null +++ b/contracts/cw1155-base/schema/tokens_response.json @@ -0,0 +1,17 @@ +{ + "$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/contracts/cw1155-base/src/contract.rs b/contracts/cw1155-base/src/contract.rs index 940a60f2b..8f7483e56 100644 --- a/contracts/cw1155-base/src/contract.rs +++ b/contracts/cw1155-base/src/contract.rs @@ -1,11 +1,11 @@ use cosmwasm_std::entry_point; use cosmwasm_std::{ - to_binary, Api, Binary, Deps, DepsMut, Env, HumanAddr, MessageInfo, Order, Response, StdResult, - Uint128, KV, + to_binary, Addr, Binary, Deps, DepsMut, Env, MessageInfo, Order, Pair, Response, StdResult, + Uint128, }; use cw_storage_plus::Bound; -use cw0::{maybe_canonical, Event}; +use cw0::{maybe_addr, Event}; use cw1155::{ ApproveAllEvent, ApprovedForAllResponse, BalanceResponse, BatchBalanceResponse, Cw1155BatchReceiveMsg, Cw1155ExecuteMsg, Cw1155QueryMsg, Cw1155ReceiveMsg, Expiration, @@ -14,7 +14,7 @@ use cw1155::{ use cw2::set_contract_version; use crate::error::ContractError; -use crate::msg::InitMsg; +use crate::msg::InstantiateMsg; use crate::state::{APPROVES, BALANCES, MINTER, TOKENS}; // version info for migration info @@ -29,10 +29,10 @@ pub fn instantiate( deps: DepsMut, _env: Env, _info: MessageInfo, - msg: InitMsg, + msg: InstantiateMsg, ) -> StdResult { set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; - let minter = deps.api.canonical_address(&msg.minter)?; + let minter = deps.api.addr_validate(&msg.minter)?; MINTER.save(deps.storage, &minter)?; Ok(Response::default()) } @@ -93,52 +93,47 @@ pub fn execute( /// Make sure permissions are checked before calling this. fn execute_transfer_inner<'a>( deps: &'a mut DepsMut, - from: Option<&'a HumanAddr>, - to: Option<&'a HumanAddr>, + from: Option<&'a Addr>, + to: Option<&'a Addr>, token_id: &'a str, amount: Uint128, ) -> Result, ContractError> { - if let Some(from) = from { - let from_raw = deps.api.canonical_address(from)?; + if let Some(from_addr) = from { BALANCES.update( deps.storage, - (from_raw.as_slice(), token_id), - |balance: Option| balance.unwrap_or_default() - amount, + (from_addr, token_id), + |balance: Option| -> StdResult<_> { + Ok(balance.unwrap_or_default().checked_sub(amount)?) + }, )?; } - if let Some(to) = to { - let canonical_to = deps.api.canonical_address(to)?; + if let Some(to_addr) = to { BALANCES.update( deps.storage, - (canonical_to.as_slice(), token_id), - |balance: Option| -> StdResult<_> { Ok(balance.unwrap_or_default() + amount) }, + (to_addr, token_id), + |balance: Option| -> StdResult<_> { + Ok(balance.unwrap_or_default().checked_add(amount)?) + }, )?; } Ok(TransferEvent { - from, - to, + from: from.map(|x| x.as_ref()), + to: to.map(|x| x.as_ref()), token_id, amount, }) } /// returns true iff the sender can execute approve or reject on the contract -fn check_can_approve( - deps: Deps, - env: &Env, - owner: &HumanAddr, - operator: &HumanAddr, -) -> StdResult { +fn check_can_approve(deps: Deps, env: &Env, owner: &Addr, operator: &Addr) -> StdResult { // owner can approve - let owner_raw = deps.api.canonical_address(owner)?; - let operator_raw = deps.api.canonical_address(operator)?; - if owner_raw == operator_raw { + if owner == operator { return Ok(true); } // operator can approve - let op = APPROVES.may_load(deps.storage, (&owner_raw, &operator_raw))?; + let op = APPROVES.may_load(deps.storage, (&owner, &operator))?; Ok(match op { Some(ex) => !ex.is_expired(&env.block), None => false, @@ -148,8 +143,8 @@ fn check_can_approve( fn guard_can_approve( deps: Deps, env: &Env, - owner: &HumanAddr, - operator: &HumanAddr, + owner: &Addr, + operator: &Addr, ) -> Result<(), ContractError> { if !check_can_approve(deps, env, owner, operator)? { Err(ContractError::Unauthorized {}) @@ -160,29 +155,38 @@ fn guard_can_approve( pub fn execute_send_from( env: ExecuteEnv, - from: HumanAddr, - to: HumanAddr, + from: String, + to: String, token_id: TokenId, amount: Uint128, msg: Option, ) -> Result { + let from_addr = env.deps.api.addr_validate(&from)?; + let to_addr = env.deps.api.addr_validate(&to)?; + let ExecuteEnv { mut deps, env, info, } = env; - guard_can_approve(deps.as_ref(), &env, &from, &info.sender)?; + guard_can_approve(deps.as_ref(), &env, &from_addr, &info.sender)?; let mut rsp = Response::default(); - let event = execute_transfer_inner(&mut deps, Some(&from), Some(&to), &token_id, amount)?; + let event = execute_transfer_inner( + &mut deps, + Some(&from_addr), + Some(&to_addr), + &token_id, + amount, + )?; event.add_attributes(&mut rsp); if let Some(msg) = msg { rsp.messages = vec![Cw1155ReceiveMsg { - operator: info.sender, - from: Some(from.clone()), + operator: info.sender.to_string(), + from: Some(from), amount, token_id: token_id.clone(), msg, @@ -195,26 +199,27 @@ pub fn execute_send_from( pub fn execute_mint( env: ExecuteEnv, - to: HumanAddr, + to: String, token_id: TokenId, amount: Uint128, msg: Option, ) -> Result { let ExecuteEnv { mut deps, info, .. } = env; - let sender = deps.api.canonical_address(&info.sender)?; - if sender != MINTER.load(deps.storage)? { + let to_addr = deps.api.addr_validate(&to)?; + + if info.sender != MINTER.load(deps.storage)? { return Err(ContractError::Unauthorized {}); } let mut rsp = Response::default(); - let event = execute_transfer_inner(&mut deps, None, Some(&to), &token_id, amount)?; + let event = execute_transfer_inner(&mut deps, None, Some(&to_addr), &token_id, amount)?; event.add_attributes(&mut rsp); if let Some(msg) = msg { rsp.messages = vec![Cw1155ReceiveMsg { - operator: info.sender, + operator: info.sender.to_string(), from: None, amount, token_id: token_id.clone(), @@ -234,7 +239,7 @@ pub fn execute_mint( pub fn execute_burn( env: ExecuteEnv, - from: HumanAddr, + from: String, token_id: TokenId, amount: Uint128, ) -> Result { @@ -244,19 +249,21 @@ pub fn execute_burn( env, } = env; + let from_addr = deps.api.addr_validate(&from)?; + // whoever can transfer these tokens can burn - guard_can_approve(deps.as_ref(), &env, &from, &info.sender)?; + guard_can_approve(deps.as_ref(), &env, &from_addr, &info.sender)?; let mut rsp = Response::default(); - let event = execute_transfer_inner(&mut deps, Some(&from), None, &token_id, amount)?; + let event = execute_transfer_inner(&mut deps, Some(&from_addr), None, &token_id, amount)?; event.add_attributes(&mut rsp); Ok(rsp) } pub fn execute_batch_send_from( env: ExecuteEnv, - from: HumanAddr, - to: HumanAddr, + from: String, + to: String, batch: Vec<(TokenId, Uint128)>, msg: Option, ) -> Result { @@ -266,17 +273,26 @@ pub fn execute_batch_send_from( info, } = env; - guard_can_approve(deps.as_ref(), &env, &from, &info.sender)?; + let from_addr = deps.api.addr_validate(&from)?; + let to_addr = deps.api.addr_validate(&to)?; + + guard_can_approve(deps.as_ref(), &env, &from_addr, &info.sender)?; let mut rsp = Response::default(); for (token_id, amount) in batch.iter() { - let event = execute_transfer_inner(&mut deps, Some(&from), Some(&to), token_id, *amount)?; + let event = execute_transfer_inner( + &mut deps, + Some(&from_addr), + Some(&to_addr), + token_id, + *amount, + )?; event.add_attributes(&mut rsp); } if let Some(msg) = msg { rsp.messages = vec![Cw1155BatchReceiveMsg { - operator: info.sender, + operator: info.sender.to_string(), from: Some(from), batch, msg, @@ -289,20 +305,21 @@ pub fn execute_batch_send_from( pub fn execute_batch_mint( env: ExecuteEnv, - to: HumanAddr, + to: String, batch: Vec<(TokenId, Uint128)>, msg: Option, ) -> Result { let ExecuteEnv { mut deps, info, .. } = env; - let sender = deps.api.canonical_address(&info.sender)?; - if sender != MINTER.load(deps.storage)? { + if info.sender != MINTER.load(deps.storage)? { return Err(ContractError::Unauthorized {}); } + let to_addr = deps.api.addr_validate(&to)?; + let mut rsp = Response::default(); for (token_id, amount) in batch.iter() { - let event = execute_transfer_inner(&mut deps, None, Some(&to), &token_id, *amount)?; + let event = execute_transfer_inner(&mut deps, None, Some(&to_addr), &token_id, *amount)?; event.add_attributes(&mut rsp); // insert if not exist @@ -315,7 +332,7 @@ pub fn execute_batch_mint( if let Some(msg) = msg { rsp.messages = vec![Cw1155BatchReceiveMsg { - operator: info.sender, + operator: info.sender.to_string(), from: None, batch, msg, @@ -328,7 +345,7 @@ pub fn execute_batch_mint( pub fn execute_batch_burn( env: ExecuteEnv, - from: HumanAddr, + from: String, batch: Vec<(TokenId, Uint128)>, ) -> Result { let ExecuteEnv { @@ -337,11 +354,13 @@ pub fn execute_batch_burn( env, } = env; - guard_can_approve(deps.as_ref(), &env, &from, &info.sender)?; + let from_addr = deps.api.addr_validate(&from)?; + + guard_can_approve(deps.as_ref(), &env, &from_addr, &info.sender)?; let mut rsp = Response::default(); for (token_id, amount) in batch.into_iter() { - let event = execute_transfer_inner(&mut deps, Some(&from), None, &token_id, amount)?; + let event = execute_transfer_inner(&mut deps, Some(&from_addr), None, &token_id, amount)?; event.add_attributes(&mut rsp); } Ok(rsp) @@ -349,7 +368,7 @@ pub fn execute_batch_burn( pub fn execute_approve_all( env: ExecuteEnv, - operator: HumanAddr, + operator: String, expires: Option, ) -> Result { let ExecuteEnv { deps, info, env } = env; @@ -361,13 +380,12 @@ pub fn execute_approve_all( } // set the operator for us - let sender_raw = deps.api.canonical_address(&info.sender)?; - let operator_raw = deps.api.canonical_address(&operator)?; - APPROVES.save(deps.storage, (&sender_raw, &operator_raw), &expires)?; + let operator_addr = deps.api.addr_validate(&operator)?; + APPROVES.save(deps.storage, (&info.sender, &operator_addr), &expires)?; let mut rsp = Response::default(); ApproveAllEvent { - sender: &info.sender, + sender: info.sender.as_ref(), operator: &operator, approved: true, } @@ -375,15 +393,14 @@ pub fn execute_approve_all( Ok(rsp) } -pub fn execute_revoke_all(env: ExecuteEnv, operator: HumanAddr) -> Result { +pub fn execute_revoke_all(env: ExecuteEnv, operator: String) -> Result { let ExecuteEnv { deps, info, .. } = env; - let sender_raw = deps.api.canonical_address(&info.sender)?; - let operator_raw = deps.api.canonical_address(&operator)?; - APPROVES.remove(deps.storage, (&sender_raw, &operator_raw)); + let operator_addr = deps.api.addr_validate(&operator)?; + APPROVES.remove(deps.storage, (&info.sender, &operator_addr)); let mut rsp = Response::default(); ApproveAllEvent { - sender: &info.sender, + sender: info.sender.as_ref(), operator: &operator, approved: false, } @@ -395,26 +412,28 @@ pub fn execute_revoke_all(env: ExecuteEnv, operator: HumanAddr) -> Result StdResult { match msg { Cw1155QueryMsg::Balance { owner, token_id } => { - let canonical_owner = deps.api.canonical_address(&owner)?; + let owner_addr = deps.api.addr_validate(&owner)?; let balance = BALANCES - .may_load(deps.storage, (canonical_owner.as_slice(), &token_id))? + .may_load(deps.storage, (&owner_addr, &token_id))? .unwrap_or_default(); to_binary(&BalanceResponse { balance }) } Cw1155QueryMsg::BatchBalance { owner, token_ids } => { - let canonical_owner = deps.api.canonical_address(&owner)?; + let owner_addr = deps.api.addr_validate(&owner)?; let balances = token_ids .into_iter() .map(|token_id| -> StdResult<_> { Ok(BALANCES - .may_load(deps.storage, (canonical_owner.as_slice(), &token_id))? + .may_load(deps.storage, (&owner_addr, &token_id))? .unwrap_or_default()) }) .collect::>()?; to_binary(&BatchBalanceResponse { balances }) } Cw1155QueryMsg::IsApprovedForAll { owner, operator } => { - let approved = check_can_approve(deps, &env, &owner, &operator)?; + let owner_addr = deps.api.addr_validate(&owner)?; + let operator_addr = deps.api.addr_validate(&operator)?; + let approved = check_can_approve(deps, &env, &owner_addr, &operator_addr)?; to_binary(&IsApprovedForAllResponse { approved }) } Cw1155QueryMsg::ApprovedForAll { @@ -422,14 +441,18 @@ pub fn query(deps: Deps, env: Env, msg: Cw1155QueryMsg) -> StdResult { include_expired, start_after, limit, - } => to_binary(&query_all_approvals( - deps, - env, - owner, - include_expired.unwrap_or(false), - start_after, - limit, - )?), + } => { + let owner_addr = deps.api.addr_validate(&owner)?; + let start_addr = maybe_addr(deps.api, start_after)?; + to_binary(&query_all_approvals( + deps, + env, + owner_addr, + include_expired.unwrap_or(false), + start_addr, + limit, + )?) + } Cw1155QueryMsg::TokenInfo { token_id } => { let url = TOKENS.load(deps.storage, &token_id)?; to_binary(&TokenInfoResponse { url }) @@ -438,16 +461,19 @@ pub fn query(deps: Deps, env: Env, msg: Cw1155QueryMsg) -> StdResult { owner, start_after, limit, - } => to_binary(&query_tokens(deps, owner, start_after, limit)?), + } => { + let owner_addr = deps.api.addr_validate(&owner)?; + to_binary(&query_tokens(deps, owner_addr, start_after, limit)?) + } Cw1155QueryMsg::AllTokens { start_after, limit } => { to_binary(&query_all_tokens(deps, start_after, limit)?) } } } -fn parse_approval(api: &dyn Api, item: StdResult>) -> StdResult { +fn parse_approval(item: StdResult>) -> StdResult { item.and_then(|(k, expires)| { - let spender = api.human_address(&k.into())?; + let spender = String::from_utf8(k)?; Ok(cw1155::Approval { spender, expires }) }) } @@ -455,38 +481,35 @@ fn parse_approval(api: &dyn Api, item: StdResult>) -> StdResult, + start_after: Option, limit: Option, ) -> StdResult { let limit = limit.unwrap_or(DEFAULT_LIMIT).min(MAX_LIMIT) as usize; - let start_canon = maybe_canonical(deps.api, start_after)?; - let start = start_canon.map(Bound::exclusive); + let start = start_after.map(|addr| Bound::exclusive(addr.as_ref())); - let owner_raw = deps.api.canonical_address(&owner)?; let operators = APPROVES - .prefix(&owner_raw) + .prefix(&owner) .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(|item| parse_approval(deps.api, item)) + .map(parse_approval) .collect::>()?; Ok(ApprovedForAllResponse { operators }) } fn query_tokens( deps: Deps, - owner: HumanAddr, + owner: Addr, 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_raw = deps.api.canonical_address(&owner)?; let tokens = BALANCES - .prefix(&owner_raw) + .prefix(&owner) .range(deps.storage, start, None, Order::Ascending) .take(limit) .map(|item| item.map(|(k, _)| String::from_utf8(k).unwrap())) @@ -511,8 +534,8 @@ fn query_all_tokens( #[cfg(test)] mod tests { - use cosmwasm_std::attr; use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info}; + use cosmwasm_std::{attr, OverflowError, StdError}; use super::*; @@ -539,12 +562,12 @@ mod tests { let token1 = "token1".to_owned(); let token2 = "token2".to_owned(); let token3 = "token3".to_owned(); - let minter: HumanAddr = "minter".into(); - let user1: HumanAddr = "user1".into(); - let user2: HumanAddr = "user2".into(); + let minter = String::from("minter"); + let user1 = String::from("user1"); + let user2 = String::from("user2"); let mut deps = mock_dependencies(&[]); - let msg = InitMsg { + let msg = InstantiateMsg { minter: minter.clone(), }; let res = instantiate(deps.as_mut(), mock_env(), mock_info("operator", &[]), msg).unwrap(); @@ -561,7 +584,7 @@ mod tests { execute( deps.as_mut(), mock_env(), - mock_info(user1.clone(), &[]), + mock_info(user1.as_ref(), &[]), mint_msg.clone(), ), Err(ContractError::Unauthorized {}) @@ -572,7 +595,7 @@ mod tests { execute( deps.as_mut(), mock_env(), - mock_info(minter.clone(), &[]), + mock_info(minter.as_ref(), &[]), mint_msg, ) .unwrap(), @@ -615,7 +638,7 @@ mod tests { execute( deps.as_mut(), mock_env(), - mock_info(minter.clone(), &[]), + mock_info(minter.as_ref(), &[]), transfer_msg.clone(), ), Err(ContractError::Unauthorized {}) @@ -625,7 +648,7 @@ mod tests { execute( deps.as_mut(), mock_env(), - mock_info(user1.clone(), &[]), + mock_info(user1.as_ref(), &[]), Cw1155ExecuteMsg::ApproveAll { operator: minter.clone(), expires: None, @@ -638,8 +661,8 @@ mod tests { execute( deps.as_mut(), mock_env(), - mock_info(minter.clone(), &[]), - transfer_msg.clone(), + mock_info(minter.as_ref(), &[]), + transfer_msg, ) .unwrap(), Response { @@ -687,7 +710,7 @@ mod tests { execute( deps.as_mut(), mock_env(), - mock_info(minter.clone(), &[]), + mock_info(minter.as_ref(), &[]), Cw1155ExecuteMsg::BatchMint { to: user2.clone(), batch: vec![(token2.clone(), 1u64.into()), (token3.clone(), 1u64.into())], @@ -725,7 +748,7 @@ mod tests { execute( deps.as_mut(), mock_env(), - mock_info(minter.clone(), &[]), + mock_info(minter.as_ref(), &[]), batch_transfer_msg.clone(), ), Err(ContractError::Unauthorized {}), @@ -735,7 +758,7 @@ mod tests { execute( deps.as_mut(), mock_env(), - mock_info(user2.clone(), &[]), + mock_info(user2.as_ref(), &[]), Cw1155ExecuteMsg::ApproveAll { operator: minter.clone(), expires: None, @@ -748,7 +771,7 @@ mod tests { execute( deps.as_mut(), mock_env(), - mock_info(minter.clone(), &[]), + mock_info(minter.as_ref(), &[]), batch_transfer_msg, ) .unwrap(), @@ -793,7 +816,7 @@ mod tests { execute( deps.as_mut(), mock_env(), - mock_info(user1.clone(), &[]), + mock_info(user1.as_ref(), &[]), Cw1155ExecuteMsg::RevokeAll { operator: minter.clone(), }, @@ -818,10 +841,10 @@ mod tests { execute( deps.as_mut(), mock_env(), - mock_info(minter.clone(), &[]), + mock_info(minter.as_ref(), &[]), Cw1155ExecuteMsg::SendFrom { from: user1.clone(), - to: user2.clone(), + to: user2, token_id: token1.clone(), value: 1u64.into(), msg: None, @@ -835,7 +858,7 @@ mod tests { execute( deps.as_mut(), mock_env(), - mock_info(user1.clone(), &[]), + mock_info(user1.as_ref(), &[]), Cw1155ExecuteMsg::Burn { from: user1.clone(), token_id: token1.clone(), @@ -859,7 +882,7 @@ mod tests { execute( deps.as_mut(), mock_env(), - mock_info(user1.clone(), &[]), + mock_info(user1.as_ref(), &[]), Cw1155ExecuteMsg::BatchBurn { from: user1.clone(), batch: vec![(token2.clone(), 1u64.into()), (token3.clone(), 1u64.into())] @@ -884,15 +907,15 @@ mod tests { #[test] fn check_send_contract() { - let receiver: HumanAddr = "receive_contract".into(); - let minter: HumanAddr = "minter".into(); - let user1: HumanAddr = "user1".into(); + let receiver = String::from("receive_contract"); + let minter = String::from("minter"); + let user1 = String::from("user1"); let token1 = "token1".to_owned(); let token2 = "token2".to_owned(); let dummy_msg = Binary::default(); let mut deps = mock_dependencies(&[]); - let msg = InitMsg { + let msg = InstantiateMsg { minter: minter.clone(), }; let res = instantiate(deps.as_mut(), mock_env(), mock_info("operator", &[]), msg).unwrap(); @@ -901,7 +924,7 @@ mod tests { execute( deps.as_mut(), mock_env(), - mock_info(minter.clone(), &[]), + mock_info(minter.as_ref(), &[]), Cw1155ExecuteMsg::Mint { to: user1.clone(), token_id: token2.clone(), @@ -916,7 +939,7 @@ mod tests { execute( deps.as_mut(), mock_env(), - mock_info(minter.clone(), &[]), + mock_info(minter.as_ref(), &[]), Cw1155ExecuteMsg::Mint { to: receiver.clone(), token_id: token1.clone(), @@ -950,7 +973,7 @@ mod tests { execute( deps.as_mut(), mock_env(), - mock_info(user1.clone(), &[]), + mock_info(user1.as_ref(), &[]), Cw1155ExecuteMsg::BatchSendFrom { from: user1.clone(), to: receiver.clone(), @@ -964,7 +987,7 @@ mod tests { operator: user1.clone(), from: Some(user1.clone()), batch: vec![(token2.clone(), 1u64.into())], - msg: dummy_msg.clone(), + msg: dummy_msg, } .into_cosmos_msg(receiver.clone()) .unwrap()], @@ -985,13 +1008,11 @@ mod tests { // mint multiple types of tokens, and query them // grant approval to multiple operators, and query them let tokens = (0..10).map(|i| format!("token{}", i)).collect::>(); - let users = (0..10) - .map(|i| HumanAddr::from(format!("user{}", i))) - .collect::>(); - let minter: HumanAddr = "minter".into(); + let users = (0..10).map(|i| format!("user{}", i)).collect::>(); + let minter = String::from("minter"); let mut deps = mock_dependencies(&[]); - let msg = InitMsg { + let msg = InstantiateMsg { minter: minter.clone(), }; let res = instantiate(deps.as_mut(), mock_env(), mock_info("operator", &[]), msg).unwrap(); @@ -1000,7 +1021,7 @@ mod tests { execute( deps.as_mut(), mock_env(), - mock_info(minter.clone(), &[]), + mock_info(minter.as_ref(), &[]), Cw1155ExecuteMsg::BatchMint { to: users[0].clone(), batch: tokens @@ -1071,7 +1092,7 @@ mod tests { execute( deps.as_mut(), mock_env(), - mock_info(users[0].clone(), &[]), + mock_info(users[0].as_ref(), &[]), Cw1155ExecuteMsg::ApproveAll { operator: user.clone(), expires: None, @@ -1087,14 +1108,13 @@ mod tests { Cw1155QueryMsg::ApprovedForAll { owner: users[0].clone(), include_expired: None, - start_after: Some("user2".into()), + start_after: Some(String::from("user2")), limit: Some(1), }, ), to_binary(&ApprovedForAllResponse { operators: vec![cw1155::Approval { - // Not ordered in the same way as HumanAddr - spender: users[8].clone().into(), + spender: users[3].clone(), expires: Expiration::Never {} }], }) @@ -1105,9 +1125,9 @@ mod tests { fn approval_expires() { let mut deps = mock_dependencies(&[]); let token1 = "token1".to_owned(); - let minter: HumanAddr = "minter".into(); - let user1: HumanAddr = "user1".into(); - let user2: HumanAddr = "user2".into(); + let minter = String::from("minter"); + let user1 = String::from("user1"); + let user2 = String::from("user2"); let env = { let mut env = mock_env(); @@ -1115,7 +1135,7 @@ mod tests { env }; - let msg = InitMsg { + let msg = InstantiateMsg { minter: minter.clone(), }; let res = instantiate(deps.as_mut(), env.clone(), mock_info("operator", &[]), msg).unwrap(); @@ -1124,10 +1144,10 @@ mod tests { execute( deps.as_mut(), env.clone(), - mock_info(minter.clone(), &[]), + mock_info(minter.as_ref(), &[]), Cw1155ExecuteMsg::Mint { to: user1.clone(), - token_id: token1.clone(), + token_id: token1, value: 1u64.into(), msg: None, }, @@ -1139,7 +1159,7 @@ mod tests { execute( deps.as_mut(), env.clone(), - mock_info(user1.clone(), &[]), + mock_info(user1.as_ref(), &[]), Cw1155ExecuteMsg::ApproveAll { operator: user2.clone(), expires: Some(Expiration::AtHeight(5)), @@ -1151,7 +1171,7 @@ mod tests { execute( deps.as_mut(), env.clone(), - mock_info(user1.clone(), &[]), + mock_info(user1.as_ref(), &[]), Cw1155ExecuteMsg::ApproveAll { operator: user2.clone(), expires: Some(Expiration::AtHeight(100)), @@ -1160,8 +1180,8 @@ mod tests { .unwrap(); let query_msg = Cw1155QueryMsg::IsApprovedForAll { - owner: user1.clone(), - operator: user2.clone(), + owner: user1, + operator: user2, }; assert_eq!( query(deps.as_ref(), env, query_msg.clone()), @@ -1181,20 +1201,14 @@ mod tests { } #[test] - #[should_panic(expected = "attempt to add with overflow")] fn mint_overflow() { let mut deps = mock_dependencies(&[]); let token1 = "token1".to_owned(); - let minter: HumanAddr = "minter".into(); - let user1: HumanAddr = "user1".into(); + let minter = String::from("minter"); + let user1 = String::from("user1"); - let env = { - let mut env = mock_env(); - env.block.height = 10; - env - }; - - let msg = InitMsg { + let env = mock_env(); + let msg = InstantiateMsg { minter: minter.clone(), }; let res = instantiate(deps.as_mut(), env.clone(), mock_info("operator", &[]), msg).unwrap(); @@ -1203,7 +1217,7 @@ mod tests { execute( deps.as_mut(), env.clone(), - mock_info(minter.clone(), &[]), + mock_info(minter.as_ref(), &[]), Cw1155ExecuteMsg::Mint { to: user1.clone(), token_id: token1.clone(), @@ -1213,17 +1227,22 @@ mod tests { ) .unwrap(); - execute( - deps.as_mut(), - env.clone(), - mock_info(minter.clone(), &[]), - Cw1155ExecuteMsg::Mint { - to: user1.clone(), - token_id: token1.clone(), - value: 1u64.into(), - msg: None, - }, - ) - .unwrap(); + assert!(matches!( + execute( + deps.as_mut(), + env, + mock_info(minter.as_ref(), &[]), + Cw1155ExecuteMsg::Mint { + to: user1, + token_id: token1, + value: 1u64.into(), + msg: None, + }, + ), + Err(ContractError::Std(StdError::Overflow { + source: OverflowError { .. }, + .. + })) + )); } } diff --git a/contracts/cw1155-base/src/lib.rs b/contracts/cw1155-base/src/lib.rs index cbb841796..d033df0d8 100644 --- a/contracts/cw1155-base/src/lib.rs +++ b/contracts/cw1155-base/src/lib.rs @@ -2,3 +2,5 @@ pub mod contract; mod error; mod msg; mod state; + +pub use msg::InstantiateMsg; diff --git a/contracts/cw1155-base/src/msg.rs b/contracts/cw1155-base/src/msg.rs index b0a44069a..4962c81c0 100644 --- a/contracts/cw1155-base/src/msg.rs +++ b/contracts/cw1155-base/src/msg.rs @@ -1,11 +1,10 @@ -use cosmwasm_std::HumanAddr; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] -pub struct InitMsg { +pub struct InstantiateMsg { /// The minter is the only one who can create new tokens. /// This is designed for a base token platform that is controlled by an external program or /// contract. - pub minter: HumanAddr, + pub minter: String, } diff --git a/contracts/cw1155-base/src/state.rs b/contracts/cw1155-base/src/state.rs index f701ec4b1..1238f5094 100644 --- a/contracts/cw1155-base/src/state.rs +++ b/contracts/cw1155-base/src/state.rs @@ -1,13 +1,13 @@ -use cosmwasm_std::{CanonicalAddr, Uint128}; +use cosmwasm_std::{Addr, Uint128}; use cw1155::Expiration; use cw_storage_plus::{Item, Map}; /// Store the minter address who have permission to mint new tokens. -pub const MINTER: Item = Item::new("minter"); +pub const MINTER: Item = Item::new("minter"); /// Store the balance map, `(owner, token_id) -> balance` -pub const BALANCES: Map<(&[u8], &str), Uint128> = Map::new("balances"); +pub const BALANCES: Map<(&Addr, &str), Uint128> = Map::new("balances"); /// Store the approval status, `(owner, spender) -> expiration` -pub const APPROVES: Map<(&[u8], &[u8]), Expiration> = Map::new("approves"); +pub const APPROVES: Map<(&Addr, &Addr), Expiration> = Map::new("approves"); /// Store the tokens metadata url, also supports enumerating tokens, /// An entry for token_id must exist as long as there's tokens in circulation. pub const TOKENS: Map<&str, String> = Map::new("tokens"); diff --git a/contracts/cw20-atomic-swap/Cargo.toml b/contracts/cw20-atomic-swap/Cargo.toml index d4dff37d8..801f6b1f6 100644 --- a/contracts/cw20-atomic-swap/Cargo.toml +++ b/contracts/cw20-atomic-swap/Cargo.toml @@ -18,13 +18,13 @@ library = [] cw0 = { path = "../../packages/cw0", version = "0.6.0-alpha3" } cw2 = { path = "../../packages/cw2", version = "0.6.0-alpha3" } cw20 = { path = "../../packages/cw20", version = "0.6.0-alpha3" } -cosmwasm-std = { version = "0.14.0-beta1", features = ["iterator"] } +cosmwasm-std = { version = "0.14.0-beta2", features = ["iterator"] } cw-storage-plus = { path = "../../packages/storage-plus", version = "0.6.0-alpha3", features = ["iterator"] } -schemars = "0.7" +schemars = "0.8.1" serde = { version = "1.0.103", default-features = false, features = ["derive"] } thiserror = { version = "1.0.20" } hex = "0.3.1" sha2 = "0.8.0" [dev-dependencies] -cosmwasm-schema = { version = "0.14.0-beta1" } +cosmwasm-schema = { version = "0.14.0-beta2" } diff --git a/contracts/cw20-atomic-swap/schema/details_response.json b/contracts/cw20-atomic-swap/schema/details_response.json index 3e3d3c94e..c8404de1d 100644 --- a/contracts/cw20-atomic-swap/schema/details_response.json +++ b/contracts/cw20-atomic-swap/schema/details_response.json @@ -12,7 +12,7 @@ ], "properties": { "balance": { - "description": "Balance in native tokens or cw20 token, with human address", + "description": "Balance in native tokens or cw20 token, with human-readable address", "allOf": [ { "$ref": "#/definitions/BalanceHuman" @@ -37,19 +37,11 @@ }, "recipient": { "description": "If released, funds go to the recipient", - "allOf": [ - { - "$ref": "#/definitions/HumanAddr" - } - ] + "type": "string" }, "source": { "description": "If refunded, funds go to the source", - "allOf": [ - { - "$ref": "#/definitions/HumanAddr" - } - ] + "type": "string" } }, "definitions": { @@ -67,7 +59,8 @@ "$ref": "#/definitions/Coin" } } - } + }, + "additionalProperties": false }, { "type": "object", @@ -76,9 +69,10 @@ ], "properties": { "Cw20": { - "$ref": "#/definitions/Cw20CoinHuman" + "$ref": "#/definitions/Cw20Coin" } - } + }, + "additionalProperties": false } ] }, @@ -97,7 +91,7 @@ } } }, - "Cw20CoinHuman": { + "Cw20Coin": { "type": "object", "required": [ "address", @@ -105,7 +99,7 @@ ], "properties": { "address": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "amount": { "$ref": "#/definitions/Uint128" @@ -127,7 +121,8 @@ "format": "uint64", "minimum": 0.0 } - } + }, + "additionalProperties": false }, { "description": "AtTime will expire when `env.block.time` >= time", @@ -141,7 +136,8 @@ "format": "uint64", "minimum": 0.0 } - } + }, + "additionalProperties": false }, { "description": "Never will never expire. Used to express the empty variant", @@ -153,13 +149,11 @@ "never": { "type": "object" } - } + }, + "additionalProperties": false } ] }, - "HumanAddr": { - "type": "string" - }, "Uint128": { "type": "string" } diff --git a/contracts/cw20-atomic-swap/schema/execute_msg.json b/contracts/cw20-atomic-swap/schema/execute_msg.json index a19027d2a..71133e048 100644 --- a/contracts/cw20-atomic-swap/schema/execute_msg.json +++ b/contracts/cw20-atomic-swap/schema/execute_msg.json @@ -11,7 +11,8 @@ "create": { "$ref": "#/definitions/CreateMsg" } - } + }, + "additionalProperties": false }, { "description": "Release sends all tokens to the recipient.", @@ -36,7 +37,8 @@ } } } - } + }, + "additionalProperties": false }, { "description": "Refund returns all remaining tokens to the original sender,", @@ -56,7 +58,8 @@ } } } - } + }, + "additionalProperties": false }, { "description": "This accepts a properly-encoded ReceiveMsg from a cw20 contract", @@ -68,7 +71,8 @@ "receive": { "$ref": "#/definitions/Cw20ReceiveMsg" } - } + }, + "additionalProperties": false } ], "definitions": { @@ -103,11 +107,7 @@ }, "recipient": { "description": "If approved, funds go to the recipient", - "allOf": [ - { - "$ref": "#/definitions/HumanAddr" - } - ] + "type": "string" } } }, @@ -133,7 +133,7 @@ ] }, "sender": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } }, @@ -152,7 +152,8 @@ "format": "uint64", "minimum": 0.0 } - } + }, + "additionalProperties": false }, { "description": "AtTime will expire when `env.block.time` >= time", @@ -166,7 +167,8 @@ "format": "uint64", "minimum": 0.0 } - } + }, + "additionalProperties": false }, { "description": "Never will never expire. Used to express the empty variant", @@ -178,13 +180,11 @@ "never": { "type": "object" } - } + }, + "additionalProperties": false } ] }, - "HumanAddr": { - "type": "string" - }, "Uint128": { "type": "string" } diff --git a/contracts/cw20-atomic-swap/schema/query_msg.json b/contracts/cw20-atomic-swap/schema/query_msg.json index 582124552..3ada6095d 100644 --- a/contracts/cw20-atomic-swap/schema/query_msg.json +++ b/contracts/cw20-atomic-swap/schema/query_msg.json @@ -28,7 +28,8 @@ } } } - } + }, + "additionalProperties": false }, { "description": "Returns the details of the named swap, error if not created. Return type: DetailsResponse.", @@ -48,7 +49,8 @@ } } } - } + }, + "additionalProperties": false } ] } diff --git a/contracts/cw20-atomic-swap/src/contract.rs b/contracts/cw20-atomic-swap/src/contract.rs index 870301882..cc64ffe74 100644 --- a/contracts/cw20-atomic-swap/src/contract.rs +++ b/contracts/cw20-atomic-swap/src/contract.rs @@ -1,13 +1,13 @@ #[cfg(not(feature = "library"))] use cosmwasm_std::entry_point; use cosmwasm_std::{ - attr, from_binary, to_binary, Api, BankMsg, Binary, CosmosMsg, Deps, DepsMut, Env, HumanAddr, + attr, from_binary, to_binary, Addr, BankMsg, Binary, CosmosMsg, Deps, DepsMut, Env, MessageInfo, Response, StdResult, WasmMsg, }; use sha2::{Digest, Sha256}; use cw2::set_contract_version; -use cw20::{Balance, Cw20Coin, Cw20CoinHuman, Cw20ExecuteMsg, Cw20ReceiveMsg}; +use cw20::{Balance, Cw20Coin, Cw20CoinVerified, Cw20ExecuteMsg, Cw20ReceiveMsg}; use crate::error::ContractError; use crate::msg::{ @@ -61,13 +61,13 @@ pub fn execute_receive( Some(bin) => Ok(from_binary(&bin)?), None => Err(ContractError::NoData {}), }?; - let token = Cw20Coin { - address: deps.api.canonical_address(&info.sender)?, + let token = Cw20CoinVerified { + address: info.sender, amount: wrapper.amount, }; // we need to update the info... so the original sender is the one authorizing with these tokens let orig_info = MessageInfo { - sender: wrapper.sender, + sender: deps.api.addr_validate(&wrapper.sender)?, funds: info.funds, }; match msg { @@ -100,12 +100,12 @@ pub fn execute_create( return Err(ContractError::Expired {}); } - let recipient_raw = deps.api.canonical_address(&msg.recipient)?; + let recipient = deps.api.addr_validate(&msg.recipient)?; let swap = AtomicSwap { hash: Binary(hash), - recipient: recipient_raw, - source: deps.api.canonical_address(&info.sender)?, + recipient, + source: info.sender, expires: msg.expires, balance, }; @@ -144,13 +144,11 @@ pub fn execute_release( return Err(ContractError::InvalidPreimage {}); } - let rcpt = deps.api.human_address(&swap.recipient)?; - // Delete the swap SWAPS.remove(deps.storage, &id); // Send all tokens out - let msgs = send_tokens(deps.api, &rcpt, swap.balance)?; + let msgs = send_tokens(&swap.recipient, swap.balance)?; Ok(Response { submessages: vec![], messages: msgs, @@ -158,7 +156,7 @@ pub fn execute_release( attr("action", "release"), attr("id", id), attr("preimage", preimage), - attr("to", rcpt), + attr("to", swap.recipient.to_string()), ], data: None, }) @@ -171,16 +169,18 @@ pub fn execute_refund(deps: DepsMut, env: Env, id: String) -> Result Result, ContractError> { } } -fn send_tokens(api: &dyn Api, to: &HumanAddr, amount: Balance) -> StdResult> { +fn send_tokens(to: &Addr, amount: Balance) -> StdResult> { if amount.is_empty() { Ok(vec![]) } else { @@ -216,7 +216,7 @@ fn send_tokens(api: &dyn Api, to: &HumanAddr, amount: Balance) -> StdResult StdResult { // Convert balance to human balance let balance_human = match swap.balance { Balance::Native(coins) => BalanceHuman::Native(coins.into_vec()), - Balance::Cw20(coin) => BalanceHuman::Cw20(Cw20CoinHuman { - address: deps.api.human_address(&coin.address)?, + Balance::Cw20(coin) => BalanceHuman::Cw20(Cw20Coin { + address: coin.address.into(), amount: coin.amount, }), }; @@ -249,8 +249,8 @@ fn query_details(deps: Deps, id: String) -> StdResult { let details = DetailsResponse { id, hash: hex::encode(swap.hash.as_slice()), - recipient: deps.api.human_address(&swap.recipient)?, - source: deps.api.human_address(&swap.source)?, + recipient: swap.recipient.into(), + source: swap.source.into(), expires: swap.expires, balance: balance_human, }; @@ -323,7 +323,7 @@ mod tests { let info = mock_info("anyone", &[]); instantiate(deps.as_mut(), mock_env(), info, InstantiateMsg {}).unwrap(); - let sender = HumanAddr::from("sender0001"); + let sender = String::from("sender0001"); let balance = coins(100, "tokens"); // Cannot create, invalid ids @@ -332,7 +332,7 @@ mod tests { let create = CreateMsg { id: id.to_string(), hash: real_hash(), - recipient: HumanAddr::from("rcpt0001"), + recipient: String::from("rcpt0001"), expires: Expiration::AtHeight(123456), }; let err = execute( @@ -443,7 +443,7 @@ mod tests { let info = mock_info("anyone", &[]); instantiate(deps.as_mut(), mock_env(), info, InstantiateMsg {}).unwrap(); - let sender = HumanAddr::from("sender0001"); + let sender = String::from("sender0001"); let balance = coins(1000, "tokens"); let info = mock_info(&sender, &balance); @@ -530,7 +530,7 @@ mod tests { let info = mock_info("anyone", &[]); instantiate(deps.as_mut(), mock_env(), info, InstantiateMsg {}).unwrap(); - let sender = HumanAddr::from("sender0001"); + let sender = String::from("sender0001"); let balance = coins(1000, "tokens"); let info = mock_info(&sender, &balance); @@ -594,8 +594,8 @@ mod tests { let info = mock_info("anyone", &[]); instantiate(deps.as_mut(), mock_env(), info, InstantiateMsg {}).unwrap(); - let sender1 = HumanAddr::from("sender0001"); - let sender2 = HumanAddr::from("sender0002"); + let sender1 = String::from("sender0001"); + let sender2 = String::from("sender0002"); // Same balance for simplicity let balance = coins(1000, "tokens"); @@ -687,8 +687,8 @@ mod tests { assert_eq!(0, res.messages.len()); // Native side (offer) - let native_sender = HumanAddr::from("A_on_X"); - let native_rcpt = HumanAddr::from("B_on_X"); + let native_sender = String::from("A_on_X"); + let native_rcpt = String::from("B_on_X"); let native_coins = coins(1000, "tokens_native"); // Create the Native swap offer @@ -705,10 +705,10 @@ mod tests { assert_eq!(attr("action", "create"), res.attributes[0]); // Cw20 side (counter offer (1:1000)) - let cw20_sender = HumanAddr::from("B_on_Y"); - let cw20_rcpt = HumanAddr::from("A_on_Y"); - let cw20_coin = Cw20CoinHuman { - address: HumanAddr::from("my_cw20_token"), + let cw20_sender = String::from("B_on_Y"); + let cw20_rcpt = String::from("A_on_Y"); + let cw20_coin = Cw20Coin { + address: String::from("my_cw20_token"), amount: Uint128(1), }; diff --git a/contracts/cw20-atomic-swap/src/msg.rs b/contracts/cw20-atomic-swap/src/msg.rs index 5ba75ae16..ed1f583b0 100644 --- a/contracts/cw20-atomic-swap/src/msg.rs +++ b/contracts/cw20-atomic-swap/src/msg.rs @@ -1,8 +1,8 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -use cosmwasm_std::{Coin, HumanAddr}; -use cw20::{Cw20CoinHuman, Cw20ReceiveMsg, Expiration}; +use cosmwasm_std::Coin; +use cw20::{Cw20Coin, Cw20ReceiveMsg, Expiration}; #[derive(Serialize, Deserialize, JsonSchema)] pub struct InstantiateMsg {} @@ -40,7 +40,7 @@ pub struct CreateMsg { /// This is hex-encoded sha-256 hash of the preimage (must be 32*2 = 64 chars) pub hash: String, /// If approved, funds go to the recipient - pub recipient: HumanAddr, + pub recipient: String, /// You can set expiration at time or at block height the contract is valid at. /// After the contract is expired, it can be returned to the original funder. pub expires: Expiration, @@ -80,17 +80,17 @@ pub struct DetailsResponse { /// This is hex-encoded sha-256 hash of the preimage (must be 32*2 = 64 chars) pub hash: String, /// If released, funds go to the recipient - pub recipient: HumanAddr, + pub recipient: String, /// If refunded, funds go to the source - pub source: HumanAddr, + pub source: String, /// Once a swap is expired, it can be returned to the original source (via "refund"). pub expires: Expiration, - /// Balance in native tokens or cw20 token, with human address + /// Balance in native tokens or cw20 token, with human-readable address pub balance: BalanceHuman, } #[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] pub enum BalanceHuman { Native(Vec), - Cw20(Cw20CoinHuman), + Cw20(Cw20Coin), } diff --git a/contracts/cw20-atomic-swap/src/state.rs b/contracts/cw20-atomic-swap/src/state.rs index 20620115d..5b7110ab2 100644 --- a/contracts/cw20-atomic-swap/src/state.rs +++ b/contracts/cw20-atomic-swap/src/state.rs @@ -1,7 +1,7 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -use cosmwasm_std::{Binary, BlockInfo, CanonicalAddr, Order, StdError, StdResult, Storage}; +use cosmwasm_std::{Addr, Binary, BlockInfo, Order, StdError, StdResult, Storage}; use cw_storage_plus::{Bound, Map}; use cw20::{Balance, Expiration}; @@ -10,8 +10,8 @@ use cw20::{Balance, Expiration}; pub struct AtomicSwap { /// This is the sha-256 hash of the preimage pub hash: Binary, - pub recipient: CanonicalAddr, - pub source: CanonicalAddr, + pub recipient: Addr, + pub source: Addr, pub expires: Expiration, /// Balance in native tokens, or cw20 token pub balance: Balance, @@ -54,8 +54,8 @@ mod tests { fn dummy_swap() -> AtomicSwap { AtomicSwap { - recipient: CanonicalAddr(Binary(b"recip".to_vec())), - source: CanonicalAddr(Binary(b"source".to_vec())), + recipient: Addr::unchecked("recip"), + source: Addr::unchecked("source"), expires: Default::default(), hash: Binary("hash".into()), balance: Default::default(), diff --git a/contracts/cw20-base/Cargo.toml b/contracts/cw20-base/Cargo.toml index fc02a8198..9e03a7065 100644 --- a/contracts/cw20-base/Cargo.toml +++ b/contracts/cw20-base/Cargo.toml @@ -22,10 +22,10 @@ cw0 = { path = "../../packages/cw0", version = "0.6.0-alpha3" } cw2 = { path = "../../packages/cw2", version = "0.6.0-alpha3" } cw20 = { path = "../../packages/cw20", version = "0.6.0-alpha3" } cw-storage-plus = { path = "../../packages/storage-plus", version = "0.6.0-alpha3", features = ["iterator"] } -cosmwasm-std = { version = "0.14.0-beta1", features = ["iterator"] } -schemars = "0.7" +cosmwasm-std = { version = "0.14.0-beta2", features = ["iterator"] } +schemars = "0.8.1" serde = { version = "1.0.103", default-features = false, features = ["derive"] } thiserror = { version = "1.0.20" } [dev-dependencies] -cosmwasm-schema = { version = "0.14.0-beta1" } +cosmwasm-schema = { version = "0.14.0-beta2" } diff --git a/contracts/cw20-base/schema/all_accounts_response.json b/contracts/cw20-base/schema/all_accounts_response.json index 8689981c0..cea50fba4 100644 --- a/contracts/cw20-base/schema/all_accounts_response.json +++ b/contracts/cw20-base/schema/all_accounts_response.json @@ -9,13 +9,8 @@ "accounts": { "type": "array", "items": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } - }, - "definitions": { - "HumanAddr": { - "type": "string" - } } } diff --git a/contracts/cw20-base/schema/all_allowances_response.json b/contracts/cw20-base/schema/all_allowances_response.json index b8c365188..1f7d683a6 100644 --- a/contracts/cw20-base/schema/all_allowances_response.json +++ b/contracts/cw20-base/schema/all_allowances_response.json @@ -29,7 +29,7 @@ "$ref": "#/definitions/Expiration" }, "spender": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } }, @@ -48,7 +48,8 @@ "format": "uint64", "minimum": 0.0 } - } + }, + "additionalProperties": false }, { "description": "AtTime will expire when `env.block.time` >= time", @@ -62,7 +63,8 @@ "format": "uint64", "minimum": 0.0 } - } + }, + "additionalProperties": false }, { "description": "Never will never expire. Used to express the empty variant", @@ -74,13 +76,11 @@ "never": { "type": "object" } - } + }, + "additionalProperties": false } ] }, - "HumanAddr": { - "type": "string" - }, "Uint128": { "type": "string" } diff --git a/contracts/cw20-base/schema/allowance_response.json b/contracts/cw20-base/schema/allowance_response.json index 596d84464..5fb08aa98 100644 --- a/contracts/cw20-base/schema/allowance_response.json +++ b/contracts/cw20-base/schema/allowance_response.json @@ -30,7 +30,8 @@ "format": "uint64", "minimum": 0.0 } - } + }, + "additionalProperties": false }, { "description": "AtTime will expire when `env.block.time` >= time", @@ -44,7 +45,8 @@ "format": "uint64", "minimum": 0.0 } - } + }, + "additionalProperties": false }, { "description": "Never will never expire. Used to express the empty variant", @@ -56,7 +58,8 @@ "never": { "type": "object" } - } + }, + "additionalProperties": false } ] }, diff --git a/contracts/cw20-base/schema/execute_msg.json b/contracts/cw20-base/schema/execute_msg.json index 992483c57..771d9e1ad 100644 --- a/contracts/cw20-base/schema/execute_msg.json +++ b/contracts/cw20-base/schema/execute_msg.json @@ -20,11 +20,12 @@ "$ref": "#/definitions/Uint128" }, "recipient": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "Burn is a base message to destroy tokens forever", @@ -44,7 +45,8 @@ } } } - } + }, + "additionalProperties": false }, { "description": "Send is a base message to transfer tokens to a contract and trigger an action on the receiving contract.", @@ -64,7 +66,7 @@ "$ref": "#/definitions/Uint128" }, "contract": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "msg": { "anyOf": [ @@ -78,7 +80,8 @@ } } } - } + }, + "additionalProperties": false }, { "description": "Only with the \"mintable\" extension. If authorized, creates amount new tokens and adds to the recipient balance.", @@ -98,11 +101,12 @@ "$ref": "#/definitions/Uint128" }, "recipient": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "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.", @@ -132,11 +136,12 @@ ] }, "spender": { - "$ref": "#/definitions/HumanAddr" + "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.", @@ -166,11 +171,12 @@ ] }, "spender": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "Only with \"approval\" extension. Transfers amount tokens from owner -> recipient if `env.sender` has sufficient pre-approval.", @@ -191,14 +197,15 @@ "$ref": "#/definitions/Uint128" }, "owner": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "recipient": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "Only with \"approval\" extension. Sends amount tokens from owner -> contract if `env.sender` has sufficient pre-approval.", @@ -219,7 +226,7 @@ "$ref": "#/definitions/Uint128" }, "contract": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "msg": { "anyOf": [ @@ -232,11 +239,12 @@ ] }, "owner": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "Only with \"approval\" extension. Destroys tokens forever", @@ -256,11 +264,12 @@ "$ref": "#/definitions/Uint128" }, "owner": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false } ], "definitions": { @@ -283,7 +292,8 @@ "format": "uint64", "minimum": 0.0 } - } + }, + "additionalProperties": false }, { "description": "AtTime will expire when `env.block.time` >= time", @@ -297,7 +307,8 @@ "format": "uint64", "minimum": 0.0 } - } + }, + "additionalProperties": false }, { "description": "Never will never expire. Used to express the empty variant", @@ -309,13 +320,11 @@ "never": { "type": "object" } - } + }, + "additionalProperties": false } ] }, - "HumanAddr": { - "type": "string" - }, "Uint128": { "type": "string" } diff --git a/contracts/cw20-base/schema/instantiate_msg.json b/contracts/cw20-base/schema/instantiate_msg.json index c7342d9ed..074fffc84 100644 --- a/contracts/cw20-base/schema/instantiate_msg.json +++ b/contracts/cw20-base/schema/instantiate_msg.json @@ -17,7 +17,7 @@ "initial_balances": { "type": "array", "items": { - "$ref": "#/definitions/Cw20CoinHuman" + "$ref": "#/definitions/Cw20Coin" } }, "mint": { @@ -38,7 +38,7 @@ } }, "definitions": { - "Cw20CoinHuman": { + "Cw20Coin": { "type": "object", "required": [ "address", @@ -46,16 +46,13 @@ ], "properties": { "address": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "amount": { "$ref": "#/definitions/Uint128" } } }, - "HumanAddr": { - "type": "string" - }, "MinterResponse": { "type": "object", "required": [ @@ -74,7 +71,7 @@ ] }, "minter": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } }, diff --git a/contracts/cw20-base/schema/query_msg.json b/contracts/cw20-base/schema/query_msg.json index 1888de787..0582d2020 100644 --- a/contracts/cw20-base/schema/query_msg.json +++ b/contracts/cw20-base/schema/query_msg.json @@ -16,11 +16,12 @@ ], "properties": { "address": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "Returns metadata on the contract - name, decimals, supply, etc. Return type: TokenInfoResponse.", @@ -32,7 +33,8 @@ "token_info": { "type": "object" } - } + }, + "additionalProperties": false }, { "description": "Only with \"mintable\" extension. Returns who can mint and how much. Return type: MinterResponse.", @@ -44,7 +46,8 @@ "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.", @@ -61,14 +64,15 @@ ], "properties": { "owner": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "spender": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "Only with \"enumerable\" extension (and \"allowances\") Returns all allowances this owner has approved. Supports pagination. Return type: AllAllowancesResponse.", @@ -92,21 +96,18 @@ "minimum": 0.0 }, "owner": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "start_after": { - "anyOf": [ - { - "$ref": "#/definitions/HumanAddr" - }, - { - "type": "null" - } + "type": [ + "string", + "null" ] } } } - } + }, + "additionalProperties": false }, { "description": "Only with \"enumerable\" extension Returns all accounts that have balances. Supports pagination. Return type: AllAccountsResponse.", @@ -127,23 +128,15 @@ "minimum": 0.0 }, "start_after": { - "anyOf": [ - { - "$ref": "#/definitions/HumanAddr" - }, - { - "type": "null" - } + "type": [ + "string", + "null" ] } } } - } - } - ], - "definitions": { - "HumanAddr": { - "type": "string" + }, + "additionalProperties": false } - } + ] } diff --git a/contracts/cw20-base/src/allowances.rs b/contracts/cw20-base/src/allowances.rs index 7bd45304c..aee3767f1 100644 --- a/contracts/cw20-base/src/allowances.rs +++ b/contracts/cw20-base/src/allowances.rs @@ -1,6 +1,6 @@ use cosmwasm_std::{ - attr, Binary, BlockInfo, CanonicalAddr, Deps, DepsMut, Env, HumanAddr, MessageInfo, Response, - StdResult, Storage, Uint128, + attr, Addr, Binary, BlockInfo, Deps, DepsMut, Env, MessageInfo, Response, StdError, StdResult, + Storage, Uint128, }; use cw20::{AllowanceResponse, Cw20ReceiveMsg, Expiration}; @@ -11,20 +11,18 @@ pub fn execute_increase_allowance( deps: DepsMut, _env: Env, info: MessageInfo, - spender: HumanAddr, + spender: String, amount: Uint128, expires: Option, ) -> Result { - let spender_raw = &deps.api.canonical_address(&spender)?; - let owner_raw = &deps.api.canonical_address(&info.sender)?; - - if spender_raw == owner_raw { + let spender_addr = deps.api.addr_validate(&spender)?; + if spender_addr == info.sender { return Err(ContractError::CannotSetOwnAccount {}); } ALLOWANCES.update( deps.storage, - (&owner_raw, &spender_raw), + (&info.sender, &spender_addr), |allow| -> StdResult<_> { let mut val = allow.unwrap_or_default(); if let Some(exp) = expires { @@ -40,7 +38,7 @@ pub fn execute_increase_allowance( messages: vec![], attributes: vec![ attr("action", "increase_allowance"), - attr("owner", deps.api.human_address(owner_raw)?), + attr("owner", info.sender), attr("spender", spender), attr("amount", amount), ], @@ -53,28 +51,30 @@ pub fn execute_decrease_allowance( deps: DepsMut, _env: Env, info: MessageInfo, - spender: HumanAddr, + spender: String, amount: Uint128, expires: Option, ) -> Result { - if spender == info.sender { + let spender_addr = deps.api.addr_validate(&spender)?; + if spender_addr == info.sender { return Err(ContractError::CannotSetOwnAccount {}); } - let spender_raw = &deps.api.canonical_address(&spender)?; - let owner_raw = &deps.api.canonical_address(&info.sender)?; - + let key = (&info.sender, &spender_addr); // load value and delete if it hits 0, or update otherwise - let mut allowance = ALLOWANCES.load(deps.storage, (&owner_raw, &spender_raw))?; + let mut allowance = ALLOWANCES.load(deps.storage, key)?; if amount < allowance.allowance { // update the new amount - allowance.allowance = (allowance.allowance - amount)?; + allowance.allowance = allowance + .allowance + .checked_sub(amount) + .map_err(StdError::overflow)?; if let Some(exp) = expires { allowance.expires = exp; } - ALLOWANCES.save(deps.storage, (&owner_raw, &spender_raw), &allowance)?; + ALLOWANCES.save(deps.storage, key, &allowance)?; } else { - ALLOWANCES.remove(deps.storage, (&owner_raw, &spender_raw)); + ALLOWANCES.remove(deps.storage, key); } let res = Response { @@ -94,19 +94,22 @@ pub fn execute_decrease_allowance( // this can be used to update a lower allowance - call bucket.update with proper keys pub fn deduct_allowance( storage: &mut dyn Storage, - owner: &CanonicalAddr, - spender: &CanonicalAddr, + owner: &Addr, + spender: &Addr, block: &BlockInfo, amount: Uint128, ) -> Result { - ALLOWANCES.update(storage, (&owner, &spender), |current| { + 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 - amount)?; + a.allowance = a + .allowance + .checked_sub(amount) + .map_err(StdError::overflow)?; Ok(a) } } @@ -119,23 +122,26 @@ pub fn execute_transfer_from( deps: DepsMut, env: Env, info: MessageInfo, - owner: HumanAddr, - recipient: HumanAddr, + owner: String, + recipient: String, amount: Uint128, ) -> Result { - let rcpt_raw = deps.api.canonical_address(&recipient)?; - let owner_raw = deps.api.canonical_address(&owner)?; - let spender_raw = deps.api.canonical_address(&info.sender)?; + 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_raw, &spender_raw, &env.block, amount)?; + deduct_allowance(deps.storage, &owner_addr, &info.sender, &env.block, amount)?; - BALANCES.update(deps.storage, &owner_raw, |balance: Option| { - balance.unwrap_or_default() - amount - })?; BALANCES.update( deps.storage, - &rcpt_raw, + &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) }, )?; @@ -146,7 +152,7 @@ pub fn execute_transfer_from( attr("action", "transfer_from"), attr("from", owner), attr("to", recipient), - attr("by", deps.api.human_address(&spender_raw)?), + attr("by", info.sender), attr("amount", amount), ], data: None, @@ -159,22 +165,25 @@ pub fn execute_burn_from( env: Env, info: MessageInfo, - owner: HumanAddr, + owner: String, amount: Uint128, ) -> Result { - let owner_raw = deps.api.canonical_address(&owner)?; - let spender_raw = deps.api.canonical_address(&info.sender)?; + let owner_addr = deps.api.addr_validate(&owner)?; // deduct allowance before doing anything else have enough allowance - deduct_allowance(deps.storage, &owner_raw, &spender_raw, &env.block, amount)?; + deduct_allowance(deps.storage, &owner_addr, &info.sender, &env.block, amount)?; // lower balance - BALANCES.update(deps.storage, &owner_raw, |balance: Option| { - balance.unwrap_or_default() - amount - })?; + 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 - amount)?; + meta.total_supply = meta.total_supply.checked_sub(amount)?; Ok(meta) })?; @@ -184,7 +193,7 @@ pub fn execute_burn_from( attributes: vec![ attr("action", "burn_from"), attr("from", owner), - attr("by", deps.api.human_address(&spender_raw)?), + attr("by", info.sender), attr("amount", amount), ], data: None, @@ -196,25 +205,28 @@ pub fn execute_send_from( deps: DepsMut, env: Env, info: MessageInfo, - owner: HumanAddr, - contract: HumanAddr, + owner: String, + contract: String, amount: Uint128, msg: Option, ) -> Result { - let rcpt_raw = deps.api.canonical_address(&contract)?; - let owner_raw = deps.api.canonical_address(&owner)?; - let spender_raw = deps.api.canonical_address(&info.sender)?; + 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_raw, &spender_raw, &env.block, amount)?; + deduct_allowance(deps.storage, &owner_addr, &info.sender, &env.block, amount)?; // move the tokens to the contract - BALANCES.update(deps.storage, &owner_raw, |balance: Option| { - balance.unwrap_or_default() - amount - })?; BALANCES.update( deps.storage, - &rcpt_raw, + &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) }, )?; @@ -228,7 +240,7 @@ pub fn execute_send_from( // create a send message let msg = Cw20ReceiveMsg { - sender: info.sender, + sender: info.sender.into(), amount, msg, } @@ -243,15 +255,11 @@ pub fn execute_send_from( Ok(res) } -pub fn query_allowance( - deps: Deps, - owner: HumanAddr, - spender: HumanAddr, -) -> StdResult { - let owner_raw = deps.api.canonical_address(&owner)?; - let spender_raw = deps.api.canonical_address(&spender)?; +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_raw, &spender_raw))? + .may_load(deps.storage, (&owner_addr, &spender_addr))? .unwrap_or_default(); Ok(allowance) } @@ -261,29 +269,33 @@ mod tests { use super::*; use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info}; - use cosmwasm_std::{coins, CosmosMsg, StdError, WasmMsg}; - use cw20::{Cw20CoinHuman, TokenInfoResponse}; + use cosmwasm_std::{coins, CosmosMsg, 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 { + 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: &HumanAddr, amount: Uint128) -> TokenInfoResponse { + 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![Cw20CoinHuman { + initial_balances: vec![Cw20Coin { address: addr.into(), amount, }], mint: None, }; - let info = mock_info(&HumanAddr("creator".to_string()), &[]); + let info = mock_info("creator", &[]); let env = mock_env(); instantiate(deps.branch(), env, info, instantiate_msg).unwrap(); query_token_info(deps.as_ref()).unwrap() @@ -293,11 +305,11 @@ mod tests { fn increase_decrease_allowances() { let mut deps = mock_dependencies(&coins(2, "token")); - let owner = HumanAddr::from("addr0001"); - let spender = HumanAddr::from("addr0002"); - let info = mock_info(owner.clone(), &[]); + 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, Uint128(12340000)); + do_instantiate(deps.as_mut(), owner.clone(), Uint128(12340000)); // no allowance to start let allowance = query_allowance(deps.as_ref(), owner.clone(), spender.clone()).unwrap(); @@ -325,7 +337,7 @@ mod tests { // decrease it a bit with no expire set - stays the same let lower = Uint128(4444); - let allow2 = (allow1 - lower).unwrap(); + let allow2 = allow1.checked_sub(lower).unwrap(); let msg = ExecuteMsg::DecreaseAllowance { spender: spender.clone(), amount: lower, @@ -375,10 +387,10 @@ mod tests { fn allowances_independent() { let mut deps = mock_dependencies(&coins(2, "token")); - let owner = HumanAddr::from("addr0001"); - let spender = HumanAddr::from("addr0002"); - let spender2 = HumanAddr::from("addr0003"); - let info = mock_info(owner.clone(), &[]); + 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(12340000)); @@ -438,7 +450,7 @@ mod tests { ); // also allow spender -> spender2 with no interference - let info = mock_info(spender.clone(), &[]); + let info = mock_info(spender.as_ref(), &[]); let env = mock_env(); let allow3 = Uint128(1821); let expires3 = Expiration::AtTime(3767626296); @@ -470,8 +482,8 @@ mod tests { fn no_self_allowance() { let mut deps = mock_dependencies(&coins(2, "token")); - let owner = HumanAddr::from("addr0001"); - let info = mock_info(owner.clone(), &[]); + let owner = String::from("addr0001"); + let info = mock_info(owner.as_ref(), &[]); let env = mock_env(); do_instantiate(deps.as_mut(), &owner, Uint128(12340000)); @@ -497,9 +509,9 @@ mod tests { #[test] fn transfer_from_respects_limits() { let mut deps = mock_dependencies(&[]); - let owner = HumanAddr::from("addr0001"); - let spender = HumanAddr::from("addr0002"); - let rcpt = HumanAddr::from("addr0003"); + let owner = String::from("addr0001"); + let spender = String::from("addr0002"); + let rcpt = String::from("addr0003"); let start = Uint128(999999); do_instantiate(deps.as_mut(), &owner, start); @@ -511,7 +523,7 @@ mod tests { amount: allow1, expires: None, }; - let info = mock_info(owner.clone(), &[]); + let info = mock_info(owner.as_ref(), &[]); let env = mock_env(); execute(deps.as_mut(), env.clone(), info.clone(), msg).unwrap(); @@ -522,22 +534,22 @@ mod tests { recipient: rcpt.clone(), amount: transfer, }; - let info = mock_info(spender.clone(), &[]); + let info = mock_info(spender.as_ref(), &[]); let env = mock_env(); let res = execute(deps.as_mut(), env.clone(), info.clone(), msg).unwrap(); assert_eq!(res.attributes[0], attr("action", "transfer_from")); // make sure money arrived assert_eq!( - get_balance(deps.as_ref(), &owner), - (start - transfer).unwrap() + get_balance(deps.as_ref(), owner.clone()), + start.checked_sub(transfer).unwrap() ); - assert_eq!(get_balance(deps.as_ref(), &rcpt), transfer); + 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 - transfer).unwrap(), + allowance: allow1.checked_sub(transfer).unwrap(), expires: Expiration::Never {}, }; assert_eq!(expect, allowance); @@ -548,16 +560,13 @@ mod tests { recipient: rcpt.clone(), amount: Uint128(33443), }; - let info = mock_info(spender.clone(), &[]); + let info = mock_info(spender.as_ref(), &[]); let env = mock_env(); let err = execute(deps.as_mut(), env.clone(), info.clone(), msg).unwrap_err(); - assert!(matches!( - err, - ContractError::Std(StdError::Underflow { .. }) - )); + 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.clone(), &[]); + let info = mock_info(owner.as_ref(), &[]); let env = mock_env(); let msg = ExecuteMsg::IncreaseAllowance { spender: spender.clone(), @@ -572,7 +581,7 @@ mod tests { recipient: rcpt.clone(), amount: Uint128(33443), }; - let info = mock_info(spender.clone(), &[]); + let info = mock_info(spender.as_ref(), &[]); let env = mock_env(); let err = execute(deps.as_mut(), env.clone(), info.clone(), msg).unwrap_err(); assert_eq!(err, ContractError::Expired {}); @@ -581,8 +590,8 @@ mod tests { #[test] fn burn_from_respects_limits() { let mut deps = mock_dependencies(&[]); - let owner = HumanAddr::from("addr0001"); - let spender = HumanAddr::from("addr0002"); + let owner = String::from("addr0001"); + let spender = String::from("addr0002"); let start = Uint128(999999); do_instantiate(deps.as_mut(), &owner, start); @@ -594,7 +603,7 @@ mod tests { amount: allow1, expires: None, }; - let info = mock_info(owner.clone(), &[]); + let info = mock_info(owner.as_ref(), &[]); let env = mock_env(); execute(deps.as_mut(), env.clone(), info.clone(), msg).unwrap(); @@ -604,21 +613,21 @@ mod tests { owner: owner.clone(), amount: transfer, }; - let info = mock_info(spender.clone(), &[]); + let info = mock_info(spender.as_ref(), &[]); let env = mock_env(); let res = execute(deps.as_mut(), env.clone(), info.clone(), msg).unwrap(); assert_eq!(res.attributes[0], attr("action", "burn_from")); // make sure money burnt assert_eq!( - get_balance(deps.as_ref(), &owner), - (start - transfer).unwrap() + 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 - transfer).unwrap(), + allowance: allow1.checked_sub(transfer).unwrap(), expires: Expiration::Never {}, }; assert_eq!(expect, allowance); @@ -628,16 +637,13 @@ mod tests { owner: owner.clone(), amount: Uint128(33443), }; - let info = mock_info(spender.clone(), &[]); + let info = mock_info(spender.as_ref(), &[]); let env = mock_env(); let err = execute(deps.as_mut(), env.clone(), info.clone(), msg).unwrap_err(); - assert!(matches!( - err, - ContractError::Std(StdError::Underflow { .. }) - )); + 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.clone(), &[]); + let info = mock_info(owner.as_ref(), &[]); let env = mock_env(); let msg = ExecuteMsg::IncreaseAllowance { spender: spender.clone(), @@ -651,7 +657,7 @@ mod tests { owner: owner.clone(), amount: Uint128(33443), }; - let info = mock_info(spender.clone(), &[]); + let info = mock_info(spender.as_ref(), &[]); let env = mock_env(); let err = execute(deps.as_mut(), env.clone(), info.clone(), msg).unwrap_err(); assert_eq!(err, ContractError::Expired {}); @@ -660,9 +666,9 @@ mod tests { #[test] fn send_from_respects_limits() { let mut deps = mock_dependencies(&[]); - let owner = HumanAddr::from("addr0001"); - let spender = HumanAddr::from("addr0002"); - let contract = HumanAddr::from("cool-dex"); + 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(999999); @@ -675,7 +681,7 @@ mod tests { amount: allow1, expires: None, }; - let info = mock_info(owner.clone(), &[]); + let info = mock_info(owner.as_ref(), &[]); let env = mock_env(); execute(deps.as_mut(), env.clone(), info.clone(), msg).unwrap(); @@ -687,7 +693,7 @@ mod tests { contract: contract.clone(), msg: Some(send_msg.clone()), }; - let info = mock_info(spender.clone(), &[]); + let info = mock_info(spender.as_ref(), &[]); let env = mock_env(); let res = execute(deps.as_mut(), env.clone(), info.clone(), msg).unwrap(); assert_eq!(res.attributes[0], attr("action", "send_from")); @@ -704,7 +710,7 @@ mod tests { assert_eq!( res.messages[0], CosmosMsg::Wasm(WasmMsg::Execute { - contract_addr: contract.clone(), + contract_addr: contract.clone().into(), msg: binary_msg, send: vec![], }) @@ -712,15 +718,15 @@ mod tests { // make sure money sent assert_eq!( - get_balance(deps.as_ref(), &owner), - (start - transfer).unwrap() + get_balance(deps.as_ref(), owner.clone()), + start.checked_sub(transfer).unwrap() ); - assert_eq!(get_balance(deps.as_ref(), &contract), transfer); + 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 - transfer).unwrap(), + allowance: allow1.checked_sub(transfer).unwrap(), expires: Expiration::Never {}, }; assert_eq!(expect, allowance); @@ -732,16 +738,13 @@ mod tests { contract: contract.clone(), msg: Some(send_msg.clone()), }; - let info = mock_info(spender.clone(), &[]); + let info = mock_info(spender.as_ref(), &[]); let env = mock_env(); let err = execute(deps.as_mut(), env.clone(), info.clone(), msg).unwrap_err(); - assert!(matches!( - err, - ContractError::Std(StdError::Underflow { .. }) - )); + assert!(matches!(err, ContractError::Std(StdError::Overflow { .. }))); // let us increase limit, but set the expiration to current block (expired) - let info = mock_info(owner.clone(), &[]); + let info = mock_info(owner.as_ref(), &[]); let env = mock_env(); let msg = ExecuteMsg::IncreaseAllowance { spender: spender.clone(), @@ -757,7 +760,7 @@ mod tests { contract: contract.clone(), msg: Some(send_msg.clone()), }; - let info = mock_info(spender.clone(), &[]); + let info = mock_info(spender.as_ref(), &[]); let env = mock_env(); let err = execute(deps.as_mut(), env.clone(), info.clone(), msg).unwrap_err(); assert_eq!(err, ContractError::Expired {}); diff --git a/contracts/cw20-base/src/contract.rs b/contracts/cw20-base/src/contract.rs index c7bd1af83..bcad35582 100644 --- a/contracts/cw20-base/src/contract.rs +++ b/contracts/cw20-base/src/contract.rs @@ -1,12 +1,12 @@ #[cfg(not(feature = "library"))] use cosmwasm_std::entry_point; use cosmwasm_std::{ - attr, to_binary, Binary, Deps, DepsMut, Env, HumanAddr, MessageInfo, Response, StdError, - StdResult, Uint128, + attr, to_binary, Binary, Deps, DepsMut, Env, MessageInfo, Response, StdError, StdResult, + Uint128, }; use cw2::set_contract_version; -use cw20::{BalanceResponse, Cw20CoinHuman, Cw20ReceiveMsg, MinterResponse, TokenInfoResponse}; +use cw20::{BalanceResponse, Cw20Coin, Cw20ReceiveMsg, MinterResponse, TokenInfoResponse}; use crate::allowances::{ execute_burn_from, execute_decrease_allowance, execute_increase_allowance, execute_send_from, @@ -42,7 +42,7 @@ pub fn instantiate( let mint = match msg.mint { Some(m) => Some(MinterData { - minter: deps.api.canonical_address(&m.minter)?, + minter: deps.api.addr_validate(&m.minter)?, cap: m.cap, }), None => None, @@ -60,11 +60,11 @@ pub fn instantiate( Ok(Response::default()) } -pub fn create_accounts(deps: &mut DepsMut, accounts: &[Cw20CoinHuman]) -> StdResult { +pub fn create_accounts(deps: &mut DepsMut, accounts: &[Cw20Coin]) -> StdResult { let mut total_supply = Uint128::zero(); for row in accounts { - let raw_address = deps.api.canonical_address(&row.address)?; - BALANCES.save(deps.storage, &raw_address, &row.amount)?; + let address = deps.api.addr_validate(&row.address)?; + BALANCES.save(deps.storage, &address, &row.amount)?; total_supply += row.amount; } Ok(total_supply) @@ -117,22 +117,25 @@ pub fn execute_transfer( deps: DepsMut, _env: Env, info: MessageInfo, - recipient: HumanAddr, + recipient: String, amount: Uint128, ) -> Result { if amount == Uint128::zero() { return Err(ContractError::InvalidZeroAmount {}); } - let rcpt_raw = deps.api.canonical_address(&recipient)?; - let sender_raw = deps.api.canonical_address(&info.sender)?; + let rcpt_addr = deps.api.addr_validate(&recipient)?; - BALANCES.update(deps.storage, &sender_raw, |balance: Option| { - balance.unwrap_or_default() - amount - })?; BALANCES.update( deps.storage, - &rcpt_raw, + &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) }, )?; @@ -141,7 +144,7 @@ pub fn execute_transfer( messages: vec![], attributes: vec![ attr("action", "transfer"), - attr("from", deps.api.human_address(&sender_raw)?), + attr("from", info.sender), attr("to", recipient), attr("amount", amount), ], @@ -160,15 +163,17 @@ pub fn execute_burn( return Err(ContractError::InvalidZeroAmount {}); } - let sender_raw = deps.api.canonical_address(&info.sender)?; - // lower balance - BALANCES.update(deps.storage, &sender_raw, |balance: Option| { - balance.unwrap_or_default() - amount - })?; + 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 - amount)?; + info.total_supply = info.total_supply.checked_sub(amount)?; Ok(info) })?; @@ -177,7 +182,7 @@ pub fn execute_burn( messages: vec![], attributes: vec![ attr("action", "burn"), - attr("from", deps.api.human_address(&sender_raw)?), + attr("from", info.sender), attr("amount", amount), ], data: None, @@ -189,7 +194,7 @@ pub fn execute_mint( deps: DepsMut, _env: Env, info: MessageInfo, - recipient: HumanAddr, + recipient: String, amount: Uint128, ) -> Result { if amount == Uint128::zero() { @@ -197,9 +202,7 @@ pub fn execute_mint( } let mut config = TOKEN_INFO.load(deps.storage)?; - if config.mint.is_none() - || config.mint.as_ref().unwrap().minter != deps.api.canonical_address(&info.sender)? - { + if config.mint.is_none() || config.mint.as_ref().unwrap().minter != info.sender { return Err(ContractError::Unauthorized {}); } @@ -213,10 +216,10 @@ pub fn execute_mint( TOKEN_INFO.save(deps.storage, &config)?; // add amount to recipient balance - let rcpt_raw = deps.api.canonical_address(&recipient)?; + let rcpt_addr = deps.api.addr_validate(&recipient)?; BALANCES.update( deps.storage, - &rcpt_raw, + &rcpt_addr, |balance: Option| -> StdResult<_> { Ok(balance.unwrap_or_default() + amount) }, )?; @@ -237,7 +240,7 @@ pub fn execute_send( deps: DepsMut, _env: Env, info: MessageInfo, - contract: HumanAddr, + contract: String, amount: Uint128, msg: Option, ) -> Result { @@ -245,30 +248,32 @@ pub fn execute_send( return Err(ContractError::InvalidZeroAmount {}); } - let rcpt_raw = deps.api.canonical_address(&contract)?; - let sender_raw = deps.api.canonical_address(&info.sender)?; + let rcpt_addr = deps.api.addr_validate(&contract)?; // move the tokens to the contract - BALANCES.update(deps.storage, &sender_raw, |balance: Option| { - balance.unwrap_or_default() - amount - })?; BALANCES.update( deps.storage, - &rcpt_raw, + &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 sender = deps.api.human_address(&sender_raw)?; let attrs = vec![ attr("action", "send"), - attr("from", &sender), + attr("from", &info.sender), attr("to", &contract), attr("amount", amount), ]; // create a send message let msg = Cw20ReceiveMsg { - sender, + sender: info.sender.into(), amount, msg, } @@ -303,10 +308,10 @@ pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult { } } -pub fn query_balance(deps: Deps, address: HumanAddr) -> StdResult { - let addr_raw = deps.api.canonical_address(&address)?; +pub fn query_balance(deps: Deps, address: String) -> StdResult { + let address = deps.api.addr_validate(&address)?; let balance = BALANCES - .may_load(deps.storage, &addr_raw)? + .may_load(deps.storage, &address)? .unwrap_or_default(); Ok(BalanceResponse { balance }) } @@ -326,7 +331,7 @@ pub fn query_minter(deps: Deps) -> StdResult> { let meta = TOKEN_INFO.load(deps.storage)?; let minter = match meta.mint { Some(m) => Some(MinterResponse { - minter: deps.api.human_address(&m.minter)?, + minter: m.minter.into(), cap: m.cap, }), None => None, @@ -341,16 +346,16 @@ mod tests { use super::*; - fn get_balance>(deps: Deps, address: T) -> Uint128 { + 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: &HumanAddr, + addr: &String, amount: Uint128, - minter: &HumanAddr, + minter: &String, cap: Option, ) -> TokenInfoResponse { _do_instantiate( @@ -358,21 +363,21 @@ mod tests { addr, amount, Some(MinterResponse { - minter: minter.into(), + minter: minter.clone(), cap, }), ) } // this will set up the instantiation for other tests - fn do_instantiate(deps: DepsMut, addr: &HumanAddr, amount: Uint128) -> TokenInfoResponse { + fn do_instantiate(deps: DepsMut, addr: &String, 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: &HumanAddr, + addr: &String, amount: Uint128, mint: Option, ) -> TokenInfoResponse { @@ -380,13 +385,13 @@ mod tests { name: "Auto Gen".to_string(), symbol: "AUTO".to_string(), decimals: 3, - initial_balances: vec![Cw20CoinHuman { - address: addr.into(), + initial_balances: vec![Cw20Coin { + address: addr.clone(), amount, }], mint: mint.clone(), }; - let info = mock_info(&HumanAddr("creator".to_string()), &[]); + 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()); @@ -401,7 +406,7 @@ mod tests { total_supply: amount, } ); - assert_eq!(get_balance(deps.as_ref(), addr), amount); + assert_eq!(get_balance(deps.as_ref(), addr.clone()), amount); assert_eq!(query_minter(deps.as_ref()).unwrap(), mint,); meta } @@ -414,13 +419,13 @@ mod tests { name: "Cash Token".to_string(), symbol: "CASH".to_string(), decimals: 9, - initial_balances: vec![Cw20CoinHuman { - address: HumanAddr("addr0000".to_string()), + initial_balances: vec![Cw20Coin { + address: String::from("addr0000"), amount, }], mint: None, }; - let info = mock_info(&HumanAddr("creator".to_string()), &[]); + let info = mock_info("creator", &[]); let env = mock_env(); let res = instantiate(deps.as_mut(), env.clone(), info.clone(), instantiate_msg).unwrap(); assert_eq!(0, res.messages.len()); @@ -441,14 +446,14 @@ mod tests { fn instantiate_mintable() { let mut deps = mock_dependencies(&[]); let amount = Uint128(11223344); - let minter = HumanAddr::from("asmodat"); + let minter = String::from("asmodat"); let limit = Uint128(511223344); let instantiate_msg = InstantiateMsg { name: "Cash Token".to_string(), symbol: "CASH".to_string(), decimals: 9, - initial_balances: vec![Cw20CoinHuman { - address: HumanAddr("addr0000".to_string()), + initial_balances: vec![Cw20Coin { + address: "addr0000".into(), amount, }], mint: Some(MinterResponse { @@ -456,7 +461,7 @@ mod tests { cap: Some(limit), }), }; - let info = mock_info(&HumanAddr("creator".to_string()), &[]); + let info = mock_info("creator", &[]); let env = mock_env(); let res = instantiate(deps.as_mut(), env.clone(), info.clone(), instantiate_msg).unwrap(); assert_eq!(0, res.messages.len()); @@ -484,14 +489,14 @@ mod tests { fn instantiate_mintable_over_cap() { let mut deps = mock_dependencies(&[]); let amount = Uint128(11223344); - let minter = HumanAddr::from("asmodat"); + let minter = String::from("asmodat"); let limit = Uint128(11223300); let instantiate_msg = InstantiateMsg { name: "Cash Token".to_string(), symbol: "CASH".to_string(), decimals: 9, - initial_balances: vec![Cw20CoinHuman { - address: HumanAddr("addr0000".to_string()), + initial_balances: vec![Cw20Coin { + address: String::from("addr0000"), amount, }], mint: Some(MinterResponse { @@ -499,7 +504,7 @@ mod tests { cap: Some(limit), }), }; - let info = mock_info(&HumanAddr("creator".to_string()), &[]); + let info = mock_info("creator", &[]); let env = mock_env(); let err = instantiate(deps.as_mut(), env.clone(), info.clone(), instantiate_msg).unwrap_err(); @@ -513,33 +518,33 @@ mod tests { fn can_mint_by_minter() { let mut deps = mock_dependencies(&[]); - let genesis = HumanAddr::from("genesis"); + let genesis = String::from("genesis"); let amount = Uint128(11223344); - let minter = HumanAddr::from("asmodat"); + let minter = String::from("asmodat"); let limit = Uint128(511223344); do_instantiate_with_minter(deps.as_mut(), &genesis, amount, &minter, Some(limit)); // minter can mint coins to some winner - let winner = HumanAddr::from("lucky"); + let winner = String::from("lucky"); let prize = Uint128(222_222_222); let msg = ExecuteMsg::Mint { recipient: winner.clone(), amount: prize, }; - let info = mock_info(&minter, &[]); + let info = mock_info(minter.as_ref(), &[]); let env = mock_env(); let res = execute(deps.as_mut(), env, info, msg.clone()).unwrap(); assert_eq!(0, res.messages.len()); - assert_eq!(get_balance(deps.as_ref(), &genesis), amount); - assert_eq!(get_balance(deps.as_ref(), &winner), prize); + assert_eq!(get_balance(deps.as_ref(), genesis.clone()), 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, &[]); + let info = mock_info(minter.as_ref(), &[]); let env = mock_env(); let err = execute(deps.as_mut(), env, info, msg.clone()).unwrap_err(); assert_eq!(err, ContractError::InvalidZeroAmount {}); @@ -550,7 +555,7 @@ mod tests { recipient: winner.clone(), amount: Uint128(333_222_222), }; - let info = mock_info(&minter, &[]); + let info = mock_info(minter.as_ref(), &[]); let env = mock_env(); let err = execute(deps.as_mut(), env, info, msg.clone()).unwrap_err(); assert_eq!(err, ContractError::CannotExceedCap {}); @@ -561,17 +566,17 @@ mod tests { let mut deps = mock_dependencies(&[]); do_instantiate_with_minter( deps.as_mut(), - &HumanAddr::from("genesis"), + &String::from("genesis"), Uint128(1234), - &HumanAddr::from("minter"), + &String::from("minter"), None, ); let msg = ExecuteMsg::Mint { - recipient: HumanAddr::from("lucky"), + recipient: String::from("lucky"), amount: Uint128(222), }; - let info = mock_info(&HumanAddr::from("anyone else"), &[]); + let info = mock_info("anyone else", &[]); let env = mock_env(); let err = execute(deps.as_mut(), env, info, msg.clone()).unwrap_err(); assert_eq!(err, ContractError::Unauthorized {}); @@ -580,13 +585,13 @@ mod tests { #[test] fn no_one_mints_if_minter_unset() { let mut deps = mock_dependencies(&[]); - do_instantiate(deps.as_mut(), &HumanAddr::from("genesis"), Uint128(1234)); + do_instantiate(deps.as_mut(), &String::from("genesis"), Uint128(1234)); let msg = ExecuteMsg::Mint { - recipient: HumanAddr::from("lucky"), + recipient: String::from("lucky"), amount: Uint128(222), }; - let info = mock_info(&HumanAddr::from("genesis"), &[]); + let info = mock_info("genesis", &[]); let env = mock_env(); let err = execute(deps.as_mut(), env, info, msg.clone()).unwrap_err(); assert_eq!(err, ContractError::Unauthorized {}); @@ -596,26 +601,26 @@ mod tests { fn instantiate_multiple_accounts() { let mut deps = mock_dependencies(&[]); let amount1 = Uint128::from(11223344u128); - let addr1 = HumanAddr::from("addr0001"); + let addr1 = String::from("addr0001"); let amount2 = Uint128::from(7890987u128); - let addr2 = HumanAddr::from("addr0002"); + let addr2 = String::from("addr0002"); let instantiate_msg = InstantiateMsg { name: "Bash Shell".to_string(), symbol: "BASH".to_string(), decimals: 6, initial_balances: vec![ - Cw20CoinHuman { + Cw20Coin { address: addr1.clone(), amount: amount1, }, - Cw20CoinHuman { + Cw20Coin { address: addr2.clone(), amount: amount2, }, ], mint: None, }; - let info = mock_info(&HumanAddr("creator".to_string()), &[]); + let info = mock_info("creator", &[]); let env = mock_env(); let res = instantiate(deps.as_mut(), env.clone(), info.clone(), instantiate_msg).unwrap(); assert_eq!(0, res.messages.len()); @@ -629,14 +634,14 @@ mod tests { total_supply: amount1 + amount2, } ); - assert_eq!(get_balance(deps.as_ref(), &addr1), amount1); - assert_eq!(get_balance(deps.as_ref(), &addr2), amount2); + assert_eq!(get_balance(deps.as_ref(), addr1.clone()), amount1); + assert_eq!(get_balance(deps.as_ref(), addr2.clone()), amount2); } #[test] fn queries_work() { let mut deps = mock_dependencies(&coins(2, "token")); - let addr1 = HumanAddr::from("addr0001"); + let addr1 = String::from("addr0001"); let amount1 = Uint128::from(12340000u128); let expected = do_instantiate(deps.as_mut(), &addr1, amount1); @@ -664,7 +669,7 @@ mod tests { deps.as_ref(), env.clone(), QueryMsg::Balance { - address: HumanAddr::from("addr0002"), + address: String::from("addr0002"), }, ) .unwrap(); @@ -675,8 +680,8 @@ mod tests { #[test] fn transfer() { let mut deps = mock_dependencies(&coins(2, "token")); - let addr1 = HumanAddr::from("addr0001"); - let addr2 = HumanAddr::from("addr0002"); + 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); @@ -684,7 +689,7 @@ mod tests { do_instantiate(deps.as_mut(), &addr1, amount1); // cannot transfer nothing - let info = mock_info(addr1.clone(), &[]); + let info = mock_info(addr1.as_ref(), &[]); let env = mock_env(); let msg = ExecuteMsg::Transfer { recipient: addr2.clone(), @@ -694,33 +699,27 @@ mod tests { assert_eq!(err, ContractError::InvalidZeroAmount {}); // cannot send more than we have - let info = mock_info(addr1.clone(), &[]); + 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::Underflow { .. }) - )); + assert!(matches!(err, ContractError::Std(StdError::Overflow { .. }))); // cannot send from empty account - let info = mock_info(addr2.clone(), &[]); + 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::Underflow { .. }) - )); + assert!(matches!(err, ContractError::Std(StdError::Overflow { .. }))); // valid transfer - let info = mock_info(addr1.clone(), &[]); + let info = mock_info(addr1.as_ref(), &[]); let env = mock_env(); let msg = ExecuteMsg::Transfer { recipient: addr2.clone(), @@ -729,9 +728,9 @@ mod tests { let res = execute(deps.as_mut(), env, info, msg).unwrap(); assert_eq!(res.messages.len(), 0); - let remainder = (amount1 - transfer).unwrap(); - assert_eq!(get_balance(deps.as_ref(), &addr1), remainder); - assert_eq!(get_balance(deps.as_ref(), &addr2), transfer); + let remainder = amount1.checked_sub(transfer).unwrap(); + assert_eq!(get_balance(deps.as_ref(), addr1.clone()), remainder); + assert_eq!(get_balance(deps.as_ref(), addr2.clone()), transfer); assert_eq!( query_token_info(deps.as_ref()).unwrap().total_supply, amount1 @@ -741,7 +740,7 @@ mod tests { #[test] fn burn() { let mut deps = mock_dependencies(&coins(2, "token")); - let addr1 = HumanAddr::from("addr0001"); + let addr1 = String::from("addr0001"); let amount1 = Uint128::from(12340000u128); let burn = Uint128::from(76543u128); let too_much = Uint128::from(12340321u128); @@ -749,7 +748,7 @@ mod tests { do_instantiate(deps.as_mut(), &addr1, amount1); // cannot burn nothing - let info = mock_info(addr1.clone(), &[]); + let info = mock_info(addr1.as_ref(), &[]); let env = mock_env(); let msg = ExecuteMsg::Burn { amount: Uint128::zero(), @@ -762,28 +761,25 @@ mod tests { ); // cannot burn more than we have - let info = mock_info(addr1.clone(), &[]); + 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::Underflow { .. }) - )); + 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.clone(), &[]); + 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 - burn).unwrap(); - assert_eq!(get_balance(deps.as_ref(), &addr1), remainder); + let remainder = amount1.checked_sub(burn).unwrap(); + assert_eq!(get_balance(deps.as_ref(), addr1.clone()), remainder); assert_eq!( query_token_info(deps.as_ref()).unwrap().total_supply, remainder @@ -793,8 +789,8 @@ mod tests { #[test] fn send() { let mut deps = mock_dependencies(&coins(2, "token")); - let addr1 = HumanAddr::from("addr0001"); - let contract = HumanAddr::from("addr0002"); + 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); @@ -803,7 +799,7 @@ mod tests { do_instantiate(deps.as_mut(), &addr1, amount1); // cannot send nothing - let info = mock_info(addr1.clone(), &[]); + let info = mock_info(addr1.as_ref(), &[]); let env = mock_env(); let msg = ExecuteMsg::Send { contract: contract.clone(), @@ -814,7 +810,7 @@ mod tests { assert_eq!(err, ContractError::InvalidZeroAmount {}); // cannot send more than we have - let info = mock_info(addr1.clone(), &[]); + let info = mock_info(addr1.as_ref(), &[]); let env = mock_env(); let msg = ExecuteMsg::Send { contract: contract.clone(), @@ -822,13 +818,10 @@ mod tests { msg: Some(send_msg.clone()), }; let err = execute(deps.as_mut(), env, info, msg).unwrap_err(); - assert!(matches!( - err, - ContractError::Std(StdError::Underflow { .. }) - )); + assert!(matches!(err, ContractError::Std(StdError::Overflow { .. }))); // valid transfer - let info = mock_info(addr1.clone(), &[]); + let info = mock_info(addr1.as_ref(), &[]); let env = mock_env(); let msg = ExecuteMsg::Send { contract: contract.clone(), @@ -851,16 +844,16 @@ mod tests { assert_eq!( res.messages[0], CosmosMsg::Wasm(WasmMsg::Execute { - contract_addr: contract.clone(), + contract_addr: contract.clone().into(), msg: binary_msg, send: vec![], }) ); // ensure balance is properly transferred - let remainder = (amount1 - transfer).unwrap(); - assert_eq!(get_balance(deps.as_ref(), &addr1), remainder); - assert_eq!(get_balance(deps.as_ref(), &contract), transfer); + let remainder = amount1.checked_sub(transfer).unwrap(); + assert_eq!(get_balance(deps.as_ref(), addr1.clone()), remainder); + assert_eq!(get_balance(deps.as_ref(), contract.clone()), transfer); assert_eq!( query_token_info(deps.as_ref()).unwrap().total_supply, amount1 diff --git a/contracts/cw20-base/src/enumerable.rs b/contracts/cw20-base/src/enumerable.rs index fcc9ed8ff..de4e0b8cb 100644 --- a/contracts/cw20-base/src/enumerable.rs +++ b/contracts/cw20-base/src/enumerable.rs @@ -1,5 +1,4 @@ -use cosmwasm_std::{CanonicalAddr, Deps, HumanAddr, Order, StdResult}; -use cw0::maybe_canonical; +use cosmwasm_std::{Deps, Order, StdResult}; use cw20::{AllAccountsResponse, AllAllowancesResponse, AllowanceInfo}; use crate::state::{ALLOWANCES, BALANCES}; @@ -11,24 +10,22 @@ const DEFAULT_LIMIT: u32 = 10; pub fn query_all_allowances( deps: Deps, - owner: HumanAddr, - start_after: Option, + owner: String, + start_after: Option, limit: Option, ) -> StdResult { - let owner_raw = deps.api.canonical_address(&owner)?; + let owner_addr = deps.api.addr_validate(&owner)?; let limit = limit.unwrap_or(DEFAULT_LIMIT).min(MAX_LIMIT) as usize; - let canon = maybe_canonical(deps.api, start_after)?; - let start = canon.map(Bound::exclusive); + let start = start_after.map(Bound::exclusive); - let api = &deps.api; let allowances: StdResult> = ALLOWANCES - .prefix(&owner_raw) + .prefix(&owner_addr) .range(deps.storage, start, None, Order::Ascending) .take(limit) .map(|item| { let (k, v) = item?; Ok(AllowanceInfo { - spender: api.human_address(&CanonicalAddr::from(k))?, + spender: String::from_utf8(k)?, allowance: v.allowance, expires: v.expires, }) @@ -41,17 +38,15 @@ pub fn query_all_allowances( pub fn query_all_accounts( deps: Deps, - start_after: Option, + start_after: Option, limit: Option, ) -> StdResult { let limit = limit.unwrap_or(DEFAULT_LIMIT).min(MAX_LIMIT) as usize; - let canon = maybe_canonical(deps.api, start_after)?; - let start = canon.map(Bound::exclusive); + let start = start_after.map(Bound::exclusive); - let api = &deps.api; - let accounts: StdResult> = BALANCES + let accounts: Result, _> = BALANCES .keys(deps.storage, start, None, Order::Ascending) - .map(|key| api.human_address(&key.into())) + .map(String::from_utf8) .take(limit) .collect(); @@ -66,24 +61,24 @@ mod tests { use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info}; use cosmwasm_std::{coins, DepsMut, Uint128}; - use cw20::{Cw20CoinHuman, Expiration, TokenInfoResponse}; + 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: &HumanAddr, amount: Uint128) -> TokenInfoResponse { + fn do_instantiate(mut deps: DepsMut, addr: &String, amount: Uint128) -> TokenInfoResponse { let instantiate_msg = InstantiateMsg { name: "Auto Gen".to_string(), symbol: "AUTO".to_string(), decimals: 3, - initial_balances: vec![Cw20CoinHuman { + initial_balances: vec![Cw20Coin { address: addr.into(), amount, }], mint: None, }; - let info = mock_info(&HumanAddr("creator".to_string()), &[]); + let info = mock_info("creator", &[]); let env = mock_env(); instantiate(deps.branch(), env, info, instantiate_msg).unwrap(); query_token_info(deps.as_ref()).unwrap() @@ -93,12 +88,12 @@ mod tests { fn query_all_allowances_works() { let mut deps = mock_dependencies(&coins(2, "token")); - let owner = HumanAddr::from("owner"); - // these are in alphabetical order different than insert order - let spender1 = HumanAddr::from("later"); - let spender2 = HumanAddr::from("earlier"); + 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.clone(), &[]); + let info = mock_info(owner.as_ref(), &[]); let env = mock_env(); do_instantiate(deps.as_mut(), &owner, Uint128(12340000)); @@ -129,7 +124,7 @@ mod tests { 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 HumanAddr) + // 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]; @@ -156,17 +151,17 @@ mod tests { fn query_all_accounts_works() { let mut deps = mock_dependencies(&coins(2, "token")); - // insert order and lexographical order are different - let acct1 = HumanAddr::from("acct01"); - let acct2 = HumanAddr::from("zebra"); - let acct3 = HumanAddr::from("nice"); - let acct4 = HumanAddr::from("aaaardvark"); - let expected_order = [acct2.clone(), acct1.clone(), acct3.clone(), acct4.clone()]; + // 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(12340000)); // put money everywhere (to create balanaces) - let info = mock_info(acct1.clone(), &[]); + let info = mock_info(acct1.as_ref(), &[]); let env = mock_env(); execute( deps.as_mut(), diff --git a/contracts/cw20-base/src/msg.rs b/contracts/cw20-base/src/msg.rs index 96f3ca829..4ad84296e 100644 --- a/contracts/cw20-base/src/msg.rs +++ b/contracts/cw20-base/src/msg.rs @@ -1,5 +1,5 @@ -use cosmwasm_std::{Binary, HumanAddr, StdError, StdResult, Uint128}; -use cw20::{Cw20CoinHuman, Expiration, MinterResponse}; +use cosmwasm_std::{Binary, StdError, StdResult, Uint128}; +use cw20::{Cw20Coin, Expiration, MinterResponse}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; @@ -8,7 +8,7 @@ pub struct InstantiateMsg { pub name: String, pub symbol: String, pub decimals: u8, - pub initial_balances: Vec, + pub initial_balances: Vec, pub mint: Option, } @@ -61,30 +61,24 @@ fn is_valid_symbol(symbol: &str) -> bool { #[serde(rename_all = "snake_case")] pub enum ExecuteMsg { /// Transfer is a base message to move tokens to another account without triggering actions - Transfer { - recipient: HumanAddr, - amount: Uint128, - }, + Transfer { recipient: String, amount: Uint128 }, /// Burn is a base message to destroy tokens forever Burn { amount: Uint128 }, /// Send is a base message to transfer tokens to a contract and trigger an action /// on the receiving contract. Send { - contract: HumanAddr, + contract: String, amount: Uint128, msg: Option, }, /// Only with the "mintable" extension. If authorized, creates amount new tokens /// and adds to the recipient balance. - Mint { - recipient: HumanAddr, - amount: Uint128, - }, + Mint { recipient: String, amount: Uint128 }, /// 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. IncreaseAllowance { - spender: HumanAddr, + spender: String, amount: Uint128, expires: Option, }, @@ -92,27 +86,27 @@ pub enum ExecuteMsg { /// from the owner's (env.sender) account by amount. If expires is Some(), overwrites current /// allowance expiration with this one. DecreaseAllowance { - spender: HumanAddr, + spender: String, amount: Uint128, expires: Option, }, /// Only with "approval" extension. Transfers amount tokens from owner -> recipient /// if `env.sender` has sufficient pre-approval. TransferFrom { - owner: HumanAddr, - recipient: HumanAddr, + owner: String, + recipient: String, amount: Uint128, }, /// Only with "approval" extension. Sends amount tokens from owner -> contract /// if `env.sender` has sufficient pre-approval. SendFrom { - owner: HumanAddr, - contract: HumanAddr, + owner: String, + contract: String, amount: Uint128, msg: Option, }, /// Only with "approval" extension. Destroys tokens forever - BurnFrom { owner: HumanAddr, amount: Uint128 }, + BurnFrom { owner: String, amount: Uint128 }, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] @@ -120,7 +114,7 @@ pub enum ExecuteMsg { pub enum QueryMsg { /// Returns the current balance of the given address, 0 if unset. /// Return type: BalanceResponse. - Balance { address: HumanAddr }, + Balance { address: String }, /// Returns metadata on the contract - name, decimals, supply, etc. /// Return type: TokenInfoResponse. TokenInfo {}, @@ -131,23 +125,20 @@ pub enum QueryMsg { /// Only with "allowance" extension. /// Returns how much spender can use from owner account, 0 if unset. /// Return type: AllowanceResponse. - Allowance { - owner: HumanAddr, - spender: HumanAddr, - }, + 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: HumanAddr, - start_after: Option, + 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, + start_after: Option, limit: Option, }, } diff --git a/contracts/cw20-base/src/state.rs b/contracts/cw20-base/src/state.rs index 7a93d28f2..a41a5b380 100644 --- a/contracts/cw20-base/src/state.rs +++ b/contracts/cw20-base/src/state.rs @@ -1,7 +1,7 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -use cosmwasm_std::{CanonicalAddr, Uint128}; +use cosmwasm_std::{Addr, Uint128}; use cw_storage_plus::{Item, Map}; use cw20::AllowanceResponse; @@ -18,7 +18,7 @@ pub struct TokenInfo { #[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] pub struct MinterData { - pub minter: CanonicalAddr, + pub minter: Addr, /// cap is how many more tokens can be issued by the minter pub cap: Option, } @@ -30,5 +30,5 @@ impl TokenInfo { } pub const TOKEN_INFO: Item = Item::new("token_info"); -pub const BALANCES: Map<&[u8], Uint128> = Map::new("balance"); -pub const ALLOWANCES: Map<(&[u8], &[u8]), AllowanceResponse> = Map::new("allowance"); +pub const BALANCES: Map<&Addr, Uint128> = Map::new("balance"); +pub const ALLOWANCES: Map<(&Addr, &Addr), AllowanceResponse> = Map::new("allowance"); diff --git a/contracts/cw20-bonding/Cargo.toml b/contracts/cw20-bonding/Cargo.toml index 975bcd6ed..eb57392f9 100644 --- a/contracts/cw20-bonding/Cargo.toml +++ b/contracts/cw20-bonding/Cargo.toml @@ -25,8 +25,8 @@ cw2 = { path = "../../packages/cw2", version = "0.6.0-alpha3" } cw20 = { path = "../../packages/cw20", version = "0.6.0-alpha3" } cw20-base = { path = "../../contracts/cw20-base", version = "0.6.0-alpha3", features = ["library"] } cw-storage-plus = { path = "../../packages/storage-plus", version = "0.6.0-alpha3" } -cosmwasm-std = { version = "0.14.0-beta1", features = ["staking"] } -schemars = "0.7" +cosmwasm-std = { version = "0.14.0-beta2", features = ["staking"] } +schemars = "0.8.1" serde = { version = "1.0.103", default-features = false, features = ["derive"] } thiserror = { version = "1.0.20" } rust_decimal = { version = "1.8.1" } @@ -34,4 +34,4 @@ integer-sqrt = { version = "0.1.5" } integer-cbrt = { version = "0.1" } [dev-dependencies] -cosmwasm-schema = { version = "0.14.0-beta1" } +cosmwasm-schema = { version = "0.14.0-beta2" } diff --git a/contracts/cw20-bonding/schema/allowance_response.json b/contracts/cw20-bonding/schema/allowance_response.json index 596d84464..5fb08aa98 100644 --- a/contracts/cw20-bonding/schema/allowance_response.json +++ b/contracts/cw20-bonding/schema/allowance_response.json @@ -30,7 +30,8 @@ "format": "uint64", "minimum": 0.0 } - } + }, + "additionalProperties": false }, { "description": "AtTime will expire when `env.block.time` >= time", @@ -44,7 +45,8 @@ "format": "uint64", "minimum": 0.0 } - } + }, + "additionalProperties": false }, { "description": "Never will never expire. Used to express the empty variant", @@ -56,7 +58,8 @@ "never": { "type": "object" } - } + }, + "additionalProperties": false } ] }, diff --git a/contracts/cw20-bonding/schema/execute_msg.json b/contracts/cw20-bonding/schema/execute_msg.json index 8d0f5cc73..625af98a4 100644 --- a/contracts/cw20-bonding/schema/execute_msg.json +++ b/contracts/cw20-bonding/schema/execute_msg.json @@ -12,7 +12,8 @@ "buy": { "type": "object" } - } + }, + "additionalProperties": false }, { "description": "Implements CW20. Transfer is a base message to move tokens to another account without triggering actions", @@ -32,11 +33,12 @@ "$ref": "#/definitions/Uint128" }, "recipient": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "Implements CW20. Burn is a base message to destroy tokens forever", @@ -56,7 +58,8 @@ } } } - } + }, + "additionalProperties": false }, { "description": "Implements CW20. Send is a base message to transfer tokens to a contract and trigger an action on the receiving contract.", @@ -76,7 +79,7 @@ "$ref": "#/definitions/Uint128" }, "contract": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "msg": { "anyOf": [ @@ -90,7 +93,8 @@ } } } - } + }, + "additionalProperties": false }, { "description": "Implements CW20 \"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.", @@ -120,11 +124,12 @@ ] }, "spender": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "Implements CW20 \"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.", @@ -154,11 +159,12 @@ ] }, "spender": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "Implements CW20 \"approval\" extension. Transfers amount tokens from owner -> recipient if `env.sender` has sufficient pre-approval.", @@ -179,14 +185,15 @@ "$ref": "#/definitions/Uint128" }, "owner": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "recipient": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "Implements CW20 \"approval\" extension. Sends amount tokens from owner -> contract if `env.sender` has sufficient pre-approval.", @@ -207,7 +214,7 @@ "$ref": "#/definitions/Uint128" }, "contract": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "msg": { "anyOf": [ @@ -220,11 +227,12 @@ ] }, "owner": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "Implements CW20 \"approval\" extension. Destroys tokens forever", @@ -244,11 +252,12 @@ "$ref": "#/definitions/Uint128" }, "owner": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false } ], "definitions": { @@ -271,7 +280,8 @@ "format": "uint64", "minimum": 0.0 } - } + }, + "additionalProperties": false }, { "description": "AtTime will expire when `env.block.time` >= time", @@ -285,7 +295,8 @@ "format": "uint64", "minimum": 0.0 } - } + }, + "additionalProperties": false }, { "description": "Never will never expire. Used to express the empty variant", @@ -297,13 +308,11 @@ "never": { "type": "object" } - } + }, + "additionalProperties": false } ] }, - "HumanAddr": { - "type": "string" - }, "Uint128": { "type": "string" } diff --git a/contracts/cw20-bonding/schema/instantiate_msg.json b/contracts/cw20-bonding/schema/instantiate_msg.json index 64985fca6..5c5b4ae49 100644 --- a/contracts/cw20-bonding/schema/instantiate_msg.json +++ b/contracts/cw20-bonding/schema/instantiate_msg.json @@ -71,7 +71,8 @@ } } } - } + }, + "additionalProperties": false }, { "description": "Linear returns `slope * 10^-scale * supply` as spot price", @@ -97,7 +98,8 @@ } } } - } + }, + "additionalProperties": false }, { "description": "SquareRoot returns `slope * 10^-scale * supply^0.5` as spot price", @@ -123,7 +125,8 @@ } } } - } + }, + "additionalProperties": false } ] }, diff --git a/contracts/cw20-bonding/schema/query_msg.json b/contracts/cw20-bonding/schema/query_msg.json index 34a7757e6..72ba5414c 100644 --- a/contracts/cw20-bonding/schema/query_msg.json +++ b/contracts/cw20-bonding/schema/query_msg.json @@ -12,7 +12,8 @@ "curve_info": { "type": "object" } - } + }, + "additionalProperties": false }, { "description": "Implements CW20. Returns the current balance of the given address, 0 if unset.", @@ -28,11 +29,12 @@ ], "properties": { "address": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "Implements CW20. Returns metadata on the contract - name, decimals, supply, etc.", @@ -44,7 +46,8 @@ "token_info": { "type": "object" } - } + }, + "additionalProperties": false }, { "description": "Implements CW20 \"allowance\" extension. Returns how much spender can use from owner account, 0 if unset.", @@ -61,19 +64,15 @@ ], "properties": { "owner": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "spender": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false } - ], - "definitions": { - "HumanAddr": { - "type": "string" - } - } + ] } diff --git a/contracts/cw20-bonding/src/contract.rs b/contracts/cw20-bonding/src/contract.rs index 87c0cb767..70ff4becd 100644 --- a/contracts/cw20-bonding/src/contract.rs +++ b/contracts/cw20-bonding/src/contract.rs @@ -1,8 +1,8 @@ #[cfg(not(feature = "library"))] use cosmwasm_std::entry_point; use cosmwasm_std::{ - attr, coins, to_binary, BankMsg, Binary, Deps, DepsMut, Env, HumanAddr, MessageInfo, Response, - StdResult, Uint128, + attr, coins, to_binary, Addr, BankMsg, Binary, Deps, DepsMut, Env, MessageInfo, Response, + StdError, StdResult, Uint128, }; use cw2::set_contract_version; @@ -43,7 +43,7 @@ pub fn instantiate( total_supply: Uint128(0), // set self as minter, so we can properly execute mint and burn mint: Some(MinterData { - minter: deps.api.canonical_address(&env.contract.address)?, + minter: env.contract.address, cap: None, }), }; @@ -146,7 +146,9 @@ pub fn execute_buy( let curve = curve_fn(state.decimals); state.reserve += payment; let new_supply = curve.supply(state.reserve); - let minted = (new_supply - state.supply)?; + let minted = new_supply + .checked_sub(state.supply) + .map_err(StdError::overflow)?; state.supply = new_supply; CURVE_STATE.save(deps.storage, &state)?; @@ -155,7 +157,7 @@ pub fn execute_buy( sender: env.contract.address.clone(), funds: vec![], }; - execute_mint(deps, env, sub_info, info.sender.clone(), minted)?; + execute_mint(deps, env, sub_info, info.sender.to_string(), minted)?; // bond them to the validator let res = Response { @@ -194,27 +196,34 @@ pub fn execute_sell_from( env: Env, info: MessageInfo, curve_fn: CurveFn, - owner: HumanAddr, + owner: String, amount: Uint128, ) -> Result { nonpayable(&info)?; - let owner_raw = deps.api.canonical_address(&owner)?; - let spender_raw = deps.api.canonical_address(&info.sender)?; + let owner_addr = deps.api.addr_validate(&owner)?; + let spender_addr = info.sender.clone(); // deduct allowance before doing anything else have enough allowance - deduct_allowance(deps.storage, &owner_raw, &spender_raw, &env.block, amount)?; + deduct_allowance(deps.storage, &owner_addr, &spender_addr, &env.block, amount)?; // do all the work in do_sell - let receiver = info.sender; + let receiver_addr = info.sender; let owner_info = MessageInfo { - sender: owner, + sender: owner_addr, funds: info.funds, }; - let mut res = do_sell(deps, env, owner_info, curve_fn, receiver.clone(), amount)?; + let mut res = do_sell( + deps, + env, + owner_info, + curve_fn, + receiver_addr.clone(), + amount, + )?; // add our custom attributes res.attributes.push(attr("action", "burn_from")); - res.attributes.push(attr("by", receiver)); + res.attributes.push(attr("by", receiver_addr)); Ok(res) } @@ -225,7 +234,7 @@ fn do_sell( info: MessageInfo, curve_fn: CurveFn, // receiver is the one who gains (same for execute_sell, diff for execute_sell_from) - receiver: HumanAddr, + receiver: Addr, amount: Uint128, ) -> Result { // burn from the caller, this ensures there are tokens to cover this @@ -234,15 +243,21 @@ fn do_sell( // calculate how many tokens can be purchased with this and mint them let mut state = CURVE_STATE.load(deps.storage)?; let curve = curve_fn(state.decimals); - state.supply = (state.supply - amount)?; + state.supply = state + .supply + .checked_sub(amount) + .map_err(StdError::overflow)?; let new_reserve = curve.reserve(state.supply); - let released = (state.reserve - new_reserve)?; + let released = state + .reserve + .checked_sub(new_reserve) + .map_err(StdError::overflow)?; state.reserve = new_reserve; CURVE_STATE.save(deps.storage, &state)?; // now send the tokens to the sender (TODO: for sell_from we do something else, right???) let msg = BankMsg::Send { - to_address: receiver, + to_address: receiver.to_string(), amount: coins(released.u128(), state.reserve_denom), }; let res = Response { @@ -309,7 +324,7 @@ mod tests { use super::*; use crate::msg::CurveType; use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info}; - use cosmwasm_std::{coin, Decimal, StdError}; + use cosmwasm_std::{coin, Decimal, OverflowError, OverflowOperation, StdError}; use cw0::PaymentError; const DENOM: &str = "satoshi"; @@ -332,13 +347,13 @@ mod tests { } } - fn get_balance>(deps: Deps, addr: U) -> Uint128 { + fn get_balance>(deps: Deps, addr: U) -> Uint128 { query_balance(deps, addr.into()).unwrap().balance } fn setup_test(deps: DepsMut, decimals: u8, reserve_decimals: u8, curve_type: CurveType) { // this matches `linear_curve` test case from curves.rs - let creator = HumanAddr::from(CREATOR); + let creator = String::from(CREATOR); let msg = default_instantiate(decimals, reserve_decimals, curve_type.clone()); let info = mock_info(&creator, &[]); @@ -352,7 +367,7 @@ mod tests { let mut deps = mock_dependencies(&[]); // this matches `linear_curve` test case from curves.rs - let creator = HumanAddr::from("creator"); + let creator = String::from("creator"); let curve_type = CurveType::SquareRoot { slope: Uint128(1), scale: 1, @@ -488,8 +503,8 @@ mod tests { let err = execute(deps.as_mut(), mock_env(), info, burn).unwrap_err(); assert_eq!( err, - ContractError::Base(cw20_base::ContractError::Std(StdError::underflow( - 2000, 3000 + ContractError::Base(cw20_base::ContractError::Std(StdError::overflow( + OverflowError::new(OverflowOperation::Sub, 2000, 3000) ))) ); @@ -603,8 +618,8 @@ mod tests { let err = execute(deps.as_mut(), mock_env(), info, burn_from).unwrap_err(); assert_eq!( err, - ContractError::Base(cw20_base::ContractError::Std(StdError::underflow( - 3000000, 3300000 + ContractError::Base(cw20_base::ContractError::Std(StdError::overflow( + OverflowError::new(OverflowOperation::Sub, 3000000, 3300000) ))) ); diff --git a/contracts/cw20-bonding/src/msg.rs b/contracts/cw20-bonding/src/msg.rs index 37797a20e..591150549 100644 --- a/contracts/cw20-bonding/src/msg.rs +++ b/contracts/cw20-bonding/src/msg.rs @@ -2,7 +2,7 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use crate::curves::{decimal, Constant, Curve, DecimalPlaces, Linear, SquareRoot}; -use cosmwasm_std::{Binary, Decimal, HumanAddr, Uint128}; +use cosmwasm_std::{Binary, Decimal, Uint128}; use cw20::Expiration; #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] @@ -74,16 +74,13 @@ pub enum ExecuteMsg { Buy {}, /// Implements CW20. Transfer is a base message to move tokens to another account without triggering actions - Transfer { - recipient: HumanAddr, - amount: Uint128, - }, + Transfer { recipient: String, amount: Uint128 }, /// Implements CW20. Burn is a base message to destroy tokens forever Burn { amount: Uint128 }, /// Implements CW20. Send is a base message to transfer tokens to a contract and trigger an action /// on the receiving contract. Send { - contract: HumanAddr, + contract: String, amount: Uint128, msg: Option, }, @@ -91,7 +88,7 @@ pub enum ExecuteMsg { /// from the owner's (env.sender) account. If expires is Some(), overwrites current allowance /// expiration with this one. IncreaseAllowance { - spender: HumanAddr, + spender: String, amount: Uint128, expires: Option, }, @@ -99,27 +96,27 @@ pub enum ExecuteMsg { /// from the owner's (env.sender) account by amount. If expires is Some(), overwrites current /// allowance expiration with this one. DecreaseAllowance { - spender: HumanAddr, + spender: String, amount: Uint128, expires: Option, }, /// Implements CW20 "approval" extension. Transfers amount tokens from owner -> recipient /// if `env.sender` has sufficient pre-approval. TransferFrom { - owner: HumanAddr, - recipient: HumanAddr, + owner: String, + recipient: String, amount: Uint128, }, /// Implements CW20 "approval" extension. Sends amount tokens from owner -> contract /// if `env.sender` has sufficient pre-approval. SendFrom { - owner: HumanAddr, - contract: HumanAddr, + owner: String, + contract: String, amount: Uint128, msg: Option, }, /// Implements CW20 "approval" extension. Destroys tokens forever - BurnFrom { owner: HumanAddr, amount: Uint128 }, + BurnFrom { owner: String, amount: Uint128 }, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] @@ -129,15 +126,12 @@ pub enum QueryMsg { CurveInfo {}, /// Implements CW20. Returns the current balance of the given address, 0 if unset. - Balance { address: HumanAddr }, + Balance { address: String }, /// Implements CW20. Returns metadata on the contract - name, decimals, supply, etc. TokenInfo {}, /// Implements CW20 "allowance" extension. /// Returns how much spender can use from owner account, 0 if unset. - Allowance { - owner: HumanAddr, - spender: HumanAddr, - }, + Allowance { owner: String, spender: String }, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] diff --git a/contracts/cw20-escrow/Cargo.toml b/contracts/cw20-escrow/Cargo.toml index 49f12a189..c0106d2a8 100644 --- a/contracts/cw20-escrow/Cargo.toml +++ b/contracts/cw20-escrow/Cargo.toml @@ -21,13 +21,13 @@ library = [] cw0 = { path = "../../packages/cw0", version = "0.6.0-alpha3" } cw2 = { path = "../../packages/cw2", version = "0.6.0-alpha3" } cw20 = { path = "../../packages/cw20", version = "0.6.0-alpha3" } -cosmwasm-std = { version = "0.14.0-beta1", features = ["iterator"] } +cosmwasm-std = { version = "0.14.0-beta2", features = ["iterator"] } cw-storage-plus = { path = "../../packages/storage-plus", version = "0.6.0-alpha3", features = ["iterator"] } -schemars = "0.7" +schemars = "0.8.1" serde = { version = "1.0.103", default-features = false, features = ["derive"] } thiserror = { version = "1.0.20" } [dev-dependencies] -cosmwasm-schema = { version = "0.14.0-beta1" } +cosmwasm-schema = { version = "0.14.0-beta2" } cw-multi-test = { path = "../../packages/multi-test", version = "0.6.0-alpha3" } cw20-base = { path = "../cw20-base", version = "0.6.0-alpha3", features = ["library"] } diff --git a/contracts/cw20-escrow/schema/details_response.json b/contracts/cw20-escrow/schema/details_response.json index 89b9ae6fc..7a7c1267d 100644 --- a/contracts/cw20-escrow/schema/details_response.json +++ b/contracts/cw20-escrow/schema/details_response.json @@ -14,24 +14,20 @@ "properties": { "arbiter": { "description": "arbiter can decide to approve or refund the escrow", - "allOf": [ - { - "$ref": "#/definitions/HumanAddr" - } - ] + "type": "string" }, "cw20_balance": { "description": "Balance in cw20 tokens", "type": "array", "items": { - "$ref": "#/definitions/Cw20CoinHuman" + "$ref": "#/definitions/Cw20Coin" } }, "cw20_whitelist": { "description": "Whitelisted cw20 tokens", "type": "array", "items": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } }, "end_height": { @@ -65,19 +61,11 @@ }, "recipient": { "description": "if approved, funds go to the recipient", - "allOf": [ - { - "$ref": "#/definitions/HumanAddr" - } - ] + "type": "string" }, "source": { "description": "if refunded, funds go to the source", - "allOf": [ - { - "$ref": "#/definitions/HumanAddr" - } - ] + "type": "string" } }, "definitions": { @@ -96,7 +84,7 @@ } } }, - "Cw20CoinHuman": { + "Cw20Coin": { "type": "object", "required": [ "address", @@ -104,16 +92,13 @@ ], "properties": { "address": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "amount": { "$ref": "#/definitions/Uint128" } } }, - "HumanAddr": { - "type": "string" - }, "Uint128": { "type": "string" } diff --git a/contracts/cw20-escrow/schema/execute_msg.json b/contracts/cw20-escrow/schema/execute_msg.json index bafbe26dd..4a13e3341 100644 --- a/contracts/cw20-escrow/schema/execute_msg.json +++ b/contracts/cw20-escrow/schema/execute_msg.json @@ -11,7 +11,8 @@ "create": { "$ref": "#/definitions/CreateMsg" } - } + }, + "additionalProperties": false }, { "description": "Adds all sent native tokens to the contract", @@ -31,7 +32,8 @@ } } } - } + }, + "additionalProperties": false }, { "description": "Approve sends all tokens to the recipient. Only the arbiter can do this", @@ -52,7 +54,8 @@ } } } - } + }, + "additionalProperties": false }, { "description": "Refund returns all remaining tokens to the original sender, The arbiter can do this any time, or anyone can do this after a timeout", @@ -73,7 +76,8 @@ } } } - } + }, + "additionalProperties": false }, { "description": "This accepts a properly-encoded ReceiveMsg from a cw20 contract", @@ -85,7 +89,8 @@ "receive": { "$ref": "#/definitions/Cw20ReceiveMsg" } - } + }, + "additionalProperties": false } ], "definitions": { @@ -103,11 +108,7 @@ "properties": { "arbiter": { "description": "arbiter can decide to approve or refund the escrow", - "allOf": [ - { - "$ref": "#/definitions/HumanAddr" - } - ] + "type": "string" }, "cw20_whitelist": { "description": "Besides any possible tokens sent with the CreateMsg, this is a list of all cw20 token addresses that are accepted by the escrow during a top-up. This is required to avoid a DoS attack by topping-up with an invalid cw20 contract. See https://github.com/CosmWasm/cosmwasm-plus/issues/19", @@ -116,7 +117,7 @@ "null" ], "items": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } }, "end_height": { @@ -143,11 +144,7 @@ }, "recipient": { "description": "if approved, funds go to the recipient", - "allOf": [ - { - "$ref": "#/definitions/HumanAddr" - } - ] + "type": "string" } } }, @@ -173,13 +170,10 @@ ] }, "sender": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } }, - "HumanAddr": { - "type": "string" - }, "Uint128": { "type": "string" } diff --git a/contracts/cw20-escrow/schema/query_msg.json b/contracts/cw20-escrow/schema/query_msg.json index 7e9348fa7..8f19ba54f 100644 --- a/contracts/cw20-escrow/schema/query_msg.json +++ b/contracts/cw20-escrow/schema/query_msg.json @@ -12,7 +12,8 @@ "list": { "type": "object" } - } + }, + "additionalProperties": false }, { "description": "Returns the details of the named escrow, error if not created Return type: DetailsResponse.", @@ -32,7 +33,8 @@ } } } - } + }, + "additionalProperties": false } ] } diff --git a/contracts/cw20-escrow/schema/receive_msg.json b/contracts/cw20-escrow/schema/receive_msg.json index eae75fb94..74de37e79 100644 --- a/contracts/cw20-escrow/schema/receive_msg.json +++ b/contracts/cw20-escrow/schema/receive_msg.json @@ -11,7 +11,8 @@ "create": { "$ref": "#/definitions/CreateMsg" } - } + }, + "additionalProperties": false }, { "description": "Adds all sent native tokens to the contract", @@ -31,7 +32,8 @@ } } } - } + }, + "additionalProperties": false } ], "definitions": { @@ -45,11 +47,7 @@ "properties": { "arbiter": { "description": "arbiter can decide to approve or refund the escrow", - "allOf": [ - { - "$ref": "#/definitions/HumanAddr" - } - ] + "type": "string" }, "cw20_whitelist": { "description": "Besides any possible tokens sent with the CreateMsg, this is a list of all cw20 token addresses that are accepted by the escrow during a top-up. This is required to avoid a DoS attack by topping-up with an invalid cw20 contract. See https://github.com/CosmWasm/cosmwasm-plus/issues/19", @@ -58,7 +56,7 @@ "null" ], "items": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } }, "end_height": { @@ -85,16 +83,9 @@ }, "recipient": { "description": "if approved, funds go to the recipient", - "allOf": [ - { - "$ref": "#/definitions/HumanAddr" - } - ] + "type": "string" } } - }, - "HumanAddr": { - "type": "string" } } } diff --git a/contracts/cw20-escrow/src/contract.rs b/contracts/cw20-escrow/src/contract.rs index 4558f5767..0b8950c9a 100644 --- a/contracts/cw20-escrow/src/contract.rs +++ b/contracts/cw20-escrow/src/contract.rs @@ -1,12 +1,12 @@ #[cfg(not(feature = "library"))] use cosmwasm_std::entry_point; use cosmwasm_std::{ - attr, from_binary, to_binary, Api, BankMsg, Binary, CosmosMsg, Deps, DepsMut, Env, HumanAddr, + attr, from_binary, to_binary, Addr, BankMsg, Binary, CosmosMsg, Deps, DepsMut, Env, MessageInfo, Response, StdResult, WasmMsg, }; use cw2::set_contract_version; -use cw20::{Balance, Cw20Coin, Cw20CoinHuman, Cw20ExecuteMsg, Cw20ReceiveMsg}; +use cw20::{Balance, Cw20Coin, Cw20CoinVerified, Cw20ExecuteMsg, Cw20ReceiveMsg}; use crate::error::ContractError; use crate::msg::{ @@ -57,12 +57,15 @@ pub fn execute_receive( Some(bin) => Ok(from_binary(&bin)?), None => Err(ContractError::NoData {}), }?; - let balance = Balance::Cw20(Cw20Coin { - address: deps.api.canonical_address(&info.sender)?, + let balance = Balance::Cw20(Cw20CoinVerified { + address: info.sender, amount: wrapper.amount, }); + let api = deps.api; match msg { - ReceiveMsg::Create(msg) => execute_create(deps, msg, balance, &wrapper.sender), + ReceiveMsg::Create(msg) => { + execute_create(deps, msg, balance, &api.addr_validate(&wrapper.sender)?) + } ReceiveMsg::TopUp { id } => execute_top_up(deps, id, balance), } } @@ -71,13 +74,13 @@ pub fn execute_create( deps: DepsMut, msg: CreateMsg, balance: Balance, - sender: &HumanAddr, + sender: &Addr, ) -> Result { if balance.is_empty() { return Err(ContractError::EmptyBalance {}); } - let mut cw20_whitelist = msg.canonical_whitelist(deps.api)?; + let mut cw20_whitelist = msg.addr_whitelist(deps.api)?; let escrow_balance = match balance { Balance::Native(balance) => GenericBalance { @@ -97,9 +100,9 @@ pub fn execute_create( }; let escrow = Escrow { - arbiter: deps.api.canonical_address(&msg.arbiter)?, - recipient: deps.api.canonical_address(&msg.recipient)?, - source: deps.api.canonical_address(&sender)?, + arbiter: deps.api.addr_validate(&msg.arbiter)?, + recipient: deps.api.addr_validate(&msg.recipient)?, + source: sender.clone(), end_height: msg.end_height, end_time: msg.end_time, balance: escrow_balance, @@ -158,7 +161,7 @@ pub fn execute_approve( // this fails is no escrow there let escrow = ESCROWS.load(deps.storage, &id)?; - if deps.api.canonical_address(&info.sender)? != escrow.arbiter { + if info.sender != escrow.arbiter { Err(ContractError::Unauthorized {}) } else if escrow.is_expired(&env) { Err(ContractError::Expired {}) @@ -166,12 +169,14 @@ pub fn execute_approve( // we delete the escrow ESCROWS.remove(deps.storage, &id); - let rcpt = deps.api.human_address(&escrow.recipient)?; - // send all tokens out - let messages = send_tokens(deps.api, &rcpt, &escrow.balance)?; + let messages = send_tokens(&escrow.recipient, &escrow.balance)?; - let attributes = vec![attr("action", "approve"), attr("id", id), attr("to", rcpt)]; + let attributes = vec![ + attr("action", "approve"), + attr("id", id), + attr("to", escrow.recipient), + ]; Ok(Response { submessages: vec![], messages, @@ -191,18 +196,20 @@ pub fn execute_refund( let escrow = ESCROWS.load(deps.storage, &id)?; // the arbiter can send anytime OR anyone can send after expiration - if !escrow.is_expired(&env) && deps.api.canonical_address(&info.sender)? != escrow.arbiter { + if !escrow.is_expired(&env) && info.sender != escrow.arbiter { Err(ContractError::Unauthorized {}) } else { // we delete the escrow ESCROWS.remove(deps.storage, &id); - let rcpt = deps.api.human_address(&escrow.source)?; - // send all tokens out - let messages = send_tokens(deps.api, &rcpt, &escrow.balance)?; + let messages = send_tokens(&escrow.source, &escrow.balance)?; - let attributes = vec![attr("action", "refund"), attr("id", id), attr("to", rcpt)]; + let attributes = vec![ + attr("action", "refund"), + attr("id", id), + attr("to", escrow.source), + ]; Ok(Response { submessages: vec![], messages, @@ -212,11 +219,7 @@ pub fn execute_refund( } } -fn send_tokens( - api: &dyn Api, - to: &HumanAddr, - balance: &GenericBalance, -) -> StdResult> { +fn send_tokens(to: &Addr, balance: &GenericBalance) -> StdResult> { let native_balance = &balance.native; let mut msgs: Vec = if native_balance.is_empty() { vec![] @@ -237,7 +240,7 @@ fn send_tokens( amount: c.amount, }; let exec = WasmMsg::Execute { - contract_addr: api.human_address(&c.address)?, + contract_addr: c.address.to_string(), msg: to_binary(&msg)?, send: vec![], }; @@ -259,7 +262,7 @@ pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult { fn query_details(deps: Deps, id: String) -> StdResult { let escrow = ESCROWS.load(deps.storage, &id)?; - let cw20_whitelist = escrow.human_whitelist(deps.api)?; + let cw20_whitelist = escrow.human_whitelist(); // transform tokens let native_balance = escrow.balance.native; @@ -269,8 +272,8 @@ fn query_details(deps: Deps, id: String) -> StdResult { .cw20 .into_iter() .map(|token| { - Ok(Cw20CoinHuman { - address: deps.api.human_address(&token.address)?, + Ok(Cw20Coin { + address: token.address.into(), amount: token.amount, }) }) @@ -278,9 +281,9 @@ fn query_details(deps: Deps, id: String) -> StdResult { let details = DetailsResponse { id, - arbiter: deps.api.human_address(&escrow.arbiter)?, - recipient: deps.api.human_address(&escrow.recipient)?, - source: deps.api.human_address(&escrow.source)?, + arbiter: escrow.arbiter.into(), + recipient: escrow.recipient.into(), + source: escrow.source.into(), end_height: escrow.end_height, end_time: escrow.end_time, native_balance, @@ -299,7 +302,7 @@ fn query_list(deps: Deps) -> StdResult { #[cfg(test)] mod tests { use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info}; - use cosmwasm_std::{coin, coins, CanonicalAddr, CosmosMsg, StdError, Uint128}; + use cosmwasm_std::{coin, coins, CosmosMsg, StdError, Uint128}; use crate::msg::ExecuteMsg::TopUp; @@ -311,20 +314,20 @@ mod tests { // instantiate an empty contract let instantiate_msg = InstantiateMsg {}; - let info = mock_info(&HumanAddr::from("anyone"), &[]); + let info = mock_info(&String::from("anyone"), &[]); let res = instantiate(deps.as_mut(), mock_env(), info, instantiate_msg).unwrap(); assert_eq!(0, res.messages.len()); // create an escrow let create = CreateMsg { id: "foobar".to_string(), - arbiter: HumanAddr::from("arbitrate"), - recipient: HumanAddr::from("recd"), + arbiter: String::from("arbitrate"), + recipient: String::from("recd"), end_time: None, end_height: Some(123456), cw20_whitelist: None, }; - let sender = HumanAddr::from("source"); + let sender = String::from("source"); let balance = coins(100, "tokens"); let info = mock_info(&sender, &balance); let msg = ExecuteMsg::Create(create.clone()); @@ -338,9 +341,9 @@ mod tests { details, DetailsResponse { id: "foobar".to_string(), - arbiter: HumanAddr::from("arbitrate"), - recipient: HumanAddr::from("recd"), - source: HumanAddr::from("source"), + arbiter: String::from("arbitrate"), + recipient: String::from("recd"), + source: String::from("source"), end_height: Some(123456), end_time: None, native_balance: balance.clone(), @@ -376,25 +379,25 @@ mod tests { // instantiate an empty contract let instantiate_msg = InstantiateMsg {}; - let info = mock_info(&HumanAddr::from("anyone"), &[]); + let info = mock_info(&String::from("anyone"), &[]); let res = instantiate(deps.as_mut(), mock_env(), info, instantiate_msg).unwrap(); assert_eq!(0, res.messages.len()); // create an escrow let create = CreateMsg { id: "foobar".to_string(), - arbiter: HumanAddr::from("arbitrate"), - recipient: HumanAddr::from("recd"), + arbiter: String::from("arbitrate"), + recipient: String::from("recd"), end_time: None, end_height: None, - cw20_whitelist: Some(vec![HumanAddr::from("other-token")]), + cw20_whitelist: Some(vec![String::from("other-token")]), }; let receive = Cw20ReceiveMsg { - sender: HumanAddr::from("source"), + sender: String::from("source"), amount: Uint128(100), msg: Some(to_binary(&ExecuteMsg::Create(create.clone())).unwrap()), }; - let token_contract = HumanAddr::from("my-cw20-token"); + let token_contract = String::from("my-cw20-token"); let info = mock_info(&token_contract, &[]); let msg = ExecuteMsg::Receive(receive.clone()); let res = execute(deps.as_mut(), mock_env(), info, msg).unwrap(); @@ -407,20 +410,17 @@ mod tests { details, DetailsResponse { id: "foobar".to_string(), - arbiter: HumanAddr::from("arbitrate"), - recipient: HumanAddr::from("recd"), - source: HumanAddr::from("source"), + arbiter: String::from("arbitrate"), + recipient: String::from("recd"), + source: String::from("source"), end_height: None, end_time: None, native_balance: vec![], - cw20_balance: vec![Cw20CoinHuman { - address: HumanAddr::from("my-cw20-token"), + cw20_balance: vec![Cw20Coin { + address: String::from("my-cw20-token"), amount: Uint128(100), }], - cw20_whitelist: vec![ - HumanAddr::from("other-token"), - HumanAddr::from("my-cw20-token") - ], + cw20_whitelist: vec![String::from("other-token"), String::from("my-cw20-token")], } ); @@ -464,28 +464,28 @@ mod tests { #[test] fn add_cw_tokens_proper() { let mut tokens = GenericBalance::default(); - let bar_token = CanonicalAddr(b"bar_token".to_vec().into()); - let foo_token = CanonicalAddr(b"foo_token".to_vec().into()); - tokens.add_tokens(Balance::Cw20(Cw20Coin { + let bar_token = Addr::unchecked("bar_token"); + let foo_token = Addr::unchecked("foo_token"); + tokens.add_tokens(Balance::Cw20(Cw20CoinVerified { address: foo_token.clone(), amount: Uint128(12345), })); - tokens.add_tokens(Balance::Cw20(Cw20Coin { + tokens.add_tokens(Balance::Cw20(Cw20CoinVerified { address: bar_token.clone(), amount: Uint128(777), })); - tokens.add_tokens(Balance::Cw20(Cw20Coin { + tokens.add_tokens(Balance::Cw20(Cw20CoinVerified { address: foo_token.clone(), amount: Uint128(23400), })); assert_eq!( tokens.cw20, vec![ - Cw20Coin { + Cw20CoinVerified { address: foo_token, amount: Uint128(35745), }, - Cw20Coin { + Cw20CoinVerified { address: bar_token, amount: Uint128(777), } @@ -499,23 +499,23 @@ mod tests { // instantiate an empty contract let instantiate_msg = InstantiateMsg {}; - let info = mock_info(&HumanAddr::from("anyone"), &[]); + let info = mock_info(&String::from("anyone"), &[]); let res = instantiate(deps.as_mut(), mock_env(), info, instantiate_msg).unwrap(); assert_eq!(0, res.messages.len()); // only accept these tokens - let whitelist = vec![HumanAddr::from("bar_token"), HumanAddr::from("foo_token")]; + let whitelist = vec![String::from("bar_token"), String::from("foo_token")]; // create an escrow with 2 native tokens let create = CreateMsg { id: "foobar".to_string(), - arbiter: HumanAddr::from("arbitrate"), - recipient: HumanAddr::from("recd"), + arbiter: String::from("arbitrate"), + recipient: String::from("recd"), end_time: None, end_height: None, cw20_whitelist: Some(whitelist), }; - let sender = HumanAddr::from("source"); + let sender = String::from("source"); let balance = vec![coin(100, "fee"), coin(200, "stake")]; let info = mock_info(&sender, &balance); let msg = ExecuteMsg::Create(create.clone()); @@ -534,12 +534,12 @@ mod tests { assert_eq!(attr("action", "top_up"), res.attributes[0]); // top up with one foreign token - let bar_token = HumanAddr::from("bar_token"); + let bar_token = String::from("bar_token"); let base = TopUp { id: create.id.clone(), }; let top_up = ExecuteMsg::Receive(Cw20ReceiveMsg { - sender: HumanAddr::from("random"), + sender: String::from("random"), amount: Uint128(7890), msg: Some(to_binary(&base).unwrap()), }); @@ -550,12 +550,12 @@ mod tests { // top with a foreign token not on the whitelist // top up with one foreign token - let baz_token = HumanAddr::from("baz_token"); + let baz_token = String::from("baz_token"); let base = TopUp { id: create.id.clone(), }; let top_up = ExecuteMsg::Receive(Cw20ReceiveMsg { - sender: HumanAddr::from("random"), + sender: String::from("random"), amount: Uint128(7890), msg: Some(to_binary(&base).unwrap()), }); @@ -564,12 +564,12 @@ mod tests { assert_eq!(err, ContractError::NotInWhitelist {}); // top up with second foreign token - let foo_token = HumanAddr::from("foo_token"); + let foo_token = String::from("foo_token"); let base = TopUp { id: create.id.clone(), }; let top_up = ExecuteMsg::Receive(Cw20ReceiveMsg { - sender: HumanAddr::from("random"), + sender: String::from("random"), amount: Uint128(888), msg: Some(to_binary(&base).unwrap()), }); diff --git a/contracts/cw20-escrow/src/integration_test.rs b/contracts/cw20-escrow/src/integration_test.rs index 941536af5..ee72275ee 100644 --- a/contracts/cw20-escrow/src/integration_test.rs +++ b/contracts/cw20-escrow/src/integration_test.rs @@ -1,8 +1,8 @@ #![cfg(test)] use cosmwasm_std::testing::{mock_env, MockApi, MockStorage}; -use cosmwasm_std::{coins, to_binary, Empty, HumanAddr, Uint128}; -use cw20::{Cw20CoinHuman, Cw20Contract, Cw20ExecuteMsg}; +use cosmwasm_std::{coins, to_binary, Addr, Empty, Uint128}; +use cw20::{Cw20Coin, Cw20Contract, Cw20ExecuteMsg}; use cw_multi_test::{App, Contract, ContractWrapper, SimpleBank}; use crate::msg::{CreateMsg, DetailsResponse, ExecuteMsg, InstantiateMsg, QueryMsg, ReceiveMsg}; @@ -39,7 +39,7 @@ fn escrow_happy_path_cw20_tokens() { let mut router = mock_app(); // set personal balance - let owner = HumanAddr::from("owner"); + let owner = Addr::unchecked("owner"); let init_funds = coins(2000, "btc"); router .set_bank_balance(owner.clone(), init_funds.clone()) @@ -51,20 +51,20 @@ fn escrow_happy_path_cw20_tokens() { name: "Cash Money".to_string(), symbol: "CASH".to_string(), decimals: 2, - initial_balances: vec![Cw20CoinHuman { - address: owner.clone(), + initial_balances: vec![Cw20Coin { + address: owner.to_string(), amount: Uint128(5000), }], mint: None, }; let cash_addr = router - .instantiate_contract(cw20_id, &owner, &msg, &[], "CASH") + .instantiate_contract(cw20_id, owner.clone(), &msg, &[], "CASH") .unwrap(); // set up reflect contract let escrow_id = router.store_code(contract_escrow()); let escrow_addr = router - .instantiate_contract(escrow_id, &owner, &InstantiateMsg {}, &[], "Escrow") + .instantiate_contract(escrow_id, owner.clone(), &InstantiateMsg {}, &[], "Escrow") .unwrap(); // they are different @@ -80,12 +80,12 @@ fn escrow_happy_path_cw20_tokens() { assert_eq!(escrow_balance, Uint128(0)); // send some tokens to create an escrow - let arb = HumanAddr::from("arbiter"); - let ben = HumanAddr::from("beneficiary"); + let arb = Addr::unchecked("arbiter"); + let ben = String::from("beneficiary"); let id = "demo".to_string(); let create_msg = ReceiveMsg::Create(CreateMsg { id: id.clone(), - arbiter: arb.clone(), + arbiter: arb.to_string(), recipient: ben.clone(), end_height: None, end_time: None, @@ -93,12 +93,12 @@ fn escrow_happy_path_cw20_tokens() { }); let create_bin = to_binary(&create_msg).unwrap(); let send_msg = Cw20ExecuteMsg::Send { - contract: escrow_addr.clone(), + contract: escrow_addr.to_string(), amount: Uint128(1200), msg: Some(create_bin), }; let res = router - .execute_contract(&owner, &cash_addr, &send_msg, &[]) + .execute_contract(owner.clone(), cash_addr.clone(), &send_msg, &[]) .unwrap(); println!("{:?}", res.attributes); assert_eq!(6, res.attributes.len()); @@ -118,8 +118,8 @@ fn escrow_happy_path_cw20_tokens() { assert_eq!(arb, details.arbiter); assert_eq!(ben, details.recipient); assert_eq!( - vec![Cw20CoinHuman { - address: cash_addr.clone(), + vec![Cw20Coin { + address: cash_addr.to_string(), amount: Uint128(1200) }], details.cw20_balance @@ -128,13 +128,13 @@ fn escrow_happy_path_cw20_tokens() { // release escrow let approve_msg = ExecuteMsg::Approve { id: id.clone() }; let _ = router - .execute_contract(&arb, &escrow_addr, &approve_msg, &[]) + .execute_contract(arb, escrow_addr.clone(), &approve_msg, &[]) .unwrap(); // ensure balances updated - release to ben let owner_balance = cash.balance(&router, owner.clone()).unwrap(); assert_eq!(owner_balance, Uint128(3800)); - let escrow_balance = cash.balance(&router, escrow_addr.clone()).unwrap(); + let escrow_balance = cash.balance(&router, escrow_addr).unwrap(); assert_eq!(escrow_balance, Uint128(0)); let ben_balance = cash.balance(&router, ben.clone()).unwrap(); assert_eq!(ben_balance, Uint128(1200)); diff --git a/contracts/cw20-escrow/src/msg.rs b/contracts/cw20-escrow/src/msg.rs index 41fc9fcba..8dbd607ea 100644 --- a/contracts/cw20-escrow/src/msg.rs +++ b/contracts/cw20-escrow/src/msg.rs @@ -1,9 +1,9 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -use cosmwasm_std::{Api, CanonicalAddr, Coin, HumanAddr, StdResult}; +use cosmwasm_std::{Addr, Api, Coin, StdResult}; -use cw20::{Cw20CoinHuman, Cw20ReceiveMsg}; +use cw20::{Cw20Coin, Cw20ReceiveMsg}; #[derive(Serialize, Deserialize, JsonSchema)] pub struct InstantiateMsg {} @@ -48,9 +48,9 @@ pub struct CreateMsg { /// 3-20 bytes of utf-8 text pub id: String, /// arbiter can decide to approve or refund the escrow - pub arbiter: HumanAddr, + pub arbiter: String, /// if approved, funds go to the recipient - pub recipient: HumanAddr, + pub recipient: String, /// When end height set and block height exceeds this value, the escrow is expired. /// Once an escrow is expired, it can be returned to the original funder (via "refund"). pub end_height: Option, @@ -61,13 +61,13 @@ pub struct CreateMsg { /// Besides any possible tokens sent with the CreateMsg, this is a list of all cw20 token addresses /// that are accepted by the escrow during a top-up. This is required to avoid a DoS attack by topping-up /// with an invalid cw20 contract. See https://github.com/CosmWasm/cosmwasm-plus/issues/19 - pub cw20_whitelist: Option>, + pub cw20_whitelist: Option>, } impl CreateMsg { - pub fn canonical_whitelist(&self, api: &dyn Api) -> StdResult> { + pub fn addr_whitelist(&self, api: &dyn Api) -> StdResult> { match self.cw20_whitelist.as_ref() { - Some(v) => v.iter().map(|h| api.canonical_address(h)).collect(), + Some(v) => v.iter().map(|h| api.addr_validate(h)).collect(), None => Ok(vec![]), } } @@ -102,11 +102,11 @@ pub struct DetailsResponse { /// id of this escrow pub id: String, /// arbiter can decide to approve or refund the escrow - pub arbiter: HumanAddr, + pub arbiter: String, /// if approved, funds go to the recipient - pub recipient: HumanAddr, + pub recipient: String, /// if refunded, funds go to the source - pub source: HumanAddr, + pub source: String, /// When end height set and block height exceeds this value, the escrow is expired. /// Once an escrow is expired, it can be returned to the original funder (via "refund"). pub end_height: Option, @@ -117,7 +117,7 @@ pub struct DetailsResponse { /// Balance in native tokens pub native_balance: Vec, /// Balance in cw20 tokens - pub cw20_balance: Vec, + pub cw20_balance: Vec, /// Whitelisted cw20 tokens - pub cw20_whitelist: Vec, + pub cw20_whitelist: Vec, } diff --git a/contracts/cw20-escrow/src/state.rs b/contracts/cw20-escrow/src/state.rs index 8289f66d6..0dc96c14a 100644 --- a/contracts/cw20-escrow/src/state.rs +++ b/contracts/cw20-escrow/src/state.rs @@ -1,15 +1,15 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -use cosmwasm_std::{Api, CanonicalAddr, Coin, Env, HumanAddr, Order, StdError, StdResult, Storage}; +use cosmwasm_std::{Addr, Coin, Env, Order, StdError, StdResult, Storage}; use cw_storage_plus::Map; -use cw20::{Balance, Cw20Coin}; +use cw20::{Balance, Cw20CoinVerified}; #[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug, Default)] pub struct GenericBalance { pub native: Vec, - pub cw20: Vec, + pub cw20: Vec, } impl GenericBalance { @@ -50,11 +50,11 @@ impl GenericBalance { #[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] pub struct Escrow { /// arbiter can decide to approve or refund the escrow - pub arbiter: CanonicalAddr, + pub arbiter: Addr, /// if approved, funds go to the recipient - pub recipient: CanonicalAddr, + pub recipient: Addr, /// if refunded, funds go to the source - pub source: CanonicalAddr, + pub source: Addr, /// When end height set and block height exceeds this value, the escrow is expired. /// Once an escrow is expired, it can be returned to the original funder (via "refund"). pub end_height: Option, @@ -65,7 +65,7 @@ pub struct Escrow { /// Balance in Native and Cw20 tokens pub balance: GenericBalance, /// All possible contracts that we accept tokens from - pub cw20_whitelist: Vec, + pub cw20_whitelist: Vec, } impl Escrow { @@ -85,11 +85,8 @@ impl Escrow { false } - pub fn human_whitelist(&self, api: &dyn Api) -> StdResult> { - self.cw20_whitelist - .iter() - .map(|h| api.human_address(h)) - .collect() + pub fn human_whitelist(&self) -> Vec { + self.cw20_whitelist.iter().map(|a| a.to_string()).collect() } } @@ -108,7 +105,6 @@ mod tests { use super::*; use cosmwasm_std::testing::MockStorage; - use cosmwasm_std::Binary; #[test] fn no_escrow_ids() { @@ -119,9 +115,9 @@ mod tests { fn dummy_escrow() -> Escrow { Escrow { - arbiter: CanonicalAddr(Binary(b"arb".to_vec())), - recipient: CanonicalAddr(Binary(b"recip".to_vec())), - source: CanonicalAddr(Binary(b"source".to_vec())), + arbiter: Addr::unchecked("arb"), + recipient: Addr::unchecked("recip"), + source: Addr::unchecked("source"), end_height: None, end_time: None, balance: Default::default(), diff --git a/contracts/cw20-ics20/Cargo.toml b/contracts/cw20-ics20/Cargo.toml index 3e85d5238..e0f3cf13a 100644 --- a/contracts/cw20-ics20/Cargo.toml +++ b/contracts/cw20-ics20/Cargo.toml @@ -23,7 +23,7 @@ cw2 = { path = "../../packages/cw2", version = "0.6.0-alpha3" } cw20 = { path = "../../packages/cw20", version = "0.6.0-alpha3" } cosmwasm-std = { version = "0.14.0-alpha2", features = ["iterator", "stargate"] } cw-storage-plus = { path = "../../packages/storage-plus", version = "0.6.0-alpha3", features = ["iterator"] } -schemars = "0.7" +schemars = "0.8.1" serde = { version = "1.0.103", default-features = false, features = ["derive"] } thiserror = { version = "1.0.20" } diff --git a/contracts/cw20-ics20/schema/channel_response.json b/contracts/cw20-ics20/schema/channel_response.json index 0fbb0fa72..dac7a9c26 100644 --- a/contracts/cw20-ics20/schema/channel_response.json +++ b/contracts/cw20-ics20/schema/channel_response.json @@ -9,14 +9,14 @@ ], "properties": { "balances": { - "description": "how many tokens we currently have pending over this channel", + "description": "How many tokens we currently have pending over this channel", "type": "array", "items": { "$ref": "#/definitions/Amount" } }, "info": { - "description": "information on the channel's connection", + "description": "Information on the channel's connection", "allOf": [ { "$ref": "#/definitions/ChannelInfo" @@ -24,7 +24,7 @@ ] }, "total_sent": { - "description": "the total number of tokens that have been sent over this channel (even if many have been returned, so balanace is low)", + "description": "The total number of tokens that have been sent over this channel (even if many have been returned, so balance is low)", "type": "array", "items": { "$ref": "#/definitions/Amount" @@ -43,7 +43,8 @@ "native": { "$ref": "#/definitions/Coin" } - } + }, + "additionalProperties": false }, { "type": "object", @@ -52,9 +53,10 @@ ], "properties": { "cw20": { - "$ref": "#/definitions/Cw20CoinHuman" + "$ref": "#/definitions/Cw20Coin" } - } + }, + "additionalProperties": false } ] }, @@ -99,7 +101,7 @@ } } }, - "Cw20CoinHuman": { + "Cw20Coin": { "type": "object", "required": [ "address", @@ -107,16 +109,13 @@ ], "properties": { "address": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "amount": { "$ref": "#/definitions/Uint128" } } }, - "HumanAddr": { - "type": "string" - }, "IbcEndpoint": { "type": "object", "required": [ diff --git a/contracts/cw20-ics20/schema/execute_msg.json b/contracts/cw20-ics20/schema/execute_msg.json index e4d6a5598..8deeadf71 100644 --- a/contracts/cw20-ics20/schema/execute_msg.json +++ b/contracts/cw20-ics20/schema/execute_msg.json @@ -12,7 +12,8 @@ "receive": { "$ref": "#/definitions/Cw20ReceiveMsg" } - } + }, + "additionalProperties": false }, { "description": "This allows us to transfer *exactly one* native token", @@ -24,7 +25,8 @@ "transfer": { "$ref": "#/definitions/TransferMsg" } - } + }, + "additionalProperties": false } ], "definitions": { @@ -54,13 +56,10 @@ ] }, "sender": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } }, - "HumanAddr": { - "type": "string" - }, "TransferMsg": { "description": "This is the message we accept via Receive", "type": "object", @@ -74,7 +73,7 @@ "type": "string" }, "remote_address": { - "description": "The remote address to send to Don't use HumanAddress as this will likely have a different Bech32 prefix than we use and cannot be validated locally", + "description": "The remote address to send to. Don't use HumanAddress as this will likely have a different Bech32 prefix than we use and cannot be validated locally", "type": "string" }, "timeout": { diff --git a/contracts/cw20-ics20/schema/init_msg.json b/contracts/cw20-ics20/schema/init_msg.json index ba4531604..5d6d75f64 100644 --- a/contracts/cw20-ics20/schema/init_msg.json +++ b/contracts/cw20-ics20/schema/init_msg.json @@ -7,7 +7,7 @@ ], "properties": { "default_timeout": { - "description": "default timeout for ics20 packets, specified in seconds", + "description": "Default timeout for ics20 packets, specified in seconds", "type": "integer", "format": "uint64", "minimum": 0.0 diff --git a/contracts/cw20-ics20/schema/query_msg.json b/contracts/cw20-ics20/schema/query_msg.json index c9c994700..652af74d4 100644 --- a/contracts/cw20-ics20/schema/query_msg.json +++ b/contracts/cw20-ics20/schema/query_msg.json @@ -12,7 +12,8 @@ "port": { "type": "object" } - } + }, + "additionalProperties": false }, { "description": "Show all channels we have connected to. Return type is ListChannelsResponse.", @@ -24,10 +25,11 @@ "list_channels": { "type": "object" } - } + }, + "additionalProperties": false }, { - "description": "Returns the details of the name channel, error if not created Return type: ChannelResponse.", + "description": "Returns the details of the name channel, error if not created. Return type: ChannelResponse.", "type": "object", "required": [ "channel" @@ -44,7 +46,8 @@ } } } - } + }, + "additionalProperties": false } ] } diff --git a/contracts/cw20-ics20/schema/transfer_msg.json b/contracts/cw20-ics20/schema/transfer_msg.json index e75d04e03..ca47b20f8 100644 --- a/contracts/cw20-ics20/schema/transfer_msg.json +++ b/contracts/cw20-ics20/schema/transfer_msg.json @@ -13,7 +13,7 @@ "type": "string" }, "remote_address": { - "description": "The remote address to send to Don't use HumanAddress as this will likely have a different Bech32 prefix than we use and cannot be validated locally", + "description": "The remote address to send to. Don't use HumanAddress as this will likely have a different Bech32 prefix than we use and cannot be validated locally", "type": "string" }, "timeout": { diff --git a/contracts/cw20-ics20/src/amount.rs b/contracts/cw20-ics20/src/amount.rs index ea17c2dd5..624a6768e 100644 --- a/contracts/cw20-ics20/src/amount.rs +++ b/contracts/cw20-ics20/src/amount.rs @@ -3,14 +3,15 @@ use serde::{Deserialize, Serialize}; use crate::error::ContractError; use cosmwasm_std::{Coin, Uint128}; -use cw20::Cw20CoinHuman; +use cw20::Cw20Coin; use std::convert::TryInto; #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] #[serde(rename_all = "snake_case")] pub enum Amount { Native(Coin), - Cw20(Cw20CoinHuman), + // FIXME? USe Cw20CoinVerified, and validate cw20 addresses + Cw20(Cw20Coin), } impl Amount { @@ -18,14 +19,14 @@ impl Amount { pub fn from_parts(denom: String, amount: Uint128) -> Self { if denom.starts_with("cw20:") { let address = denom.get(5..).unwrap().into(); - Amount::Cw20(Cw20CoinHuman { address, amount }) + Amount::Cw20(Cw20Coin { address, amount }) } else { Amount::Native(Coin { denom, amount }) } } pub fn cw20(amount: u128, addr: &str) -> Self { - Amount::Cw20(Cw20CoinHuman { + Amount::Cw20(Cw20Coin { address: addr.into(), amount: Uint128(amount), }) diff --git a/contracts/cw20-ics20/src/contract.rs b/contracts/cw20-ics20/src/contract.rs index 2daea086c..3d20e3f27 100644 --- a/contracts/cw20-ics20/src/contract.rs +++ b/contracts/cw20-ics20/src/contract.rs @@ -1,12 +1,12 @@ #[cfg(not(feature = "library"))] use cosmwasm_std::entry_point; use cosmwasm_std::{ - attr, from_binary, to_binary, Binary, Deps, DepsMut, Env, HumanAddr, IbcMsg, IbcQuery, - MessageInfo, Order, PortIdResponse, Response, StdResult, + attr, from_binary, to_binary, Addr, Binary, Deps, DepsMut, Env, IbcMsg, IbcQuery, MessageInfo, + Order, PortIdResponse, Response, StdResult, }; use cw2::{get_contract_version, set_contract_version}; -use cw20::{Cw20CoinHuman, Cw20ReceiveMsg}; +use cw20::{Cw20Coin, Cw20ReceiveMsg}; use crate::amount::Amount; use crate::error::ContractError; @@ -65,11 +65,12 @@ pub fn execute_receive( Some(bin) => from_binary(&bin)?, None => return Err(ContractError::NoData {}), }; - let amount = Amount::Cw20(Cw20CoinHuman { - address: info.sender, + let amount = Amount::Cw20(Cw20Coin { + address: info.sender.to_string(), amount: wrapper.amount, }); - execute_transfer(deps, env, msg, amount, wrapper.sender) + let api = deps.api; + execute_transfer(deps, env, msg, amount, api.addr_validate(&wrapper.sender)?) } pub fn execute_transfer( @@ -77,7 +78,7 @@ pub fn execute_transfer( env: Env, msg: TransferMsg, amount: Amount, - sender: HumanAddr, + sender: Addr, ) -> Result { if amount.is_empty() { return Err(ContractError::NoFunds {}); @@ -100,7 +101,7 @@ pub fn execute_transfer( let packet = Ics20Packet::new( amount.amount(), amount.denom(), - &sender, + sender.as_ref(), &msg.remote_address, ); packet.validate()?; diff --git a/contracts/cw20-ics20/src/ibc.rs b/contracts/cw20-ics20/src/ibc.rs index 08bb165d3..94b5d4a02 100644 --- a/contracts/cw20-ics20/src/ibc.rs +++ b/contracts/cw20-ics20/src/ibc.rs @@ -2,7 +2,7 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use cosmwasm_std::{ - attr, entry_point, from_binary, to_binary, BankMsg, Binary, CosmosMsg, DepsMut, Env, HumanAddr, + attr, entry_point, from_binary, to_binary, BankMsg, Binary, CosmosMsg, DepsMut, Env, IbcAcknowledgement, IbcBasicResponse, IbcChannel, IbcEndpoint, IbcOrder, IbcPacket, IbcReceiveResponse, StdResult, Uint128, WasmMsg, }; @@ -157,7 +157,7 @@ pub fn ibc_packet_receive( attr("success", "true"), ]; let to_send = Amount::from_parts(denom.into(), msg.amount); - let msg = send_amount(to_send, HumanAddr::from(msg.receiver)); + let msg = send_amount(to_send, msg.receiver); IbcReceiveResponse { acknowledgement: ack_success(), submessages: vec![], @@ -222,8 +222,10 @@ fn do_ibc_packet_receive(deps: DepsMut, packet: &IbcPacket) -> Result Result<_, ContractError> { // this will return error if we don't have the funds there to cover the request (or no denom registered) let mut cur = orig.ok_or(ContractError::InsufficientFunds {})?; - cur.outstanding = - (cur.outstanding - amount).or(Err(ContractError::InsufficientFunds {}))?; + cur.outstanding = cur + .outstanding + .checked_sub(amount) + .or(Err(ContractError::InsufficientFunds {}))?; Ok(cur) }, )?; @@ -305,7 +307,7 @@ fn on_packet_failure( ]; let amount = Amount::from_parts(msg.denom, msg.amount); - let msg = send_amount(amount, HumanAddr::from(msg.sender)); + let msg = send_amount(amount, msg.sender); let res = IbcBasicResponse { submessages: vec![], messages: vec![msg], @@ -314,7 +316,7 @@ fn on_packet_failure( Ok(res) } -fn send_amount(amount: Amount, recipient: HumanAddr) -> CosmosMsg { +fn send_amount(amount: Amount, recipient: String) -> CosmosMsg { match amount { Amount::Native(coin) => BankMsg::Send { to_address: recipient, diff --git a/contracts/cw20-ics20/src/msg.rs b/contracts/cw20-ics20/src/msg.rs index bb0f8d940..afa0c6259 100644 --- a/contracts/cw20-ics20/src/msg.rs +++ b/contracts/cw20-ics20/src/msg.rs @@ -8,7 +8,7 @@ use crate::state::ChannelInfo; #[derive(Serialize, Deserialize, Clone, Debug, JsonSchema)] pub struct InitMsg { - /// default timeout for ics20 packets, specified in seconds + /// Default timeout for ics20 packets, specified in seconds pub default_timeout: u64, } @@ -29,7 +29,7 @@ pub enum ExecuteMsg { pub struct TransferMsg { /// The local channel to send the packets on pub channel: String, - /// The remote address to send to + /// The remote address to send to. /// Don't use HumanAddress as this will likely have a different Bech32 prefix than we use /// and cannot be validated locally pub remote_address: String, @@ -44,7 +44,7 @@ pub enum QueryMsg { Port {}, /// Show all channels we have connected to. Return type is ListChannelsResponse. ListChannels {}, - /// Returns the details of the name channel, error if not created + /// Returns the details of the name channel, error if not created. /// Return type: ChannelResponse. Channel { id: String }, } @@ -56,12 +56,12 @@ pub struct ListChannelsResponse { #[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] pub struct ChannelResponse { - /// information on the channel's connection + /// Information on the channel's connection pub info: ChannelInfo, - /// how many tokens we currently have pending over this channel + /// How many tokens we currently have pending over this channel pub balances: Vec, - /// the total number of tokens that have been sent over this channel - /// (even if many have been returned, so balanace is low) + /// The total number of tokens that have been sent over this channel + /// (even if many have been returned, so balance is low) pub total_sent: Vec, } diff --git a/contracts/cw20-ics20/src/test_helpers.rs b/contracts/cw20-ics20/src/test_helpers.rs index e69b01352..8d86b87f0 100644 --- a/contracts/cw20-ics20/src/test_helpers.rs +++ b/contracts/cw20-ics20/src/test_helpers.rs @@ -7,7 +7,7 @@ use crate::state::ChannelInfo; use cosmwasm_std::testing::{ mock_dependencies, mock_env, mock_info, MockApi, MockQuerier, MockStorage, }; -use cosmwasm_std::{DepsMut, HumanAddr, IbcChannel, IbcEndpoint, OwnedDeps}; +use cosmwasm_std::{DepsMut, IbcChannel, IbcEndpoint, OwnedDeps}; use crate::msg::InitMsg; @@ -59,7 +59,7 @@ pub fn setup(channels: &[&str]) -> OwnedDeps let instantiate_msg = InitMsg { default_timeout: DEFAULT_TIMEOUT, }; - let info = mock_info(&HumanAddr::from("anyone"), &[]); + let info = mock_info(&String::from("anyone"), &[]); let res = instantiate(deps.as_mut(), mock_env(), info, instantiate_msg).unwrap(); assert_eq!(0, res.messages.len()); diff --git a/contracts/cw20-staking/Cargo.toml b/contracts/cw20-staking/Cargo.toml index 53c8c7a52..893946c86 100644 --- a/contracts/cw20-staking/Cargo.toml +++ b/contracts/cw20-staking/Cargo.toml @@ -25,11 +25,11 @@ cw2 = { path = "../../packages/cw2", version = "0.6.0-alpha3" } cw20 = { path = "../../packages/cw20", version = "0.6.0-alpha3" } cw-controllers = { path = "../../packages/controllers", version = "0.6.0-alpha3" } cw20-base = { path = "../../contracts/cw20-base", version = "0.6.0-alpha3", features = ["library"] } -cosmwasm-std = { version = "0.14.0-beta1", features = ["staking"] } +cosmwasm-std = { version = "0.14.0-beta2", features = ["staking"] } cw-storage-plus = { path = "../../packages/storage-plus", version = "0.6.0-alpha3", features = ["iterator"] } -schemars = "0.7" +schemars = "0.8.1" serde = { version = "1.0.103", default-features = false, features = ["derive"] } thiserror = { version = "1.0.20" } [dev-dependencies] -cosmwasm-schema = { version = "0.14.0-beta1" } +cosmwasm-schema = { version = "0.14.0-beta2" } diff --git a/contracts/cw20-staking/schema/allowance_response.json b/contracts/cw20-staking/schema/allowance_response.json index 596d84464..5fb08aa98 100644 --- a/contracts/cw20-staking/schema/allowance_response.json +++ b/contracts/cw20-staking/schema/allowance_response.json @@ -30,7 +30,8 @@ "format": "uint64", "minimum": 0.0 } - } + }, + "additionalProperties": false }, { "description": "AtTime will expire when `env.block.time` >= time", @@ -44,7 +45,8 @@ "format": "uint64", "minimum": 0.0 } - } + }, + "additionalProperties": false }, { "description": "Never will never expire. Used to express the empty variant", @@ -56,7 +58,8 @@ "never": { "type": "object" } - } + }, + "additionalProperties": false } ] }, diff --git a/contracts/cw20-staking/schema/claims_response.json b/contracts/cw20-staking/schema/claims_response.json index efadc9a12..13e15aa51 100644 --- a/contracts/cw20-staking/schema/claims_response.json +++ b/contracts/cw20-staking/schema/claims_response.json @@ -44,7 +44,8 @@ "format": "uint64", "minimum": 0.0 } - } + }, + "additionalProperties": false }, { "description": "AtTime will expire when `env.block.time` >= time", @@ -58,7 +59,8 @@ "format": "uint64", "minimum": 0.0 } - } + }, + "additionalProperties": false }, { "description": "Never will never expire. Used to express the empty variant", @@ -70,7 +72,8 @@ "never": { "type": "object" } - } + }, + "additionalProperties": false } ] }, diff --git a/contracts/cw20-staking/schema/execute_msg.json b/contracts/cw20-staking/schema/execute_msg.json index 69be3b234..2a20bfb90 100644 --- a/contracts/cw20-staking/schema/execute_msg.json +++ b/contracts/cw20-staking/schema/execute_msg.json @@ -12,7 +12,8 @@ "bond": { "type": "object" } - } + }, + "additionalProperties": false }, { "description": "Unbond will \"burn\" the given amount of derivative tokens and send the unbonded staking tokens to the message sender (after exit tax is deducted)", @@ -32,7 +33,8 @@ } } } - } + }, + "additionalProperties": false }, { "description": "Claim is used to claim your native tokens that you previously \"unbonded\" after the chain-defined waiting period (eg. 3 weeks)", @@ -44,7 +46,8 @@ "claim": { "type": "object" } - } + }, + "additionalProperties": false }, { "description": "Reinvest will check for all accumulated rewards, withdraw them, and re-bond them to the same validator. Anyone can call this, which updates the value of the token (how much under custody).", @@ -56,7 +59,8 @@ "reinvest": { "type": "object" } - } + }, + "additionalProperties": false }, { "description": "_BondAllTokens can only be called by the contract itself, after all rewards have been withdrawn. This is an example of using \"callbacks\" in message flows. This can only be invoked by the contract itself as a return from Reinvest", @@ -68,7 +72,8 @@ "__bond_all_tokens": { "type": "object" } - } + }, + "additionalProperties": false }, { "description": "Implements CW20. Transfer is a base message to move tokens to another account without triggering actions", @@ -88,11 +93,12 @@ "$ref": "#/definitions/Uint128" }, "recipient": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "Implements CW20. Burn is a base message to destroy tokens forever", @@ -112,7 +118,8 @@ } } } - } + }, + "additionalProperties": false }, { "description": "Implements CW20. Send is a base message to transfer tokens to a contract and trigger an action on the receiving contract.", @@ -132,7 +139,7 @@ "$ref": "#/definitions/Uint128" }, "contract": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "msg": { "anyOf": [ @@ -146,7 +153,8 @@ } } } - } + }, + "additionalProperties": false }, { "description": "Implements CW20 \"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.", @@ -176,11 +184,12 @@ ] }, "spender": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "Implements CW20 \"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.", @@ -210,11 +219,12 @@ ] }, "spender": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "Implements CW20 \"approval\" extension. Transfers amount tokens from owner -> recipient if `env.sender` has sufficient pre-approval.", @@ -235,14 +245,15 @@ "$ref": "#/definitions/Uint128" }, "owner": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "recipient": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "Implements CW20 \"approval\" extension. Sends amount tokens from owner -> contract if `env.sender` has sufficient pre-approval.", @@ -263,7 +274,7 @@ "$ref": "#/definitions/Uint128" }, "contract": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "msg": { "anyOf": [ @@ -276,11 +287,12 @@ ] }, "owner": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "Implements CW20 \"approval\" extension. Destroys tokens forever", @@ -300,11 +312,12 @@ "$ref": "#/definitions/Uint128" }, "owner": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false } ], "definitions": { @@ -327,7 +340,8 @@ "format": "uint64", "minimum": 0.0 } - } + }, + "additionalProperties": false }, { "description": "AtTime will expire when `env.block.time` >= time", @@ -341,7 +355,8 @@ "format": "uint64", "minimum": 0.0 } - } + }, + "additionalProperties": false }, { "description": "Never will never expire. Used to express the empty variant", @@ -353,13 +368,11 @@ "never": { "type": "object" } - } + }, + "additionalProperties": false } ] }, - "HumanAddr": { - "type": "string" - }, "Uint128": { "type": "string" } diff --git a/contracts/cw20-staking/schema/instantiate_msg.json b/contracts/cw20-staking/schema/instantiate_msg.json index d1799dc69..bfd147430 100644 --- a/contracts/cw20-staking/schema/instantiate_msg.json +++ b/contracts/cw20-staking/schema/instantiate_msg.json @@ -27,7 +27,7 @@ ] }, "min_withdrawal": { - "description": "This is the minimum amount we will pull out to reinvest, as well as a minumum that can be unbonded (to avoid needless staking tx)", + "description": "This is the minimum amount we will pull out to reinvest, as well as a minimum that can be unbonded (to avoid needless staking tx)", "allOf": [ { "$ref": "#/definitions/Uint128" @@ -52,11 +52,7 @@ }, "validator": { "description": "This is the validator that all tokens will be bonded to", - "allOf": [ - { - "$ref": "#/definitions/HumanAddr" - } - ] + "type": "string" } }, "definitions": { @@ -78,7 +74,8 @@ "format": "uint64", "minimum": 0.0 } - } + }, + "additionalProperties": false }, { "type": "object", @@ -91,13 +88,11 @@ "format": "uint64", "minimum": 0.0 } - } + }, + "additionalProperties": false } ] }, - "HumanAddr": { - "type": "string" - }, "Uint128": { "type": "string" } diff --git a/contracts/cw20-staking/schema/investment_response.json b/contracts/cw20-staking/schema/investment_response.json index cbaaafef5..0636baf69 100644 --- a/contracts/cw20-staking/schema/investment_response.json +++ b/contracts/cw20-staking/schema/investment_response.json @@ -21,7 +21,7 @@ ] }, "min_withdrawal": { - "description": "This is the minimum amount we will pull out to reinvest, as well as a minumum that can be unbonded (to avoid needless staking tx)", + "description": "This is the minimum amount we will pull out to reinvest, as well as a minimum that can be unbonded (to avoid needless staking tx)", "allOf": [ { "$ref": "#/definitions/Uint128" @@ -33,11 +33,7 @@ }, "owner": { "description": "owner created the contract and takes a cut", - "allOf": [ - { - "$ref": "#/definitions/HumanAddr" - } - ] + "type": "string" }, "staked_tokens": { "$ref": "#/definitions/Coin" @@ -47,11 +43,7 @@ }, "validator": { "description": "All tokens are bonded to this validator", - "allOf": [ - { - "$ref": "#/definitions/HumanAddr" - } - ] + "type": "string" } }, "definitions": { @@ -74,9 +66,6 @@ "description": "A fixed-point decimal value with 18 fractional digits, i.e. Decimal(1_000_000_000_000_000_000) == 1.0\n\nThe greatest possible value that can be represented is 340282366920938463463.374607431768211455 (which is (2^128 - 1) / 10^18)", "type": "string" }, - "HumanAddr": { - "type": "string" - }, "Uint128": { "type": "string" } diff --git a/contracts/cw20-staking/schema/query_msg.json b/contracts/cw20-staking/schema/query_msg.json index 8aa25d675..b1e7d3c98 100644 --- a/contracts/cw20-staking/schema/query_msg.json +++ b/contracts/cw20-staking/schema/query_msg.json @@ -16,11 +16,12 @@ ], "properties": { "address": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "Investment shows metadata on the staking info of the contract", @@ -32,7 +33,8 @@ "investment": { "type": "object" } - } + }, + "additionalProperties": false }, { "description": "Implements CW20. Returns the current balance of the given address, 0 if unset.", @@ -48,11 +50,12 @@ ], "properties": { "address": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "Implements CW20. Returns metadata on the contract - name, decimals, supply, etc.", @@ -64,7 +67,8 @@ "token_info": { "type": "object" } - } + }, + "additionalProperties": false }, { "description": "Implements CW20 \"allowance\" extension. Returns how much spender can use from owner account, 0 if unset.", @@ -81,19 +85,15 @@ ], "properties": { "owner": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "spender": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false } - ], - "definitions": { - "HumanAddr": { - "type": "string" - } - } + ] } diff --git a/contracts/cw20-staking/src/contract.rs b/contracts/cw20-staking/src/contract.rs index 06d064c9b..093a97bfb 100644 --- a/contracts/cw20-staking/src/contract.rs +++ b/contracts/cw20-staking/src/contract.rs @@ -1,7 +1,7 @@ #[cfg(not(feature = "library"))] use cosmwasm_std::entry_point; use cosmwasm_std::{ - attr, coin, to_binary, BankMsg, Binary, Decimal, Deps, DepsMut, Env, HumanAddr, MessageInfo, + attr, coin, to_binary, Addr, BankMsg, Binary, Decimal, Deps, DepsMut, Env, MessageInfo, QuerierWrapper, Response, StakingMsg, StdError, StdResult, Uint128, WasmMsg, }; @@ -38,7 +38,7 @@ pub fn instantiate( let vals = deps.querier.query_validators()?; if !vals.iter().any(|v| v.address == msg.validator) { return Err(ContractError::NotInValidatorSet { - validator: msg.validator.to_string(), + validator: msg.validator, }); } @@ -50,7 +50,7 @@ pub fn instantiate( total_supply: Uint128(0), // set self as minter, so we can properly execute mint and burn mint: Some(MinterData { - minter: deps.api.canonical_address(&env.contract.address)?, + minter: env.contract.address, cap: None, }), }; @@ -58,7 +58,7 @@ pub fn instantiate( let denom = deps.querier.query_bonded_denom()?; let invest = InvestmentInfo { - owner: deps.api.canonical_address(&info.sender)?, + owner: info.sender, exit_tax: msg.exit_tax, unbonding_period: msg.unbonding_period, bond_denom: denom, @@ -135,7 +135,7 @@ pub fn execute( // get_bonded returns the total amount of delegations from contract // it ensures they are all the same denom -fn get_bonded(querier: &QuerierWrapper, contract: &HumanAddr) -> Result { +fn get_bonded(querier: &QuerierWrapper, contract: &Addr) -> Result { let bonds = querier.query_all_delegations(contract)?; if bonds.is_empty() { return Ok(Uint128(0)); @@ -200,7 +200,7 @@ pub fn bond(deps: DepsMut, env: Env, info: MessageInfo) -> Result Result { - let sender_raw = deps.api.canonical_address(&info.sender)?; - let invest = INVESTMENT.load(deps.storage)?; // ensure it is big enough to care if amount < invest.min_withdrawal { @@ -248,8 +246,13 @@ pub fn unbond( funds: vec![], }; // call into cw20-base to mint tokens to owner, call as self as no one else is allowed - let human_owner = deps.api.human_address(&invest.owner)?; - execute_mint(deps.branch(), env.clone(), sub_info, human_owner, tax)?; + execute_mint( + deps.branch(), + env.clone(), + sub_info, + invest.owner.to_string(), + tax, + )?; } // re-calculate bonded to ensure we have real values @@ -257,21 +260,24 @@ pub fn unbond( let bonded = get_bonded(&deps.querier, &env.contract.address)?; // calculate how many native tokens this is worth and update supply - let remainder = (amount - tax)?; + let remainder = amount.checked_sub(tax).map_err(StdError::overflow)?; let mut supply = TOTAL_SUPPLY.load(deps.storage)?; // TODO: this is just a safety assertion - do we keep it, or remove caching? // in the end supply is just there to cache the (expected) results of get_bonded() so we don't // have expensive queries everywhere assert_bonds(&supply, bonded)?; let unbond = remainder.multiply_ratio(bonded, supply.issued); - supply.bonded = (bonded - unbond)?; - supply.issued = (supply.issued - remainder)?; + supply.bonded = bonded.checked_sub(unbond).map_err(StdError::overflow)?; + supply.issued = supply + .issued + .checked_sub(remainder) + .map_err(StdError::overflow)?; supply.claims += unbond; TOTAL_SUPPLY.save(deps.storage, &supply)?; CLAIMS.create_claim( deps.storage, - &sender_raw, + &info.sender, unbond, invest.unbonding_period.after(&env.block), )?; @@ -307,16 +313,15 @@ pub fn claim(deps: DepsMut, env: Env, info: MessageInfo) -> Result StdResult<_> { - supply.claims = (supply.claims - to_send)?; + supply.claims = supply.claims.checked_sub(to_send)?; Ok(supply) })?; @@ -325,7 +330,7 @@ pub fn claim(deps: DepsMut, env: Env, info: MessageInfo) -> Result Result StdResult<_> { - balance.amount = (balance.amount - supply.claims)?; + balance.amount = balance.amount.checked_sub(supply.claims)?; // this just triggers the "no op" case if we don't have min_withdrawal left to reinvest - (balance.amount - invest.min_withdrawal)?; + balance.amount.checked_sub(invest.min_withdrawal)?; supply.bonded += balance.amount; Ok(supply) }) { Ok(_) => {} // if it is below the minimum, we do a no-op (do not revert other state from withdrawal) - Err(StdError::Underflow { .. }) => return Ok(Response::default()), + Err(StdError::Overflow { .. }) => return Ok(Response::default()), Err(e) => return Err(ContractError::Std(e)), } @@ -418,7 +423,9 @@ pub fn _bond_all_tokens( pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult { match msg { // custom queries - QueryMsg::Claims { address } => to_binary(&CLAIMS.query_claims(deps, address)?), + QueryMsg::Claims { address } => { + to_binary(&CLAIMS.query_claims(deps, &deps.api.addr_validate(&address)?)?) + } QueryMsg::Investment {} => to_binary(&query_investment(deps)?), // inherited from cw20-base QueryMsg::TokenInfo {} => to_binary(&query_token_info(deps)?), @@ -434,7 +441,7 @@ pub fn query_investment(deps: Deps) -> StdResult { let supply = TOTAL_SUPPLY.load(deps.storage)?; let res = InvestmentResponse { - owner: deps.api.human_address(&invest.owner)?, + owner: invest.owner.to_string(), exit_tax: invest.exit_tax, validator: invest.validator, min_withdrawal: invest.min_withdrawal, @@ -457,25 +464,28 @@ mod tests { use cosmwasm_std::testing::{ mock_dependencies, mock_env, mock_info, MockQuerier, MOCK_CONTRACT_ADDR, }; - use cosmwasm_std::{coins, Coin, CosmosMsg, Decimal, FullDelegation, Validator}; + use cosmwasm_std::{ + coins, Coin, CosmosMsg, Decimal, FullDelegation, OverflowError, OverflowOperation, + Validator, + }; use cw0::{Duration, DAY, HOUR, WEEK}; use cw_controllers::Claim; - fn sample_validator>(addr: U) -> Validator { + fn sample_validator(addr: &str) -> Validator { Validator { - address: addr.into(), + address: Addr::unchecked(addr), commission: Decimal::percent(3), max_commission: Decimal::percent(10), max_change_rate: Decimal::percent(1), } } - fn sample_delegation>(addr: U, amount: Coin) -> FullDelegation { + fn sample_delegation(addr: &str, amount: Coin) -> FullDelegation { let can_redelegate = amount.clone(); let accumulated_rewards = coins(0, &amount.denom); FullDelegation { - validator: addr.into(), - delegator: HumanAddr::from(MOCK_CONTRACT_ADDR), + validator: Addr::unchecked(addr), + delegator: Addr::unchecked(MOCK_CONTRACT_ADDR), amount, can_redelegate, accumulated_rewards, @@ -512,19 +522,22 @@ mod tests { name: "Cool Derivative".to_string(), symbol: "DRV".to_string(), decimals: 9, - validator: HumanAddr::from(DEFAULT_VALIDATOR), + validator: String::from(DEFAULT_VALIDATOR), unbonding_period: DAY * 3, exit_tax: Decimal::percent(tax_percent), min_withdrawal: Uint128(min_withdrawal), } } - fn get_balance>(deps: Deps, addr: U) -> Uint128 { + fn get_balance>(deps: Deps, addr: U) -> Uint128 { query_balance(deps, addr.into()).unwrap().balance } - fn get_claims>(deps: Deps, addr: U) -> Vec { - CLAIMS.query_claims(deps, addr.into()).unwrap().claims + fn get_claims(deps: Deps, addr: &str) -> Vec { + CLAIMS + .query_claims(deps, &Addr::unchecked(addr)) + .unwrap() + .claims } #[test] @@ -533,12 +546,12 @@ mod tests { deps.querier .update_staking("ustake", &[sample_validator("john")], &[]); - let creator = HumanAddr::from("creator"); + let creator = String::from("creator"); let msg = InstantiateMsg { name: "Cool Derivative".to_string(), symbol: "DRV".to_string(), decimals: 9, - validator: HumanAddr::from("my-validator"), + validator: String::from("my-validator"), unbonding_period: WEEK, exit_tax: Decimal::percent(2), min_withdrawal: Uint128(50), @@ -568,12 +581,12 @@ mod tests { &[], ); - let creator = HumanAddr::from("creator"); + let creator = String::from("creator"); let msg = InstantiateMsg { name: "Cool Derivative".to_string(), symbol: "DRV".to_string(), decimals: 0, - validator: HumanAddr::from("my-validator"), + validator: String::from("my-validator"), unbonding_period: HOUR * 12, exit_tax: Decimal::percent(2), min_withdrawal: Uint128(50), @@ -613,7 +626,7 @@ mod tests { let mut deps = mock_dependencies(&[]); set_validator(&mut deps.querier); - let creator = HumanAddr::from("creator"); + let creator = String::from("creator"); let instantiate_msg = default_instantiate(2, 50); let info = mock_info(&creator, &[]); @@ -622,7 +635,7 @@ mod tests { assert_eq!(0, res.messages.len()); // let's bond some tokens now - let bob = HumanAddr::from("bob"); + let bob = String::from("bob"); let bond_msg = ExecuteMsg::Bond {}; let info = mock_info(&bob, &[coin(10, "random"), coin(1000, "ustake")]); @@ -657,7 +670,7 @@ mod tests { let mut deps = mock_dependencies(&[]); set_validator(&mut deps.querier); - let creator = HumanAddr::from("creator"); + let creator = String::from("creator"); let instantiate_msg = default_instantiate(2, 50); let info = mock_info(&creator, &[]); @@ -666,7 +679,7 @@ mod tests { assert_eq!(0, res.messages.len()); // let's bond some tokens now - let bob = HumanAddr::from("bob"); + let bob = String::from("bob"); let bond_msg = ExecuteMsg::Bond {}; let info = mock_info(&bob, &[coin(10, "random"), coin(1000, "ustake")]); let res = execute(deps.as_mut(), mock_env(), info, bond_msg).unwrap(); @@ -693,7 +706,7 @@ mod tests { assert_eq!(invest.nominal_value, ratio); // we bond some other tokens and get a different issuance price (maintaining the ratio) - let alice = HumanAddr::from("alice"); + let alice = String::from("alice"); let bond_msg = ExecuteMsg::Bond {}; let info = mock_info(&alice, &[coin(3000, "ustake")]); let res = execute(deps.as_mut(), mock_env(), info, bond_msg).unwrap(); @@ -716,7 +729,7 @@ mod tests { let mut deps = mock_dependencies(&[]); set_validator(&mut deps.querier); - let creator = HumanAddr::from("creator"); + let creator = String::from("creator"); let instantiate_msg = default_instantiate(2, 50); let info = mock_info(&creator, &[]); @@ -725,7 +738,7 @@ mod tests { assert_eq!(0, res.messages.len()); // let's bond some tokens now - let bob = HumanAddr::from("bob"); + let bob = String::from("bob"); let bond_msg = ExecuteMsg::Bond {}; let info = mock_info(&bob, &[coin(500, "photon")]); @@ -744,7 +757,7 @@ mod tests { let mut deps = mock_dependencies(&[]); set_validator(&mut deps.querier); - let creator = HumanAddr::from("creator"); + let creator = String::from("creator"); let instantiate_msg = default_instantiate(10, 50); let info = mock_info(&creator, &[]); @@ -753,7 +766,7 @@ mod tests { assert_eq!(0, res.messages.len()); // let's bond some tokens now - let bob = HumanAddr::from("bob"); + let bob = String::from("bob"); let bond_msg = ExecuteMsg::Bond {}; let info = mock_info(&bob, &[coin(10, "random"), coin(1000, "ustake")]); let res = execute(deps.as_mut(), mock_env(), info, bond_msg).unwrap(); @@ -780,7 +793,14 @@ mod tests { }; let info = mock_info(&creator, &[]); let err = execute(deps.as_mut(), mock_env(), info, unbond_msg).unwrap_err(); - assert_eq!(err, ContractError::Std(StdError::underflow(0, 600))); + assert_eq!( + err, + ContractError::Std(StdError::overflow(OverflowError::new( + OverflowOperation::Sub, + 0, + 600 + ))) + ); // bob unbonds 600 tokens at 10% tax... // 60 are taken and send to the owner @@ -832,13 +852,13 @@ mod tests { set_validator(&mut deps.querier); // create contract - let creator = HumanAddr::from("creator"); + let creator = String::from("creator"); let instantiate_msg = default_instantiate(10, 50); let info = mock_info(&creator, &[]); instantiate(deps.as_mut(), mock_env(), info, instantiate_msg).unwrap(); // bond some tokens - let bob = HumanAddr::from("bob"); + let bob = String::from("bob"); let info = mock_info(&bob, &coins(1000, "ustake")); execute(deps.as_mut(), mock_env(), info, ExecuteMsg::Bond {}).unwrap(); set_delegation(&mut deps.querier, 1000, "ustake"); @@ -905,12 +925,12 @@ mod tests { set_validator(&mut deps.querier); // set the actors... bob stakes, sends coins to carl, and gives allowance to alice - let bob = HumanAddr::from("bob"); - let alice = HumanAddr::from("alice"); - let carl = HumanAddr::from("carl"); + let bob = String::from("bob"); + let alice = String::from("alice"); + let carl = String::from("carl"); // create the contract - let creator = HumanAddr::from("creator"); + let creator = String::from("creator"); let instantiate_msg = default_instantiate(2, 50); let info = mock_info(&creator, &[]); instantiate(deps.as_mut(), mock_env(), info, instantiate_msg).unwrap(); diff --git a/contracts/cw20-staking/src/msg.rs b/contracts/cw20-staking/src/msg.rs index 2e5082e28..d49613c54 100644 --- a/contracts/cw20-staking/src/msg.rs +++ b/contracts/cw20-staking/src/msg.rs @@ -1,7 +1,7 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -use cosmwasm_std::{Binary, Coin, Decimal, HumanAddr, Uint128}; +use cosmwasm_std::{Binary, Coin, Decimal, Uint128}; use cw0::Duration; use cw20::Expiration; pub use cw_controllers::ClaimsResponse; @@ -16,14 +16,14 @@ pub struct InstantiateMsg { pub decimals: u8, /// This is the validator that all tokens will be bonded to - pub validator: HumanAddr, + pub validator: String, /// This is the unbonding period of the native staking module /// We need this to only allow claims to be redeemed after the money has arrived pub unbonding_period: Duration, /// this is how much the owner takes as a cut when someone unbonds pub exit_tax: Decimal, - /// This is the minimum amount we will pull out to reinvest, as well as a minumum + /// This is the minimum amount we will pull out to reinvest, as well as a minimum /// that can be unbonded (to avoid needless staking tx) pub min_withdrawal: Uint128, } @@ -49,16 +49,13 @@ pub enum ExecuteMsg { _BondAllTokens {}, /// Implements CW20. Transfer is a base message to move tokens to another account without triggering actions - Transfer { - recipient: HumanAddr, - amount: Uint128, - }, + Transfer { recipient: String, amount: Uint128 }, /// Implements CW20. Burn is a base message to destroy tokens forever Burn { amount: Uint128 }, /// Implements CW20. Send is a base message to transfer tokens to a contract and trigger an action /// on the receiving contract. Send { - contract: HumanAddr, + contract: String, amount: Uint128, msg: Option, }, @@ -66,7 +63,7 @@ pub enum ExecuteMsg { /// from the owner's (env.sender) account. If expires is Some(), overwrites current allowance /// expiration with this one. IncreaseAllowance { - spender: HumanAddr, + spender: String, amount: Uint128, expires: Option, }, @@ -74,47 +71,44 @@ pub enum ExecuteMsg { /// from the owner's (env.sender) account by amount. If expires is Some(), overwrites current /// allowance expiration with this one. DecreaseAllowance { - spender: HumanAddr, + spender: String, amount: Uint128, expires: Option, }, /// Implements CW20 "approval" extension. Transfers amount tokens from owner -> recipient /// if `env.sender` has sufficient pre-approval. TransferFrom { - owner: HumanAddr, - recipient: HumanAddr, + owner: String, + recipient: String, amount: Uint128, }, /// Implements CW20 "approval" extension. Sends amount tokens from owner -> contract /// if `env.sender` has sufficient pre-approval. SendFrom { - owner: HumanAddr, - contract: HumanAddr, + owner: String, + contract: String, amount: Uint128, msg: Option, }, /// Implements CW20 "approval" extension. Destroys tokens forever - BurnFrom { owner: HumanAddr, amount: Uint128 }, + BurnFrom { owner: String, amount: Uint128 }, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] #[serde(rename_all = "snake_case")] pub enum QueryMsg { /// Claims shows the number of tokens this address can access when they are done unbonding - Claims { address: HumanAddr }, + Claims { address: String }, /// Investment shows metadata on the staking info of the contract Investment {}, /// Implements CW20. Returns the current balance of the given address, 0 if unset. - Balance { address: HumanAddr }, + Balance { address: String }, /// Implements CW20. Returns metadata on the contract - name, decimals, supply, etc. TokenInfo {}, /// Implements CW20 "allowance" extension. /// Returns how much spender can use from owner account, 0 if unset. - Allowance { - owner: HumanAddr, - spender: HumanAddr, - }, + Allowance { owner: String, spender: String }, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] @@ -125,12 +119,12 @@ pub struct InvestmentResponse { pub nominal_value: Decimal, /// owner created the contract and takes a cut - pub owner: HumanAddr, + pub owner: String, /// this is how much the owner takes as a cut when someone unbonds pub exit_tax: Decimal, /// All tokens are bonded to this validator - pub validator: HumanAddr, - /// This is the minimum amount we will pull out to reinvest, as well as a minumum + pub validator: String, + /// This is the minimum amount we will pull out to reinvest, as well as a minimum /// that can be unbonded (to avoid needless staking tx) pub min_withdrawal: Uint128, } diff --git a/contracts/cw20-staking/src/state.rs b/contracts/cw20-staking/src/state.rs index 3902420f8..2b5cd04ab 100644 --- a/contracts/cw20-staking/src/state.rs +++ b/contracts/cw20-staking/src/state.rs @@ -1,29 +1,29 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -use cosmwasm_std::{CanonicalAddr, Decimal, HumanAddr, Uint128}; +use cosmwasm_std::{Addr, Decimal, Uint128}; use cw0::Duration; use cw_controllers::Claims; use cw_storage_plus::Item; pub const CLAIMS: Claims = Claims::new("claims"); -/// Investment info is fixed at instatiation, and is used to control the function of the contract +/// Investment info is fixed at instantiation, and is used to control the function of the contract #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] pub struct InvestmentInfo { - /// owner created the contract and takes a cut - pub owner: CanonicalAddr, - /// this is the denomination we can stake (and only one we accept for payments) + /// Owner created the contract and takes a cut + pub owner: Addr, + /// This is the denomination we can stake (and only one we accept for payments) pub bond_denom: String, /// This is the unbonding period of the native staking module /// We need this to only allow claims to be redeemed after the money has arrived pub unbonding_period: Duration, - /// this is how much the owner takes as a cut when someone unbonds + /// This is how much the owner takes as a cut when someone unbonds pub exit_tax: Decimal, /// All tokens are bonded to this validator - /// FIXME: humanize/canonicalize address doesn't work for validator addrresses - pub validator: HumanAddr, - /// This is the minimum amount we will pull out to reinvest, as well as a minumum + /// FIXME: address validation doesn't work for validator addresses + pub validator: String, + /// This is the minimum amount we will pull out to reinvest, as well as a minimum /// that can be unbonded (to avoid needless staking tx) pub min_withdrawal: Uint128, } diff --git a/contracts/cw3-fixed-multisig/Cargo.toml b/contracts/cw3-fixed-multisig/Cargo.toml index 69e3a9139..364e29881 100644 --- a/contracts/cw3-fixed-multisig/Cargo.toml +++ b/contracts/cw3-fixed-multisig/Cargo.toml @@ -22,13 +22,13 @@ cw0 = { path = "../../packages/cw0", version = "0.6.0-alpha3" } cw2 = { path = "../../packages/cw2", version = "0.6.0-alpha3" } cw3 = { path = "../../packages/cw3", version = "0.6.0-alpha3" } cw-storage-plus = { path = "../../packages/storage-plus", version = "0.6.0-alpha3", features = ["iterator"] } -cosmwasm-std = { version = "0.14.0-beta1", features = ["iterator"] } -schemars = "0.7" +cosmwasm-std = { version = "0.14.0-beta2", features = ["iterator"] } +schemars = "0.8.1" serde = { version = "1.0.103", default-features = false, features = ["derive"] } thiserror = { version = "1.0.20" } [dev-dependencies] -cosmwasm-schema = { version = "0.14.0-beta1" } -cw20 = { path = "../../packages/cw20", version = "0.6.0-alpha3" } -cw20-base = { path = "../cw20-base", version = "0.6.0-alpha3", features = ["library"] } -cw-multi-test = { path = "../../packages/multi-test", version = "0.6.0-alpha3" } +cosmwasm-schema = { version = "0.14.0-beta2" } +#cw20 = { path = "../../packages/cw20", version = "0.6.0-alpha3" } +#cw20-base = { path = "../cw20-base", version = "0.6.0-alpha3", features = ["library"] } +#cw-multi-test = { path = "../../packages/multi-test", version = "0.6.0-alpha3" } diff --git a/contracts/cw3-fixed-multisig/schema/execute_msg.json b/contracts/cw3-fixed-multisig/schema/execute_msg.json index 5410ec958..80aecc1ba 100644 --- a/contracts/cw3-fixed-multisig/schema/execute_msg.json +++ b/contracts/cw3-fixed-multisig/schema/execute_msg.json @@ -40,7 +40,8 @@ } } } - } + }, + "additionalProperties": false }, { "type": "object", @@ -65,7 +66,8 @@ } } } - } + }, + "additionalProperties": false }, { "type": "object", @@ -86,7 +88,8 @@ } } } - } + }, + "additionalProperties": false }, { "type": "object", @@ -107,7 +110,8 @@ } } } - } + }, + "additionalProperties": false } ], "definitions": { @@ -135,11 +139,12 @@ } }, "to_address": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false } ] }, @@ -173,7 +178,8 @@ "bank": { "$ref": "#/definitions/BankMsg" } - } + }, + "additionalProperties": false }, { "type": "object", @@ -184,7 +190,8 @@ "custom": { "$ref": "#/definitions/Empty" } - } + }, + "additionalProperties": false }, { "type": "object", @@ -195,7 +202,8 @@ "staking": { "$ref": "#/definitions/StakingMsg" } - } + }, + "additionalProperties": false }, { "type": "object", @@ -206,7 +214,8 @@ "wasm": { "$ref": "#/definitions/WasmMsg" } - } + }, + "additionalProperties": false } ] }, @@ -229,7 +238,8 @@ "format": "uint64", "minimum": 0.0 } - } + }, + "additionalProperties": false }, { "description": "AtTime will expire when `env.block.time` >= time", @@ -243,7 +253,8 @@ "format": "uint64", "minimum": 0.0 } - } + }, + "additionalProperties": false }, { "description": "Never will never expire. Used to express the empty variant", @@ -255,13 +266,11 @@ "never": { "type": "object" } - } + }, + "additionalProperties": false } ] }, - "HumanAddr": { - "type": "string" - }, "StakingMsg": { "description": "The message types of the staking module.\n\nSee https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto", "anyOf": [ @@ -283,11 +292,12 @@ "$ref": "#/definitions/Coin" }, "validator": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "This is translated to a [MsgUndelegate](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L112-L121). `delegator_address` is automatically filled with the current contract's address.", @@ -307,11 +317,12 @@ "$ref": "#/definitions/Coin" }, "validator": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "This is translated to a [MsgSetWithdrawAddress](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/distribution/v1beta1/tx.proto#L29-L37) followed by a [MsgWithdrawDelegatorReward](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/distribution/v1beta1/tx.proto#L42-L50). `delegator_address` is automatically filled with the current contract's address.", @@ -328,21 +339,18 @@ "properties": { "recipient": { "description": "this is the \"withdraw address\", the one that should receive the rewards if None, then use delegator address", - "anyOf": [ - { - "$ref": "#/definitions/HumanAddr" - }, - { - "type": "null" - } + "type": [ + "string", + "null" ] }, "validator": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "This is translated to a [MsgBeginRedelegate](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L95-L105). `delegator_address` is automatically filled with the current contract's address.", @@ -363,14 +371,15 @@ "$ref": "#/definitions/Coin" }, "dst_validator": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "src_validator": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false } ] }, @@ -405,7 +414,7 @@ ], "properties": { "contract_addr": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "msg": { "description": "msg is the json-encoded ExecuteMsg struct (as raw Binary)", @@ -423,7 +432,8 @@ } } } - } + }, + "additionalProperties": false }, { "description": "Instantiates a new contracts from previously uploaded Wasm code.\n\nThis is translated to a [MsgInstantiateContract](https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto#L47-L61). `sender` is automatically filled with the current contract's address.", @@ -466,7 +476,8 @@ } } } - } + }, + "additionalProperties": false }, { "description": "Migrates a given contracts to use new wasm code. Passes a MigrateMsg to allow us to customize behavior.\n\nOnly the contract admin (as defined in wasmd), if any, is able to make this call.\n\nThis is translated to a [MsgMigrateContract](https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto#L86-L96). `sender` is automatically filled with the current contract's address.", @@ -484,7 +495,7 @@ ], "properties": { "contract_addr": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "msg": { "description": "msg is the json-encoded MigrateMsg struct that will be passed to the new code", @@ -502,7 +513,8 @@ } } } - } + }, + "additionalProperties": false } ] } diff --git a/contracts/cw3-fixed-multisig/schema/instantiate_msg.json b/contracts/cw3-fixed-multisig/schema/instantiate_msg.json index ca7f2870a..d3e766159 100644 --- a/contracts/cw3-fixed-multisig/schema/instantiate_msg.json +++ b/contracts/cw3-fixed-multisig/schema/instantiate_msg.json @@ -38,7 +38,8 @@ "format": "uint64", "minimum": 0.0 } - } + }, + "additionalProperties": false }, { "type": "object", @@ -51,13 +52,11 @@ "format": "uint64", "minimum": 0.0 } - } + }, + "additionalProperties": false } ] }, - "HumanAddr": { - "type": "string" - }, "Voter": { "type": "object", "required": [ @@ -66,7 +65,7 @@ ], "properties": { "addr": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "weight": { "type": "integer", diff --git a/contracts/cw3-fixed-multisig/schema/query_msg.json b/contracts/cw3-fixed-multisig/schema/query_msg.json index e4f0b9938..7fcdeccdb 100644 --- a/contracts/cw3-fixed-multisig/schema/query_msg.json +++ b/contracts/cw3-fixed-multisig/schema/query_msg.json @@ -12,7 +12,8 @@ "threshold": { "type": "object" } - } + }, + "additionalProperties": false }, { "description": "Returns ProposalResponse", @@ -34,7 +35,8 @@ } } } - } + }, + "additionalProperties": false }, { "description": "Returns ProposalListResponse", @@ -64,7 +66,8 @@ } } } - } + }, + "additionalProperties": false }, { "description": "Returns ProposalListResponse", @@ -94,7 +97,8 @@ } } } - } + }, + "additionalProperties": false }, { "description": "Returns VoteResponse", @@ -116,11 +120,12 @@ "minimum": 0.0 }, "voter": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "Returns VoteListResponse", @@ -149,18 +154,15 @@ "minimum": 0.0 }, "start_after": { - "anyOf": [ - { - "$ref": "#/definitions/HumanAddr" - }, - { - "type": "null" - } + "type": [ + "string", + "null" ] } } } - } + }, + "additionalProperties": false }, { "description": "Returns VoterInfo", @@ -176,11 +178,12 @@ ], "properties": { "address": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "Returns VoterListResponse", @@ -201,23 +204,15 @@ "minimum": 0.0 }, "start_after": { - "anyOf": [ - { - "$ref": "#/definitions/HumanAddr" - }, - { - "type": "null" - } + "type": [ + "string", + "null" ] } } } - } - } - ], - "definitions": { - "HumanAddr": { - "type": "string" + }, + "additionalProperties": false } - } + ] } diff --git a/contracts/cw3-fixed-multisig/src/contract.rs b/contracts/cw3-fixed-multisig/src/contract.rs index 68257e3d3..4b336e3f3 100644 --- a/contracts/cw3-fixed-multisig/src/contract.rs +++ b/contracts/cw3-fixed-multisig/src/contract.rs @@ -3,11 +3,11 @@ use std::cmp::Ordering; #[cfg(not(feature = "library"))] use cosmwasm_std::entry_point; use cosmwasm_std::{ - attr, to_binary, Binary, BlockInfo, CanonicalAddr, CosmosMsg, Deps, DepsMut, Empty, Env, - HumanAddr, MessageInfo, Order, Response, StdResult, + attr, to_binary, Binary, BlockInfo, CosmosMsg, Deps, DepsMut, Empty, Env, MessageInfo, Order, + Response, StdResult, }; -use cw0::{maybe_canonical, Expiration}; +use cw0::Expiration; use cw2::set_contract_version; use cw3::{ ProposalListResponse, ProposalResponse, Status, ThresholdResponse, Vote, VoteInfo, @@ -55,7 +55,7 @@ pub fn instantiate( // add all voters for voter in msg.voters.iter() { - let key = deps.api.canonical_address(&voter.addr)?; + let key = deps.api.addr_validate(&voter.addr)?; VOTERS.save(deps.storage, &key, &voter.weight)?; } Ok(Response::default()) @@ -92,9 +92,8 @@ pub fn execute_propose( latest: Option, ) -> Result, ContractError> { // only members of the multisig can create a proposal - let raw_sender = deps.api.canonical_address(&info.sender)?; let vote_power = VOTERS - .may_load(deps.storage, &raw_sender)? + .may_load(deps.storage, &info.sender)? .ok_or(ContractError::Unauthorized {})?; let cfg = CONFIG.load(deps.storage)?; @@ -133,7 +132,7 @@ pub fn execute_propose( weight: vote_power, vote: Vote::Yes, }; - BALLOTS.save(deps.storage, (id.into(), &raw_sender), &ballot)?; + BALLOTS.save(deps.storage, (id.into(), &info.sender), &ballot)?; Ok(Response { submessages: vec![], @@ -156,9 +155,8 @@ pub fn execute_vote( vote: Vote, ) -> Result, ContractError> { // only members of the multisig can vote - let raw_sender = deps.api.canonical_address(&info.sender)?; let vote_power = VOTERS - .may_load(deps.storage, &raw_sender)? + .may_load(deps.storage, &info.sender)? .ok_or(ContractError::Unauthorized {})?; // ensure proposal exists and can be voted on @@ -173,7 +171,7 @@ pub fn execute_vote( // cast vote if no vote previously cast BALLOTS.update( deps.storage, - (proposal_id.into(), &raw_sender), + (proposal_id.into(), &info.sender), |bal| match bal { Some(_) => Err(ContractError::AlreadyVoted {}), None => Ok(Ballot { @@ -394,11 +392,11 @@ fn map_proposal( }) } -fn query_vote(deps: Deps, proposal_id: u64, voter: HumanAddr) -> StdResult { - let voter_raw = deps.api.canonical_address(&voter)?; - let ballot = BALLOTS.may_load(deps.storage, (proposal_id.into(), &voter_raw))?; +fn query_vote(deps: Deps, proposal_id: u64, voter: String) -> StdResult { + let voter = deps.api.addr_validate(&voter)?; + let ballot = BALLOTS.may_load(deps.storage, (proposal_id.into(), &voter))?; let vote = ballot.map(|b| VoteInfo { - voter, + voter: voter.into(), vote: b.vote, weight: b.weight, }); @@ -408,14 +406,12 @@ fn query_vote(deps: Deps, proposal_id: u64, voter: HumanAddr) -> StdResult, + start_after: Option, limit: Option, ) -> StdResult { let limit = limit.unwrap_or(DEFAULT_LIMIT).min(MAX_LIMIT) as usize; - let canon = maybe_canonical(deps.api, start_after)?; - let start = canon.map(Bound::exclusive); + let start = start_after.map(Bound::exclusive); - let api = &deps.api; let votes: StdResult> = BALLOTS .prefix(proposal_id.into()) .range(deps.storage, start, None, Order::Ascending) @@ -423,7 +419,7 @@ fn list_votes( .map(|item| { let (key, ballot) = item?; Ok(VoteInfo { - voter: api.human_address(&CanonicalAddr::from(key))?, + voter: String::from_utf8(key)?, vote: ballot.vote, weight: ballot.weight, }) @@ -433,29 +429,27 @@ fn list_votes( Ok(VoteListResponse { votes: votes? }) } -fn query_voter(deps: Deps, voter: HumanAddr) -> StdResult { - let voter_raw = deps.api.canonical_address(&voter)?; - let weight = VOTERS.may_load(deps.storage, &voter_raw)?; +fn query_voter(deps: Deps, voter: String) -> StdResult { + let voter = deps.api.addr_validate(&voter)?; + let weight = VOTERS.may_load(deps.storage, &voter)?; Ok(VoterResponse { weight }) } fn list_voters( deps: Deps, - start_after: Option, + start_after: Option, limit: Option, ) -> StdResult { let limit = limit.unwrap_or(DEFAULT_LIMIT).min(MAX_LIMIT) as usize; - let canon = maybe_canonical(deps.api, start_after)?; - let start = canon.map(Bound::exclusive); + let start = start_after.map(Bound::exclusive); - let api = &deps.api; let voters: StdResult> = VOTERS .range(deps.storage, start, None, Order::Ascending) .take(limit) .map(|item| { let (key, weight) = item?; Ok(VoterDetail { - addr: api.human_address(&CanonicalAddr::from(key))?, + addr: String::from_utf8(key)?, weight, }) }) @@ -496,7 +490,7 @@ mod tests { const VOTER5: &str = "voter0005"; const SOMEBODY: &str = "somebody"; - fn voter>(addr: T, weight: u64) -> Voter { + fn voter>(addr: T, weight: u64) -> Voter { Voter { addr: addr.into(), weight, diff --git a/contracts/cw3-fixed-multisig/src/integration_tests.rs b/contracts/cw3-fixed-multisig/src/integration_tests.rs index 846f43847..3f69f2e06 100644 --- a/contracts/cw3-fixed-multisig/src/integration_tests.rs +++ b/contracts/cw3-fixed-multisig/src/integration_tests.rs @@ -1,156 +1,156 @@ -#![cfg(test)] - -use crate::contract::{execute, instantiate, query}; -use crate::msg::{ExecuteMsg, InstantiateMsg, Voter}; -use cosmwasm_std::testing::{mock_env, MockApi, MockStorage}; -use cosmwasm_std::{from_binary, to_binary, Empty, HumanAddr, Uint128, WasmMsg, WasmQuery}; -use cw0::Duration; -use cw20::{BalanceResponse, MinterResponse}; -use cw20_base::msg::QueryMsg; -use cw3::Vote; -use cw_multi_test::{App, Contract, ContractWrapper, SimpleBank}; - -fn mock_app() -> App { - let env = mock_env(); - let api = Box::new(MockApi::default()); - let bank = SimpleBank {}; - - App::new(api, env.block, bank, || Box::new(MockStorage::new())) -} - -pub fn contract_cw3_fixed_multisig() -> Box> { - let contract = ContractWrapper::new(execute, instantiate, query); - Box::new(contract) -} - -pub fn contract_cw20() -> Box> { - let contract = ContractWrapper::new( - cw20_base::contract::execute, - cw20_base::contract::instantiate, - cw20_base::contract::query, - ); - Box::new(contract) -} - -#[test] -// cw3 multisig account can control cw20 admin actions -fn cw3_controls_cw20() { - let mut router = mock_app(); - - // setup cw3 multisig with 3 accounts - let cw3_id = router.store_code(contract_cw3_fixed_multisig()); - - let addr1 = HumanAddr::from("addr1"); - let addr2 = HumanAddr::from("addr2"); - let addr3 = HumanAddr::from("addr3"); - let cw3_instantiate_msg = InstantiateMsg { - voters: vec![ - Voter { - addr: addr1.clone(), - weight: 1, - }, - Voter { - addr: addr2.clone(), - weight: 1, - }, - Voter { - addr: addr3, - weight: 1, - }, - ], - required_weight: 2, - max_voting_period: Duration::Height(3), - }; - - let multisig_addr = router - .instantiate_contract( - cw3_id, - &addr1.clone(), - &cw3_instantiate_msg, - &[], - "Consortium", - ) - .unwrap(); - - // setup cw20 as cw3 multisig admin - let cw20_id = router.store_code(contract_cw20()); - - let cw20_instantiate_msg = cw20_base::msg::InstantiateMsg { - name: "Consortium Token".parse().unwrap(), - symbol: "CST".parse().unwrap(), - decimals: 6, - initial_balances: vec![], - mint: Some(MinterResponse { - minter: multisig_addr.clone(), - cap: None, - }), - }; - let cw20_addr = router - .instantiate_contract( - cw20_id, - &multisig_addr, - &cw20_instantiate_msg, - &[], - "Consortium", - ) - .unwrap(); - - // mint some cw20 tokens according to proposal result - let mint_recipient = HumanAddr::from("recipient"); - let mint_amount = Uint128(1000); - let cw20_mint_msg = cw20_base::msg::ExecuteMsg::Mint { - recipient: mint_recipient.clone(), - amount: mint_amount, - }; - - let execute_mint_msg = WasmMsg::Execute { - contract_addr: cw20_addr.clone(), - msg: to_binary(&cw20_mint_msg).unwrap(), - send: vec![], - }; - let propose_msg = ExecuteMsg::Propose { - title: "Mint tokens".to_string(), - description: "Need to mint tokens".to_string(), - msgs: vec![execute_mint_msg.into()], - latest: None, - }; - // propose mint - router - .execute_contract(addr1.clone(), multisig_addr.clone(), &propose_msg, &[]) - .unwrap(); - - // second votes - let vote2_msg = ExecuteMsg::Vote { - proposal_id: 1, - vote: Vote::Yes, - }; - router - .execute_contract(addr2.clone(), multisig_addr.clone(), &vote2_msg, &[]) - .unwrap(); - - // only 1 vote and msg mint fails - let execute_proposal_msg = ExecuteMsg::Execute { proposal_id: 1 }; - // execute mint - router - .execute_contract( - addr1.clone(), - multisig_addr.clone(), - &execute_proposal_msg, - &[], - ) - .unwrap(); - - // check the mint is successful - let cw20_balance_query = QueryMsg::Balance { - address: mint_recipient, - }; - let wasm_query = WasmQuery::Smart { - contract_addr: cw20_addr, - msg: to_binary(&cw20_balance_query).unwrap(), - }; - let query_res = router.query(wasm_query.into()).unwrap(); - let balance: BalanceResponse = from_binary(&query_res).unwrap(); - - // compare minted amount - assert_eq!(balance.balance, mint_amount); -} +// #![cfg(test)] +// +// use crate::contract::{execute, instantiate, query}; +// use crate::msg::{ExecuteMsg, InstantiateMsg, Voter}; +// use cosmwasm_std::testing::{mock_env, MockApi, MockStorage}; +// use cosmwasm_std::{from_binary, to_binary, Empty, HumanAddr, Uint128, WasmMsg, WasmQuery}; +// use cw0::Duration; +// use cw20::{BalanceResponse, MinterResponse}; +// use cw20_base::msg::QueryMsg; +// use cw3::Vote; +// use cw_multi_test::{App, Contract, ContractWrapper, SimpleBank}; +// +// fn mock_app() -> App { +// let env = mock_env(); +// let api = Box::new(MockApi::default()); +// let bank = SimpleBank {}; +// +// App::new(api, env.block, bank, || Box::new(MockStorage::new())) +// } +// +// pub fn contract_cw3_fixed_multisig() -> Box> { +// let contract = ContractWrapper::new(execute, instantiate, query); +// Box::new(contract) +// } +// +// pub fn contract_cw20() -> Box> { +// let contract = ContractWrapper::new( +// cw20_base::contract::execute, +// cw20_base::contract::instantiate, +// cw20_base::contract::query, +// ); +// Box::new(contract) +// } +// +// #[test] +// // cw3 multisig account can control cw20 admin actions +// fn cw3_controls_cw20() { +// let mut router = mock_app(); +// +// // setup cw3 multisig with 3 accounts +// let cw3_id = router.store_code(contract_cw3_fixed_multisig()); +// +// let addr1 = HumanAddr::from("addr1"); +// let addr2 = HumanAddr::from("addr2"); +// let addr3 = HumanAddr::from("addr3"); +// let cw3_instantiate_msg = InstantiateMsg { +// voters: vec![ +// Voter { +// addr: addr1.clone(), +// weight: 1, +// }, +// Voter { +// addr: addr2.clone(), +// weight: 1, +// }, +// Voter { +// addr: addr3, +// weight: 1, +// }, +// ], +// required_weight: 2, +// max_voting_period: Duration::Height(3), +// }; +// +// let multisig_addr = router +// .instantiate_contract( +// cw3_id, +// &addr1.clone(), +// &cw3_instantiate_msg, +// &[], +// "Consortium", +// ) +// .unwrap(); +// +// // setup cw20 as cw3 multisig admin +// let cw20_id = router.store_code(contract_cw20()); +// +// let cw20_instantiate_msg = cw20_base::msg::InstantiateMsg { +// name: "Consortium Token".parse().unwrap(), +// symbol: "CST".parse().unwrap(), +// decimals: 6, +// initial_balances: vec![], +// mint: Some(MinterResponse { +// minter: multisig_addr.clone(), +// cap: None, +// }), +// }; +// let cw20_addr = router +// .instantiate_contract( +// cw20_id, +// &multisig_addr, +// &cw20_instantiate_msg, +// &[], +// "Consortium", +// ) +// .unwrap(); +// +// // mint some cw20 tokens according to proposal result +// let mint_recipient = HumanAddr::from("recipient"); +// let mint_amount = Uint128(1000); +// let cw20_mint_msg = cw20_base::msg::ExecuteMsg::Mint { +// recipient: mint_recipient.clone(), +// amount: mint_amount, +// }; +// +// let execute_mint_msg = WasmMsg::Execute { +// contract_addr: cw20_addr.clone(), +// msg: to_binary(&cw20_mint_msg).unwrap(), +// send: vec![], +// }; +// let propose_msg = ExecuteMsg::Propose { +// title: "Mint tokens".to_string(), +// description: "Need to mint tokens".to_string(), +// msgs: vec![execute_mint_msg.into()], +// latest: None, +// }; +// // propose mint +// router +// .execute_contract(addr1.clone(), multisig_addr.clone(), &propose_msg, &[]) +// .unwrap(); +// +// // second votes +// let vote2_msg = ExecuteMsg::Vote { +// proposal_id: 1, +// vote: Vote::Yes, +// }; +// router +// .execute_contract(addr2.clone(), multisig_addr.clone(), &vote2_msg, &[]) +// .unwrap(); +// +// // only 1 vote and msg mint fails +// let execute_proposal_msg = ExecuteMsg::Execute { proposal_id: 1 }; +// // execute mint +// router +// .execute_contract( +// addr1.clone(), +// multisig_addr.clone(), +// &execute_proposal_msg, +// &[], +// ) +// .unwrap(); +// +// // check the mint is successful +// let cw20_balance_query = QueryMsg::Balance { +// address: mint_recipient, +// }; +// let wasm_query = WasmQuery::Smart { +// contract_addr: cw20_addr, +// msg: to_binary(&cw20_balance_query).unwrap(), +// }; +// let query_res = router.query(wasm_query.into()).unwrap(); +// let balance: BalanceResponse = from_binary(&query_res).unwrap(); +// +// // compare minted amount +// assert_eq!(balance.balance, mint_amount); +// } diff --git a/contracts/cw3-fixed-multisig/src/msg.rs b/contracts/cw3-fixed-multisig/src/msg.rs index d970df5eb..a42be8399 100644 --- a/contracts/cw3-fixed-multisig/src/msg.rs +++ b/contracts/cw3-fixed-multisig/src/msg.rs @@ -1,7 +1,7 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -use cosmwasm_std::{CosmosMsg, Empty, HumanAddr}; +use cosmwasm_std::{CosmosMsg, Empty}; use cw0::{Duration, Expiration}; use cw3::Vote; @@ -14,7 +14,7 @@ pub struct InstantiateMsg { #[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] pub struct Voter { - pub addr: HumanAddr, + pub addr: String, pub weight: u64, } @@ -60,18 +60,18 @@ pub enum QueryMsg { limit: Option, }, /// Returns VoteResponse - Vote { proposal_id: u64, voter: HumanAddr }, + Vote { proposal_id: u64, voter: String }, /// Returns VoteListResponse ListVotes { proposal_id: u64, - start_after: Option, + start_after: Option, limit: Option, }, /// Returns VoterInfo - Voter { address: HumanAddr }, + Voter { address: String }, /// Returns VoterListResponse ListVoters { - start_after: Option, + start_after: Option, limit: Option, }, } diff --git a/contracts/cw3-fixed-multisig/src/state.rs b/contracts/cw3-fixed-multisig/src/state.rs index f702e52c2..8ebc86934 100644 --- a/contracts/cw3-fixed-multisig/src/state.rs +++ b/contracts/cw3-fixed-multisig/src/state.rs @@ -2,7 +2,7 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use std::convert::TryInto; -use cosmwasm_std::{BlockInfo, CosmosMsg, Empty, StdError, StdResult, Storage}; +use cosmwasm_std::{Addr, BlockInfo, CosmosMsg, Empty, StdError, StdResult, Storage}; use cw0::{Duration, Expiration}; use cw3::{Status, Vote}; @@ -57,9 +57,9 @@ pub const CONFIG: Item = Item::new("config"); pub const PROPOSAL_COUNT: Item = Item::new("proposal_count"); // multiple-item maps -pub const VOTERS: Map<&[u8], u64> = Map::new("voters"); +pub const VOTERS: Map<&Addr, u64> = Map::new("voters"); pub const PROPOSALS: Map = Map::new("proposals"); -pub const BALLOTS: Map<(U64Key, &[u8]), Ballot> = Map::new("votes"); +pub const BALLOTS: Map<(U64Key, &Addr), Ballot> = Map::new("ballots"); pub fn next_id(store: &mut dyn Storage) -> StdResult { let id: u64 = PROPOSAL_COUNT.may_load(store)?.unwrap_or_default() + 1; diff --git a/contracts/cw3-flex-multisig/Cargo.toml b/contracts/cw3-flex-multisig/Cargo.toml index 87f538a21..4fb6213e1 100644 --- a/contracts/cw3-flex-multisig/Cargo.toml +++ b/contracts/cw3-flex-multisig/Cargo.toml @@ -23,12 +23,12 @@ cw2 = { path = "../../packages/cw2", version = "0.6.0-alpha3" } cw3 = { path = "../../packages/cw3", version = "0.6.0-alpha3" } cw4 = { path = "../../packages/cw4", version = "0.6.0-alpha3" } cw-storage-plus = { path = "../../packages/storage-plus", version = "0.6.0-alpha3", features = ["iterator"] } -cosmwasm-std = { version = "0.14.0-beta1", features = ["iterator"] } -schemars = "0.7" +cosmwasm-std = { version = "0.14.0-beta2", features = ["iterator"] } +schemars = "0.8.1" serde = { version = "1.0.103", default-features = false, features = ["derive"] } thiserror = { version = "1.0.20" } [dev-dependencies] -cosmwasm-schema = { version = "0.14.0-beta1" } +cosmwasm-schema = { version = "0.14.0-beta2" } cw4-group = { path = "../cw4-group", version = "0.6.0-alpha3" } cw-multi-test = { path = "../../packages/multi-test", version = "0.6.0-alpha3" } diff --git a/contracts/cw3-flex-multisig/schema/execute_msg.json b/contracts/cw3-flex-multisig/schema/execute_msg.json index f444b6921..29d5fe0a1 100644 --- a/contracts/cw3-flex-multisig/schema/execute_msg.json +++ b/contracts/cw3-flex-multisig/schema/execute_msg.json @@ -40,7 +40,8 @@ } } } - } + }, + "additionalProperties": false }, { "type": "object", @@ -65,7 +66,8 @@ } } } - } + }, + "additionalProperties": false }, { "type": "object", @@ -86,7 +88,8 @@ } } } - } + }, + "additionalProperties": false }, { "type": "object", @@ -107,7 +110,8 @@ } } } - } + }, + "additionalProperties": false }, { "description": "Handles update hook messages from the group contract", @@ -119,7 +123,8 @@ "member_changed_hook": { "$ref": "#/definitions/MemberChangedHookMsg" } - } + }, + "additionalProperties": false } ], "definitions": { @@ -147,11 +152,12 @@ } }, "to_address": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false } ] }, @@ -185,7 +191,8 @@ "bank": { "$ref": "#/definitions/BankMsg" } - } + }, + "additionalProperties": false }, { "type": "object", @@ -196,7 +203,8 @@ "custom": { "$ref": "#/definitions/Empty" } - } + }, + "additionalProperties": false }, { "type": "object", @@ -207,7 +215,8 @@ "staking": { "$ref": "#/definitions/StakingMsg" } - } + }, + "additionalProperties": false }, { "type": "object", @@ -218,7 +227,8 @@ "wasm": { "$ref": "#/definitions/WasmMsg" } - } + }, + "additionalProperties": false } ] }, @@ -241,7 +251,8 @@ "format": "uint64", "minimum": 0.0 } - } + }, + "additionalProperties": false }, { "description": "AtTime will expire when `env.block.time` >= time", @@ -255,7 +266,8 @@ "format": "uint64", "minimum": 0.0 } - } + }, + "additionalProperties": false }, { "description": "Never will never expire. Used to express the empty variant", @@ -267,13 +279,11 @@ "never": { "type": "object" } - } + }, + "additionalProperties": false } ] }, - "HumanAddr": { - "type": "string" - }, "MemberChangedHookMsg": { "description": "MemberChangedHookMsg should be de/serialized under `MemberChangedHook()` variant in a ExecuteMsg. This contains a list of all diffs on the given transaction.", "type": "object", @@ -297,7 +307,7 @@ ], "properties": { "key": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "new": { "type": [ @@ -338,11 +348,12 @@ "$ref": "#/definitions/Coin" }, "validator": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "This is translated to a [MsgUndelegate](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L112-L121). `delegator_address` is automatically filled with the current contract's address.", @@ -362,11 +373,12 @@ "$ref": "#/definitions/Coin" }, "validator": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "This is translated to a [MsgSetWithdrawAddress](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/distribution/v1beta1/tx.proto#L29-L37) followed by a [MsgWithdrawDelegatorReward](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/distribution/v1beta1/tx.proto#L42-L50). `delegator_address` is automatically filled with the current contract's address.", @@ -383,21 +395,18 @@ "properties": { "recipient": { "description": "this is the \"withdraw address\", the one that should receive the rewards if None, then use delegator address", - "anyOf": [ - { - "$ref": "#/definitions/HumanAddr" - }, - { - "type": "null" - } + "type": [ + "string", + "null" ] }, "validator": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "This is translated to a [MsgBeginRedelegate](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L95-L105). `delegator_address` is automatically filled with the current contract's address.", @@ -418,14 +427,15 @@ "$ref": "#/definitions/Coin" }, "dst_validator": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "src_validator": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false } ] }, @@ -460,7 +470,7 @@ ], "properties": { "contract_addr": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "msg": { "description": "msg is the json-encoded ExecuteMsg struct (as raw Binary)", @@ -478,7 +488,8 @@ } } } - } + }, + "additionalProperties": false }, { "description": "Instantiates a new contracts from previously uploaded Wasm code.\n\nThis is translated to a [MsgInstantiateContract](https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto#L47-L61). `sender` is automatically filled with the current contract's address.", @@ -521,7 +532,8 @@ } } } - } + }, + "additionalProperties": false }, { "description": "Migrates a given contracts to use new wasm code. Passes a MigrateMsg to allow us to customize behavior.\n\nOnly the contract admin (as defined in wasmd), if any, is able to make this call.\n\nThis is translated to a [MsgMigrateContract](https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto#L86-L96). `sender` is automatically filled with the current contract's address.", @@ -539,7 +551,7 @@ ], "properties": { "contract_addr": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "msg": { "description": "msg is the json-encoded MigrateMsg struct that will be passed to the new code", @@ -557,7 +569,8 @@ } } } - } + }, + "additionalProperties": false } ] } diff --git a/contracts/cw3-flex-multisig/schema/instantiate_msg.json b/contracts/cw3-flex-multisig/schema/instantiate_msg.json index 656308f94..38fda2297 100644 --- a/contracts/cw3-flex-multisig/schema/instantiate_msg.json +++ b/contracts/cw3-flex-multisig/schema/instantiate_msg.json @@ -9,7 +9,7 @@ ], "properties": { "group_addr": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "max_voting_period": { "$ref": "#/definitions/Duration" @@ -37,7 +37,8 @@ "format": "uint64", "minimum": 0.0 } - } + }, + "additionalProperties": false }, { "type": "object", @@ -50,13 +51,11 @@ "format": "uint64", "minimum": 0.0 } - } + }, + "additionalProperties": false } ] }, - "HumanAddr": { - "type": "string" - }, "Threshold": { "description": "This defines the different ways tallies can happen.\n\nThe total_weight used for calculating success as well as the weights of each individual voter used in tallying should be snapshotted at the beginning of the block at which the proposal starts (this is likely the responsibility of a correct cw4 implementation). See also `ThresholdResponse` in the cw3 spec.", "anyOf": [ @@ -80,7 +79,8 @@ } } } - } + }, + "additionalProperties": false }, { "description": "Declares a percentage of the total weight that must cast Yes votes in order for a proposal to pass. See `ThresholdResponse.AbsolutePercentage` in the cw3 spec for details.", @@ -100,7 +100,8 @@ } } } - } + }, + "additionalProperties": false }, { "description": "Declares a `quorum` of the total votes that must participate in the election in order for the vote to be considered at all. See `ThresholdResponse.ThresholdQuorum` in the cw3 spec for details.", @@ -124,7 +125,8 @@ } } } - } + }, + "additionalProperties": false } ] } diff --git a/contracts/cw3-flex-multisig/schema/query_msg.json b/contracts/cw3-flex-multisig/schema/query_msg.json index e4f0b9938..7fcdeccdb 100644 --- a/contracts/cw3-flex-multisig/schema/query_msg.json +++ b/contracts/cw3-flex-multisig/schema/query_msg.json @@ -12,7 +12,8 @@ "threshold": { "type": "object" } - } + }, + "additionalProperties": false }, { "description": "Returns ProposalResponse", @@ -34,7 +35,8 @@ } } } - } + }, + "additionalProperties": false }, { "description": "Returns ProposalListResponse", @@ -64,7 +66,8 @@ } } } - } + }, + "additionalProperties": false }, { "description": "Returns ProposalListResponse", @@ -94,7 +97,8 @@ } } } - } + }, + "additionalProperties": false }, { "description": "Returns VoteResponse", @@ -116,11 +120,12 @@ "minimum": 0.0 }, "voter": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "Returns VoteListResponse", @@ -149,18 +154,15 @@ "minimum": 0.0 }, "start_after": { - "anyOf": [ - { - "$ref": "#/definitions/HumanAddr" - }, - { - "type": "null" - } + "type": [ + "string", + "null" ] } } } - } + }, + "additionalProperties": false }, { "description": "Returns VoterInfo", @@ -176,11 +178,12 @@ ], "properties": { "address": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "Returns VoterListResponse", @@ -201,23 +204,15 @@ "minimum": 0.0 }, "start_after": { - "anyOf": [ - { - "$ref": "#/definitions/HumanAddr" - }, - { - "type": "null" - } + "type": [ + "string", + "null" ] } } } - } - } - ], - "definitions": { - "HumanAddr": { - "type": "string" + }, + "additionalProperties": false } - } + ] } diff --git a/contracts/cw3-flex-multisig/src/contract.rs b/contracts/cw3-flex-multisig/src/contract.rs index 07c529e45..fb04f7d16 100644 --- a/contracts/cw3-flex-multisig/src/contract.rs +++ b/contracts/cw3-flex-multisig/src/contract.rs @@ -3,11 +3,11 @@ use std::cmp::Ordering; #[cfg(not(feature = "library"))] use cosmwasm_std::entry_point; use cosmwasm_std::{ - attr, to_binary, Binary, BlockInfo, CanonicalAddr, CosmosMsg, Deps, DepsMut, Empty, Env, - HumanAddr, MessageInfo, Order, Response, StdResult, + attr, to_binary, Binary, BlockInfo, CosmosMsg, Deps, DepsMut, Empty, Env, MessageInfo, Order, + Response, StdResult, }; -use cw0::{maybe_canonical, Expiration}; +use cw0::{maybe_addr, Expiration}; use cw2::set_contract_version; use cw3::{ ProposalListResponse, ProposalResponse, Status, ThresholdResponse, Vote, VoteInfo, @@ -33,15 +33,12 @@ pub fn instantiate( _info: MessageInfo, msg: InstantiateMsg, ) -> Result { - // we just convert to canonical to check if this is a valid format - if deps.api.canonical_address(&msg.group_addr).is_err() { - return Err(ContractError::InvalidGroup { - addr: msg.group_addr, - }); - } - - let group = Cw4Contract(msg.group_addr); - let total_weight = group.total_weight(&deps.querier)?; + let group_addr = Cw4Contract(deps.api.addr_validate(&msg.group_addr).map_err(|_| { + ContractError::InvalidGroup { + addr: msg.group_addr.clone(), + } + })?); + let total_weight = group_addr.total_weight(&deps.querier)?; msg.threshold.validate(total_weight)?; set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; @@ -49,7 +46,7 @@ pub fn instantiate( let cfg = Config { threshold: msg.threshold, max_voting_period: msg.max_voting_period, - group_addr: group, + group_addr, }; CONFIG.save(deps.storage, &cfg)?; @@ -90,12 +87,11 @@ pub fn execute_propose( latest: Option, ) -> Result, ContractError> { // only members of the multisig can create a proposal - let raw_sender = deps.api.canonical_address(&info.sender)?; let cfg = CONFIG.load(deps.storage)?; let vote_power = cfg .group_addr - .is_member(&deps.querier, &raw_sender)? + .is_member(&deps.querier, &info.sender)? .ok_or(ContractError::Unauthorized {})?; // max expires also used as default @@ -129,7 +125,7 @@ pub fn execute_propose( weight: vote_power, vote: Vote::Yes, }; - BALLOTS.save(deps.storage, (id.into(), &raw_sender), &ballot)?; + BALLOTS.save(deps.storage, (id.into(), &info.sender), &ballot)?; Ok(Response { submessages: vec![], @@ -152,7 +148,6 @@ pub fn execute_vote( vote: Vote, ) -> Result, ContractError> { // only members of the multisig can vote - let raw_sender = deps.api.canonical_address(&info.sender)?; let cfg = CONFIG.load(deps.storage)?; // ensure proposal exists and can be voted on @@ -173,7 +168,7 @@ pub fn execute_vote( // cast vote if no vote previously cast BALLOTS.update( deps.storage, - (proposal_id.into(), &raw_sender), + (proposal_id.into(), &info.sender), |bal| match bal { Some(_) => Err(ContractError::AlreadyVoted {}), None => Ok(Ballot { @@ -386,9 +381,9 @@ fn map_proposal( }) } -fn query_vote(deps: Deps, proposal_id: u64, voter: HumanAddr) -> StdResult { - let voter_raw = deps.api.canonical_address(&voter)?; - let prop = BALLOTS.may_load(deps.storage, (proposal_id.into(), &voter_raw))?; +fn query_vote(deps: Deps, proposal_id: u64, voter: String) -> StdResult { + let voter_addr = deps.api.addr_validate(&voter)?; + let prop = BALLOTS.may_load(deps.storage, (proposal_id.into(), &voter_addr))?; let vote = prop.map(|b| VoteInfo { voter, vote: b.vote, @@ -400,22 +395,21 @@ fn query_vote(deps: Deps, proposal_id: u64, voter: HumanAddr) -> StdResult, + start_after: Option, limit: Option, ) -> StdResult { let limit = limit.unwrap_or(DEFAULT_LIMIT).min(MAX_LIMIT) as usize; - let canon = maybe_canonical(deps.api, start_after)?; - let start = canon.map(Bound::exclusive); + let addr = maybe_addr(deps.api, start_after)?; + let start = addr.map(|addr| Bound::exclusive(addr.as_ref())); - let api = &deps.api; let votes: StdResult> = BALLOTS .prefix(proposal_id.into()) .range(deps.storage, start, None, Order::Ascending) .take(limit) .map(|item| { - let (key, ballot) = item?; + let (voter, ballot) = item?; Ok(VoteInfo { - voter: api.human_address(&CanonicalAddr::from(key))?, + voter: String::from_utf8(voter)?, vote: ballot.vote, weight: ballot.weight, }) @@ -425,17 +419,17 @@ fn list_votes( Ok(VoteListResponse { votes: votes? }) } -fn query_voter(deps: Deps, voter: HumanAddr) -> StdResult { +fn query_voter(deps: Deps, voter: String) -> StdResult { let cfg = CONFIG.load(deps.storage)?; - let voter_raw = deps.api.canonical_address(&voter)?; - let weight = cfg.group_addr.is_member(&deps.querier, &voter_raw)?; + let voter_addr = deps.api.addr_validate(&voter)?; + let weight = cfg.group_addr.is_member(&deps.querier, &voter_addr)?; Ok(VoterResponse { weight }) } fn list_voters( deps: Deps, - start_after: Option, + start_after: Option, limit: Option, ) -> StdResult { let cfg = CONFIG.load(deps.storage)?; @@ -454,7 +448,7 @@ fn list_voters( #[cfg(test)] mod tests { use cosmwasm_std::testing::{mock_env, MockApi, MockStorage}; - use cosmwasm_std::{coin, coins, BankMsg, Coin, Decimal}; + use cosmwasm_std::{coin, coins, Addr, BankMsg, Coin, Decimal}; use cw0::Duration; use cw2::{query_contract_info, ContractVersion}; @@ -473,7 +467,7 @@ mod tests { const VOTER5: &str = "voter0005"; const SOMEBODY: &str = "somebody"; - fn member>(addr: T, weight: u64) -> Member { + fn member>(addr: T, weight: u64) -> Member { Member { addr: addr.into(), weight, @@ -507,29 +501,29 @@ mod tests { } // uploads code and returns address of group contract - fn instantiate_group(app: &mut App, members: Vec) -> HumanAddr { + fn instantiate_group(app: &mut App, members: Vec) -> Addr { let group_id = app.store_code(contract_group()); let msg = cw4_group::msg::InstantiateMsg { admin: Some(OWNER.into()), members, }; - app.instantiate_contract(group_id, OWNER, &msg, &[], "group") + app.instantiate_contract(group_id, Addr::unchecked(OWNER), &msg, &[], "group") .unwrap() } fn instantiate_flex( app: &mut App, - group: HumanAddr, + group: Addr, threshold: Threshold, max_voting_period: Duration, - ) -> HumanAddr { + ) -> Addr { let flex_id = app.store_code(contract_flex()); let msg = crate::msg::InstantiateMsg { - group_addr: group, + group_addr: group.to_string(), threshold, max_voting_period, }; - app.instantiate_contract(flex_id, OWNER, &msg, &[], "flex") + app.instantiate_contract(flex_id, Addr::unchecked(OWNER), &msg, &[], "flex") .unwrap() } @@ -542,7 +536,7 @@ mod tests { max_voting_period: Duration, init_funds: Vec, multisig_as_group_admin: bool, - ) -> (HumanAddr, HumanAddr) { + ) -> (Addr, Addr) { setup_test_case( app, Threshold::AbsoluteCount { @@ -560,7 +554,7 @@ mod tests { max_voting_period: Duration, init_funds: Vec, multisig_as_group_admin: bool, - ) -> (HumanAddr, HumanAddr) { + ) -> (Addr, Addr) { // 1. Instantiate group contract with members (and OWNER as admin) let members = vec![ member(OWNER, 0), @@ -580,10 +574,15 @@ mod tests { // 3. (Optional) Set the multisig as the group owner if multisig_as_group_admin { let update_admin = Cw4ExecuteMsg::UpdateAdmin { - admin: Some(flex_addr.clone()), + admin: Some(flex_addr.to_string()), }; - app.execute_contract(OWNER, &group_addr, &update_admin, &[]) - .unwrap(); + app.execute_contract( + Addr::unchecked(OWNER), + group_addr.clone(), + &update_admin, + &[], + ) + .unwrap(); app.update_block(next_block); } @@ -627,14 +626,14 @@ mod tests { // Zero required weight fails let instantiate_msg = InstantiateMsg { - group_addr: group_addr.clone(), + group_addr: group_addr.to_string(), threshold: Threshold::AbsoluteCount { weight: 0 }, max_voting_period, }; let err = app .instantiate_contract( flex_id, - OWNER, + Addr::unchecked(OWNER), &instantiate_msg, &[], "zero required weight", @@ -644,14 +643,14 @@ mod tests { // Total weight less than required weight not allowed let instantiate_msg = InstantiateMsg { - group_addr: group_addr.clone(), + group_addr: group_addr.to_string(), threshold: Threshold::AbsoluteCount { weight: 100 }, max_voting_period, }; let err = app .instantiate_contract( flex_id, - OWNER, + Addr::unchecked(OWNER), &instantiate_msg, &[], "high required weight", @@ -661,16 +660,22 @@ mod tests { // All valid let instantiate_msg = InstantiateMsg { - group_addr: group_addr.clone(), + group_addr: group_addr.to_string(), threshold: Threshold::AbsoluteCount { weight: 1 }, max_voting_period, }; let flex_addr = app - .instantiate_contract(flex_id, OWNER, &instantiate_msg, &[], "all good") + .instantiate_contract( + flex_id, + Addr::unchecked(OWNER), + &instantiate_msg, + &[], + "all good", + ) .unwrap(); // Verify contract version set properly - let version = query_contract_info(&app, &flex_addr).unwrap(); + let version = query_contract_info(&app, flex_addr.clone()).unwrap(); assert_eq!( ContractVersion { contract: CONTRACT_NAME.to_string(), @@ -716,7 +721,7 @@ mod tests { let proposal = pay_somebody_proposal(); // Only voters can propose let err = app - .execute_contract(SOMEBODY, &flex_addr, &proposal, &[]) + .execute_contract(Addr::unchecked(SOMEBODY), flex_addr.clone(), &proposal, &[]) .unwrap_err(); assert_eq!(err, ContractError::Unauthorized {}.to_string()); @@ -732,13 +737,18 @@ mod tests { latest: Some(Expiration::AtHeight(123456)), }; let err = app - .execute_contract(OWNER, &flex_addr, &proposal_wrong_exp, &[]) + .execute_contract( + Addr::unchecked(OWNER), + flex_addr.clone(), + &proposal_wrong_exp, + &[], + ) .unwrap_err(); assert_eq!(err, ContractError::WrongExpiration {}.to_string()); // Proposal from voter works let res = app - .execute_contract(VOTER3, &flex_addr, &proposal, &[]) + .execute_contract(Addr::unchecked(VOTER3), flex_addr.clone(), &proposal, &[]) .unwrap(); assert_eq!( res.attributes, @@ -752,7 +762,7 @@ mod tests { // Proposal from voter with enough vote power directly passes let res = app - .execute_contract(VOTER4, &flex_addr, &proposal, &[]) + .execute_contract(Addr::unchecked(VOTER4), flex_addr, &proposal, &[]) .unwrap(); assert_eq!( res.attributes, @@ -765,7 +775,7 @@ mod tests { ); } - fn get_tally(app: &App, flex_addr: &HumanAddr, proposal_id: u64) -> u64 { + fn get_tally(app: &App, flex_addr: &str, proposal_id: u64) -> u64 { // Get all the voters on the proposal let voters = QueryMsg::ListVotes { proposal_id, @@ -817,7 +827,7 @@ mod tests { // create proposal with 1 vote power let proposal = pay_somebody_proposal(); let res = app - .execute_contract(VOTER1, &flex_addr, &proposal, &[]) + .execute_contract(Addr::unchecked(VOTER1), flex_addr.clone(), &proposal, &[]) .unwrap(); let proposal_id1: u64 = res.attributes[2].value.parse().unwrap(); @@ -825,7 +835,7 @@ mod tests { app.update_block(next_block); let proposal = pay_somebody_proposal(); let res = app - .execute_contract(VOTER3, &flex_addr, &proposal, &[]) + .execute_contract(Addr::unchecked(VOTER3), flex_addr.clone(), &proposal, &[]) .unwrap(); let proposal_id2: u64 = res.attributes[2].value.parse().unwrap(); @@ -835,7 +845,7 @@ mod tests { // add one more open proposal, 2 votes let proposal = pay_somebody_proposal(); let res = app - .execute_contract(VOTER2, &flex_addr, &proposal, &[]) + .execute_contract(Addr::unchecked(VOTER2), flex_addr.clone(), &proposal, &[]) .unwrap(); let proposal_id3: u64 = res.attributes[2].value.parse().unwrap(); let proposed_at = app.block_info(); @@ -913,7 +923,7 @@ mod tests { // create proposal with 0 vote power let proposal = pay_somebody_proposal(); let res = app - .execute_contract(OWNER, &flex_addr, &proposal, &[]) + .execute_contract(Addr::unchecked(OWNER), flex_addr.clone(), &proposal, &[]) .unwrap(); // Get the proposal id from the logs @@ -925,19 +935,19 @@ mod tests { vote: Vote::Yes, }; let err = app - .execute_contract(OWNER, &flex_addr, &yes_vote, &[]) + .execute_contract(Addr::unchecked(OWNER), flex_addr.clone(), &yes_vote, &[]) .unwrap_err(); assert_eq!(ContractError::AlreadyVoted {}.to_string(), err); // Only voters can vote let err = app - .execute_contract(SOMEBODY, &flex_addr, &yes_vote, &[]) + .execute_contract(Addr::unchecked(SOMEBODY), flex_addr.clone(), &yes_vote, &[]) .unwrap_err(); assert_eq!(ContractError::Unauthorized {}.to_string(), err); // But voter1 can let res = app - .execute_contract(VOTER1, &flex_addr, &yes_vote, &[]) + .execute_contract(Addr::unchecked(VOTER1), flex_addr.clone(), &yes_vote, &[]) .unwrap(); assert_eq!( res.attributes, @@ -951,7 +961,7 @@ mod tests { // No/Veto votes have no effect on the tally // Compute the current tally - let tally = get_tally(&app, &flex_addr, proposal_id); + let tally = get_tally(&app, flex_addr.as_ref(), proposal_id); assert_eq!(tally, 1); // Cast a No vote @@ -960,7 +970,7 @@ mod tests { vote: Vote::No, }; let _ = app - .execute_contract(VOTER2, &flex_addr, &no_vote, &[]) + .execute_contract(Addr::unchecked(VOTER2), flex_addr.clone(), &no_vote, &[]) .unwrap(); // Cast a Veto vote @@ -969,28 +979,28 @@ mod tests { vote: Vote::Veto, }; let _ = app - .execute_contract(VOTER3, &flex_addr, &veto_vote, &[]) + .execute_contract(Addr::unchecked(VOTER3), flex_addr.clone(), &veto_vote, &[]) .unwrap(); // Tally unchanged - assert_eq!(tally, get_tally(&app, &flex_addr, proposal_id)); + assert_eq!(tally, get_tally(&app, flex_addr.as_ref(), proposal_id)); let err = app - .execute_contract(VOTER3, &flex_addr, &yes_vote, &[]) + .execute_contract(Addr::unchecked(VOTER3), flex_addr.clone(), &yes_vote, &[]) .unwrap_err(); assert_eq!(ContractError::AlreadyVoted {}.to_string(), err); // Expired proposals cannot be voted app.update_block(expire(voting_period)); let err = app - .execute_contract(VOTER4, &flex_addr, &yes_vote, &[]) + .execute_contract(Addr::unchecked(VOTER4), flex_addr.clone(), &yes_vote, &[]) .unwrap_err(); assert_eq!(ContractError::Expired {}.to_string(), err); app.update_block(unexpire(voting_period)); // Powerful voter supports it, so it passes let res = app - .execute_contract(VOTER4, &flex_addr, &yes_vote, &[]) + .execute_contract(Addr::unchecked(VOTER4), flex_addr.clone(), &yes_vote, &[]) .unwrap(); assert_eq!( res.attributes, @@ -1004,7 +1014,7 @@ mod tests { // non-Open proposals cannot be voted let err = app - .execute_contract(VOTER5, &flex_addr, &yes_vote, &[]) + .execute_contract(Addr::unchecked(VOTER5), flex_addr.clone(), &yes_vote, &[]) .unwrap_err(); assert_eq!(ContractError::NotOpen {}.to_string(), err); @@ -1069,7 +1079,7 @@ mod tests { // create proposal with 0 vote power let proposal = pay_somebody_proposal(); let res = app - .execute_contract(OWNER, &flex_addr, &proposal, &[]) + .execute_contract(Addr::unchecked(OWNER), flex_addr.clone(), &proposal, &[]) .unwrap(); // Get the proposal id from the logs @@ -1078,7 +1088,7 @@ mod tests { // Only Passed can be executed let execution = ExecuteMsg::Execute { proposal_id }; let err = app - .execute_contract(OWNER, &flex_addr, &execution, &[]) + .execute_contract(Addr::unchecked(OWNER), flex_addr.clone(), &execution, &[]) .unwrap_err(); assert_eq!(ContractError::WrongExecuteStatus {}.to_string(), err); @@ -1088,7 +1098,7 @@ mod tests { vote: Vote::Yes, }; let res = app - .execute_contract(VOTER3, &flex_addr, &vote, &[]) + .execute_contract(Addr::unchecked(VOTER3), flex_addr.clone(), &vote, &[]) .unwrap(); assert_eq!( res.attributes, @@ -1103,13 +1113,18 @@ mod tests { // In passing: Try to close Passed fails let closing = ExecuteMsg::Close { proposal_id }; let err = app - .execute_contract(OWNER, &flex_addr, &closing, &[]) + .execute_contract(Addr::unchecked(OWNER), flex_addr.clone(), &closing, &[]) .unwrap_err(); assert_eq!(ContractError::WrongCloseStatus {}.to_string(), err); // Execute works. Anybody can execute Passed proposals let res = app - .execute_contract(SOMEBODY, &flex_addr, &execution, &[]) + .execute_contract( + Addr::unchecked(SOMEBODY), + flex_addr.clone(), + &execution, + &[], + ) .unwrap(); assert_eq!( res.attributes, @@ -1128,7 +1143,7 @@ mod tests { // In passing: Try to close Executed fails let err = app - .execute_contract(OWNER, &flex_addr, &closing, &[]) + .execute_contract(Addr::unchecked(OWNER), flex_addr, &closing, &[]) .unwrap_err(); assert_eq!(ContractError::WrongCloseStatus {}.to_string(), err); } @@ -1150,7 +1165,7 @@ mod tests { // create proposal with 0 vote power let proposal = pay_somebody_proposal(); let res = app - .execute_contract(OWNER, &flex_addr, &proposal, &[]) + .execute_contract(Addr::unchecked(OWNER), flex_addr.clone(), &proposal, &[]) .unwrap(); // Get the proposal id from the logs @@ -1159,14 +1174,14 @@ mod tests { // Non-expired proposals cannot be closed let closing = ExecuteMsg::Close { proposal_id }; let err = app - .execute_contract(SOMEBODY, &flex_addr, &closing, &[]) + .execute_contract(Addr::unchecked(SOMEBODY), flex_addr.clone(), &closing, &[]) .unwrap_err(); assert_eq!(ContractError::NotExpired {}.to_string(), err); // Expired proposals can be closed app.update_block(expire(voting_period)); let res = app - .execute_contract(SOMEBODY, &flex_addr, &closing, &[]) + .execute_contract(Addr::unchecked(SOMEBODY), flex_addr.clone(), &closing, &[]) .unwrap(); assert_eq!( res.attributes, @@ -1180,7 +1195,7 @@ mod tests { // Trying to close it again fails let closing = ExecuteMsg::Close { proposal_id }; let err = app - .execute_contract(SOMEBODY, &flex_addr, &closing, &[]) + .execute_contract(Addr::unchecked(SOMEBODY), flex_addr, &closing, &[]) .unwrap_err(); assert_eq!(ContractError::WrongCloseStatus {}.to_string(), err); } @@ -1203,7 +1218,7 @@ mod tests { // VOTER1 starts a proposal to send some tokens (1/4 votes) let proposal = pay_somebody_proposal(); let res = app - .execute_contract(VOTER1, &flex_addr, &proposal, &[]) + .execute_contract(Addr::unchecked(VOTER1), flex_addr.clone(), &proposal, &[]) .unwrap(); // Get the proposal id from the logs let proposal_id: u64 = res.attributes[2].value.parse().unwrap(); @@ -1242,7 +1257,7 @@ mod tests { remove: vec![VOTER3.into()], add: vec![member(VOTER2, 7), member(newbie, 2)], }; - app.execute_contract(OWNER, &group_addr, &update_msg, &[]) + app.execute_contract(Addr::unchecked(OWNER), group_addr, &update_msg, &[]) .unwrap(); // check membership queries properly updated @@ -1264,7 +1279,7 @@ mod tests { // make a second proposal let proposal2 = pay_somebody_proposal(); let res = app - .execute_contract(VOTER1, &flex_addr, &proposal2, &[]) + .execute_contract(Addr::unchecked(VOTER1), flex_addr.clone(), &proposal2, &[]) .unwrap(); // Get the proposal id from the logs let proposal_id2: u64 = res.attributes[2].value.parse().unwrap(); @@ -1274,7 +1289,7 @@ mod tests { proposal_id: proposal_id2, vote: Vote::Yes, }; - app.execute_contract(VOTER2, &flex_addr, &yes_vote, &[]) + app.execute_contract(Addr::unchecked(VOTER2), flex_addr.clone(), &yes_vote, &[]) .unwrap(); assert_eq!(prop_status(&app, proposal_id2), Status::Passed); @@ -1283,18 +1298,18 @@ mod tests { proposal_id, vote: Vote::Yes, }; - app.execute_contract(VOTER2, &flex_addr, &yes_vote, &[]) + app.execute_contract(Addr::unchecked(VOTER2), flex_addr.clone(), &yes_vote, &[]) .unwrap(); assert_eq!(prop_status(&app, proposal_id), Status::Open); // newbie cannot vote let err = app - .execute_contract(newbie, &flex_addr, &yes_vote, &[]) + .execute_contract(Addr::unchecked(newbie), flex_addr.clone(), &yes_vote, &[]) .unwrap_err(); assert_eq!(ContractError::Unauthorized {}.to_string(), err); // previously removed VOTER3 can still vote, passing the proposal - app.execute_contract(VOTER3, &flex_addr, &yes_vote, &[]) + app.execute_contract(Addr::unchecked(VOTER3), flex_addr.clone(), &yes_vote, &[]) .unwrap(); assert_eq!(prop_status(&app, proposal_id), Status::Passed); @@ -1330,7 +1345,7 @@ mod tests { ); // Start a proposal to remove VOTER3 from the set - let update_msg = Cw4GroupContract::new(group_addr.clone()) + let update_msg = Cw4GroupContract::new(group_addr) .update_members(vec![VOTER3.into()], vec![]) .unwrap(); let update_proposal = ExecuteMsg::Propose { @@ -1340,7 +1355,12 @@ mod tests { latest: None, }; let res = app - .execute_contract(VOTER1, &flex_addr, &update_proposal, &[]) + .execute_contract( + Addr::unchecked(VOTER1), + flex_addr.clone(), + &update_proposal, + &[], + ) .unwrap(); // Get the proposal id from the logs let update_proposal_id: u64 = res.attributes[2].value.parse().unwrap(); @@ -1351,7 +1371,12 @@ mod tests { // VOTER1 starts a proposal to send some tokens let cash_proposal = pay_somebody_proposal(); let res = app - .execute_contract(VOTER1, &flex_addr, &cash_proposal, &[]) + .execute_contract( + Addr::unchecked(VOTER1), + flex_addr.clone(), + &cash_proposal, + &[], + ) .unwrap(); // Get the proposal id from the logs let cash_proposal_id: u64 = res.attributes[2].value.parse().unwrap(); @@ -1377,12 +1402,12 @@ mod tests { proposal_id: update_proposal_id, vote: Vote::Yes, }; - app.execute_contract(VOTER4, &flex_addr, &yes_vote, &[]) + app.execute_contract(Addr::unchecked(VOTER4), flex_addr.clone(), &yes_vote, &[]) .unwrap(); let execution = ExecuteMsg::Execute { proposal_id: update_proposal_id, }; - app.execute_contract(VOTER4, &flex_addr, &execution, &[]) + app.execute_contract(Addr::unchecked(VOTER4), flex_addr.clone(), &execution, &[]) .unwrap(); // ensure that the update_proposal is executed, but the other unchanged @@ -1398,14 +1423,19 @@ mod tests { proposal_id: cash_proposal_id, vote: Vote::Yes, }; - app.execute_contract(VOTER3, &flex_addr, &yes_vote, &[]) + app.execute_contract(Addr::unchecked(VOTER3), flex_addr.clone(), &yes_vote, &[]) .unwrap(); assert_eq!(prop_status(&app, cash_proposal_id), Status::Passed); // but cannot open a new one let cash_proposal = pay_somebody_proposal(); let err = app - .execute_contract(VOTER3, &flex_addr, &cash_proposal, &[]) + .execute_contract( + Addr::unchecked(VOTER3), + flex_addr.clone(), + &cash_proposal, + &[], + ) .unwrap_err(); assert_eq!(ContractError::Unauthorized {}.to_string(), err); @@ -1414,7 +1444,7 @@ mod tests { diffs: vec![MemberDiff::new(VOTER1, Some(1), None)], }); let err = app - .execute_contract(VOTER2, &flex_addr, &hook_hack, &[]) + .execute_contract(Addr::unchecked(VOTER2), flex_addr.clone(), &hook_hack, &[]) .unwrap_err(); assert_eq!(ContractError::Unauthorized {}.to_string(), err); } @@ -1439,7 +1469,7 @@ mod tests { // VOTER3 starts a proposal to send some tokens (3/5 votes) let proposal = pay_somebody_proposal(); let res = app - .execute_contract(VOTER3, &flex_addr, &proposal, &[]) + .execute_contract(Addr::unchecked(VOTER3), flex_addr.clone(), &proposal, &[]) .unwrap(); // Get the proposal id from the logs let proposal_id: u64 = res.attributes[2].value.parse().unwrap(); @@ -1464,7 +1494,7 @@ mod tests { remove: vec![VOTER3.into()], add: vec![member(VOTER2, 7), member(newbie, 15)], }; - app.execute_contract(OWNER, &group_addr, &update_msg, &[]) + app.execute_contract(Addr::unchecked(OWNER), group_addr, &update_msg, &[]) .unwrap(); // a few blocks later... @@ -1476,14 +1506,14 @@ mod tests { proposal_id, vote: Vote::Yes, }; - app.execute_contract(VOTER2, &flex_addr, &yes_vote, &[]) + app.execute_contract(Addr::unchecked(VOTER2), flex_addr.clone(), &yes_vote, &[]) .unwrap(); assert_eq!(prop_status(&app), Status::Passed); // new proposal can be passed single-handedly by newbie let proposal = pay_somebody_proposal(); let res = app - .execute_contract(newbie, &flex_addr, &proposal, &[]) + .execute_contract(Addr::unchecked(newbie), flex_addr.clone(), &proposal, &[]) .unwrap(); // Get the proposal id from the logs let proposal_id2: u64 = res.attributes[2].value.parse().unwrap(); @@ -1521,7 +1551,7 @@ mod tests { // VOTER3 starts a proposal to send some tokens (3 votes) let proposal = pay_somebody_proposal(); let res = app - .execute_contract(VOTER3, &flex_addr, &proposal, &[]) + .execute_contract(Addr::unchecked(VOTER3), flex_addr.clone(), &proposal, &[]) .unwrap(); // Get the proposal id from the logs let proposal_id: u64 = res.attributes[2].value.parse().unwrap(); @@ -1546,7 +1576,7 @@ mod tests { remove: vec![VOTER3.into()], add: vec![member(VOTER2, 7), member(newbie, 15)], }; - app.execute_contract(OWNER, &group_addr, &update_msg, &[]) + app.execute_contract(Addr::unchecked(OWNER), group_addr, &update_msg, &[]) .unwrap(); // a few blocks later... @@ -1558,7 +1588,7 @@ mod tests { proposal_id, vote: Vote::No, }; - app.execute_contract(VOTER2, &flex_addr, &yes_vote, &[]) + app.execute_contract(Addr::unchecked(VOTER2), flex_addr.clone(), &yes_vote, &[]) .unwrap(); // not expired yet assert_eq!(prop_status(&app), Status::Open); @@ -1590,7 +1620,7 @@ mod tests { // create proposal let proposal = pay_somebody_proposal(); let res = app - .execute_contract(VOTER5, &flex_addr, &proposal, &[]) + .execute_contract(Addr::unchecked(VOTER5), flex_addr.clone(), &proposal, &[]) .unwrap(); // Get the proposal id from the logs let proposal_id: u64 = res.attributes[2].value.parse().unwrap(); @@ -1610,7 +1640,7 @@ mod tests { proposal_id, vote: Vote::Yes, }; - app.execute_contract(VOTER4, &flex_addr, &yes_vote, &[]) + app.execute_contract(Addr::unchecked(VOTER4), flex_addr.clone(), &yes_vote, &[]) .unwrap(); // 9 of 15 is 60% absolute threshold, but less than 12 (80% quorum needed) assert_eq!(prop_status(&app), Status::Open); @@ -1620,7 +1650,7 @@ mod tests { proposal_id, vote: Vote::No, }; - app.execute_contract(VOTER3, &flex_addr, &no_vote, &[]) + app.execute_contract(Addr::unchecked(VOTER3), flex_addr.clone(), &no_vote, &[]) .unwrap(); assert_eq!(prop_status(&app), Status::Passed); } diff --git a/contracts/cw3-flex-multisig/src/error.rs b/contracts/cw3-flex-multisig/src/error.rs index 7709fa7be..2a965644c 100644 --- a/contracts/cw3-flex-multisig/src/error.rs +++ b/contracts/cw3-flex-multisig/src/error.rs @@ -1,4 +1,4 @@ -use cosmwasm_std::{HumanAddr, StdError}; +use cosmwasm_std::StdError; use thiserror::Error; #[derive(Error, Debug, PartialEq)] @@ -13,7 +13,7 @@ pub enum ContractError { UnreachableThreshold {}, #[error("Group contract invalid address '{addr}'")] - InvalidGroup { addr: HumanAddr }, + InvalidGroup { addr: String }, #[error("Unauthorized")] Unauthorized {}, diff --git a/contracts/cw3-flex-multisig/src/msg.rs b/contracts/cw3-flex-multisig/src/msg.rs index 8dbdb78ac..5fda0de91 100644 --- a/contracts/cw3-flex-multisig/src/msg.rs +++ b/contracts/cw3-flex-multisig/src/msg.rs @@ -2,7 +2,7 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use crate::error::ContractError; -use cosmwasm_std::{CosmosMsg, Decimal, Empty, HumanAddr}; +use cosmwasm_std::{CosmosMsg, Decimal, Empty}; use cw0::{Duration, Expiration}; use cw3::{ThresholdResponse, Vote}; use cw4::MemberChangedHookMsg; @@ -10,7 +10,7 @@ use cw4::MemberChangedHookMsg; #[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] pub struct InstantiateMsg { // this is the group contract that contains the member list - pub group_addr: HumanAddr, + pub group_addr: String, pub threshold: Threshold, pub max_voting_period: Duration, } @@ -146,18 +146,18 @@ pub enum QueryMsg { limit: Option, }, /// Returns VoteResponse - Vote { proposal_id: u64, voter: HumanAddr }, + Vote { proposal_id: u64, voter: String }, /// Returns VoteListResponse ListVotes { proposal_id: u64, - start_after: Option, + start_after: Option, limit: Option, }, /// Returns VoterInfo - Voter { address: HumanAddr }, + Voter { address: String }, /// Returns VoterListResponse ListVoters { - start_after: Option, + start_after: Option, limit: Option, }, } diff --git a/contracts/cw3-flex-multisig/src/state.rs b/contracts/cw3-flex-multisig/src/state.rs index 14465b815..c01207a73 100644 --- a/contracts/cw3-flex-multisig/src/state.rs +++ b/contracts/cw3-flex-multisig/src/state.rs @@ -2,7 +2,9 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use std::convert::TryInto; -use cosmwasm_std::{BlockInfo, CosmosMsg, Decimal, Empty, StdError, StdResult, Storage, Uint128}; +use cosmwasm_std::{ + Addr, BlockInfo, CosmosMsg, Decimal, Empty, StdError, StdResult, Storage, Uint128, +}; use cw0::{Duration, Expiration}; use cw3::{Status, Vote}; @@ -151,7 +153,7 @@ pub const CONFIG: Item = Item::new("config"); pub const PROPOSAL_COUNT: Item = Item::new("proposal_count"); // multiple-item map -pub const BALLOTS: Map<(U64Key, &[u8]), Ballot> = Map::new("votes"); +pub const BALLOTS: Map<(U64Key, &Addr), Ballot> = Map::new("votes"); pub const PROPOSALS: Map = Map::new("proposals"); pub fn next_id(store: &mut dyn Storage) -> StdResult { @@ -248,10 +250,7 @@ mod test { true, check_is_passed(fixed.clone(), votes.clone(), 30, false) ); - assert_eq!( - true, - check_is_passed(fixed.clone(), votes.clone(), 30, true) - ); + assert_eq!(true, check_is_passed(fixed, votes, 30, true)); } #[test] @@ -283,10 +282,7 @@ mod test { true, check_is_passed(percent.clone(), votes.clone(), 14, false) ); - assert_eq!( - true, - check_is_passed(percent.clone(), votes.clone(), 14, true) - ); + assert_eq!(true, check_is_passed(percent, votes, 14, true)); } #[test] @@ -336,10 +332,7 @@ mod test { check_is_passed(quorum.clone(), passes_ignoring_abstain.clone(), 40, true) ); // over quorum, but under threshold fails also - assert_eq!( - false, - check_is_passed(quorum.clone(), failing.clone(), 20, true) - ); + assert_eq!(false, check_is_passed(quorum.clone(), failing, 20, true)); // now, check with open voting period // would pass if closed, but fail here, as remaining votes no -> fail @@ -359,13 +352,10 @@ mod test { // all votes have been cast, some abstain assert_eq!( true, - check_is_passed(quorum.clone(), passes_ignoring_abstain.clone(), 17, false) + check_is_passed(quorum.clone(), passes_ignoring_abstain, 17, false) ); // 3 votes uncast, if they all vote no, we have 7 yes, 7 no+veto, 2 abstain (out of 16) - assert_eq!( - true, - check_is_passed(quorum.clone(), passing.clone(), 16, false) - ); + assert_eq!(true, check_is_passed(quorum, passing, 16, false)); } #[test] @@ -390,7 +380,7 @@ mod test { ); assert_eq!( false, - check_is_passed(quorum.clone(), missing_voters.clone(), 15, true) + check_is_passed(quorum.clone(), missing_voters, 15, true) ); // 1 less yes, 3 vetos and this passes only when expired @@ -406,7 +396,7 @@ mod test { ); assert_eq!( true, - check_is_passed(quorum.clone(), wait_til_expired.clone(), 15, true) + check_is_passed(quorum.clone(), wait_til_expired, 15, true) ); // 9 yes and 3 nos passes early @@ -420,9 +410,6 @@ mod test { true, check_is_passed(quorum.clone(), passes_early.clone(), 15, false) ); - assert_eq!( - true, - check_is_passed(quorum.clone(), passes_early.clone(), 15, true) - ); + assert_eq!(true, check_is_passed(quorum, passes_early, 15, true)); } } diff --git a/contracts/cw4-group/Cargo.toml b/contracts/cw4-group/Cargo.toml index 43a8d755c..fae9e3801 100644 --- a/contracts/cw4-group/Cargo.toml +++ b/contracts/cw4-group/Cargo.toml @@ -31,10 +31,10 @@ cw2 = { path = "../../packages/cw2", version = "0.6.0-alpha3" } cw4 = { path = "../../packages/cw4", version = "0.6.0-alpha3" } cw-controllers = { path = "../../packages/controllers", version = "0.6.0-alpha3" } cw-storage-plus = { path = "../../packages/storage-plus", version = "0.6.0-alpha3", features = ["iterator"] } -cosmwasm-std = { version = "0.14.0-beta1" } -schemars = "0.7" +cosmwasm-std = { version = "0.14.0-beta2" } +schemars = "0.8.1" serde = { version = "1.0.103", default-features = false, features = ["derive"] } thiserror = { version = "1.0.21" } [dev-dependencies] -cosmwasm-schema = { version = "0.14.0-beta1" } +cosmwasm-schema = { version = "0.14.0-beta2" } diff --git a/contracts/cw4-group/schema/admin_response.json b/contracts/cw4-group/schema/admin_response.json index 71edb382e..82bf62a3a 100644 --- a/contracts/cw4-group/schema/admin_response.json +++ b/contracts/cw4-group/schema/admin_response.json @@ -4,19 +4,10 @@ "type": "object", "properties": { "admin": { - "anyOf": [ - { - "$ref": "#/definitions/HumanAddr" - }, - { - "type": "null" - } + "type": [ + "string", + "null" ] } - }, - "definitions": { - "HumanAddr": { - "type": "string" - } } } diff --git a/contracts/cw4-group/schema/execute_msg.json b/contracts/cw4-group/schema/execute_msg.json index d2f8a367f..584424607 100644 --- a/contracts/cw4-group/schema/execute_msg.json +++ b/contracts/cw4-group/schema/execute_msg.json @@ -13,18 +13,15 @@ "type": "object", "properties": { "admin": { - "anyOf": [ - { - "$ref": "#/definitions/HumanAddr" - }, - { - "type": "null" - } + "type": [ + "string", + "null" ] } } } - } + }, + "additionalProperties": false }, { "description": "apply a diff to the existing members. remove is applied after add, so if an address is in both, it is removed", @@ -49,12 +46,13 @@ "remove": { "type": "array", "items": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } } - } + }, + "additionalProperties": false }, { "description": "Add a new hook to be informed of all membership changes. Must be called by Admin", @@ -70,11 +68,12 @@ ], "properties": { "addr": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "Remove a hook. Must be called by Admin", @@ -90,17 +89,15 @@ ], "properties": { "addr": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false } ], "definitions": { - "HumanAddr": { - "type": "string" - }, "Member": { "description": "A group member has a weight associated with them. This may all be equal, or may have meaning in the app that makes use of the group (eg. voting power)", "type": "object", @@ -110,7 +107,7 @@ ], "properties": { "addr": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "weight": { "type": "integer", diff --git a/contracts/cw4-group/schema/instantiate_msg.json b/contracts/cw4-group/schema/instantiate_msg.json index ba90850cf..efa676c03 100644 --- a/contracts/cw4-group/schema/instantiate_msg.json +++ b/contracts/cw4-group/schema/instantiate_msg.json @@ -8,13 +8,9 @@ "properties": { "admin": { "description": "The admin is the only account that can update the group state. Omit it to make the group immutable.", - "anyOf": [ - { - "$ref": "#/definitions/HumanAddr" - }, - { - "type": "null" - } + "type": [ + "string", + "null" ] }, "members": { @@ -25,9 +21,6 @@ } }, "definitions": { - "HumanAddr": { - "type": "string" - }, "Member": { "description": "A group member has a weight associated with them. This may all be equal, or may have meaning in the app that makes use of the group (eg. voting power)", "type": "object", @@ -37,7 +30,7 @@ ], "properties": { "addr": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "weight": { "type": "integer", diff --git a/contracts/cw4-group/schema/member_list_response.json b/contracts/cw4-group/schema/member_list_response.json index cad6cf104..ae09f9bba 100644 --- a/contracts/cw4-group/schema/member_list_response.json +++ b/contracts/cw4-group/schema/member_list_response.json @@ -14,9 +14,6 @@ } }, "definitions": { - "HumanAddr": { - "type": "string" - }, "Member": { "description": "A group member has a weight associated with them. This may all be equal, or may have meaning in the app that makes use of the group (eg. voting power)", "type": "object", @@ -26,7 +23,7 @@ ], "properties": { "addr": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "weight": { "type": "integer", diff --git a/contracts/cw4-group/schema/query_msg.json b/contracts/cw4-group/schema/query_msg.json index f8461d9a3..8f994c9c0 100644 --- a/contracts/cw4-group/schema/query_msg.json +++ b/contracts/cw4-group/schema/query_msg.json @@ -12,7 +12,8 @@ "admin": { "type": "object" } - } + }, + "additionalProperties": false }, { "description": "Return TotalWeightResponse", @@ -24,7 +25,8 @@ "total_weight": { "type": "object" } - } + }, + "additionalProperties": false }, { "description": "Returns MembersListResponse", @@ -45,18 +47,15 @@ "minimum": 0.0 }, "start_after": { - "anyOf": [ - { - "$ref": "#/definitions/HumanAddr" - }, - { - "type": "null" - } + "type": [ + "string", + "null" ] } } } - } + }, + "additionalProperties": false }, { "description": "Returns MemberResponse", @@ -72,7 +71,7 @@ ], "properties": { "addr": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "at_height": { "type": [ @@ -84,7 +83,8 @@ } } } - } + }, + "additionalProperties": false }, { "description": "Shows all registered hooks. Returns HooksResponse.", @@ -96,12 +96,8 @@ "hooks": { "type": "object" } - } - } - ], - "definitions": { - "HumanAddr": { - "type": "string" + }, + "additionalProperties": false } - } + ] } diff --git a/contracts/cw4-group/src/contract.rs b/contracts/cw4-group/src/contract.rs index 42fd36706..232a4dd8d 100644 --- a/contracts/cw4-group/src/contract.rs +++ b/contracts/cw4-group/src/contract.rs @@ -1,10 +1,9 @@ #[cfg(not(feature = "library"))] use cosmwasm_std::entry_point; use cosmwasm_std::{ - attr, to_binary, Binary, CanonicalAddr, Deps, DepsMut, Env, HumanAddr, MessageInfo, Order, - Response, StdResult, + attr, to_binary, Addr, Binary, Deps, DepsMut, Env, MessageInfo, Order, Response, StdResult, }; -use cw0::maybe_canonical; +use cw0::maybe_addr; use cw2::set_contract_version; use cw4::{ Member, MemberChangedHookMsg, MemberDiff, MemberListResponse, MemberResponse, @@ -38,17 +37,20 @@ pub fn instantiate( // easily be imported in other contracts pub fn create( mut deps: DepsMut, - admin: Option, + admin: Option, members: Vec, height: u64, ) -> Result<(), ContractError> { - ADMIN.set(deps.branch(), admin)?; + let admin_addr = admin + .map(|admin| deps.api.addr_validate(&admin)) + .transpose()?; + ADMIN.set(deps.branch(), admin_addr)?; let mut total = 0u64; for member in members.into_iter() { total += member.weight; - let raw = deps.api.canonical_address(&member.addr)?; - MEMBERS.save(deps.storage, &raw, &member.weight, height)?; + let member_addr = deps.api.addr_validate(&member.addr)?; + MEMBERS.save(deps.storage, &member_addr, &member.weight, height)?; } TOTAL.save(deps.storage, &total)?; @@ -63,13 +65,22 @@ pub fn execute( info: MessageInfo, msg: ExecuteMsg, ) -> Result { + let api = deps.api; match msg { - ExecuteMsg::UpdateAdmin { admin } => Ok(ADMIN.execute_update_admin(deps, info, admin)?), + ExecuteMsg::UpdateAdmin { admin } => Ok(ADMIN.execute_update_admin( + deps, + info, + admin.map(|admin| api.addr_validate(&admin)).transpose()?, + )?), ExecuteMsg::UpdateMembers { add, remove } => { execute_update_members(deps, env, info, add, remove) } - ExecuteMsg::AddHook { addr } => Ok(HOOKS.execute_add_hook(&ADMIN, deps, info, addr)?), - ExecuteMsg::RemoveHook { addr } => Ok(HOOKS.execute_remove_hook(&ADMIN, deps, info, addr)?), + ExecuteMsg::AddHook { addr } => { + Ok(HOOKS.execute_add_hook(&ADMIN, deps, info, api.addr_validate(&addr)?)?) + } + ExecuteMsg::RemoveHook { addr } => { + Ok(HOOKS.execute_remove_hook(&ADMIN, deps, info, api.addr_validate(&addr)?)?) + } } } @@ -78,7 +89,7 @@ pub fn execute_update_members( env: Env, info: MessageInfo, add: Vec, - remove: Vec, + remove: Vec, ) -> Result { let attributes = vec![ attr("action", "update_members"), @@ -103,9 +114,9 @@ pub fn execute_update_members( pub fn update_members( deps: DepsMut, height: u64, - sender: HumanAddr, + sender: Addr, to_add: Vec, - to_remove: Vec, + to_remove: Vec, ) -> Result { ADMIN.assert_admin(deps.as_ref(), &sender)?; @@ -114,8 +125,8 @@ pub fn update_members( // add all new members and update total for add in to_add.into_iter() { - let raw = deps.api.canonical_address(&add.addr)?; - MEMBERS.update(deps.storage, &raw, height, |old| -> StdResult<_> { + let add_addr = deps.api.addr_validate(&add.addr)?; + MEMBERS.update(deps.storage, &add_addr, height, |old| -> StdResult<_> { total -= old.unwrap_or_default(); total += add.weight; diffs.push(MemberDiff::new(add.addr, old, Some(add.weight))); @@ -124,13 +135,13 @@ pub fn update_members( } for remove in to_remove.into_iter() { - let raw = deps.api.canonical_address(&remove)?; - let old = MEMBERS.may_load(deps.storage, &raw)?; + let remove_addr = deps.api.addr_validate(&remove)?; + let old = MEMBERS.may_load(deps.storage, &remove_addr)?; // Only process this if they were actually in the list before if let Some(weight) = old { diffs.push(MemberDiff::new(remove, Some(weight), None)); total -= weight; - MEMBERS.remove(deps.storage, &raw, height)?; + MEMBERS.remove(deps.storage, &remove_addr, height)?; } } @@ -159,11 +170,11 @@ fn query_total_weight(deps: Deps) -> StdResult { Ok(TotalWeightResponse { weight }) } -fn query_member(deps: Deps, addr: HumanAddr, height: Option) -> StdResult { - let raw = deps.api.canonical_address(&addr)?; +fn query_member(deps: Deps, addr: String, height: Option) -> StdResult { + let addr = deps.api.addr_validate(&addr)?; let weight = match height { - Some(h) => MEMBERS.may_load_at_height(deps.storage, &raw, h), - None => MEMBERS.may_load(deps.storage, &raw), + Some(h) => MEMBERS.may_load_at_height(deps.storage, &addr, h), + None => MEMBERS.may_load(deps.storage, &addr), }?; Ok(MemberResponse { weight }) } @@ -174,21 +185,20 @@ const DEFAULT_LIMIT: u32 = 10; fn list_members( deps: Deps, - start_after: Option, + start_after: Option, limit: Option, ) -> StdResult { let limit = limit.unwrap_or(DEFAULT_LIMIT).min(MAX_LIMIT) as usize; - let canon = maybe_canonical(deps.api, start_after)?; - let start = canon.map(Bound::exclusive); + let addr = maybe_addr(deps.api, start_after)?; + let start = addr.map(|addr| Bound::exclusive(addr.to_string())); - let api = &deps.api; let members: StdResult> = MEMBERS .range(deps.storage, start, None, Order::Ascending) .take(limit) .map(|item| { let (key, weight) = item?; Ok(Member { - addr: api.human_address(&CanonicalAddr::from(key))?, + addr: String::from_utf8(key)?, weight, }) }) @@ -235,7 +245,7 @@ mod tests { // it worked, let's query the state let res = ADMIN.query_admin(deps.as_ref()).unwrap(); - assert_eq!(Some(HumanAddr::from(INIT_ADMIN)), res.admin); + assert_eq!(Some(INIT_ADMIN.into()), res.admin); let res = query_total_weight(deps.as_ref()).unwrap(); assert_eq!(17, res.weight); @@ -309,7 +319,7 @@ mod tests { let err = update_members( deps.as_mut(), height + 5, - USER1.into(), + Addr::unchecked(USER1), add.clone(), remove.clone(), ) @@ -324,7 +334,14 @@ mod tests { assert_users(&deps, Some(11), Some(6), None, Some(height + 1)); // admin updates properly - update_members(deps.as_mut(), height + 10, INIT_ADMIN.into(), add, remove).unwrap(); + update_members( + deps.as_mut(), + height + 10, + Addr::unchecked(INIT_ADMIN), + add, + remove, + ) + .unwrap(); // updated properly assert_users(&deps, None, Some(6), Some(15), None); @@ -348,7 +365,14 @@ mod tests { // admin updates properly let height = mock_env().block.height; - update_members(deps.as_mut(), height, INIT_ADMIN.into(), add, remove).unwrap(); + update_members( + deps.as_mut(), + height, + Addr::unchecked(INIT_ADMIN), + add, + remove, + ) + .unwrap(); assert_users(&deps, Some(4), Some(6), None, None); } @@ -373,7 +397,14 @@ mod tests { // admin updates properly let height = mock_env().block.height; - update_members(deps.as_mut(), height, INIT_ADMIN.into(), add, remove).unwrap(); + update_members( + deps.as_mut(), + height, + Addr::unchecked(INIT_ADMIN), + add, + remove, + ) + .unwrap(); assert_users(&deps, None, Some(6), Some(5), None); } @@ -386,8 +417,8 @@ mod tests { let hooks = HOOKS.query_hooks(deps.as_ref()).unwrap(); assert!(hooks.hooks.is_empty()); - let contract1 = HumanAddr::from("hook1"); - let contract2 = HumanAddr::from("hook2"); + let contract1 = String::from("hook1"); + let contract2 = String::from("hook2"); let add_msg = ExecuteMsg::AddHook { addr: contract1.clone(), @@ -405,7 +436,7 @@ mod tests { assert_eq!(err, HookError::Admin(AdminError::NotAdmin {}).into()); // admin can add it, and it appears in the query - let admin_info = mock_info(INIT_ADMIN, &[]); + let admin_info = mock_info(INIT_ADMIN.as_ref(), &[]); let _ = execute( deps.as_mut(), mock_env(), @@ -480,11 +511,11 @@ mod tests { let hooks = HOOKS.query_hooks(deps.as_ref()).unwrap(); assert!(hooks.hooks.is_empty()); - let contract1 = HumanAddr::from("hook1"); - let contract2 = HumanAddr::from("hook2"); + let contract1 = String::from("hook1"); + let contract2 = String::from("hook2"); // register 2 hooks - let admin_info = mock_info(INIT_ADMIN, &[]); + let admin_info = mock_info(INIT_ADMIN.as_ref(), &[]); let add_msg = ExecuteMsg::AddHook { addr: contract1.clone(), }; @@ -541,14 +572,12 @@ mod tests { assert_eq!(17, total); // get member votes from raw key - let member2_canon = deps.api.canonical_address(&USER2.into()).unwrap(); - let member2_raw = deps.storage.get(&member_key(&member2_canon)).unwrap(); + let member2_raw = deps.storage.get(&member_key(USER2.as_ref())).unwrap(); let member2: u64 = from_slice(&member2_raw).unwrap(); assert_eq!(6, member2); // and execute misses - let member3_canon = deps.api.canonical_address(&USER3.into()).unwrap(); - let member3_raw = deps.storage.get(&member_key(&member3_canon)); + let member3_raw = deps.storage.get(&member_key(USER3.as_ref())); assert_eq!(None, member3_raw); } } diff --git a/contracts/cw4-group/src/helpers.rs b/contracts/cw4-group/src/helpers.rs index 1fe748e14..070b23503 100644 --- a/contracts/cw4-group/src/helpers.rs +++ b/contracts/cw4-group/src/helpers.rs @@ -2,12 +2,12 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use std::ops::Deref; -use cosmwasm_std::{to_binary, CosmosMsg, HumanAddr, StdResult, WasmMsg}; +use cosmwasm_std::{to_binary, Addr, CosmosMsg, StdResult, WasmMsg}; use cw4::{Cw4Contract, Member}; use crate::msg::ExecuteMsg; -/// Cw4GroupContract is a wrapper around HumanAddr that provides a lot of helpers +/// Cw4GroupContract is a wrapper around Cw4Contract that provides a lot of helpers /// for working with cw4-group contracts. /// /// It extends Cw4Contract to add the extra calls from cw4-group. @@ -23,20 +23,20 @@ impl Deref for Cw4GroupContract { } impl Cw4GroupContract { - pub fn new(addr: HumanAddr) -> Self { + pub fn new(addr: Addr) -> Self { Cw4GroupContract(Cw4Contract(addr)) } fn encode_msg(&self, msg: ExecuteMsg) -> StdResult { Ok(WasmMsg::Execute { - contract_addr: self.addr(), + contract_addr: self.addr().into(), msg: to_binary(&msg)?, send: vec![], } .into()) } - pub fn update_members(&self, remove: Vec, add: Vec) -> StdResult { + pub fn update_members(&self, remove: Vec, add: Vec) -> StdResult { let msg = ExecuteMsg::UpdateMembers { remove, add }; self.encode_msg(msg) } diff --git a/contracts/cw4-group/src/msg.rs b/contracts/cw4-group/src/msg.rs index e77e428ac..e1759ac54 100644 --- a/contracts/cw4-group/src/msg.rs +++ b/contracts/cw4-group/src/msg.rs @@ -1,7 +1,6 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -use cosmwasm_std::HumanAddr; use cw4::Member; #[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] @@ -9,7 +8,7 @@ use cw4::Member; pub struct InstantiateMsg { /// The admin is the only account that can update the group state. /// Omit it to make the group immutable. - pub admin: Option, + pub admin: Option, pub members: Vec, } @@ -17,17 +16,17 @@ pub struct InstantiateMsg { #[serde(rename_all = "snake_case")] pub enum ExecuteMsg { /// Change the admin - UpdateAdmin { admin: Option }, + UpdateAdmin { admin: Option }, /// apply a diff to the existing members. /// remove is applied after add, so if an address is in both, it is removed UpdateMembers { - remove: Vec, + remove: Vec, add: Vec, }, /// Add a new hook to be informed of all membership changes. Must be called by Admin - AddHook { addr: HumanAddr }, + AddHook { addr: String }, /// Remove a hook. Must be called by Admin - RemoveHook { addr: HumanAddr }, + RemoveHook { addr: String }, } #[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] @@ -39,12 +38,12 @@ pub enum QueryMsg { TotalWeight {}, /// Returns MembersListResponse ListMembers { - start_after: Option, + start_after: Option, limit: Option, }, /// Returns MemberResponse Member { - addr: HumanAddr, + addr: String, at_height: Option, }, /// Shows all registered hooks. Returns HooksResponse. diff --git a/contracts/cw4-group/src/state.rs b/contracts/cw4-group/src/state.rs index f6b12d7d3..1b5003c98 100644 --- a/contracts/cw4-group/src/state.rs +++ b/contracts/cw4-group/src/state.rs @@ -1,3 +1,4 @@ +use cosmwasm_std::Addr; use cw4::TOTAL_KEY; use cw_controllers::{Admin, Hooks}; use cw_storage_plus::{Item, SnapshotMap, Strategy}; @@ -7,7 +8,7 @@ pub const HOOKS: Hooks = Hooks::new("cw4-hooks"); pub const TOTAL: Item = Item::new(TOTAL_KEY); -pub const MEMBERS: SnapshotMap<&[u8], u64> = SnapshotMap::new( +pub const MEMBERS: SnapshotMap<&Addr, u64> = SnapshotMap::new( cw4::MEMBERS_KEY, cw4::MEMBERS_CHECKPOINTS, cw4::MEMBERS_CHANGELOG, diff --git a/contracts/cw4-stake/Cargo.toml b/contracts/cw4-stake/Cargo.toml index 1f3387a36..434c9e413 100644 --- a/contracts/cw4-stake/Cargo.toml +++ b/contracts/cw4-stake/Cargo.toml @@ -32,10 +32,10 @@ cw4 = { path = "../../packages/cw4", version = "0.6.0-alpha3" } cw20 = { path = "../../packages/cw20", version = "0.6.0-alpha3" } cw-controllers = { path = "../../packages/controllers", version = "0.6.0-alpha3" } cw-storage-plus = { path = "../../packages/storage-plus", version = "0.6.0-alpha3", features = ["iterator"] } -cosmwasm-std = { version = "0.14.0-beta1" } -schemars = "0.7" +cosmwasm-std = { version = "0.14.0-beta2" } +schemars = "0.8.1" serde = { version = "1.0.103", default-features = false, features = ["derive"] } thiserror = { version = "1.0.21" } [dev-dependencies] -cosmwasm-schema = { version = "0.14.0-beta1" } +cosmwasm-schema = { version = "0.14.0-beta2" } diff --git a/contracts/cw4-stake/schema/admin_response.json b/contracts/cw4-stake/schema/admin_response.json index 71edb382e..82bf62a3a 100644 --- a/contracts/cw4-stake/schema/admin_response.json +++ b/contracts/cw4-stake/schema/admin_response.json @@ -4,19 +4,10 @@ "type": "object", "properties": { "admin": { - "anyOf": [ - { - "$ref": "#/definitions/HumanAddr" - }, - { - "type": "null" - } + "type": [ + "string", + "null" ] } - }, - "definitions": { - "HumanAddr": { - "type": "string" - } } } diff --git a/contracts/cw4-stake/schema/claims_response.json b/contracts/cw4-stake/schema/claims_response.json index efadc9a12..13e15aa51 100644 --- a/contracts/cw4-stake/schema/claims_response.json +++ b/contracts/cw4-stake/schema/claims_response.json @@ -44,7 +44,8 @@ "format": "uint64", "minimum": 0.0 } - } + }, + "additionalProperties": false }, { "description": "AtTime will expire when `env.block.time` >= time", @@ -58,7 +59,8 @@ "format": "uint64", "minimum": 0.0 } - } + }, + "additionalProperties": false }, { "description": "Never will never expire. Used to express the empty variant", @@ -70,7 +72,8 @@ "never": { "type": "object" } - } + }, + "additionalProperties": false } ] }, diff --git a/contracts/cw4-stake/schema/execute_msg.json b/contracts/cw4-stake/schema/execute_msg.json index 3c5c6f766..98d45a984 100644 --- a/contracts/cw4-stake/schema/execute_msg.json +++ b/contracts/cw4-stake/schema/execute_msg.json @@ -12,7 +12,8 @@ "bond": { "type": "object" } - } + }, + "additionalProperties": false }, { "description": "Unbond will start the unbonding process for the given number of tokens. The sender immediately loses weight from these tokens, and can claim them back to his wallet after `unbonding_period`", @@ -32,7 +33,8 @@ } } } - } + }, + "additionalProperties": false }, { "description": "Claim is used to claim your native tokens that you previously \"unbonded\" after the contract-defined waiting period (eg. 1 week)", @@ -44,7 +46,8 @@ "claim": { "type": "object" } - } + }, + "additionalProperties": false }, { "description": "Change the admin", @@ -57,18 +60,15 @@ "type": "object", "properties": { "admin": { - "anyOf": [ - { - "$ref": "#/definitions/HumanAddr" - }, - { - "type": "null" - } + "type": [ + "string", + "null" ] } } } - } + }, + "additionalProperties": false }, { "description": "Add a new hook to be informed of all membership changes. Must be called by Admin", @@ -84,11 +84,12 @@ ], "properties": { "addr": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "Remove a hook. Must be called by Admin", @@ -104,17 +105,15 @@ ], "properties": { "addr": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false } ], "definitions": { - "HumanAddr": { - "type": "string" - }, "Uint128": { "type": "string" } diff --git a/contracts/cw4-stake/schema/instantiate_msg.json b/contracts/cw4-stake/schema/instantiate_msg.json index c33fc46b2..2fb074dc1 100644 --- a/contracts/cw4-stake/schema/instantiate_msg.json +++ b/contracts/cw4-stake/schema/instantiate_msg.json @@ -10,13 +10,9 @@ ], "properties": { "admin": { - "anyOf": [ - { - "$ref": "#/definitions/HumanAddr" - }, - { - "type": "null" - } + "type": [ + "string", + "null" ] }, "denom": { @@ -38,13 +34,10 @@ } }, "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", + "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" }, - "CanonicalAddr": { - "$ref": "#/definitions/Binary" - }, "Denom": { "anyOf": [ { @@ -56,7 +49,8 @@ "native": { "type": "string" } - } + }, + "additionalProperties": false }, { "type": "object", @@ -65,9 +59,10 @@ ], "properties": { "cw20": { - "$ref": "#/definitions/CanonicalAddr" + "$ref": "#/definitions/Addr" } - } + }, + "additionalProperties": false } ] }, @@ -85,7 +80,8 @@ "format": "uint64", "minimum": 0.0 } - } + }, + "additionalProperties": false }, { "type": "object", @@ -98,13 +94,11 @@ "format": "uint64", "minimum": 0.0 } - } + }, + "additionalProperties": false } ] }, - "HumanAddr": { - "type": "string" - }, "Uint128": { "type": "string" } diff --git a/contracts/cw4-stake/schema/member_list_response.json b/contracts/cw4-stake/schema/member_list_response.json index cad6cf104..ae09f9bba 100644 --- a/contracts/cw4-stake/schema/member_list_response.json +++ b/contracts/cw4-stake/schema/member_list_response.json @@ -14,9 +14,6 @@ } }, "definitions": { - "HumanAddr": { - "type": "string" - }, "Member": { "description": "A group member has a weight associated with them. This may all be equal, or may have meaning in the app that makes use of the group (eg. voting power)", "type": "object", @@ -26,7 +23,7 @@ ], "properties": { "addr": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "weight": { "type": "integer", diff --git a/contracts/cw4-stake/schema/query_msg.json b/contracts/cw4-stake/schema/query_msg.json index 1a607ec4b..a72a836d8 100644 --- a/contracts/cw4-stake/schema/query_msg.json +++ b/contracts/cw4-stake/schema/query_msg.json @@ -16,11 +16,12 @@ ], "properties": { "address": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false }, { "type": "object", @@ -35,11 +36,12 @@ ], "properties": { "address": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "Return AdminResponse", @@ -51,7 +53,8 @@ "admin": { "type": "object" } - } + }, + "additionalProperties": false }, { "description": "Return TotalWeightResponse", @@ -63,7 +66,8 @@ "total_weight": { "type": "object" } - } + }, + "additionalProperties": false }, { "description": "Returns MembersListResponse", @@ -84,18 +88,15 @@ "minimum": 0.0 }, "start_after": { - "anyOf": [ - { - "$ref": "#/definitions/HumanAddr" - }, - { - "type": "null" - } + "type": [ + "string", + "null" ] } } } - } + }, + "additionalProperties": false }, { "description": "Returns MemberResponse", @@ -111,7 +112,7 @@ ], "properties": { "addr": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "at_height": { "type": [ @@ -123,7 +124,8 @@ } } } - } + }, + "additionalProperties": false }, { "description": "Shows all registered hooks. Returns HooksResponse.", @@ -135,12 +137,8 @@ "hooks": { "type": "object" } - } - } - ], - "definitions": { - "HumanAddr": { - "type": "string" + }, + "additionalProperties": false } - } + ] } diff --git a/contracts/cw4-stake/src/contract.rs b/contracts/cw4-stake/src/contract.rs index deb39dd89..3047d9c5b 100644 --- a/contracts/cw4-stake/src/contract.rs +++ b/contracts/cw4-stake/src/contract.rs @@ -1,11 +1,11 @@ #[cfg(not(feature = "library"))] use cosmwasm_std::entry_point; use cosmwasm_std::{ - attr, coin, coins, to_binary, BankMsg, Binary, CanonicalAddr, Coin, CosmosMsg, Deps, DepsMut, - Env, HumanAddr, MessageInfo, Order, Response, StdError, StdResult, Storage, Uint128, + attr, coin, coins, to_binary, Addr, BankMsg, Binary, Coin, CosmosMsg, Deps, DepsMut, Env, + MessageInfo, Order, Response, StdError, StdResult, Storage, Uint128, }; -use cw0::{maybe_canonical, NativeBalance}; +use cw0::{maybe_addr, NativeBalance}; use cw2::set_contract_version; use cw20::{Balance, Denom}; use cw4::{ @@ -32,7 +32,8 @@ pub fn instantiate( msg: InstantiateMsg, ) -> Result { set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; - ADMIN.set(deps.branch(), msg.admin)?; + let api = deps.api; + ADMIN.set(deps.branch(), maybe_addr(api, msg.admin)?)?; // min_bond is at least 1, so 0 stake -> non-membership let min_bond = match msg.min_bond { @@ -60,10 +61,17 @@ pub fn execute( info: MessageInfo, msg: ExecuteMsg, ) -> Result { + let api = deps.api; match msg { - ExecuteMsg::UpdateAdmin { admin } => Ok(ADMIN.execute_update_admin(deps, info, admin)?), - ExecuteMsg::AddHook { addr } => Ok(HOOKS.execute_add_hook(&ADMIN, deps, info, addr)?), - ExecuteMsg::RemoveHook { addr } => Ok(HOOKS.execute_remove_hook(&ADMIN, deps, info, addr)?), + ExecuteMsg::UpdateAdmin { admin } => { + Ok(ADMIN.execute_update_admin(deps, info, maybe_addr(api, admin)?)?) + } + ExecuteMsg::AddHook { addr } => { + Ok(HOOKS.execute_add_hook(&ADMIN, deps, info, api.addr_validate(&addr)?)?) + } + ExecuteMsg::RemoveHook { addr } => { + Ok(HOOKS.execute_remove_hook(&ADMIN, deps, info, api.addr_validate(&addr)?)?) + } ExecuteMsg::Bond {} => execute_bond(deps, env, Balance::from(info.funds), info.sender), ExecuteMsg::Unbond { tokens: amount } => execute_unbond(deps, env, info, amount), ExecuteMsg::Claim {} => execute_claim(deps, env, info), @@ -74,7 +82,7 @@ pub fn execute_bond( deps: DepsMut, env: Env, amount: Balance, - sender: HumanAddr, + sender: Addr, ) -> Result { let cfg = CONFIG.load(deps.storage)?; @@ -87,7 +95,7 @@ pub fn execute_bond( if want == &have.address { Ok(have.amount) } else { - Err(ContractError::InvalidDenom(deps.api.human_address(&want)?)) + Err(ContractError::InvalidDenom(want.into())) } } _ => Err(ContractError::MixedNativeAndCw20( @@ -96,15 +104,13 @@ pub fn execute_bond( }?; // update the sender's stake - let sender_raw = deps.api.canonical_address(&sender)?; - let new_stake = STAKE.update(deps.storage, &sender_raw, |stake| -> StdResult<_> { + let new_stake = STAKE.update(deps.storage, &sender, |stake| -> StdResult<_> { Ok(stake.unwrap_or_default() + amount) })?; let messages = update_membership( deps.storage, sender.clone(), - &sender_raw, new_stake, &cfg, env.block.height, @@ -130,16 +136,15 @@ pub fn execute_unbond( amount: Uint128, ) -> Result { // reduce the sender's stake - aborting if insufficient - let sender_raw = deps.api.canonical_address(&info.sender)?; - let new_stake = STAKE.update(deps.storage, &sender_raw, |stake| -> StdResult<_> { - stake.unwrap_or_default() - amount + let new_stake = STAKE.update(deps.storage, &info.sender, |stake| -> StdResult<_> { + Ok(stake.unwrap_or_default().checked_sub(amount)?) })?; // provide them a claim let cfg = CONFIG.load(deps.storage)?; CLAIMS.create_claim( deps.storage, - &sender_raw, + &info.sender, amount, cfg.unbonding_period.after(&env.block), )?; @@ -147,7 +152,6 @@ pub fn execute_unbond( let messages = update_membership( deps.storage, info.sender.clone(), - &sender_raw, new_stake, &cfg, env.block.height, @@ -184,15 +188,14 @@ pub fn must_pay_funds(balance: &NativeBalance, denom: &str) -> Result StdResult> { // update their membership weight let new = calc_weight(new_stake, cfg); - let old = MEMBERS.may_load(storage, sender_raw)?; + let old = MEMBERS.may_load(storage, &sender)?; // short-circuit if no change if new == old { @@ -200,8 +203,8 @@ fn update_membership( } // otherwise, record change of weight match new.as_ref() { - Some(w) => MEMBERS.save(storage, sender_raw, w, height), - None => MEMBERS.remove(storage, sender_raw, height), + Some(w) => MEMBERS.save(storage, &sender, w, height), + None => MEMBERS.remove(storage, &sender, height), }?; // update total @@ -230,8 +233,7 @@ pub fn execute_claim( env: Env, info: MessageInfo, ) -> Result { - let sender_raw = deps.api.canonical_address(&info.sender)?; - let release = CLAIMS.claim_tokens(deps.storage, &sender_raw, &env.block, None)?; + let release = CLAIMS.claim_tokens(deps.storage, &info.sender, &env.block, None)?; if release.is_zero() { return Err(ContractError::NothingToClaim {}); } @@ -247,7 +249,7 @@ pub fn execute_claim( let amount_str = coins_to_string(&amount); let messages = vec![BankMsg::Send { - to_address: info.sender.clone(), + to_address: info.sender.clone().into(), amount, } .into()]; @@ -285,7 +287,9 @@ pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult { to_binary(&list_members(deps, start_after, limit)?) } QueryMsg::TotalWeight {} => to_binary(&query_total_weight(deps)?), - QueryMsg::Claims { address } => to_binary(&CLAIMS.query_claims(deps, address)?), + QueryMsg::Claims { address } => { + to_binary(&CLAIMS.query_claims(deps, &deps.api.addr_validate(&address)?)?) + } QueryMsg::Staked { address } => to_binary(&query_staked(deps, address)?), QueryMsg::Admin {} => to_binary(&ADMIN.query_admin(deps)?), QueryMsg::Hooks {} => to_binary(&HOOKS.query_hooks(deps)?), @@ -297,11 +301,9 @@ fn query_total_weight(deps: Deps) -> StdResult { Ok(TotalWeightResponse { weight }) } -pub fn query_staked(deps: Deps, address: HumanAddr) -> StdResult { - let address_raw = deps.api.canonical_address(&address)?; - let stake = STAKE - .may_load(deps.storage, &address_raw)? - .unwrap_or_default(); +pub fn query_staked(deps: Deps, addr: String) -> StdResult { + let addr = deps.api.addr_validate(&addr)?; + let stake = STAKE.may_load(deps.storage, &addr)?.unwrap_or_default(); let denom = match CONFIG.load(deps.storage)?.denom { Denom::Native(want) => want, _ => { @@ -315,11 +317,11 @@ pub fn query_staked(deps: Deps, address: HumanAddr) -> StdResult }) } -fn query_member(deps: Deps, addr: HumanAddr, height: Option) -> StdResult { - let raw = deps.api.canonical_address(&addr)?; +fn query_member(deps: Deps, addr: String, height: Option) -> StdResult { + let addr = deps.api.addr_validate(&addr)?; let weight = match height { - Some(h) => MEMBERS.may_load_at_height(deps.storage, &raw, h), - None => MEMBERS.may_load(deps.storage, &raw), + Some(h) => MEMBERS.may_load_at_height(deps.storage, &addr, h), + None => MEMBERS.may_load(deps.storage, &addr), }?; Ok(MemberResponse { weight }) } @@ -330,21 +332,20 @@ const DEFAULT_LIMIT: u32 = 10; fn list_members( deps: Deps, - start_after: Option, + start_after: Option, limit: Option, ) -> StdResult { let limit = limit.unwrap_or(DEFAULT_LIMIT).min(MAX_LIMIT) as usize; - let canon = maybe_canonical(deps.api, start_after)?; - let start = canon.map(Bound::exclusive); + let addr = maybe_addr(deps.api, start_after)?; + let start = addr.map(|addr| Bound::exclusive(addr.as_ref())); - let api = &deps.api; let members: StdResult> = MEMBERS .range(deps.storage, start, None, Order::Ascending) .take(limit) .map(|item| { let (key, weight) = item?; Ok(Member { - addr: api.human_address(&CanonicalAddr::from(key))?, + addr: String::from_utf8(key)?, weight, }) }) @@ -356,7 +357,7 @@ fn list_members( #[cfg(test)] mod tests { use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info}; - use cosmwasm_std::{from_slice, Api, StdError, Storage}; + use cosmwasm_std::{from_slice, OverflowError, OverflowOperation, StdError, Storage}; use cw0::Duration; use cw20::Denom; use cw4::{member_key, TOTAL_KEY}; @@ -408,7 +409,7 @@ mod tests { for (addr, stake) in &[(USER1, user1), (USER2, user2), (USER3, user3)] { if *stake != 0 { let msg = ExecuteMsg::Bond {}; - let info = mock_info(HumanAddr::from(*addr), &coins(*stake, DENOM)); + let info = mock_info(addr, &coins(*stake, DENOM)); execute(deps.branch(), env.clone(), info, msg).unwrap(); } } @@ -423,7 +424,7 @@ mod tests { let msg = ExecuteMsg::Unbond { tokens: Uint128(*stake), }; - let info = mock_info(HumanAddr::from(*addr), &[]); + let info = mock_info(addr, &[]); execute(deps.branch(), env.clone(), info, msg).unwrap(); } } @@ -436,13 +437,13 @@ mod tests { // it worked, let's query the state let res = ADMIN.query_admin(deps.as_ref()).unwrap(); - assert_eq!(Some(HumanAddr::from(INIT_ADMIN)), res.admin); + assert_eq!(Some(INIT_ADMIN.into()), res.admin); let res = query_total_weight(deps.as_ref()).unwrap(); assert_eq!(0, res.weight); } - fn get_member(deps: Deps, addr: HumanAddr, at_height: Option) -> Option { + fn get_member(deps: Deps, addr: String, at_height: Option) -> Option { let raw = query(deps, mock_env(), QueryMsg::Member { addr, at_height }).unwrap(); let res: MemberResponse = from_slice(&raw).unwrap(); res.weight @@ -563,7 +564,14 @@ mod tests { env.block.height += 5; let info = mock_info(USER2, &[]); let err = execute(deps.as_mut(), env, info, msg).unwrap_err(); - assert_eq!(err, ContractError::Std(StdError::underflow(5000, 5100))); + assert_eq!( + err, + ContractError::Std(StdError::overflow(OverflowError::new( + OverflowOperation::Sub, + 5000, + 5100 + ))) + ); } #[test] @@ -580,19 +588,17 @@ mod tests { assert_eq!(17, total); // get member votes from raw key - let member2_canon = deps.api.canonical_address(&USER2.into()).unwrap(); - let member2_raw = deps.storage.get(&member_key(&member2_canon)).unwrap(); + let member2_raw = deps.storage.get(&member_key(USER2.as_ref())).unwrap(); let member2: u64 = from_slice(&member2_raw).unwrap(); assert_eq!(6, member2); // and execute misses - let member3_canon = deps.api.canonical_address(&USER3.into()).unwrap(); - let member3_raw = deps.storage.get(&member_key(&member3_canon)); + let member3_raw = deps.storage.get(&member_key(USER3.as_ref())); assert_eq!(None, member3_raw); } - fn get_claims>(deps: Deps, addr: U) -> Vec { - CLAIMS.query_claims(deps, addr.into()).unwrap().claims + fn get_claims(deps: Deps, addr: &Addr) -> Vec { + CLAIMS.query_claims(deps, addr).unwrap().claims } #[test] @@ -609,14 +615,14 @@ mod tests { // check the claims for each user let expires = Duration::Height(UNBONDING_BLOCKS).after(&env.block); assert_eq!( - get_claims(deps.as_ref(), USER1), + get_claims(deps.as_ref(), &Addr::unchecked(USER1)), vec![Claim::new(4_500, expires)] ); assert_eq!( - get_claims(deps.as_ref(), USER2), + get_claims(deps.as_ref(), &Addr::unchecked(USER2)), vec![Claim::new(2_600, expires)] ); - assert_eq!(get_claims(deps.as_ref(), USER3), vec![]); + assert_eq!(get_claims(deps.as_ref(), &Addr::unchecked(USER3)), vec![]); // do another unbond later on let mut env2 = mock_env(); @@ -626,15 +632,15 @@ mod tests { // with updated claims let expires2 = Duration::Height(UNBONDING_BLOCKS).after(&env2.block); assert_eq!( - get_claims(deps.as_ref(), USER1), + get_claims(deps.as_ref(), &Addr::unchecked(USER1)), vec![Claim::new(4_500, expires)] ); assert_eq!( - get_claims(deps.as_ref(), USER2), + get_claims(deps.as_ref(), &Addr::unchecked(USER2)), vec![Claim::new(2_600, expires), Claim::new(1_345, expires2)] ); assert_eq!( - get_claims(deps.as_ref(), USER3), + get_claims(deps.as_ref(), &Addr::unchecked(USER3)), vec![Claim::new(1_500, expires2)] ); @@ -696,13 +702,13 @@ mod tests { assert_eq!(err, ContractError::NothingToClaim {}); // claims updated properly - assert_eq!(get_claims(deps.as_ref(), USER1), vec![]); + assert_eq!(get_claims(deps.as_ref(), &Addr::unchecked(USER1)), vec![]); assert_eq!( - get_claims(deps.as_ref(), USER2), + get_claims(deps.as_ref(), &Addr::unchecked(USER2)), vec![Claim::new(1_345, expires2)] ); assert_eq!( - get_claims(deps.as_ref(), USER3), + get_claims(deps.as_ref(), &Addr::unchecked(USER3)), vec![Claim::new(1_500, expires2)] ); @@ -729,7 +735,7 @@ mod tests { } .into()] ); - assert_eq!(get_claims(deps.as_ref(), USER2), vec![]); + assert_eq!(get_claims(deps.as_ref(), &Addr::unchecked(USER2)), vec![]); } #[test] @@ -741,8 +747,8 @@ mod tests { let hooks = HOOKS.query_hooks(deps.as_ref()).unwrap(); assert!(hooks.hooks.is_empty()); - let contract1 = HumanAddr::from("hook1"); - let contract2 = HumanAddr::from("hook2"); + let contract1 = String::from("hook1"); + let contract2 = String::from("hook2"); let add_msg = ExecuteMsg::AddHook { addr: contract1.clone(), @@ -835,8 +841,8 @@ mod tests { let hooks = HOOKS.query_hooks(deps.as_ref()).unwrap(); assert!(hooks.hooks.is_empty()); - let contract1 = HumanAddr::from("hook1"); - let contract2 = HumanAddr::from("hook2"); + let contract1 = String::from("hook1"); + let contract2 = String::from("hook2"); // register 2 hooks let admin_info = mock_info(INIT_ADMIN, &[]); @@ -887,26 +893,23 @@ mod tests { default_instantiate(deps.as_mut()); // cannot bond with 0 coins - let info = mock_info(HumanAddr::from(USER1), &[]); + let info = mock_info(USER1, &[]); let err = execute(deps.as_mut(), mock_env(), info, ExecuteMsg::Bond {}).unwrap_err(); assert_eq!(err, ContractError::NoFunds {}); // cannot bond with incorrect denom - let info = mock_info(HumanAddr::from(USER1), &[coin(500, "FOO")]); + let info = mock_info(USER1, &[coin(500, "FOO")]); let err = execute(deps.as_mut(), mock_env(), info, ExecuteMsg::Bond {}).unwrap_err(); assert_eq!(err, ContractError::MissingDenom(DENOM.to_string())); // cannot bond with 2 coins (even if one is correct) - let info = mock_info( - HumanAddr::from(USER1), - &[coin(1234, DENOM), coin(5000, "BAR")], - ); + let info = mock_info(USER1, &[coin(1234, DENOM), coin(5000, "BAR")]); let err = execute(deps.as_mut(), mock_env(), info, ExecuteMsg::Bond {}).unwrap_err(); assert_eq!(err, ContractError::ExtraDenoms(DENOM.to_string())); // can bond with just the proper denom // cannot bond with incorrect denom - let info = mock_info(HumanAddr::from(USER1), &[coin(500, DENOM)]); + let info = mock_info(USER1, &[coin(500, DENOM)]); execute(deps.as_mut(), mock_env(), info, ExecuteMsg::Bond {}).unwrap(); } diff --git a/contracts/cw4-stake/src/error.rs b/contracts/cw4-stake/src/error.rs index 7f502f61a..ae2fe970a 100644 --- a/contracts/cw4-stake/src/error.rs +++ b/contracts/cw4-stake/src/error.rs @@ -1,4 +1,4 @@ -use cosmwasm_std::{HumanAddr, StdError}; +use cosmwasm_std::StdError; use thiserror::Error; use cw_controllers::{AdminError, HookError}; @@ -27,7 +27,7 @@ pub enum ContractError { ExtraDenoms(String), #[error("Must send valid address to stake")] - InvalidDenom(HumanAddr), + InvalidDenom(String), #[error("Missed address or denom")] MixedNativeAndCw20(String), diff --git a/contracts/cw4-stake/src/msg.rs b/contracts/cw4-stake/src/msg.rs index 17bd73685..eacb14a70 100644 --- a/contracts/cw4-stake/src/msg.rs +++ b/contracts/cw4-stake/src/msg.rs @@ -1,4 +1,4 @@ -use cosmwasm_std::{Coin, HumanAddr, Uint128}; +use cosmwasm_std::{Coin, Uint128}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; @@ -15,7 +15,7 @@ pub struct InstantiateMsg { pub unbonding_period: Duration, // admin can only add/remove hooks, not change other parameters - pub admin: Option, + pub admin: Option, } #[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] @@ -32,11 +32,11 @@ pub enum ExecuteMsg { Claim {}, /// Change the admin - UpdateAdmin { admin: Option }, + UpdateAdmin { admin: Option }, /// Add a new hook to be informed of all membership changes. Must be called by Admin - AddHook { addr: HumanAddr }, + AddHook { addr: String }, /// Remove a hook. Must be called by Admin - RemoveHook { addr: HumanAddr }, + RemoveHook { addr: String }, } #[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] @@ -44,11 +44,11 @@ pub enum ExecuteMsg { pub enum QueryMsg { /// Claims shows the tokens in process of unbonding for this address Claims { - address: HumanAddr, + address: String, }, // Show the number of tokens currently staked by this address. Staked { - address: HumanAddr, + address: String, }, /// Return AdminResponse @@ -57,12 +57,12 @@ pub enum QueryMsg { TotalWeight {}, /// Returns MembersListResponse ListMembers { - start_after: Option, + start_after: Option, limit: Option, }, /// Returns MemberResponse Member { - addr: HumanAddr, + addr: String, at_height: Option, }, /// Shows all registered hooks. Returns HooksResponse. diff --git a/contracts/cw4-stake/src/state.rs b/contracts/cw4-stake/src/state.rs index 4cafade4e..224c52aae 100644 --- a/contracts/cw4-stake/src/state.rs +++ b/contracts/cw4-stake/src/state.rs @@ -1,7 +1,7 @@ -use cosmwasm_std::Uint128; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; +use cosmwasm_std::{Addr, Uint128}; use cw0::Duration; use cw20::Denom; use cw4::TOTAL_KEY; @@ -24,11 +24,11 @@ pub const HOOKS: Hooks = Hooks::new("cw4-hooks"); pub const CONFIG: Item = Item::new("config"); pub const TOTAL: Item = Item::new(TOTAL_KEY); -pub const MEMBERS: SnapshotMap<&[u8], u64> = SnapshotMap::new( +pub const MEMBERS: SnapshotMap<&Addr, u64> = SnapshotMap::new( cw4::MEMBERS_KEY, cw4::MEMBERS_CHECKPOINTS, cw4::MEMBERS_CHANGELOG, Strategy::EveryBlock, ); -pub const STAKE: Map<&[u8], Uint128> = Map::new("stake"); +pub const STAKE: Map<&Addr, Uint128> = Map::new("stake"); diff --git a/contracts/cw721-base/Cargo.toml b/contracts/cw721-base/Cargo.toml index 66c402ed0..7f539abbc 100644 --- a/contracts/cw721-base/Cargo.toml +++ b/contracts/cw721-base/Cargo.toml @@ -29,10 +29,10 @@ cw0 = { path = "../../packages/cw0", version = "0.6.0-alpha3" } cw2 = { path = "../../packages/cw2", version = "0.6.0-alpha3" } cw721 = { path = "../../packages/cw721", version = "0.6.0-alpha3" } cw-storage-plus = { path = "../../packages/storage-plus", version = "0.6.0-alpha3" , features = ["iterator"]} -cosmwasm-std = { version = "0.14.0-beta1" } -schemars = "0.7" +cosmwasm-std = { version = "0.14.0-beta2" } +schemars = "0.8.1" serde = { version = "1.0.103", default-features = false, features = ["derive"] } thiserror = { version = "1.0.20" } [dev-dependencies] -cosmwasm-schema = { version = "0.14.0-beta1" } +cosmwasm-schema = { version = "0.14.0-beta2" } diff --git a/contracts/cw721-base/schema/all_nft_info_response.json b/contracts/cw721-base/schema/all_nft_info_response.json index 1a3214ed1..317248590 100644 --- a/contracts/cw721-base/schema/all_nft_info_response.json +++ b/contracts/cw721-base/schema/all_nft_info_response.json @@ -42,11 +42,7 @@ }, "spender": { "description": "Account that can transfer/send the token", - "allOf": [ - { - "$ref": "#/definitions/HumanAddr" - } - ] + "type": "string" } } }, @@ -65,7 +61,8 @@ "format": "uint64", "minimum": 0.0 } - } + }, + "additionalProperties": false }, { "description": "AtTime will expire when `env.block.time` >= time", @@ -79,7 +76,8 @@ "format": "uint64", "minimum": 0.0 } - } + }, + "additionalProperties": false }, { "description": "Never will never expire. Used to express the empty variant", @@ -91,13 +89,11 @@ "never": { "type": "object" } - } + }, + "additionalProperties": false } ] }, - "HumanAddr": { - "type": "string" - }, "NftInfoResponse": { "type": "object", "required": [ @@ -138,11 +134,7 @@ }, "owner": { "description": "Owner of the token", - "allOf": [ - { - "$ref": "#/definitions/HumanAddr" - } - ] + "type": "string" } } } diff --git a/contracts/cw721-base/schema/approved_for_all_response.json b/contracts/cw721-base/schema/approved_for_all_response.json index 5b013ee49..ce7407ba5 100644 --- a/contracts/cw721-base/schema/approved_for_all_response.json +++ b/contracts/cw721-base/schema/approved_for_all_response.json @@ -31,11 +31,7 @@ }, "spender": { "description": "Account that can transfer/send the token", - "allOf": [ - { - "$ref": "#/definitions/HumanAddr" - } - ] + "type": "string" } } }, @@ -54,7 +50,8 @@ "format": "uint64", "minimum": 0.0 } - } + }, + "additionalProperties": false }, { "description": "AtTime will expire when `env.block.time` >= time", @@ -68,7 +65,8 @@ "format": "uint64", "minimum": 0.0 } - } + }, + "additionalProperties": false }, { "description": "Never will never expire. Used to express the empty variant", @@ -80,12 +78,10 @@ "never": { "type": "object" } - } + }, + "additionalProperties": false } ] - }, - "HumanAddr": { - "type": "string" } } } diff --git a/contracts/cw721-base/schema/execute_msg.json b/contracts/cw721-base/schema/execute_msg.json index 84046f3c0..1dd658d3a 100644 --- a/contracts/cw721-base/schema/execute_msg.json +++ b/contracts/cw721-base/schema/execute_msg.json @@ -18,14 +18,15 @@ ], "properties": { "recipient": { - "$ref": "#/definitions/HumanAddr" + "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.", @@ -42,7 +43,7 @@ ], "properties": { "contract": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "msg": { "anyOf": [ @@ -59,7 +60,8 @@ } } } - } + }, + "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", @@ -86,14 +88,15 @@ ] }, "spender": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "token_id": { "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "Remove previously granted Approval", @@ -110,14 +113,15 @@ ], "properties": { "spender": { - "$ref": "#/definitions/HumanAddr" + "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", @@ -143,11 +147,12 @@ ] }, "operator": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "Remove previously granted ApproveAll permission", @@ -163,11 +168,12 @@ ], "properties": { "operator": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "Mint a new NFT, can only be called by the contract minter", @@ -179,7 +185,8 @@ "mint": { "$ref": "#/definitions/MintMsg" } - } + }, + "additionalProperties": false } ], "definitions": { @@ -202,7 +209,8 @@ "format": "uint64", "minimum": 0.0 } - } + }, + "additionalProperties": false }, { "description": "AtTime will expire when `env.block.time` >= time", @@ -216,7 +224,8 @@ "format": "uint64", "minimum": 0.0 } - } + }, + "additionalProperties": false }, { "description": "Never will never expire. Used to express the empty variant", @@ -228,13 +237,11 @@ "never": { "type": "object" } - } + }, + "additionalProperties": false } ] }, - "HumanAddr": { - "type": "string" - }, "MintMsg": { "type": "object", "required": [ @@ -263,11 +270,7 @@ }, "owner": { "description": "The owner of the newly minter NFT", - "allOf": [ - { - "$ref": "#/definitions/HumanAddr" - } - ] + "type": "string" }, "token_id": { "description": "Unique ID of the NFT", diff --git a/contracts/cw721-base/schema/instantiate_msg.json b/contracts/cw721-base/schema/instantiate_msg.json index f17fd62d4..b024c82c1 100644 --- a/contracts/cw721-base/schema/instantiate_msg.json +++ b/contracts/cw721-base/schema/instantiate_msg.json @@ -10,23 +10,14 @@ "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", - "allOf": [ - { - "$ref": "#/definitions/HumanAddr" - } - ] + "type": "string" }, "name": { - "description": "name of the NFT contract", + "description": "Name of the NFT contract", "type": "string" }, "symbol": { - "description": "symbol of the NFT contract", - "type": "string" - } - }, - "definitions": { - "HumanAddr": { + "description": "Symbol of the NFT contract", "type": "string" } } diff --git a/contracts/cw721-base/schema/minter_response.json b/contracts/cw721-base/schema/minter_response.json index 48fc9857c..a20e0d767 100644 --- a/contracts/cw721-base/schema/minter_response.json +++ b/contracts/cw721-base/schema/minter_response.json @@ -8,11 +8,6 @@ ], "properties": { "minter": { - "$ref": "#/definitions/HumanAddr" - } - }, - "definitions": { - "HumanAddr": { "type": "string" } } diff --git a/contracts/cw721-base/schema/owner_of_response.json b/contracts/cw721-base/schema/owner_of_response.json index 8aa467831..2e861d5e4 100644 --- a/contracts/cw721-base/schema/owner_of_response.json +++ b/contracts/cw721-base/schema/owner_of_response.json @@ -16,11 +16,7 @@ }, "owner": { "description": "Owner of the token", - "allOf": [ - { - "$ref": "#/definitions/HumanAddr" - } - ] + "type": "string" } }, "definitions": { @@ -41,11 +37,7 @@ }, "spender": { "description": "Account that can transfer/send the token", - "allOf": [ - { - "$ref": "#/definitions/HumanAddr" - } - ] + "type": "string" } } }, @@ -64,7 +56,8 @@ "format": "uint64", "minimum": 0.0 } - } + }, + "additionalProperties": false }, { "description": "AtTime will expire when `env.block.time` >= time", @@ -78,7 +71,8 @@ "format": "uint64", "minimum": 0.0 } - } + }, + "additionalProperties": false }, { "description": "Never will never expire. Used to express the empty variant", @@ -90,12 +84,10 @@ "never": { "type": "object" } - } + }, + "additionalProperties": false } ] - }, - "HumanAddr": { - "type": "string" } } } diff --git a/contracts/cw721-base/schema/query_msg.json b/contracts/cw721-base/schema/query_msg.json index 06f5c55a3..471924bf0 100644 --- a/contracts/cw721-base/schema/query_msg.json +++ b/contracts/cw721-base/schema/query_msg.json @@ -27,7 +27,8 @@ } } } - } + }, + "additionalProperties": false }, { "description": "List all operators that can access all of the owner's tokens Return type: `ApprovedForAllResponse`", @@ -58,21 +59,18 @@ "minimum": 0.0 }, "owner": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "start_after": { - "anyOf": [ - { - "$ref": "#/definitions/HumanAddr" - }, - { - "type": "null" - } + "type": [ + "string", + "null" ] } } } - } + }, + "additionalProperties": false }, { "description": "Total number of tokens issued", @@ -84,7 +82,8 @@ "num_tokens": { "type": "object" } - } + }, + "additionalProperties": false }, { "description": "With MetaData Extension. Returns top-level metadata about the contract: `ContractInfoResponse`", @@ -96,7 +95,8 @@ "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`", @@ -116,7 +116,8 @@ } } } - } + }, + "additionalProperties": false }, { "description": "With MetaData Extension. Returns the result of both `NftInfo` and `OwnerOf` as one query as an optimization for clients: `AllNftInfo`", @@ -143,7 +144,8 @@ } } } - } + }, + "additionalProperties": false }, { "description": "With Enumerable extension. Returns all tokens owned by the given address, [] if unset. Return type: TokensResponse.", @@ -167,7 +169,7 @@ "minimum": 0.0 }, "owner": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "start_after": { "type": [ @@ -177,7 +179,8 @@ } } } - } + }, + "additionalProperties": false }, { "description": "With Enumerable extension. Requires pagination. Lists all token_ids controlled by the contract. Return type: TokensResponse.", @@ -205,7 +208,8 @@ } } } - } + }, + "additionalProperties": false }, { "type": "object", @@ -216,12 +220,8 @@ "minter": { "type": "object" } - } - } - ], - "definitions": { - "HumanAddr": { - "type": "string" + }, + "additionalProperties": false } - } + ] } diff --git a/contracts/cw721-base/src/contract.rs b/contracts/cw721-base/src/contract.rs index 26b04ec2f..2fa85dd32 100644 --- a/contracts/cw721-base/src/contract.rs +++ b/contracts/cw721-base/src/contract.rs @@ -1,11 +1,11 @@ #[cfg(not(feature = "library"))] use cosmwasm_std::entry_point; use cosmwasm_std::{ - attr, to_binary, Api, Binary, BlockInfo, Deps, DepsMut, Env, HumanAddr, MessageInfo, Order, - Response, StdError, StdResult, KV, + attr, to_binary, Binary, BlockInfo, Deps, DepsMut, Env, MessageInfo, Order, Pair, Response, + StdError, StdResult, }; -use cw0::maybe_canonical; +use cw0::maybe_addr; use cw2::set_contract_version; use cw721::{ AllNftInfoResponse, ApprovedForAllResponse, ContractInfoResponse, Cw721ReceiveMsg, Expiration, @@ -37,7 +37,7 @@ pub fn instantiate( symbol: msg.symbol, }; CONTRACT_INFO.save(deps.storage, &info)?; - let minter = deps.api.canonical_address(&msg.minter)?; + let minter = deps.api.addr_validate(&msg.minter)?; MINTER.save(deps.storage, &minter)?; Ok(Response::default()) } @@ -82,15 +82,14 @@ pub fn execute_mint( msg: MintMsg, ) -> Result { let minter = MINTER.load(deps.storage)?; - let sender_raw = deps.api.canonical_address(&info.sender)?; - if sender_raw != minter { + if info.sender != minter { return Err(ContractError::Unauthorized {}); } // create the token let token = TokenInfo { - owner: deps.api.canonical_address(&msg.owner)?, + owner: deps.api.addr_validate(&msg.owner)?, approvals: vec![], name: msg.name, description: msg.description.unwrap_or_default(), @@ -119,7 +118,7 @@ pub fn execute_transfer_nft( deps: DepsMut, env: Env, info: MessageInfo, - recipient: HumanAddr, + recipient: String, token_id: String, ) -> Result { _transfer_nft(deps, &env, &info, &recipient, &token_id)?; @@ -141,7 +140,7 @@ pub fn execute_send_nft( deps: DepsMut, env: Env, info: MessageInfo, - contract: HumanAddr, + contract: String, token_id: String, msg: Option, ) -> Result { @@ -149,7 +148,7 @@ pub fn execute_send_nft( _transfer_nft(deps, &env, &info, &contract, &token_id)?; let send = Cw721ReceiveMsg { - sender: info.sender.clone(), + sender: info.sender.to_string(), token_id: token_id.clone(), msg, }; @@ -172,14 +171,14 @@ pub fn _transfer_nft( deps: DepsMut, env: &Env, info: &MessageInfo, - recipient: &HumanAddr, + recipient: &str, token_id: &str, ) -> Result { let mut token = tokens().load(deps.storage, &token_id)?; // ensure we have permissions check_can_send(deps.as_ref(), env, info, &token)?; // set owner and remove existing approvals - token.owner = deps.api.canonical_address(recipient)?; + token.owner = deps.api.addr_validate(recipient)?; token.approvals = vec![]; tokens().save(deps.storage, &token_id, &token)?; Ok(token) @@ -189,7 +188,7 @@ pub fn execute_approve( deps: DepsMut, env: Env, info: MessageInfo, - spender: HumanAddr, + spender: String, token_id: String, expires: Option, ) -> Result { @@ -212,7 +211,7 @@ pub fn execute_revoke( deps: DepsMut, env: Env, info: MessageInfo, - spender: HumanAddr, + spender: String, token_id: String, ) -> Result { _update_approvals(deps, &env, &info, &spender, &token_id, false, None)?; @@ -234,7 +233,7 @@ pub fn _update_approvals( deps: DepsMut, env: &Env, info: &MessageInfo, - spender: &HumanAddr, + spender: &str, token_id: &str, // if add == false, remove. if add == true, remove then set with this expiration add: bool, @@ -245,11 +244,11 @@ pub fn _update_approvals( check_can_approve(deps.as_ref(), env, info, &token)?; // update the approval list (remove any for the same spender before adding) - let spender_raw = deps.api.canonical_address(&spender)?; + let spender_addr = deps.api.addr_validate(spender)?; token.approvals = token .approvals .into_iter() - .filter(|apr| apr.spender != spender_raw) + .filter(|apr| apr.spender != spender_addr) .collect(); // only difference between approve and revoke @@ -260,7 +259,7 @@ pub fn _update_approvals( return Err(ContractError::Expired {}); } let approval = Approval { - spender: spender_raw, + spender: spender_addr, expires, }; token.approvals.push(approval); @@ -275,7 +274,7 @@ pub fn execute_approve_all( deps: DepsMut, env: Env, info: MessageInfo, - operator: HumanAddr, + operator: String, expires: Option, ) -> Result { // reject expired data as invalid @@ -285,9 +284,8 @@ pub fn execute_approve_all( } // set the operator for us - let sender_raw = deps.api.canonical_address(&info.sender)?; - let operator_raw = deps.api.canonical_address(&operator)?; - OPERATORS.save(deps.storage, (&sender_raw, &operator_raw), &expires)?; + let operator_addr = deps.api.addr_validate(&operator)?; + OPERATORS.save(deps.storage, (&info.sender, &operator_addr), &expires)?; Ok(Response { submessages: vec![], @@ -305,11 +303,10 @@ pub fn execute_revoke_all( deps: DepsMut, _env: Env, info: MessageInfo, - operator: HumanAddr, + operator: String, ) -> Result { - let sender_raw = deps.api.canonical_address(&info.sender)?; - let operator_raw = deps.api.canonical_address(&operator)?; - OPERATORS.remove(deps.storage, (&sender_raw, &operator_raw)); + let operator_addr = deps.api.addr_validate(&operator)?; + OPERATORS.remove(deps.storage, (&info.sender, &operator_addr)); Ok(Response { submessages: vec![], @@ -331,12 +328,11 @@ fn check_can_approve( token: &TokenInfo, ) -> Result<(), ContractError> { // owner can approve - let sender_raw = deps.api.canonical_address(&info.sender)?; - if token.owner == sender_raw { + if token.owner == info.sender { return Ok(()); } // operator can approve - let op = OPERATORS.may_load(deps.storage, (&token.owner, &sender_raw))?; + let op = OPERATORS.may_load(deps.storage, (&token.owner, &info.sender))?; match op { Some(ex) => { if ex.is_expired(&env.block) { @@ -357,8 +353,7 @@ fn check_can_send( token: &TokenInfo, ) -> Result<(), ContractError> { // owner can send - let sender_raw = deps.api.canonical_address(&info.sender)?; - if token.owner == sender_raw { + if token.owner == info.sender { return Ok(()); } @@ -366,13 +361,13 @@ fn check_can_send( if token .approvals .iter() - .any(|apr| apr.spender == sender_raw && !apr.expires.is_expired(&env.block)) + .any(|apr| apr.spender == info.sender && !apr.is_expired(&env.block)) { return Ok(()); } // operator can send - let op = OPERATORS.may_load(deps.storage, (&token.owner, &sender_raw))?; + let op = OPERATORS.may_load(deps.storage, (&token.owner, &info.sender))?; match op { Some(ex) => { if ex.is_expired(&env.block) { @@ -435,9 +430,10 @@ pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> StdResult { } fn query_minter(deps: Deps) -> StdResult { - let minter_raw = MINTER.load(deps.storage)?; - let minter = deps.api.human_address(&minter_raw)?; - Ok(MinterResponse { minter }) + let minter_addr = MINTER.load(deps.storage)?; + Ok(MinterResponse { + minter: minter_addr.to_string(), + }) } fn query_contract_info(deps: Deps) -> StdResult { @@ -466,8 +462,8 @@ fn query_owner_of( ) -> StdResult { let info = tokens().load(deps.storage, &token_id)?; Ok(OwnerOfResponse { - owner: deps.api.human_address(&info.owner)?, - approvals: humanize_approvals(deps.api, &env.block, &info, include_expired)?, + owner: info.owner.to_string(), + approvals: humanize_approvals(&env.block, &info, include_expired), }) } @@ -477,49 +473,50 @@ const MAX_LIMIT: u32 = 30; fn query_all_approvals( deps: Deps, env: Env, - owner: HumanAddr, + owner: String, include_expired: bool, - start_after: Option, + start_after: Option, limit: Option, ) -> StdResult { let limit = limit.unwrap_or(DEFAULT_LIMIT).min(MAX_LIMIT) as usize; - let start_canon = maybe_canonical(deps.api, start_after)?; - let start = start_canon.map(Bound::exclusive); + let start_addr = maybe_addr(deps.api, start_after)?; + let start = start_addr.map(|addr| Bound::exclusive(addr.as_ref())); - let owner_raw = deps.api.canonical_address(&owner)?; + let owner_addr = deps.api.addr_validate(&owner)?; let res: StdResult> = OPERATORS - .prefix(&owner_raw) + .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(|item| parse_approval(deps.api, item)) + .map(parse_approval) .collect(); Ok(ApprovedForAllResponse { operators: res? }) } -fn parse_approval(api: &dyn Api, item: StdResult>) -> StdResult { +fn parse_approval(item: StdResult>) -> StdResult { item.and_then(|(k, expires)| { - let spender = api.human_address(&k.into())?; + let spender = String::from_utf8(k)?; Ok(cw721::Approval { spender, expires }) }) } fn query_tokens( deps: Deps, - owner: HumanAddr, + 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 start_addr = maybe_addr(deps.api, start_after)?; + let start = start_addr.map(|addr| Bound::exclusive(addr.as_ref())); - let owner_raw = deps.api.canonical_address(&owner)?; + let owner_addr = deps.api.addr_validate(&owner)?; let res: Result, _> = tokens() .idx .owner .pks( deps.storage, - PkOwned(owner_raw.into()), + PkOwned(Vec::from(owner_addr.as_ref())), start, None, Order::Ascending, @@ -539,7 +536,8 @@ fn query_all_tokens( limit: Option, ) -> StdResult { let limit = limit.unwrap_or(DEFAULT_LIMIT).min(MAX_LIMIT) as usize; - let start = start_after.map(Bound::exclusive); + let start_addr = maybe_addr(deps.api, start_after)?; + let start = start_addr.map(|addr| Bound::exclusive(addr.as_ref())); let tokens: StdResult> = tokens() .range(deps.storage, start, None, Order::Ascending) @@ -558,8 +556,8 @@ fn query_all_nft_info( let info = tokens().load(deps.storage, &token_id)?; Ok(AllNftInfoResponse { access: OwnerOfResponse { - owner: deps.api.human_address(&info.owner)?, - approvals: humanize_approvals(deps.api, &env.block, &info, include_expired)?, + owner: info.owner.to_string(), + approvals: humanize_approvals(&env.block, &info, include_expired), }, info: NftInfoResponse { name: info.name, @@ -570,22 +568,22 @@ fn query_all_nft_info( } fn humanize_approvals( - api: &dyn Api, block: &BlockInfo, info: &TokenInfo, include_expired: bool, -) -> StdResult> { - let iter = info.approvals.iter(); - iter.filter(|apr| include_expired || !apr.expires.is_expired(block)) - .map(|apr| humanize_approval(api, apr)) +) -> Vec { + info.approvals + .iter() + .filter(|apr| include_expired || !apr.is_expired(block)) + .map(humanize_approval) .collect() } -fn humanize_approval(api: &dyn Api, approval: &Approval) -> StdResult { - Ok(cw721::Approval { - spender: api.human_address(&approval.spender)?, +fn humanize_approval(approval: &Approval) -> cw721::Approval { + cw721::Approval { + spender: approval.spender.to_string(), expires: approval.expires, - }) + } } #[cfg(test)] @@ -604,7 +602,7 @@ mod tests { let msg = InstantiateMsg { name: CONTRACT_NAME.to_string(), symbol: SYMBOL.to_string(), - minter: MINTER.into(), + minter: String::from(MINTER), }; let info = mock_info("creator", &[]); let res = instantiate(deps, mock_env(), info, msg).unwrap(); @@ -618,7 +616,7 @@ mod tests { let msg = InstantiateMsg { name: CONTRACT_NAME.to_string(), symbol: SYMBOL.to_string(), - minter: MINTER.into(), + minter: String::from(MINTER), }; let info = mock_info("creator", &[]); @@ -628,7 +626,7 @@ mod tests { // it worked, let's query the state let res = query_minter(deps.as_ref()).unwrap(); - assert_eq!(MINTER, res.minter.as_str()); + assert_eq!(MINTER, res.minter); let info = query_contract_info(deps.as_ref()).unwrap(); assert_eq!( info, @@ -657,7 +655,7 @@ mod tests { let mint_msg = ExecuteMsg::Mint(MintMsg { token_id: token_id.clone(), - owner: "medusa".into(), + owner: String::from("medusa"), name: name.clone(), description: Some(description.clone()), image: None, @@ -670,7 +668,7 @@ mod tests { // minter can mint let allowed = mock_info(MINTER, &[]); - let _ = execute(deps.as_mut(), mock_env(), allowed, mint_msg.clone()).unwrap(); + let _ = execute(deps.as_mut(), mock_env(), allowed, mint_msg).unwrap(); // ensure num tokens increases let count = query_num_tokens(deps.as_ref()).unwrap(); @@ -684,8 +682,8 @@ mod tests { assert_eq!( info, NftInfoResponse { - name: name.clone(), - description: description.clone(), + name, + description, image: None, } ); @@ -695,7 +693,7 @@ mod tests { assert_eq!( owner, OwnerOfResponse { - owner: "medusa".into(), + owner: String::from("medusa"), approvals: vec![], } ); @@ -703,7 +701,7 @@ mod tests { // Cannot mint same token_id again let mint_msg2 = ExecuteMsg::Mint(MintMsg { token_id: token_id.clone(), - owner: "hercules".into(), + owner: String::from("hercules"), name: "copy cat".into(), description: None, image: None, @@ -731,9 +729,9 @@ mod tests { let mint_msg = ExecuteMsg::Mint(MintMsg { token_id: token_id.clone(), - owner: "venus".into(), - name: name.clone(), - description: Some(description.clone()), + owner: String::from("venus"), + name, + description: Some(description), image: None, }); @@ -743,21 +741,21 @@ mod tests { // random cannot transfer let random = mock_info("random", &[]); let transfer_msg = ExecuteMsg::TransferNft { - recipient: "random".into(), + recipient: String::from("random"), token_id: token_id.clone(), }; - let err = execute(deps.as_mut(), mock_env(), random, transfer_msg.clone()).unwrap_err(); + let err = 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: "random".into(), + recipient: String::from("random"), token_id: token_id.clone(), }; - let res = execute(deps.as_mut(), mock_env(), random, transfer_msg.clone()).unwrap(); + let res = execute(deps.as_mut(), mock_env(), random, transfer_msg).unwrap(); assert_eq!( res, @@ -787,9 +785,9 @@ mod tests { let mint_msg = ExecuteMsg::Mint(MintMsg { token_id: token_id.clone(), - owner: "venus".into(), - name: name.clone(), - description: Some(description.clone()), + owner: String::from("venus"), + name, + description: Some(description), image: None, }); @@ -797,7 +795,7 @@ mod tests { execute(deps.as_mut(), mock_env(), minter, mint_msg).unwrap(); let msg = to_binary("You now have the melting power").unwrap(); - let target = HumanAddr::from("another_contract"); + let target = String::from("another_contract"); let send_msg = ExecuteMsg::SendNft { contract: target.clone(), token_id: token_id.clone(), @@ -813,7 +811,7 @@ mod tests { let res = execute(deps.as_mut(), mock_env(), random, send_msg).unwrap(); let payload = Cw721ReceiveMsg { - sender: "venus".into(), + sender: String::from("venus"), token_id: token_id.clone(), msg: Some(msg), }; @@ -854,9 +852,9 @@ mod tests { let mint_msg = ExecuteMsg::Mint(MintMsg { token_id: token_id.clone(), - owner: "demeter".into(), - name: name.clone(), - description: Some(description.clone()), + owner: String::from("demeter"), + name, + description: Some(description), image: None, }); @@ -865,7 +863,7 @@ mod tests { // Give random transferring power let approve_msg = ExecuteMsg::Approve { - spender: "random".into(), + spender: String::from("random"), token_id: token_id.clone(), expires: None, }; @@ -889,7 +887,7 @@ mod tests { // random can now transfer let random = mock_info("random", &[]); let transfer_msg = ExecuteMsg::TransferNft { - recipient: "person".into(), + recipient: String::from("person"), token_id: token_id.clone(), }; execute(deps.as_mut(), mock_env(), random, transfer_msg).unwrap(); @@ -904,14 +902,14 @@ mod tests { assert_eq!( res, OwnerOfResponse { - owner: "person".into(), + owner: String::from("person"), approvals: vec![], } ); // Approve, revoke, and check for empty, to test revoke let approve_msg = ExecuteMsg::Approve { - spender: "random".into(), + spender: String::from("random"), token_id: token_id.clone(), expires: None, }; @@ -919,8 +917,8 @@ mod tests { execute(deps.as_mut(), mock_env(), owner.clone(), approve_msg).unwrap(); let revoke_msg = ExecuteMsg::Revoke { - spender: "random".into(), - token_id: token_id.clone(), + spender: String::from("random"), + token_id, }; execute(deps.as_mut(), mock_env(), owner, revoke_msg).unwrap(); @@ -930,7 +928,7 @@ mod tests { assert_eq!( res, OwnerOfResponse { - owner: "person".into(), + owner: String::from("person"), approvals: vec![], } ); @@ -951,9 +949,9 @@ mod tests { let mint_msg1 = ExecuteMsg::Mint(MintMsg { token_id: token_id1.clone(), - owner: "demeter".into(), - name: name1.clone(), - description: Some(description1.clone()), + owner: String::from("demeter"), + name: name1, + description: Some(description1), image: None, }); @@ -962,9 +960,9 @@ mod tests { let mint_msg2 = ExecuteMsg::Mint(MintMsg { token_id: token_id2.clone(), - owner: "demeter".into(), - name: name2.clone(), - description: Some(description2.clone()), + owner: String::from("demeter"), + name: name2, + description: Some(description2), image: None, }); @@ -980,7 +978,7 @@ mod tests { // demeter gives random full (operator) power over her tokens let approve_all_msg = ExecuteMsg::ApproveAll { - operator: "random".into(), + operator: String::from("random"), expires: None, }; let owner = mock_info("demeter", &[]); @@ -1002,8 +1000,8 @@ mod tests { // random can now transfer let random = mock_info("random", &[]); let transfer_msg = ExecuteMsg::TransferNft { - recipient: "person".into(), - token_id: token_id1.clone(), + recipient: String::from("person"), + token_id: token_id1, }; execute(deps.as_mut(), mock_env(), random.clone(), transfer_msg).unwrap(); @@ -1016,28 +1014,35 @@ mod tests { let msg: CosmosMsg = CosmosMsg::Wasm(inner_msg); let send_msg = ExecuteMsg::SendNft { - contract: "another_contract".into(), - token_id: token_id2.clone(), + contract: String::from("another_contract"), + token_id: token_id2, msg: Some(to_binary(&msg).unwrap()), }; 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: "operator".into(), + operator: String::from("operator"), expires: None, }; // person is now the owner of the tokens let owner = mock_info("person", &[]); - execute(deps.as_mut(), mock_env(), owner.clone(), approve_all_msg).unwrap(); + execute(deps.as_mut(), mock_env(), owner, approve_all_msg).unwrap(); - let res = query_all_approvals(deps.as_ref(), mock_env(), "person".into(), true, None, None) - .unwrap(); + let res = query_all_approvals( + deps.as_ref(), + mock_env(), + String::from("person"), + true, + None, + None, + ) + .unwrap(); assert_eq!( res, ApprovedForAllResponse { operators: vec![cw721::Approval { - spender: "operator".into(), + spender: String::from("operator"), expires: Expiration::Never {} }] } @@ -1046,7 +1051,7 @@ mod tests { // second approval let buddy_expires = Expiration::AtHeight(1234567); let approve_all_msg = ExecuteMsg::ApproveAll { - operator: "buddy".into(), + operator: String::from("buddy"), expires: Some(buddy_expires), }; let owner = mock_info("person", &[]); @@ -1056,7 +1061,7 @@ mod tests { let res = query_all_approvals( deps.as_ref(), mock_env(), - "person".into(), + String::from("person"), true, None, Some(1), @@ -1066,7 +1071,7 @@ mod tests { res, ApprovedForAllResponse { operators: vec![cw721::Approval { - spender: "buddy".into(), + spender: String::from("buddy"), expires: buddy_expires, }] } @@ -1074,9 +1079,9 @@ mod tests { let res = query_all_approvals( deps.as_ref(), mock_env(), - "person".into(), + String::from("person"), true, - Some("buddy".into()), + Some(String::from("buddy")), Some(2), ) .unwrap(); @@ -1084,14 +1089,14 @@ mod tests { res, ApprovedForAllResponse { operators: vec![cw721::Approval { - spender: "operator".into(), + spender: String::from("operator"), expires: Expiration::Never {} }] } ); let revoke_all_msg = ExecuteMsg::RevokeAll { - operator: "operator".into(), + operator: String::from("operator"), }; execute(deps.as_mut(), mock_env(), owner, revoke_all_msg).unwrap(); @@ -1099,7 +1104,7 @@ mod tests { let res = query_all_approvals( deps.as_ref(), mock_env(), - "person".into(), + String::from("person"), false, None, None, @@ -1109,7 +1114,7 @@ mod tests { res, ApprovedForAllResponse { operators: vec![cw721::Approval { - spender: "buddy".into(), + spender: String::from("buddy"), expires: buddy_expires, }] } @@ -1118,8 +1123,15 @@ mod tests { // ensure the filter works (nothing should be here let mut late_env = mock_env(); late_env.block.height = 1234568; //expired - let res = query_all_approvals(deps.as_ref(), late_env, "person".into(), false, None, None) - .unwrap(); + let res = query_all_approvals( + deps.as_ref(), + late_env, + String::from("person"), + false, + None, + None, + ) + .unwrap(); assert_eq!(0, res.operators.len()); } @@ -1131,9 +1143,9 @@ mod tests { // Mint a couple tokens (from the same owner) let token_id1 = "grow1".to_string(); - let demeter = HumanAddr::from("Demeter"); + let demeter = String::from("Demeter"); let token_id2 = "grow2".to_string(); - let ceres = HumanAddr::from("Ceres"); + let ceres = String::from("Ceres"); let token_id3 = "sing".to_string(); let mint_msg = ExecuteMsg::Mint(MintMsg { @@ -1163,7 +1175,7 @@ mod tests { description: Some("Calm even the most excited children".to_string()), image: None, }); - execute(deps.as_mut(), mock_env(), minter.clone(), mint_msg).unwrap(); + 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()]; @@ -1176,24 +1188,19 @@ mod tests { assert_eq!(&expected[2..], &tokens.tokens[..]); // get by owner - let by_ceres = vec![token_id2.clone()]; - let by_demeter = vec![token_id1.clone(), token_id3.clone()]; + let by_ceres = vec![token_id2]; + let by_demeter = vec![token_id1, token_id3]; // all tokens by owner let tokens = query_tokens(deps.as_ref(), demeter.clone(), None, None).unwrap(); assert_eq!(&by_demeter, &tokens.tokens); - let tokens = query_tokens(deps.as_ref(), ceres.clone(), None, None).unwrap(); + let tokens = query_tokens(deps.as_ref(), ceres, None, None).unwrap(); assert_eq!(&by_ceres, &tokens.tokens); // paginate for demeter let tokens = query_tokens(deps.as_ref(), demeter.clone(), None, Some(1)).unwrap(); assert_eq!(&by_demeter[..1], &tokens.tokens[..]); - let tokens = query_tokens( - deps.as_ref(), - demeter.clone(), - Some(by_demeter[0].clone()), - Some(3), - ) - .unwrap(); + let tokens = + query_tokens(deps.as_ref(), demeter, Some(by_demeter[0].clone()), Some(3)).unwrap(); assert_eq!(&by_demeter[1..], &tokens.tokens[..]); } } diff --git a/contracts/cw721-base/src/msg.rs b/contracts/cw721-base/src/msg.rs index 434fbfce8..bb8f56764 100644 --- a/contracts/cw721-base/src/msg.rs +++ b/contracts/cw721-base/src/msg.rs @@ -1,19 +1,19 @@ -use cosmwasm_std::{Binary, HumanAddr}; +use cosmwasm_std::Binary; use cw721::Expiration; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] pub struct InstantiateMsg { - /// name of the NFT contract + /// Name of the NFT contract pub name: String, - /// symbol of the NFT contract + /// 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: HumanAddr, + pub minter: String, } /// This is like Cw721ExecuteMsg but we add a Mint command for an owner @@ -23,37 +23,31 @@ pub struct InstantiateMsg { #[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: HumanAddr, - token_id: String, - }, + 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: HumanAddr, + contract: String, token_id: String, msg: Option, }, /// 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: HumanAddr, + spender: String, token_id: String, expires: Option, }, /// Remove previously granted Approval - Revoke { - spender: HumanAddr, - token_id: String, - }, + 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: HumanAddr, + operator: String, expires: Option, }, /// Remove previously granted ApproveAll permission - RevokeAll { operator: HumanAddr }, + RevokeAll { operator: String }, /// Mint a new NFT, can only be called by the contract minter Mint(MintMsg), @@ -64,7 +58,7 @@ pub struct MintMsg { /// Unique ID of the NFT pub token_id: String, /// The owner of the newly minter NFT - pub owner: HumanAddr, + pub owner: String, /// Identifies the asset to which this NFT represents pub name: String, /// Describes the asset to which this NFT represents (may be empty) @@ -86,10 +80,10 @@ pub enum QueryMsg { /// List all operators that can access all of the owner's tokens /// Return type: `ApprovedForAllResponse` ApprovedForAll { - owner: HumanAddr, + owner: String, /// unset or false will filter out expired items, you must set to true to see them include_expired: Option, - start_after: Option, + start_after: Option, limit: Option, }, /// Total number of tokens issued @@ -117,7 +111,7 @@ pub enum QueryMsg { /// Returns all tokens owned by the given address, [] if unset. /// Return type: TokensResponse. Tokens { - owner: HumanAddr, + owner: String, start_after: Option, limit: Option, }, @@ -136,5 +130,5 @@ pub enum QueryMsg { /// Shows who can mint these tokens #[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] pub struct MinterResponse { - pub minter: HumanAddr, + pub minter: String, } diff --git a/contracts/cw721-base/src/state.rs b/contracts/cw721-base/src/state.rs index fd9910b26..c6c4d3f05 100644 --- a/contracts/cw721-base/src/state.rs +++ b/contracts/cw721-base/src/state.rs @@ -1,15 +1,15 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -use cosmwasm_std::{CanonicalAddr, StdResult, Storage}; +use cosmwasm_std::{Addr, BlockInfo, StdResult, Storage}; use cw721::{ContractInfoResponse, Expiration}; use cw_storage_plus::{Index, IndexList, IndexedMap, Item, Map, MultiIndex, PkOwned}; #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] pub struct TokenInfo { - /// The owner of the newly minter NFT - pub owner: CanonicalAddr, - /// approvals are stored here, as we clear them all upon transfer and cannot accumulate much + /// 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, /// Identifies the asset to which this NFT represents @@ -23,17 +23,23 @@ pub struct TokenInfo { #[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] pub struct Approval { /// Account that can transfer/send the token - pub spender: CanonicalAddr, + 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 const CONTRACT_INFO: Item = Item::new("nft_info"); -pub const MINTER: Item = Item::new("minter"); +pub const MINTER: Item = Item::new("minter"); pub const TOKEN_COUNT: Item = Item::new("num_tokens"); -// pub const TOKENS: Map<&str, TokenInfo> = Map::new("tokens"); -pub const OPERATORS: Map<(&[u8], &[u8]), Expiration> = Map::new("operators"); +// Stored as (granter, operator) giving operator full control over granter's account +pub const OPERATORS: Map<(&Addr, &Addr), Expiration> = Map::new("operators"); pub fn num_tokens(storage: &dyn Storage) -> StdResult { Ok(TOKEN_COUNT.may_load(storage)?.unwrap_or_default()) @@ -60,7 +66,7 @@ impl<'a> IndexList for TokenIndexes<'a> { pub fn tokens<'a>() -> IndexedMap<'a, &'a str, TokenInfo, TokenIndexes<'a>> { let indexes = TokenIndexes { owner: MultiIndex::new( - |d, k| (PkOwned(d.owner.to_vec()), PkOwned(k)), + |d, k| (PkOwned(Vec::from(d.owner.as_ref())), PkOwned(k)), "tokens", "tokens__owner", ), diff --git a/packages/controllers/Cargo.toml b/packages/controllers/Cargo.toml index 60ac7101f..511bc3612 100644 --- a/packages/controllers/Cargo.toml +++ b/packages/controllers/Cargo.toml @@ -12,9 +12,9 @@ documentation = "https://docs.cosmwasm.com" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -cosmwasm-std = { version = "0.14.0-beta1" } +cosmwasm-std = { version = "0.14.0-beta2" } cw0 = { path = "../cw0", version = "0.6.0-alpha3" } cw-storage-plus = { path = "../storage-plus", version = "0.6.0-alpha3", features = ["iterator"] } -schemars = "0.7" +schemars = "0.8.1" serde = { version = "1.0.103", default-features = false, features = ["derive"] } thiserror = { version = "1.0.21" } diff --git a/packages/controllers/src/admin.rs b/packages/controllers/src/admin.rs index 3d19e7d38..f591a486a 100644 --- a/packages/controllers/src/admin.rs +++ b/packages/controllers/src/admin.rs @@ -2,17 +2,14 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use thiserror::Error; -use cosmwasm_std::{ - attr, CanonicalAddr, Deps, DepsMut, HumanAddr, MessageInfo, Response, StdError, StdResult, -}; -use cw0::maybe_canonical; +use cosmwasm_std::{attr, Addr, Deps, DepsMut, MessageInfo, Response, StdError, StdResult}; use cw_storage_plus::Item; // TODO: should the return values end up in cw0, so eg. cw4 can import them as well as this module? /// Returned from Admin.query_admin() #[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] pub struct AdminResponse { - pub admin: Option, + pub admin: Option, } /// Errors returned from Admin @@ -26,7 +23,7 @@ pub enum AdminError { } // state/logic -pub struct Admin<'a>(Item<'a, Option>); +pub struct Admin<'a>(Item<'a, Option>); // this is the core business logic we expose impl<'a> Admin<'a> { @@ -34,31 +31,26 @@ impl<'a> Admin<'a> { Admin(Item::new(namespace)) } - pub fn set(&self, deps: DepsMut, admin: Option) -> StdResult<()> { - let admin_raw = maybe_canonical(deps.api, admin)?; - self.0.save(deps.storage, &admin_raw) + pub fn set(&self, deps: DepsMut, admin: Option) -> StdResult<()> { + self.0.save(deps.storage, &admin) } - pub fn get(&self, deps: Deps) -> StdResult> { - let canon = self.0.load(deps.storage)?; - canon.map(|c| deps.api.human_address(&c)).transpose() + pub fn get(&self, deps: Deps) -> StdResult> { + self.0.load(deps.storage) } /// Returns Ok(true) if this is an admin, Ok(false) if not and an Error if /// we hit an error with Api or Storage usage - pub fn is_admin(&self, deps: Deps, caller: &HumanAddr) -> StdResult { + pub fn is_admin(&self, deps: Deps, caller: &Addr) -> StdResult { match self.0.load(deps.storage)? { - Some(owner) => { - let caller_raw = deps.api.canonical_address(caller)?; - Ok(caller_raw == owner) - } + Some(owner) => Ok(caller == &owner), None => Ok(false), } } /// Like is_admin but returns AdminError::NotAdmin if not admin. /// Helper for a nice one-line auth check. - pub fn assert_admin(&self, deps: Deps, caller: &HumanAddr) -> Result<(), AdminError> { + pub fn assert_admin(&self, deps: Deps, caller: &Addr) -> Result<(), AdminError> { if !self.is_admin(deps, caller)? { Err(AdminError::NotAdmin {}) } else { @@ -70,7 +62,7 @@ impl<'a> Admin<'a> { &self, deps: DepsMut, info: MessageInfo, - new_admin: Option, + new_admin: Option, ) -> Result { self.assert_admin(deps.as_ref(), &info.sender)?; @@ -95,7 +87,7 @@ impl<'a> Admin<'a> { } pub fn query_admin(&self, deps: Deps) -> StdResult { - let admin = self.get(deps)?; + let admin = self.get(deps)?.map(String::from); Ok(AdminResponse { admin }) } } @@ -112,7 +104,7 @@ mod tests { let control = Admin::new("foo"); // initialize and check - let admin = Some(HumanAddr::from("admin")); + let admin = Some(Addr::unchecked("admin")); control.set(deps.as_mut(), admin.clone()).unwrap(); let got = control.get(deps.as_ref()).unwrap(); assert_eq!(admin, got); @@ -128,8 +120,8 @@ mod tests { let mut deps = mock_dependencies(&[]); let control = Admin::new("foo"); - let owner = HumanAddr::from("big boss"); - let imposter = HumanAddr::from("imposter"); + let owner = Addr::unchecked("big boss"); + let imposter = Addr::unchecked("imposter"); // ensure checks proper with owner set control.set(deps.as_mut(), Some(owner.clone())).unwrap(); @@ -155,17 +147,17 @@ mod tests { // initial setup let control = Admin::new("foo"); - let owner = HumanAddr::from("big boss"); - let imposter = HumanAddr::from("imposter"); - let friend = HumanAddr::from("buddy"); + let owner = Addr::unchecked("big boss"); + let imposter = Addr::unchecked("imposter"); + let friend = Addr::unchecked("buddy"); control.set(deps.as_mut(), Some(owner.clone())).unwrap(); // query shows results let res = control.query_admin(deps.as_ref()).unwrap(); - assert_eq!(Some(owner.clone()), res.admin); + assert_eq!(Some(owner.to_string()), res.admin); // imposter cannot update - let info = mock_info(&imposter, &[]); + let info = mock_info(imposter.as_ref(), &[]); let new_admin = Some(friend.clone()); let err = control .execute_update_admin(deps.as_mut(), info, new_admin.clone()) @@ -173,7 +165,7 @@ mod tests { assert_eq!(AdminError::NotAdmin {}, err); // owner can update - let info = mock_info(&owner, &[]); + let info = mock_info(owner.as_ref(), &[]); let res = control .execute_update_admin(deps.as_mut(), info, new_admin) .unwrap(); @@ -181,6 +173,6 @@ mod tests { // query shows results let res = control.query_admin(deps.as_ref()).unwrap(); - assert_eq!(Some(friend.clone()), res.admin); + assert_eq!(Some(friend.to_string()), res.admin); } } diff --git a/packages/controllers/src/claim.rs b/packages/controllers/src/claim.rs index 1250eac9d..d1d54e610 100644 --- a/packages/controllers/src/claim.rs +++ b/packages/controllers/src/claim.rs @@ -1,7 +1,7 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -use cosmwasm_std::{BlockInfo, CanonicalAddr, Deps, HumanAddr, StdResult, Storage, Uint128}; +use cosmwasm_std::{Addr, BlockInfo, Deps, StdResult, Storage, Uint128}; use cw0::Expiration; use cw_storage_plus::Map; @@ -28,7 +28,7 @@ impl Claim { } // TODO: revisit design (split each claim on own key?) -pub struct Claims<'a>(Map<'a, &'a [u8], Vec>); +pub struct Claims<'a>(Map<'a, &'a Addr, Vec>); impl<'a> Claims<'a> { pub const fn new(storage_key: &'a str) -> Self { @@ -40,12 +40,12 @@ impl<'a> Claims<'a> { pub fn create_claim( &self, storage: &mut dyn Storage, - addr: &CanonicalAddr, + addr: &Addr, amount: Uint128, release_at: Expiration, ) -> StdResult<()> { // add a claim to this user to get their tokens after the unbonding period - self.0.update(storage, &addr, |old| -> StdResult<_> { + self.0.update(storage, addr, |old| -> StdResult<_> { let mut claims = old.unwrap_or_default(); claims.push(Claim { amount, release_at }); Ok(claims) @@ -58,12 +58,12 @@ impl<'a> Claims<'a> { pub fn claim_tokens( &self, storage: &mut dyn Storage, - addr: &CanonicalAddr, + addr: &Addr, block: &BlockInfo, cap: Option, ) -> StdResult { let mut to_send = Uint128(0); - self.0.update(storage, &addr, |claim| -> StdResult<_> { + self.0.update(storage, addr, |claim| -> StdResult<_> { let (_send, waiting): (Vec<_>, _) = claim.unwrap_or_default().iter().cloned().partition(|c| { // if mature and we can pay fully, then include in _send @@ -86,12 +86,8 @@ impl<'a> Claims<'a> { Ok(to_send) } - pub fn query_claims(&self, deps: Deps, address: HumanAddr) -> StdResult { - let address_raw = deps.api.canonical_address(&address)?; - let claims = self - .0 - .may_load(deps.storage, &address_raw)? - .unwrap_or_default(); + pub fn query_claims(&self, deps: Deps, address: &Addr) -> StdResult { + let claims = self.0.may_load(deps.storage, address)?.unwrap_or_default(); Ok(ClaimsResponse { claims }) } } diff --git a/packages/controllers/src/hooks.rs b/packages/controllers/src/hooks.rs index 105f9a0bd..203247bbd 100644 --- a/packages/controllers/src/hooks.rs +++ b/packages/controllers/src/hooks.rs @@ -3,7 +3,7 @@ use serde::{Deserialize, Serialize}; use thiserror::Error; use cosmwasm_std::{ - attr, CosmosMsg, Deps, DepsMut, HumanAddr, MessageInfo, Response, StdError, StdResult, Storage, + attr, Addr, CosmosMsg, Deps, DepsMut, MessageInfo, Response, StdError, StdResult, Storage, }; use cw_storage_plus::Item; @@ -13,7 +13,7 @@ use crate::admin::{Admin, AdminError}; // TODO: pull into cw0 as common dep #[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] pub struct HooksResponse { - pub hooks: Vec, + pub hooks: Vec, } #[derive(Error, Debug, PartialEq)] @@ -32,14 +32,14 @@ pub enum HookError { } // store all hook addresses in one item. We cannot have many of them before the contract becomes unusable anyway. -pub struct Hooks<'a>(Item<'a, Vec>); +pub struct Hooks<'a>(Item<'a, Vec>); impl<'a> Hooks<'a> { pub const fn new(storage_key: &'a str) -> Self { Hooks(Item::new(storage_key)) } - pub fn add_hook(&self, storage: &mut dyn Storage, addr: HumanAddr) -> Result<(), HookError> { + pub fn add_hook(&self, storage: &mut dyn Storage, addr: Addr) -> Result<(), HookError> { let mut hooks = self.0.may_load(storage)?.unwrap_or_default(); if !hooks.iter().any(|h| h == &addr) { hooks.push(addr); @@ -49,7 +49,7 @@ impl<'a> Hooks<'a> { Ok(self.0.save(storage, &hooks)?) } - pub fn remove_hook(&self, storage: &mut dyn Storage, addr: HumanAddr) -> Result<(), HookError> { + pub fn remove_hook(&self, storage: &mut dyn Storage, addr: Addr) -> Result<(), HookError> { let mut hooks = self.0.load(storage)?; if let Some(p) = hooks.iter().position(|x| x == &addr) { hooks.remove(p); @@ -59,7 +59,7 @@ impl<'a> Hooks<'a> { Ok(self.0.save(storage, &hooks)?) } - pub fn prepare_hooks StdResult>( + pub fn prepare_hooks StdResult>( &self, storage: &dyn Storage, prep: F, @@ -77,7 +77,7 @@ impl<'a> Hooks<'a> { admin: &Admin, deps: DepsMut, info: MessageInfo, - addr: HumanAddr, + addr: Addr, ) -> Result { admin.assert_admin(deps.as_ref(), &info.sender)?; self.add_hook(deps.storage, addr.clone())?; @@ -100,7 +100,7 @@ impl<'a> Hooks<'a> { admin: &Admin, deps: DepsMut, info: MessageInfo, - addr: HumanAddr, + addr: Addr, ) -> Result { admin.assert_admin(deps.as_ref(), &info.sender)?; self.remove_hook(deps.storage, addr.clone())?; @@ -120,6 +120,7 @@ impl<'a> Hooks<'a> { pub fn query_hooks(&self, deps: Deps) -> StdResult { let hooks = self.0.may_load(deps.storage)?.unwrap_or_default(); + let hooks = hooks.into_iter().map(String::from).collect(); Ok(HooksResponse { hooks }) } } diff --git a/packages/cw0/Cargo.toml b/packages/cw0/Cargo.toml index 8dc355f52..e23622a17 100644 --- a/packages/cw0/Cargo.toml +++ b/packages/cw0/Cargo.toml @@ -12,7 +12,7 @@ documentation = "https://docs.cosmwasm.com" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -cosmwasm-std = { version = "0.14.0-beta1" } -schemars = "0.7" +cosmwasm-std = { version = "0.14.0-beta2" } +schemars = "0.8.1" serde = { version = "1.0.103", default-features = false, features = ["derive"] } thiserror = { version = "1.0.21" } diff --git a/packages/cw0/src/balance.rs b/packages/cw0/src/balance.rs index 745a792e9..44319ca64 100644 --- a/packages/cw0/src/balance.rs +++ b/packages/cw0/src/balance.rs @@ -2,7 +2,7 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use std::ops; -use cosmwasm_std::{Coin, StdError, StdResult, Uint128}; +use cosmwasm_std::{Coin, OverflowError, OverflowOperation, StdError, StdResult, Uint128}; // Balance wraps Vec and provides some nice helpers. It mutates the Vec and can be // unwrapped when done. @@ -75,11 +75,17 @@ impl NativeBalance { if c.amount <= other.amount { self.0.remove(i); } else { - self.0[i].amount = (self.0[i].amount - other.amount)?; + self.0[i].amount = self.0[i].amount.checked_sub(other.amount)?; } } // error if no tokens - None => return Err(StdError::underflow(0, other.amount.u128())), + None => { + return Err(StdError::overflow(OverflowError::new( + OverflowOperation::Sub, + 0, + other.amount.u128(), + ))) + } }; Ok(self) } @@ -132,7 +138,7 @@ impl ops::Sub for NativeBalance { fn sub(mut self, other: Coin) -> StdResult { match self.find(&other.denom) { Some((i, c)) => { - let remainder = (c.amount - other.amount)?; + let remainder = c.amount.checked_sub(other.amount)?; if remainder.u128() == 0 { self.0.remove(i); } else { @@ -140,7 +146,13 @@ impl ops::Sub for NativeBalance { } } // error if no tokens - None => return Err(StdError::underflow(0, other.amount.u128())), + None => { + return Err(StdError::overflow(OverflowError::new( + OverflowOperation::Sub, + 0, + other.amount.u128(), + ))) + } }; Ok(self) } diff --git a/packages/cw0/src/lib.rs b/packages/cw0/src/lib.rs index 5fac7f7f6..69698b377 100644 --- a/packages/cw0/src/lib.rs +++ b/packages/cw0/src/lib.rs @@ -5,7 +5,8 @@ mod pagination; mod payment; pub use pagination::{ - calc_range_end_human, calc_range_start_human, calc_range_start_string, maybe_canonical, + calc_range_end_human, calc_range_start_human, calc_range_start_string, maybe_addr, + maybe_canonical, }; pub use payment::{may_pay, must_pay, nonpayable, one_coin, PaymentError}; diff --git a/packages/cw0/src/pagination.rs b/packages/cw0/src/pagination.rs index fe1ec2e17..a3307b545 100644 --- a/packages/cw0/src/pagination.rs +++ b/packages/cw0/src/pagination.rs @@ -1,21 +1,23 @@ -use cosmwasm_std::{Api, CanonicalAddr, HumanAddr, StdResult}; +use cosmwasm_std::{Addr, Api, CanonicalAddr, StdResult}; // this is used for pagination. Maybe we move it into the std lib one day? -pub fn maybe_canonical( - api: &dyn Api, - human: Option, -) -> StdResult> { - human.map(|x| api.canonical_address(&x)).transpose() +pub fn maybe_canonical(api: &dyn Api, human: Option) -> StdResult> { + human.map(|x| api.addr_canonicalize(x.as_ref())).transpose() +} + +// This is used for pagination. Maybe we move it into the std lib one day? +pub fn maybe_addr(api: &dyn Api, human: Option) -> StdResult> { + human.map(|x| api.addr_validate(&x)).transpose() } // this will set the first key after the provided key, by appending a 0 byte pub fn calc_range_start_human( api: &dyn Api, - start_after: Option, + start_after: Option, ) -> StdResult>> { match start_after { Some(human) => { - let mut v: Vec = api.canonical_address(&human)?.0.into(); + let mut v: Vec = api.addr_canonicalize(human.as_ref())?.0.into(); v.push(0); Ok(Some(v)) } @@ -24,13 +26,10 @@ pub fn calc_range_start_human( } // set the end to the canonicalized format (used for Order::Descending) -pub fn calc_range_end_human( - api: &dyn Api, - end_before: Option, -) -> StdResult>> { +pub fn calc_range_end_human(api: &dyn Api, end_before: Option) -> StdResult>> { match end_before { Some(human) => { - let v: Vec = api.canonical_address(&human)?.0.into(); + let v: Vec = api.addr_canonicalize(human.as_ref())?.into(); Ok(Some(v)) } None => Ok(None), diff --git a/packages/cw1/Cargo.toml b/packages/cw1/Cargo.toml index 28e2f0b1b..90a94992d 100644 --- a/packages/cw1/Cargo.toml +++ b/packages/cw1/Cargo.toml @@ -10,9 +10,9 @@ homepage = "https://cosmwasm.com" documentation = "https://docs.cosmwasm.com" [dependencies] -cosmwasm-std = { version = "0.14.0-beta1" } -schemars = "0.7" +cosmwasm-std = { version = "0.14.0-beta2" } +schemars = "0.8.1" serde = { version = "1.0.103", default-features = false, features = ["derive"] } [dev-dependencies] -cosmwasm-schema = { version = "0.14.0-beta1" } +cosmwasm-schema = { version = "0.14.0-beta2" } diff --git a/packages/cw1/schema/execute_msg.json b/packages/cw1/schema/execute_msg.json index ef81d9100..7fa82f0f4 100644 --- a/packages/cw1/schema/execute_msg.json +++ b/packages/cw1/schema/execute_msg.json @@ -23,7 +23,8 @@ } } } - } + }, + "additionalProperties": false } ], "definitions": { @@ -51,11 +52,12 @@ } }, "to_address": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false } ] }, @@ -89,7 +91,8 @@ "bank": { "$ref": "#/definitions/BankMsg" } - } + }, + "additionalProperties": false }, { "type": "object", @@ -100,7 +103,8 @@ "custom": { "$ref": "#/definitions/Empty" } - } + }, + "additionalProperties": false }, { "type": "object", @@ -111,7 +115,8 @@ "staking": { "$ref": "#/definitions/StakingMsg" } - } + }, + "additionalProperties": false }, { "type": "object", @@ -122,7 +127,8 @@ "wasm": { "$ref": "#/definitions/WasmMsg" } - } + }, + "additionalProperties": false } ] }, @@ -130,9 +136,6 @@ "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" }, - "HumanAddr": { - "type": "string" - }, "StakingMsg": { "description": "The message types of the staking module.\n\nSee https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto", "anyOf": [ @@ -154,11 +157,12 @@ "$ref": "#/definitions/Coin" }, "validator": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "This is translated to a [MsgUndelegate](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L112-L121). `delegator_address` is automatically filled with the current contract's address.", @@ -178,11 +182,12 @@ "$ref": "#/definitions/Coin" }, "validator": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "This is translated to a [MsgSetWithdrawAddress](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/distribution/v1beta1/tx.proto#L29-L37) followed by a [MsgWithdrawDelegatorReward](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/distribution/v1beta1/tx.proto#L42-L50). `delegator_address` is automatically filled with the current contract's address.", @@ -199,21 +204,18 @@ "properties": { "recipient": { "description": "this is the \"withdraw address\", the one that should receive the rewards if None, then use delegator address", - "anyOf": [ - { - "$ref": "#/definitions/HumanAddr" - }, - { - "type": "null" - } + "type": [ + "string", + "null" ] }, "validator": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "This is translated to a [MsgBeginRedelegate](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L95-L105). `delegator_address` is automatically filled with the current contract's address.", @@ -234,14 +236,15 @@ "$ref": "#/definitions/Coin" }, "dst_validator": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "src_validator": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false } ] }, @@ -267,7 +270,7 @@ ], "properties": { "contract_addr": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "msg": { "description": "msg is the json-encoded ExecuteMsg struct (as raw Binary)", @@ -285,7 +288,8 @@ } } } - } + }, + "additionalProperties": false }, { "description": "Instantiates a new contracts from previously uploaded Wasm code.\n\nThis is translated to a [MsgInstantiateContract](https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto#L47-L61). `sender` is automatically filled with the current contract's address.", @@ -328,7 +332,8 @@ } } } - } + }, + "additionalProperties": false }, { "description": "Migrates a given contracts to use new wasm code. Passes a MigrateMsg to allow us to customize behavior.\n\nOnly the contract admin (as defined in wasmd), if any, is able to make this call.\n\nThis is translated to a [MsgMigrateContract](https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto#L86-L96). `sender` is automatically filled with the current contract's address.", @@ -346,7 +351,7 @@ ], "properties": { "contract_addr": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "msg": { "description": "msg is the json-encoded MigrateMsg struct that will be passed to the new code", @@ -364,7 +369,8 @@ } } } - } + }, + "additionalProperties": false } ] } diff --git a/packages/cw1/schema/query_msg.json b/packages/cw1/schema/query_msg.json index 7f24f313f..4463f8b47 100644 --- a/packages/cw1/schema/query_msg.json +++ b/packages/cw1/schema/query_msg.json @@ -20,11 +20,12 @@ "$ref": "#/definitions/CosmosMsg_for_Empty" }, "sender": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false } ], "definitions": { @@ -52,11 +53,12 @@ } }, "to_address": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false } ] }, @@ -90,7 +92,8 @@ "bank": { "$ref": "#/definitions/BankMsg" } - } + }, + "additionalProperties": false }, { "type": "object", @@ -101,7 +104,8 @@ "custom": { "$ref": "#/definitions/Empty" } - } + }, + "additionalProperties": false }, { "type": "object", @@ -112,7 +116,8 @@ "staking": { "$ref": "#/definitions/StakingMsg" } - } + }, + "additionalProperties": false }, { "type": "object", @@ -123,7 +128,8 @@ "wasm": { "$ref": "#/definitions/WasmMsg" } - } + }, + "additionalProperties": false } ] }, @@ -131,9 +137,6 @@ "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" }, - "HumanAddr": { - "type": "string" - }, "StakingMsg": { "description": "The message types of the staking module.\n\nSee https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto", "anyOf": [ @@ -155,11 +158,12 @@ "$ref": "#/definitions/Coin" }, "validator": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "This is translated to a [MsgUndelegate](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L112-L121). `delegator_address` is automatically filled with the current contract's address.", @@ -179,11 +183,12 @@ "$ref": "#/definitions/Coin" }, "validator": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "This is translated to a [MsgSetWithdrawAddress](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/distribution/v1beta1/tx.proto#L29-L37) followed by a [MsgWithdrawDelegatorReward](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/distribution/v1beta1/tx.proto#L42-L50). `delegator_address` is automatically filled with the current contract's address.", @@ -200,21 +205,18 @@ "properties": { "recipient": { "description": "this is the \"withdraw address\", the one that should receive the rewards if None, then use delegator address", - "anyOf": [ - { - "$ref": "#/definitions/HumanAddr" - }, - { - "type": "null" - } + "type": [ + "string", + "null" ] }, "validator": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "This is translated to a [MsgBeginRedelegate](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L95-L105). `delegator_address` is automatically filled with the current contract's address.", @@ -235,14 +237,15 @@ "$ref": "#/definitions/Coin" }, "dst_validator": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "src_validator": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false } ] }, @@ -268,7 +271,7 @@ ], "properties": { "contract_addr": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "msg": { "description": "msg is the json-encoded ExecuteMsg struct (as raw Binary)", @@ -286,7 +289,8 @@ } } } - } + }, + "additionalProperties": false }, { "description": "Instantiates a new contracts from previously uploaded Wasm code.\n\nThis is translated to a [MsgInstantiateContract](https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto#L47-L61). `sender` is automatically filled with the current contract's address.", @@ -329,7 +333,8 @@ } } } - } + }, + "additionalProperties": false }, { "description": "Migrates a given contracts to use new wasm code. Passes a MigrateMsg to allow us to customize behavior.\n\nOnly the contract admin (as defined in wasmd), if any, is able to make this call.\n\nThis is translated to a [MsgMigrateContract](https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto#L86-L96). `sender` is automatically filled with the current contract's address.", @@ -347,7 +352,7 @@ ], "properties": { "contract_addr": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "msg": { "description": "msg is the json-encoded MigrateMsg struct that will be passed to the new code", @@ -365,7 +370,8 @@ } } } - } + }, + "additionalProperties": false } ] } diff --git a/packages/cw1/src/helpers.rs b/packages/cw1/src/helpers.rs index ab08325bc..0333a65ff 100644 --- a/packages/cw1/src/helpers.rs +++ b/packages/cw1/src/helpers.rs @@ -1,48 +1,29 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -use cosmwasm_std::{to_binary, Api, CanonicalAddr, CosmosMsg, HumanAddr, StdResult, WasmMsg}; +use cosmwasm_std::{to_binary, Addr, CosmosMsg, StdResult, WasmMsg}; use crate::msg::Cw1ExecuteMsg; -/// Cw1Contract is a wrapper around HumanAddr that provides a lot of helpers +/// Cw1Contract is a wrapper around Addr that provides a lot of helpers /// for working with this. /// /// If you wish to persist this, convert to Cw1CanonicalContract via .canonical() #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] -pub struct Cw1Contract(pub HumanAddr); +pub struct Cw1Contract(pub Addr); impl Cw1Contract { - pub fn addr(&self) -> HumanAddr { + pub fn addr(&self) -> Addr { self.0.clone() } - /// Convert this address to a form fit for storage - pub fn canonical(&self, api: &A) -> StdResult { - let canon = api.canonical_address(&self.0)?; - Ok(Cw1CanonicalContract(canon)) - } - pub fn execute>>(&self, msgs: T) -> StdResult { let msg = Cw1ExecuteMsg::Execute { msgs: msgs.into() }; Ok(WasmMsg::Execute { - contract_addr: self.addr(), + contract_addr: self.addr().into(), msg: to_binary(&msg)?, send: vec![], } .into()) } } - -/// This is a respresentation of Cw1Contract for storage. -/// Don't use it directly, just translate to the Cw1Contract when needed. -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] -pub struct Cw1CanonicalContract(pub CanonicalAddr); - -impl Cw1CanonicalContract { - /// Convert this address to a form fit for usage in messages and queries - pub fn human(&self, api: &A) -> StdResult { - let human = api.human_address(&self.0)?; - Ok(Cw1Contract(human)) - } -} diff --git a/packages/cw1/src/lib.rs b/packages/cw1/src/lib.rs index 7c6f1d1bf..0cdd1010c 100644 --- a/packages/cw1/src/lib.rs +++ b/packages/cw1/src/lib.rs @@ -2,7 +2,7 @@ pub mod helpers; pub mod msg; pub mod query; -pub use crate::helpers::{Cw1CanonicalContract, Cw1Contract}; +pub use crate::helpers::Cw1Contract; pub use crate::msg::Cw1ExecuteMsg; pub use crate::query::{CanExecuteResponse, Cw1QueryMsg}; diff --git a/packages/cw1/src/query.rs b/packages/cw1/src/query.rs index 137647f11..749ab73f7 100644 --- a/packages/cw1/src/query.rs +++ b/packages/cw1/src/query.rs @@ -2,7 +2,7 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use std::fmt; -use cosmwasm_std::{CosmosMsg, Empty, HumanAddr}; +use cosmwasm_std::{CosmosMsg, Empty}; #[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] #[serde(rename_all = "snake_case")] @@ -13,10 +13,7 @@ where /// Checks permissions of the caller on this proxy. /// If CanExecute returns true then a call to `Execute` with the same message, /// from the given sender, before any further state changes, should also succeed. - CanExecute { - sender: HumanAddr, - msg: CosmosMsg, - }, + CanExecute { sender: String, msg: CosmosMsg }, } #[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] diff --git a/packages/cw1155/Cargo.toml b/packages/cw1155/Cargo.toml index 058327b9c..a1cba86b6 100644 --- a/packages/cw1155/Cargo.toml +++ b/packages/cw1155/Cargo.toml @@ -11,9 +11,9 @@ documentation = "https://docs.cosmwasm.com" [dependencies] cw0 = { path = "../../packages/cw0", version = "0.6.0-alpha3" } -cosmwasm-std = { version = "0.14.0-beta1" } -schemars = "0.7" +cosmwasm-std = { version = "0.14.0-beta2" } +schemars = "0.8.1" serde = { version = "1.0.103", default-features = false, features = ["derive"] } [dev-dependencies] -cosmwasm-schema = { version = "0.14.0-beta1" } +cosmwasm-schema = { version = "0.14.0-beta2" } diff --git a/packages/cw1155/schema/approved_for_all_response.json b/packages/cw1155/schema/approved_for_all_response.json index 5b013ee49..ce7407ba5 100644 --- a/packages/cw1155/schema/approved_for_all_response.json +++ b/packages/cw1155/schema/approved_for_all_response.json @@ -31,11 +31,7 @@ }, "spender": { "description": "Account that can transfer/send the token", - "allOf": [ - { - "$ref": "#/definitions/HumanAddr" - } - ] + "type": "string" } } }, @@ -54,7 +50,8 @@ "format": "uint64", "minimum": 0.0 } - } + }, + "additionalProperties": false }, { "description": "AtTime will expire when `env.block.time` >= time", @@ -68,7 +65,8 @@ "format": "uint64", "minimum": 0.0 } - } + }, + "additionalProperties": false }, { "description": "Never will never expire. Used to express the empty variant", @@ -80,12 +78,10 @@ "never": { "type": "object" } - } + }, + "additionalProperties": false } ] - }, - "HumanAddr": { - "type": "string" } } } diff --git a/packages/cw1155/schema/cw1155_batch_receive_msg.json b/packages/cw1155/schema/cw1155_batch_receive_msg.json index c20869f0f..e4541af6c 100644 --- a/packages/cw1155/schema/cw1155_batch_receive_msg.json +++ b/packages/cw1155/schema/cw1155_batch_receive_msg.json @@ -26,20 +26,16 @@ } }, "from": { - "anyOf": [ - { - "$ref": "#/definitions/HumanAddr" - }, - { - "type": "null" - } + "type": [ + "string", + "null" ] }, "msg": { "$ref": "#/definitions/Binary" }, "operator": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } }, "definitions": { @@ -47,9 +43,6 @@ "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" }, - "HumanAddr": { - "type": "string" - }, "Uint128": { "type": "string" } diff --git a/packages/cw1155/schema/cw1155_execute_msg.json b/packages/cw1155/schema/cw1155_execute_msg.json index b5e5aea3f..4da6ba57b 100644 --- a/packages/cw1155/schema/cw1155_execute_msg.json +++ b/packages/cw1155/schema/cw1155_execute_msg.json @@ -19,7 +19,7 @@ ], "properties": { "from": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "msg": { "description": "`None` means don't call the receiver interface", @@ -34,11 +34,7 @@ }, "to": { "description": "If `to` is not contract, `msg` should be `None`", - "allOf": [ - { - "$ref": "#/definitions/HumanAddr" - } - ] + "type": "string" }, "token_id": { "type": "string" @@ -48,7 +44,8 @@ } } } - } + }, + "additionalProperties": false }, { "description": "BatchSendFrom is a base message to move multiple types of tokens in batch, if `env.sender` is the owner or has sufficient pre-approval.", @@ -82,7 +79,7 @@ } }, "from": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "msg": { "description": "`None` means don't call the receiver interface", @@ -97,15 +94,12 @@ }, "to": { "description": "if `to` is not contract, `msg` should be `None`", - "allOf": [ - { - "$ref": "#/definitions/HumanAddr" - } - ] + "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "Mint is a base message to mint tokens.", @@ -135,11 +129,7 @@ }, "to": { "description": "If `to` is not contract, `msg` should be `None`", - "allOf": [ - { - "$ref": "#/definitions/HumanAddr" - } - ] + "type": "string" }, "token_id": { "type": "string" @@ -149,7 +139,8 @@ } } } - } + }, + "additionalProperties": false }, { "description": "BatchMint is a base message to mint multiple types of tokens in batch.", @@ -194,15 +185,12 @@ }, "to": { "description": "If `to` is not contract, `msg` should be `None`", - "allOf": [ - { - "$ref": "#/definitions/HumanAddr" - } - ] + "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "Burn is a base message to burn tokens.", @@ -220,7 +208,7 @@ ], "properties": { "from": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "token_id": { "type": "string" @@ -230,7 +218,8 @@ } } } - } + }, + "additionalProperties": false }, { "description": "BatchBurn is a base message to burn multiple types of tokens in batch.", @@ -263,11 +252,12 @@ } }, "from": { - "$ref": "#/definitions/HumanAddr" + "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", @@ -293,11 +283,12 @@ ] }, "operator": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "Remove previously granted ApproveAll permission", @@ -313,11 +304,12 @@ ], "properties": { "operator": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false } ], "definitions": { @@ -340,7 +332,8 @@ "format": "uint64", "minimum": 0.0 } - } + }, + "additionalProperties": false }, { "description": "AtTime will expire when `env.block.time` >= time", @@ -354,7 +347,8 @@ "format": "uint64", "minimum": 0.0 } - } + }, + "additionalProperties": false }, { "description": "Never will never expire. Used to express the empty variant", @@ -366,13 +360,11 @@ "never": { "type": "object" } - } + }, + "additionalProperties": false } ] }, - "HumanAddr": { - "type": "string" - }, "Uint128": { "type": "string" } diff --git a/packages/cw1155/schema/cw1155_query_msg.json b/packages/cw1155/schema/cw1155_query_msg.json index 6e97a5f94..33537818c 100644 --- a/packages/cw1155/schema/cw1155_query_msg.json +++ b/packages/cw1155/schema/cw1155_query_msg.json @@ -17,14 +17,15 @@ ], "properties": { "owner": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "token_id": { "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "Returns the current balance of the given address for a batch of tokens, 0 if unset. Return type: BatchBalanceResponse.", @@ -41,7 +42,7 @@ ], "properties": { "owner": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "token_ids": { "type": "array", @@ -51,7 +52,8 @@ } } } - } + }, + "additionalProperties": false }, { "description": "List all operators that can access all of the owner's tokens. Return type: ApprovedForAllResponse.", @@ -82,21 +84,18 @@ "minimum": 0.0 }, "owner": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "start_after": { - "anyOf": [ - { - "$ref": "#/definitions/HumanAddr" - }, - { - "type": "null" - } + "type": [ + "string", + "null" ] } } } - } + }, + "additionalProperties": false }, { "description": "Query approved status `owner` granted to `operator`. Return type: IsApprovedForAllResponse", @@ -113,14 +112,15 @@ ], "properties": { "operator": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "owner": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "With MetaData Extension. Query metadata of token Return type: TokenInfoResponse.", @@ -140,7 +140,8 @@ } } } - } + }, + "additionalProperties": false }, { "description": "With Enumerable extension. Returns all tokens owned by the given address, [] if unset. Return type: TokensResponse.", @@ -164,7 +165,7 @@ "minimum": 0.0 }, "owner": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "start_after": { "type": [ @@ -174,7 +175,8 @@ } } } - } + }, + "additionalProperties": false }, { "description": "With Enumerable extension. Requires pagination. Lists all token_ids controlled by the contract. Return type: TokensResponse.", @@ -202,12 +204,8 @@ } } } - } - } - ], - "definitions": { - "HumanAddr": { - "type": "string" + }, + "additionalProperties": false } - } + ] } diff --git a/packages/cw1155/schema/cw1155_receive_msg.json b/packages/cw1155/schema/cw1155_receive_msg.json index 434aa3936..4879dbb34 100644 --- a/packages/cw1155/schema/cw1155_receive_msg.json +++ b/packages/cw1155/schema/cw1155_receive_msg.json @@ -15,13 +15,9 @@ }, "from": { "description": "The account that the token transfered from", - "anyOf": [ - { - "$ref": "#/definitions/HumanAddr" - }, - { - "type": "null" - } + "type": [ + "string", + "null" ] }, "msg": { @@ -29,11 +25,7 @@ }, "operator": { "description": "The account that executed the send message", - "allOf": [ - { - "$ref": "#/definitions/HumanAddr" - } - ] + "type": "string" }, "token_id": { "type": "string" @@ -44,9 +36,6 @@ "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" }, - "HumanAddr": { - "type": "string" - }, "Uint128": { "type": "string" } diff --git a/packages/cw1155/src/event.rs b/packages/cw1155/src/event.rs index d9bfbc658..14d642d48 100644 --- a/packages/cw1155/src/event.rs +++ b/packages/cw1155/src/event.rs @@ -1,10 +1,10 @@ -use cosmwasm_std::{HumanAddr, Response, Uint128}; +use cosmwasm_std::{Response, Uint128}; use cw0::Event; /// Tracks token transfer/mint/burn actions pub struct TransferEvent<'a> { - pub from: Option<&'a HumanAddr>, - pub to: Option<&'a HumanAddr>, + pub from: Option<&'a str>, + pub to: Option<&'a str>, pub token_id: &'a str, pub amount: Uint128, } @@ -39,8 +39,8 @@ impl<'a> Event for MetadataEvent<'a> { /// Tracks approve_all status changes pub struct ApproveAllEvent<'a> { - pub sender: &'a HumanAddr, - pub operator: &'a HumanAddr, + pub sender: &'a str, + pub operator: &'a str, pub approved: bool, } diff --git a/packages/cw1155/src/msg.rs b/packages/cw1155/src/msg.rs index 1542d0b65..bae102a4d 100644 --- a/packages/cw1155/src/msg.rs +++ b/packages/cw1155/src/msg.rs @@ -1,7 +1,7 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -use cosmwasm_std::{Binary, HumanAddr, Uint128}; +use cosmwasm_std::{Binary, Uint128}; use cw0::Expiration; pub type TokenId = String; @@ -12,9 +12,9 @@ pub enum Cw1155ExecuteMsg { /// SendFrom is a base message to move tokens, /// if `env.sender` is the owner or has sufficient pre-approval. SendFrom { - from: HumanAddr, + from: String, /// If `to` is not contract, `msg` should be `None` - to: HumanAddr, + to: String, token_id: TokenId, value: Uint128, /// `None` means don't call the receiver interface @@ -23,9 +23,9 @@ pub enum Cw1155ExecuteMsg { /// BatchSendFrom is a base message to move multiple types of tokens in batch, /// if `env.sender` is the owner or has sufficient pre-approval. BatchSendFrom { - from: HumanAddr, + from: String, /// if `to` is not contract, `msg` should be `None` - to: HumanAddr, + to: String, batch: Vec<(TokenId, Uint128)>, /// `None` means don't call the receiver interface msg: Option, @@ -33,7 +33,7 @@ pub enum Cw1155ExecuteMsg { /// Mint is a base message to mint tokens. Mint { /// If `to` is not contract, `msg` should be `None` - to: HumanAddr, + to: String, token_id: TokenId, value: Uint128, /// `None` means don't call the receiver interface @@ -42,28 +42,28 @@ pub enum Cw1155ExecuteMsg { /// BatchMint is a base message to mint multiple types of tokens in batch. BatchMint { /// If `to` is not contract, `msg` should be `None` - to: HumanAddr, + to: String, batch: Vec<(TokenId, Uint128)>, /// `None` means don't call the receiver interface msg: Option, }, /// Burn is a base message to burn tokens. Burn { - from: HumanAddr, + from: String, token_id: TokenId, value: Uint128, }, /// BatchBurn is a base message to burn multiple types of tokens in batch. BatchBurn { - from: HumanAddr, + from: String, batch: Vec<(TokenId, Uint128)>, }, /// 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: HumanAddr, + operator: String, expires: Option, }, /// Remove previously granted ApproveAll permission - RevokeAll { operator: HumanAddr }, + RevokeAll { operator: String }, } diff --git a/packages/cw1155/src/query.rs b/packages/cw1155/src/query.rs index 379c3a4bd..2bc3f6b62 100644 --- a/packages/cw1155/src/query.rs +++ b/packages/cw1155/src/query.rs @@ -1,7 +1,7 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -use cosmwasm_std::{HumanAddr, Uint128}; +use cosmwasm_std::Uint128; use cw0::Expiration; use crate::msg::TokenId; @@ -11,28 +11,25 @@ use crate::msg::TokenId; pub enum Cw1155QueryMsg { /// Returns the current balance of the given address, 0 if unset. /// Return type: BalanceResponse. - Balance { owner: HumanAddr, token_id: TokenId }, + Balance { owner: String, token_id: TokenId }, /// Returns the current balance of the given address for a batch of tokens, 0 if unset. /// Return type: BatchBalanceResponse. BatchBalance { - owner: HumanAddr, + owner: String, token_ids: Vec, }, /// List all operators that can access all of the owner's tokens. /// Return type: ApprovedForAllResponse. ApprovedForAll { - owner: HumanAddr, + owner: String, /// unset or false will filter out expired approvals, you must set to true to see them include_expired: Option, - start_after: Option, + start_after: Option, limit: Option, }, /// Query approved status `owner` granted to `operator`. /// Return type: IsApprovedForAllResponse - IsApprovedForAll { - owner: HumanAddr, - operator: HumanAddr, - }, + IsApprovedForAll { owner: String, operator: String }, /// With MetaData Extension. /// Query metadata of token @@ -43,7 +40,7 @@ pub enum Cw1155QueryMsg { /// Returns all tokens owned by the given address, [] if unset. /// Return type: TokensResponse. Tokens { - owner: HumanAddr, + owner: String, start_after: Option, limit: Option, }, @@ -69,7 +66,7 @@ pub struct BatchBalanceResponse { #[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] pub struct Approval { /// Account that can transfer/send the token - pub spender: HumanAddr, + pub spender: String, /// When the Approval expires (maybe Expiration::never) pub expires: Expiration, } diff --git a/packages/cw1155/src/receiver.rs b/packages/cw1155/src/receiver.rs index 3bc74d33e..66cb288b9 100644 --- a/packages/cw1155/src/receiver.rs +++ b/packages/cw1155/src/receiver.rs @@ -1,7 +1,7 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -use cosmwasm_std::{to_binary, Binary, CosmosMsg, HumanAddr, StdResult, Uint128, WasmMsg}; +use cosmwasm_std::{to_binary, Binary, CosmosMsg, StdResult, Uint128, WasmMsg}; use crate::msg::TokenId; @@ -10,9 +10,9 @@ use crate::msg::TokenId; #[serde(rename_all = "snake_case")] pub struct Cw1155ReceiveMsg { /// The account that executed the send message - pub operator: HumanAddr, + pub operator: String, /// The account that the token transfered from - pub from: Option, + pub from: Option, pub token_id: TokenId, pub amount: Uint128, pub msg: Binary, @@ -26,10 +26,10 @@ impl Cw1155ReceiveMsg { } /// creates a cosmos_msg sending this struct to the named contract - pub fn into_cosmos_msg(self, contract_addr: HumanAddr) -> StdResult { + pub fn into_cosmos_msg>(self, contract_addr: T) -> StdResult { let msg = self.into_binary()?; let execute = WasmMsg::Execute { - contract_addr, + contract_addr: contract_addr.into(), msg, send: vec![], }; @@ -41,8 +41,8 @@ impl Cw1155ReceiveMsg { #[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] #[serde(rename_all = "snake_case")] pub struct Cw1155BatchReceiveMsg { - pub operator: HumanAddr, - pub from: Option, + pub operator: String, + pub from: Option, pub batch: Vec<(TokenId, Uint128)>, pub msg: Binary, } @@ -55,10 +55,10 @@ impl Cw1155BatchReceiveMsg { } /// creates a cosmos_msg sending this struct to the named contract - pub fn into_cosmos_msg(self, contract_addr: HumanAddr) -> StdResult { + pub fn into_cosmos_msg>(self, contract_addr: T) -> StdResult { let msg = self.into_binary()?; let execute = WasmMsg::Execute { - contract_addr, + contract_addr: contract_addr.into(), msg, send: vec![], }; diff --git a/packages/cw2/Cargo.toml b/packages/cw2/Cargo.toml index 2c2b9888f..1724bc48c 100644 --- a/packages/cw2/Cargo.toml +++ b/packages/cw2/Cargo.toml @@ -10,7 +10,7 @@ homepage = "https://cosmwasm.com" documentation = "https://docs.cosmwasm.com" [dependencies] -cosmwasm-std = { version = "0.14.0-beta1" } +cosmwasm-std = { version = "0.14.0-beta2" } cw-storage-plus = { path = "../../packages/storage-plus", version = "0.6.0-alpha3" } -schemars = "0.7" +schemars = "0.8.1" serde = { version = "1.0.103", default-features = false, features = ["derive"] } diff --git a/packages/cw2/src/lib.rs b/packages/cw2/src/lib.rs index c3b5873c6..1c364e961 100644 --- a/packages/cw2/src/lib.rs +++ b/packages/cw2/src/lib.rs @@ -1,9 +1,7 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -use cosmwasm_std::{ - HumanAddr, Querier, QuerierWrapper, QueryRequest, StdResult, Storage, WasmQuery, -}; +use cosmwasm_std::{Querier, QuerierWrapper, QueryRequest, StdResult, Storage, WasmQuery}; use cw_storage_plus::Item; pub const CONTRACT: Item = Item::new("contract_info"); @@ -44,7 +42,7 @@ pub fn set_contract_version, U: Into>( /// if the other contract exists and claims to be a cw20-base contract for example. /// (Note: you usually want to require *interfaces* not *implementations* of the /// contracts you compose with, so be careful of overuse) -pub fn query_contract_info>( +pub fn query_contract_info>( querier: &Q, contract_addr: T, ) -> StdResult { diff --git a/packages/cw20/Cargo.toml b/packages/cw20/Cargo.toml index 08c91eb49..43bb986aa 100644 --- a/packages/cw20/Cargo.toml +++ b/packages/cw20/Cargo.toml @@ -11,9 +11,9 @@ documentation = "https://docs.cosmwasm.com" [dependencies] cw0 = { path = "../../packages/cw0", version = "0.6.0-alpha3" } -cosmwasm-std = { version = "0.14.0-beta1" } -schemars = "0.7" +cosmwasm-std = { version = "0.14.0-beta2" } +schemars = "0.8.1" serde = { version = "1.0.103", default-features = false, features = ["derive"] } [dev-dependencies] -cosmwasm-schema = { version = "0.14.0-beta1" } +cosmwasm-schema = { version = "0.14.0-beta2" } diff --git a/packages/cw20/schema/all_accounts_response.json b/packages/cw20/schema/all_accounts_response.json index 8689981c0..cea50fba4 100644 --- a/packages/cw20/schema/all_accounts_response.json +++ b/packages/cw20/schema/all_accounts_response.json @@ -9,13 +9,8 @@ "accounts": { "type": "array", "items": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } - }, - "definitions": { - "HumanAddr": { - "type": "string" - } } } diff --git a/packages/cw20/schema/all_allowances_response.json b/packages/cw20/schema/all_allowances_response.json index b8c365188..1f7d683a6 100644 --- a/packages/cw20/schema/all_allowances_response.json +++ b/packages/cw20/schema/all_allowances_response.json @@ -29,7 +29,7 @@ "$ref": "#/definitions/Expiration" }, "spender": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } }, @@ -48,7 +48,8 @@ "format": "uint64", "minimum": 0.0 } - } + }, + "additionalProperties": false }, { "description": "AtTime will expire when `env.block.time` >= time", @@ -62,7 +63,8 @@ "format": "uint64", "minimum": 0.0 } - } + }, + "additionalProperties": false }, { "description": "Never will never expire. Used to express the empty variant", @@ -74,13 +76,11 @@ "never": { "type": "object" } - } + }, + "additionalProperties": false } ] }, - "HumanAddr": { - "type": "string" - }, "Uint128": { "type": "string" } diff --git a/packages/cw20/schema/allowance_response.json b/packages/cw20/schema/allowance_response.json index 596d84464..5fb08aa98 100644 --- a/packages/cw20/schema/allowance_response.json +++ b/packages/cw20/schema/allowance_response.json @@ -30,7 +30,8 @@ "format": "uint64", "minimum": 0.0 } - } + }, + "additionalProperties": false }, { "description": "AtTime will expire when `env.block.time` >= time", @@ -44,7 +45,8 @@ "format": "uint64", "minimum": 0.0 } - } + }, + "additionalProperties": false }, { "description": "Never will never expire. Used to express the empty variant", @@ -56,7 +58,8 @@ "never": { "type": "object" } - } + }, + "additionalProperties": false } ] }, diff --git a/packages/cw20/schema/cw20_execute_msg.json b/packages/cw20/schema/cw20_execute_msg.json index c23f6cdef..35aba2495 100644 --- a/packages/cw20/schema/cw20_execute_msg.json +++ b/packages/cw20/schema/cw20_execute_msg.json @@ -20,11 +20,12 @@ "$ref": "#/definitions/Uint128" }, "recipient": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "Burn is a base message to destroy tokens forever", @@ -44,7 +45,8 @@ } } } - } + }, + "additionalProperties": false }, { "description": "Send is a base message to transfer tokens to a contract and trigger an action on the receiving contract.", @@ -64,7 +66,7 @@ "$ref": "#/definitions/Uint128" }, "contract": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "msg": { "anyOf": [ @@ -78,7 +80,8 @@ } } } - } + }, + "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.", @@ -108,11 +111,12 @@ ] }, "spender": { - "$ref": "#/definitions/HumanAddr" + "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.", @@ -142,11 +146,12 @@ ] }, "spender": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "Only with \"approval\" extension. Transfers amount tokens from owner -> recipient if `env.sender` has sufficient pre-approval.", @@ -167,14 +172,15 @@ "$ref": "#/definitions/Uint128" }, "owner": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "recipient": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "Only with \"approval\" extension. Sends amount tokens from owner -> contract if `env.sender` has sufficient pre-approval.", @@ -195,7 +201,7 @@ "$ref": "#/definitions/Uint128" }, "contract": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "msg": { "anyOf": [ @@ -208,11 +214,12 @@ ] }, "owner": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "Only with \"approval\" extension. Destroys tokens forever", @@ -232,11 +239,12 @@ "$ref": "#/definitions/Uint128" }, "owner": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "Only with the \"mintable\" extension. If authorized, creates amount new tokens and adds to the recipient balance.", @@ -256,11 +264,12 @@ "$ref": "#/definitions/Uint128" }, "recipient": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false } ], "definitions": { @@ -283,7 +292,8 @@ "format": "uint64", "minimum": 0.0 } - } + }, + "additionalProperties": false }, { "description": "AtTime will expire when `env.block.time` >= time", @@ -297,7 +307,8 @@ "format": "uint64", "minimum": 0.0 } - } + }, + "additionalProperties": false }, { "description": "Never will never expire. Used to express the empty variant", @@ -309,13 +320,11 @@ "never": { "type": "object" } - } + }, + "additionalProperties": false } ] }, - "HumanAddr": { - "type": "string" - }, "Uint128": { "type": "string" } diff --git a/packages/cw20/schema/cw20_query_msg.json b/packages/cw20/schema/cw20_query_msg.json index 5622baa7c..84e68a750 100644 --- a/packages/cw20/schema/cw20_query_msg.json +++ b/packages/cw20/schema/cw20_query_msg.json @@ -16,11 +16,12 @@ ], "properties": { "address": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "Returns metadata on the contract - name, decimals, supply, etc. Return type: TokenInfoResponse.", @@ -32,7 +33,8 @@ "token_info": { "type": "object" } - } + }, + "additionalProperties": false }, { "description": "Only with \"allowance\" extension. Returns how much spender can use from owner account, 0 if unset. Return type: AllowanceResponse.", @@ -49,14 +51,15 @@ ], "properties": { "owner": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "spender": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "Only with \"mintable\" extension. Returns who can mint and how much. Return type: MinterResponse.", @@ -68,7 +71,8 @@ "minter": { "type": "object" } - } + }, + "additionalProperties": false }, { "description": "Only with \"enumerable\" extension (and \"allowances\") Returns all allowances this owner has approved. Supports pagination. Return type: AllAllowancesResponse.", @@ -92,21 +96,18 @@ "minimum": 0.0 }, "owner": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "start_after": { - "anyOf": [ - { - "$ref": "#/definitions/HumanAddr" - }, - { - "type": "null" - } + "type": [ + "string", + "null" ] } } } - } + }, + "additionalProperties": false }, { "description": "Only with \"enumerable\" extension Returns all accounts that have balances. Supports pagination. Return type: AllAccountsResponse.", @@ -127,23 +128,15 @@ "minimum": 0.0 }, "start_after": { - "anyOf": [ - { - "$ref": "#/definitions/HumanAddr" - }, - { - "type": "null" - } + "type": [ + "string", + "null" ] } } } - } - } - ], - "definitions": { - "HumanAddr": { - "type": "string" + }, + "additionalProperties": false } - } + ] } diff --git a/packages/cw20/schema/cw20_receive_msg.json b/packages/cw20/schema/cw20_receive_msg.json index 7575b6782..34ddb09a8 100644 --- a/packages/cw20/schema/cw20_receive_msg.json +++ b/packages/cw20/schema/cw20_receive_msg.json @@ -22,7 +22,7 @@ ] }, "sender": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } }, "definitions": { @@ -30,9 +30,6 @@ "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" }, - "HumanAddr": { - "type": "string" - }, "Uint128": { "type": "string" } diff --git a/packages/cw20/schema/minter_response.json b/packages/cw20/schema/minter_response.json index 38df5a302..06ec18ad0 100644 --- a/packages/cw20/schema/minter_response.json +++ b/packages/cw20/schema/minter_response.json @@ -18,13 +18,10 @@ ] }, "minter": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } }, "definitions": { - "HumanAddr": { - "type": "string" - }, "Uint128": { "type": "string" } diff --git a/packages/cw20/src/balance.rs b/packages/cw20/src/balance.rs index ec6c8af02..aa3e89fdd 100644 --- a/packages/cw20/src/balance.rs +++ b/packages/cw20/src/balance.rs @@ -4,13 +4,13 @@ use serde::{Deserialize, Serialize}; use cw0::NativeBalance; -use crate::Cw20Coin; +use crate::Cw20CoinVerified; #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] #[serde(rename_all = "snake_case")] pub enum Balance { Native(NativeBalance), - Cw20(Cw20Coin), + Cw20(Cw20CoinVerified), } impl Default for Balance { @@ -42,8 +42,8 @@ impl From> for Balance { } } -impl From for Balance { - fn from(cw20_coin: Cw20Coin) -> Balance { +impl From for Balance { + fn from(cw20_coin: Cw20CoinVerified) -> Balance { Balance::Cw20(cw20_coin) } } diff --git a/packages/cw20/src/coin.rs b/packages/cw20/src/coin.rs index b43ff4ee7..4f5ad59c8 100644 --- a/packages/cw20/src/coin.rs +++ b/packages/cw20/src/coin.rs @@ -1,22 +1,28 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -use cosmwasm_std::{CanonicalAddr, HumanAddr, Uint128}; +use cosmwasm_std::{Addr, Uint128}; #[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] pub struct Cw20Coin { - pub address: CanonicalAddr, + pub address: String, pub amount: Uint128, } impl Cw20Coin { pub fn is_empty(&self) -> bool { - self.amount == Uint128(0) + self.amount == Uint128::zero() } } #[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] -pub struct Cw20CoinHuman { - pub address: HumanAddr, +pub struct Cw20CoinVerified { + pub address: Addr, pub amount: Uint128, } + +impl Cw20CoinVerified { + pub fn is_empty(&self) -> bool { + self.amount == Uint128::zero() + } +} diff --git a/packages/cw20/src/denom.rs b/packages/cw20/src/denom.rs index a9d11dfc0..1b4e001d2 100644 --- a/packages/cw20/src/denom.rs +++ b/packages/cw20/src/denom.rs @@ -1,4 +1,4 @@ -use cosmwasm_std::CanonicalAddr; +use cosmwasm_std::Addr; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; @@ -6,9 +6,10 @@ use serde::{Deserialize, Serialize}; #[serde(rename_all = "snake_case")] pub enum Denom { Native(String), - Cw20(CanonicalAddr), + Cw20(Addr), } +// TODO: remove or figure out where needed impl Default for Denom { fn default() -> Denom { Denom::Native(String::default()) @@ -19,7 +20,7 @@ impl Denom { pub fn is_empty(&self) -> bool { match self { Denom::Native(string) => string.is_empty(), - Denom::Cw20(canonical_addr) => canonical_addr.is_empty(), + Denom::Cw20(addr) => addr.as_ref().is_empty(), } } } diff --git a/packages/cw20/src/helpers.rs b/packages/cw20/src/helpers.rs index c29bb31bd..06b8b30fd 100644 --- a/packages/cw20/src/helpers.rs +++ b/packages/cw20/src/helpers.rs @@ -2,8 +2,7 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use cosmwasm_std::{ - to_binary, CosmosMsg, HumanAddr, Querier, QuerierWrapper, StdResult, Uint128, WasmMsg, - WasmQuery, + to_binary, Addr, CosmosMsg, Querier, QuerierWrapper, StdResult, Uint128, WasmMsg, WasmQuery, }; use crate::{ @@ -11,22 +10,22 @@ use crate::{ TokenInfoResponse, }; -/// Cw20Contract is a wrapper around HumanAddr that provides a lot of helpers +/// Cw20Contract is a wrapper around Addr that provides a lot of helpers /// for working with this. /// /// If you wish to persist this, convert to Cw20CanonicalContract via .canonical() #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] -pub struct Cw20Contract(pub HumanAddr); +pub struct Cw20Contract(pub Addr); impl Cw20Contract { - pub fn addr(&self) -> HumanAddr { + pub fn addr(&self) -> Addr { self.0.clone() } pub fn call>(&self, msg: T) -> StdResult { let msg = to_binary(&msg.into())?; Ok(WasmMsg::Execute { - contract_addr: self.addr(), + contract_addr: self.addr().into(), msg, send: vec![], } @@ -34,10 +33,16 @@ impl Cw20Contract { } /// Get token balance for the given address - pub fn balance(&self, querier: &Q, address: HumanAddr) -> StdResult { - let msg = Cw20QueryMsg::Balance { address }; + pub fn balance>( + &self, + querier: &Q, + address: T, + ) -> StdResult { + let msg = Cw20QueryMsg::Balance { + address: address.into(), + }; let query = WasmQuery::Smart { - contract_addr: self.addr(), + contract_addr: self.addr().into(), msg: to_binary(&msg)?, } .into(); @@ -50,7 +55,7 @@ impl Cw20Contract { pub fn meta(&self, querier: &Q) -> StdResult { let msg = Cw20QueryMsg::TokenInfo {}; let query = WasmQuery::Smart { - contract_addr: self.addr(), + contract_addr: self.addr().into(), msg: to_binary(&msg)?, } .into(); @@ -58,15 +63,18 @@ impl Cw20Contract { } /// Get allowance of spender to use owner's account - pub fn allowance( + pub fn allowance, U: Into>( &self, querier: &Q, - owner: HumanAddr, - spender: HumanAddr, + owner: T, + spender: U, ) -> StdResult { - let msg = Cw20QueryMsg::Allowance { owner, spender }; + let msg = Cw20QueryMsg::Allowance { + owner: owner.into(), + spender: spender.into(), + }; let query = WasmQuery::Smart { - contract_addr: self.addr(), + contract_addr: self.addr().into(), msg: to_binary(&msg)?, } .into(); @@ -77,7 +85,7 @@ impl Cw20Contract { pub fn minter(&self, querier: &Q) -> StdResult> { let msg = Cw20QueryMsg::Minter {}; let query = WasmQuery::Smart { - contract_addr: self.addr(), + contract_addr: self.addr().into(), msg: to_binary(&msg)?, } .into(); diff --git a/packages/cw20/src/lib.rs b/packages/cw20/src/lib.rs index fac2e4923..0dbb33306 100644 --- a/packages/cw20/src/lib.rs +++ b/packages/cw20/src/lib.rs @@ -1,7 +1,7 @@ pub use cw0::Expiration; pub use crate::balance::Balance; -pub use crate::coin::{Cw20Coin, Cw20CoinHuman}; +pub use crate::coin::{Cw20Coin, Cw20CoinVerified}; pub use crate::denom::Denom; pub use crate::helpers::Cw20Contract; pub use crate::msg::Cw20ExecuteMsg; diff --git a/packages/cw20/src/msg.rs b/packages/cw20/src/msg.rs index 16cb874c1..2a40997ac 100644 --- a/packages/cw20/src/msg.rs +++ b/packages/cw20/src/msg.rs @@ -1,23 +1,20 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -use cosmwasm_std::{Binary, HumanAddr, Uint128}; +use cosmwasm_std::{Binary, Uint128}; use cw0::Expiration; #[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] #[serde(rename_all = "snake_case")] pub enum Cw20ExecuteMsg { /// Transfer is a base message to move tokens to another account without triggering actions - Transfer { - recipient: HumanAddr, - amount: Uint128, - }, + Transfer { recipient: String, amount: Uint128 }, /// Burn is a base message to destroy tokens forever Burn { amount: Uint128 }, /// Send is a base message to transfer tokens to a contract and trigger an action /// on the receiving contract. Send { - contract: HumanAddr, + contract: String, amount: Uint128, msg: Option, }, @@ -25,7 +22,7 @@ pub enum Cw20ExecuteMsg { /// from the owner's (env.sender) account. If expires is Some(), overwrites current allowance /// expiration with this one. IncreaseAllowance { - spender: HumanAddr, + spender: String, amount: Uint128, expires: Option, }, @@ -33,31 +30,28 @@ pub enum Cw20ExecuteMsg { /// from the owner's (env.sender) account by amount. If expires is Some(), overwrites current /// allowance expiration with this one. DecreaseAllowance { - spender: HumanAddr, + spender: String, amount: Uint128, expires: Option, }, /// Only with "approval" extension. Transfers amount tokens from owner -> recipient /// if `env.sender` has sufficient pre-approval. TransferFrom { - owner: HumanAddr, - recipient: HumanAddr, + owner: String, + recipient: String, amount: Uint128, }, /// Only with "approval" extension. Sends amount tokens from owner -> contract /// if `env.sender` has sufficient pre-approval. SendFrom { - owner: HumanAddr, - contract: HumanAddr, + owner: String, + contract: String, amount: Uint128, msg: Option, }, /// Only with "approval" extension. Destroys tokens forever - BurnFrom { owner: HumanAddr, amount: Uint128 }, + BurnFrom { owner: String, amount: Uint128 }, /// Only with the "mintable" extension. If authorized, creates amount new tokens /// and adds to the recipient balance. - Mint { - recipient: HumanAddr, - amount: Uint128, - }, + Mint { recipient: String, amount: Uint128 }, } diff --git a/packages/cw20/src/query.rs b/packages/cw20/src/query.rs index 64bf695de..a3b01544d 100644 --- a/packages/cw20/src/query.rs +++ b/packages/cw20/src/query.rs @@ -1,7 +1,7 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -use cosmwasm_std::{HumanAddr, Uint128}; +use cosmwasm_std::Uint128; use cw0::Expiration; @@ -10,17 +10,14 @@ use cw0::Expiration; pub enum Cw20QueryMsg { /// Returns the current balance of the given address, 0 if unset. /// Return type: BalanceResponse. - Balance { address: HumanAddr }, + Balance { address: String }, /// Returns metadata on the contract - name, decimals, supply, etc. /// Return type: TokenInfoResponse. TokenInfo {}, /// Only with "allowance" extension. /// Returns how much spender can use from owner account, 0 if unset. /// Return type: AllowanceResponse. - Allowance { - owner: HumanAddr, - spender: HumanAddr, - }, + Allowance { owner: String, spender: String }, /// Only with "mintable" extension. /// Returns who can mint and how much. /// Return type: MinterResponse. @@ -29,15 +26,15 @@ pub enum Cw20QueryMsg { /// Returns all allowances this owner has approved. Supports pagination. /// Return type: AllAllowancesResponse. AllAllowances { - owner: HumanAddr, - start_after: Option, + 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, + start_after: Option, limit: Option, }, } @@ -63,14 +60,14 @@ pub struct AllowanceResponse { #[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] pub struct MinterResponse { - pub minter: HumanAddr, + pub minter: String, /// cap is how many more tokens can be issued by the minter pub cap: Option, } #[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] pub struct AllowanceInfo { - pub spender: HumanAddr, + pub spender: String, pub allowance: Uint128, pub expires: Expiration, } @@ -82,5 +79,5 @@ pub struct AllAllowancesResponse { #[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug, Default)] pub struct AllAccountsResponse { - pub accounts: Vec, + pub accounts: Vec, } diff --git a/packages/cw20/src/receiver.rs b/packages/cw20/src/receiver.rs index 80839ad50..fb6629c34 100644 --- a/packages/cw20/src/receiver.rs +++ b/packages/cw20/src/receiver.rs @@ -1,13 +1,13 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -use cosmwasm_std::{to_binary, Binary, CosmosMsg, HumanAddr, StdResult, Uint128, WasmMsg}; +use cosmwasm_std::{to_binary, Binary, CosmosMsg, StdResult, Uint128, WasmMsg}; /// Cw20ReceiveMsg should be de/serialized under `Receive()` variant in a ExecuteMsg #[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] #[serde(rename_all = "snake_case")] pub struct Cw20ReceiveMsg { - pub sender: HumanAddr, + pub sender: String, pub amount: Uint128, pub msg: Option, } @@ -20,10 +20,10 @@ impl Cw20ReceiveMsg { } /// creates a cosmos_msg sending this struct to the named contract - pub fn into_cosmos_msg(self, contract_addr: HumanAddr) -> StdResult { + pub fn into_cosmos_msg>(self, contract_addr: T) -> StdResult { let msg = self.into_binary()?; let execute = WasmMsg::Execute { - contract_addr, + contract_addr: contract_addr.into(), msg, send: vec![], }; diff --git a/packages/cw3/Cargo.toml b/packages/cw3/Cargo.toml index e1b4ad468..24303a7f3 100644 --- a/packages/cw3/Cargo.toml +++ b/packages/cw3/Cargo.toml @@ -11,9 +11,9 @@ documentation = "https://docs.cosmwasm.com" [dependencies] cw0 = { path = "../../packages/cw0", version = "0.6.0-alpha3" } -cosmwasm-std = { version = "0.14.0-beta1" } -schemars = "0.7" +cosmwasm-std = { version = "0.14.0-beta2" } +schemars = "0.8.1" serde = { version = "1.0.103", default-features = false, features = ["derive"] } [dev-dependencies] -cosmwasm-schema = { version = "0.14.0-beta1" } +cosmwasm-schema = { version = "0.14.0-beta2" } diff --git a/packages/cw3/schema/execute_msg.json b/packages/cw3/schema/execute_msg.json index 64d509a2c..b1512871c 100644 --- a/packages/cw3/schema/execute_msg.json +++ b/packages/cw3/schema/execute_msg.json @@ -50,7 +50,8 @@ } } } - } + }, + "additionalProperties": false }, { "type": "object", @@ -75,7 +76,8 @@ } } } - } + }, + "additionalProperties": false }, { "type": "object", @@ -96,7 +98,8 @@ } } } - } + }, + "additionalProperties": false }, { "type": "object", @@ -117,7 +120,8 @@ } } } - } + }, + "additionalProperties": false } ], "definitions": { @@ -145,11 +149,12 @@ } }, "to_address": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false } ] }, @@ -183,7 +188,8 @@ "bank": { "$ref": "#/definitions/BankMsg" } - } + }, + "additionalProperties": false }, { "type": "object", @@ -194,7 +200,8 @@ "custom": { "$ref": "#/definitions/Empty" } - } + }, + "additionalProperties": false }, { "type": "object", @@ -205,7 +212,8 @@ "staking": { "$ref": "#/definitions/StakingMsg" } - } + }, + "additionalProperties": false }, { "type": "object", @@ -216,7 +224,8 @@ "wasm": { "$ref": "#/definitions/WasmMsg" } - } + }, + "additionalProperties": false } ] }, @@ -239,7 +248,8 @@ "format": "uint64", "minimum": 0.0 } - } + }, + "additionalProperties": false }, { "description": "AtTime will expire when `env.block.time` >= time", @@ -253,7 +263,8 @@ "format": "uint64", "minimum": 0.0 } - } + }, + "additionalProperties": false }, { "description": "Never will never expire. Used to express the empty variant", @@ -265,13 +276,11 @@ "never": { "type": "object" } - } + }, + "additionalProperties": false } ] }, - "HumanAddr": { - "type": "string" - }, "StakingMsg": { "description": "The message types of the staking module.\n\nSee https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto", "anyOf": [ @@ -293,11 +302,12 @@ "$ref": "#/definitions/Coin" }, "validator": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "This is translated to a [MsgUndelegate](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L112-L121). `delegator_address` is automatically filled with the current contract's address.", @@ -317,11 +327,12 @@ "$ref": "#/definitions/Coin" }, "validator": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "This is translated to a [MsgSetWithdrawAddress](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/distribution/v1beta1/tx.proto#L29-L37) followed by a [MsgWithdrawDelegatorReward](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/distribution/v1beta1/tx.proto#L42-L50). `delegator_address` is automatically filled with the current contract's address.", @@ -338,21 +349,18 @@ "properties": { "recipient": { "description": "this is the \"withdraw address\", the one that should receive the rewards if None, then use delegator address", - "anyOf": [ - { - "$ref": "#/definitions/HumanAddr" - }, - { - "type": "null" - } + "type": [ + "string", + "null" ] }, "validator": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "This is translated to a [MsgBeginRedelegate](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L95-L105). `delegator_address` is automatically filled with the current contract's address.", @@ -373,14 +381,15 @@ "$ref": "#/definitions/Coin" }, "dst_validator": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "src_validator": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false } ] }, @@ -415,7 +424,7 @@ ], "properties": { "contract_addr": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "msg": { "description": "msg is the json-encoded ExecuteMsg struct (as raw Binary)", @@ -433,7 +442,8 @@ } } } - } + }, + "additionalProperties": false }, { "description": "Instantiates a new contracts from previously uploaded Wasm code.\n\nThis is translated to a [MsgInstantiateContract](https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto#L47-L61). `sender` is automatically filled with the current contract's address.", @@ -476,7 +486,8 @@ } } } - } + }, + "additionalProperties": false }, { "description": "Migrates a given contracts to use new wasm code. Passes a MigrateMsg to allow us to customize behavior.\n\nOnly the contract admin (as defined in wasmd), if any, is able to make this call.\n\nThis is translated to a [MsgMigrateContract](https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto#L86-L96). `sender` is automatically filled with the current contract's address.", @@ -494,7 +505,7 @@ ], "properties": { "contract_addr": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "msg": { "description": "msg is the json-encoded MigrateMsg struct that will be passed to the new code", @@ -512,7 +523,8 @@ } } } - } + }, + "additionalProperties": false } ] } diff --git a/packages/cw3/schema/proposal_list_response.json b/packages/cw3/schema/proposal_list_response.json index 03f7e8f2a..3791efda6 100644 --- a/packages/cw3/schema/proposal_list_response.json +++ b/packages/cw3/schema/proposal_list_response.json @@ -38,11 +38,12 @@ } }, "to_address": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false } ] }, @@ -76,7 +77,8 @@ "bank": { "$ref": "#/definitions/BankMsg" } - } + }, + "additionalProperties": false }, { "type": "object", @@ -87,7 +89,8 @@ "custom": { "$ref": "#/definitions/Empty" } - } + }, + "additionalProperties": false }, { "type": "object", @@ -98,7 +101,8 @@ "staking": { "$ref": "#/definitions/StakingMsg" } - } + }, + "additionalProperties": false }, { "type": "object", @@ -109,7 +113,8 @@ "wasm": { "$ref": "#/definitions/WasmMsg" } - } + }, + "additionalProperties": false } ] }, @@ -136,7 +141,8 @@ "format": "uint64", "minimum": 0.0 } - } + }, + "additionalProperties": false }, { "description": "AtTime will expire when `env.block.time` >= time", @@ -150,7 +156,8 @@ "format": "uint64", "minimum": 0.0 } - } + }, + "additionalProperties": false }, { "description": "Never will never expire. Used to express the empty variant", @@ -162,13 +169,11 @@ "never": { "type": "object" } - } + }, + "additionalProperties": false } ] }, - "HumanAddr": { - "type": "string" - }, "ProposalResponse_for_Empty": { "description": "Note, if you are storing custom messages in the proposal, the querier needs to know what possible custom message types those are in order to parse the response", "type": "object", @@ -236,11 +241,12 @@ "$ref": "#/definitions/Coin" }, "validator": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "This is translated to a [MsgUndelegate](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L112-L121). `delegator_address` is automatically filled with the current contract's address.", @@ -260,11 +266,12 @@ "$ref": "#/definitions/Coin" }, "validator": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "This is translated to a [MsgSetWithdrawAddress](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/distribution/v1beta1/tx.proto#L29-L37) followed by a [MsgWithdrawDelegatorReward](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/distribution/v1beta1/tx.proto#L42-L50). `delegator_address` is automatically filled with the current contract's address.", @@ -281,21 +288,18 @@ "properties": { "recipient": { "description": "this is the \"withdraw address\", the one that should receive the rewards if None, then use delegator address", - "anyOf": [ - { - "$ref": "#/definitions/HumanAddr" - }, - { - "type": "null" - } + "type": [ + "string", + "null" ] }, "validator": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "This is translated to a [MsgBeginRedelegate](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L95-L105). `delegator_address` is automatically filled with the current contract's address.", @@ -316,14 +320,15 @@ "$ref": "#/definitions/Coin" }, "dst_validator": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "src_validator": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false } ] }, @@ -366,7 +371,8 @@ } } } - } + }, + "additionalProperties": false }, { "description": "Declares a percentage of the total weight that must cast Yes votes, in order for a proposal to pass. The passing weight is computed over the total weight minus the weight of the abstained votes.\n\nThis is useful for similar circumstances as `AbsoluteCount`, where we have a relatively small set of voters, and participation is required. It is understood that if the voting set (group) changes between different proposals that refer to the same group, each proposal will work with a different set of voter weights (the ones snapshotted at proposal creation), and the passing weight for each proposal will be computed based on the absolute percentage, times the total weights of the members at the time of each proposal creation.\n\nExample: we set `percentage` to 51%. Proposal 1 starts when there is a `total_weight` of 5. This will require 3 weight of Yes votes in order to pass. Later, the Proposal 2 starts but the `total_weight` of the group has increased to 9. That proposal will then automatically require 5 Yes of 9 to pass, rather than 3 yes of 9 as would be the case with `AbsoluteCount`.", @@ -392,7 +398,8 @@ } } } - } + }, + "additionalProperties": false }, { "description": "In addition to a `threshold`, declares a `quorum` of the total votes that must participate in the election in order for the vote to be considered at all. Within the votes that were cast, it requires `threshold` votes in favor. That is calculated by ignoring the Abstain votes (they count towards `quorum`, but do not influence `threshold`). That is, we calculate `Yes / (Yes + No + Veto)` and compare it with `threshold` to consider if the proposal was passed.\n\nIt is rather difficult for a proposal of this type to pass early. That can only happen if the required quorum has been already met, and there are already enough Yes votes for the proposal to pass.\n\n30% Yes votes, 10% No votes, and 20% Abstain would pass early if quorum <= 60% (who has cast votes) and if the threshold is <= 37.5% (the remaining 40% voting no => 30% yes + 50% no). Once the voting period has passed with no additional votes, that same proposal would be considered successful if quorum <= 60% and threshold <= 75% (percent in favor if we ignore abstain votes).\n\nThis type is more common in general elections, where participation is often expected to be low, and `AbsolutePercentage` would either be too high to pass anything, or allow low percentages to pass, independently of if there was high participation in the election or not.", @@ -422,7 +429,8 @@ } } } - } + }, + "additionalProperties": false } ] }, @@ -448,7 +456,7 @@ ], "properties": { "contract_addr": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "msg": { "description": "msg is the json-encoded ExecuteMsg struct (as raw Binary)", @@ -466,7 +474,8 @@ } } } - } + }, + "additionalProperties": false }, { "description": "Instantiates a new contracts from previously uploaded Wasm code.\n\nThis is translated to a [MsgInstantiateContract](https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto#L47-L61). `sender` is automatically filled with the current contract's address.", @@ -509,7 +518,8 @@ } } } - } + }, + "additionalProperties": false }, { "description": "Migrates a given contracts to use new wasm code. Passes a MigrateMsg to allow us to customize behavior.\n\nOnly the contract admin (as defined in wasmd), if any, is able to make this call.\n\nThis is translated to a [MsgMigrateContract](https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto#L86-L96). `sender` is automatically filled with the current contract's address.", @@ -527,7 +537,7 @@ ], "properties": { "contract_addr": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "msg": { "description": "msg is the json-encoded MigrateMsg struct that will be passed to the new code", @@ -545,7 +555,8 @@ } } } - } + }, + "additionalProperties": false } ] } diff --git a/packages/cw3/schema/proposal_response.json b/packages/cw3/schema/proposal_response.json index 02c5eac54..a150f15d5 100644 --- a/packages/cw3/schema/proposal_response.json +++ b/packages/cw3/schema/proposal_response.json @@ -70,11 +70,12 @@ } }, "to_address": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false } ] }, @@ -108,7 +109,8 @@ "bank": { "$ref": "#/definitions/BankMsg" } - } + }, + "additionalProperties": false }, { "type": "object", @@ -119,7 +121,8 @@ "custom": { "$ref": "#/definitions/Empty" } - } + }, + "additionalProperties": false }, { "type": "object", @@ -130,7 +133,8 @@ "staking": { "$ref": "#/definitions/StakingMsg" } - } + }, + "additionalProperties": false }, { "type": "object", @@ -141,7 +145,8 @@ "wasm": { "$ref": "#/definitions/WasmMsg" } - } + }, + "additionalProperties": false } ] }, @@ -168,7 +173,8 @@ "format": "uint64", "minimum": 0.0 } - } + }, + "additionalProperties": false }, { "description": "AtTime will expire when `env.block.time` >= time", @@ -182,7 +188,8 @@ "format": "uint64", "minimum": 0.0 } - } + }, + "additionalProperties": false }, { "description": "Never will never expire. Used to express the empty variant", @@ -194,13 +201,11 @@ "never": { "type": "object" } - } + }, + "additionalProperties": false } ] }, - "HumanAddr": { - "type": "string" - }, "StakingMsg": { "description": "The message types of the staking module.\n\nSee https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto", "anyOf": [ @@ -222,11 +227,12 @@ "$ref": "#/definitions/Coin" }, "validator": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "This is translated to a [MsgUndelegate](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L112-L121). `delegator_address` is automatically filled with the current contract's address.", @@ -246,11 +252,12 @@ "$ref": "#/definitions/Coin" }, "validator": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "This is translated to a [MsgSetWithdrawAddress](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/distribution/v1beta1/tx.proto#L29-L37) followed by a [MsgWithdrawDelegatorReward](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/distribution/v1beta1/tx.proto#L42-L50). `delegator_address` is automatically filled with the current contract's address.", @@ -267,21 +274,18 @@ "properties": { "recipient": { "description": "this is the \"withdraw address\", the one that should receive the rewards if None, then use delegator address", - "anyOf": [ - { - "$ref": "#/definitions/HumanAddr" - }, - { - "type": "null" - } + "type": [ + "string", + "null" ] }, "validator": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "This is translated to a [MsgBeginRedelegate](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L95-L105). `delegator_address` is automatically filled with the current contract's address.", @@ -302,14 +306,15 @@ "$ref": "#/definitions/Coin" }, "dst_validator": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "src_validator": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false } ] }, @@ -352,7 +357,8 @@ } } } - } + }, + "additionalProperties": false }, { "description": "Declares a percentage of the total weight that must cast Yes votes, in order for a proposal to pass. The passing weight is computed over the total weight minus the weight of the abstained votes.\n\nThis is useful for similar circumstances as `AbsoluteCount`, where we have a relatively small set of voters, and participation is required. It is understood that if the voting set (group) changes between different proposals that refer to the same group, each proposal will work with a different set of voter weights (the ones snapshotted at proposal creation), and the passing weight for each proposal will be computed based on the absolute percentage, times the total weights of the members at the time of each proposal creation.\n\nExample: we set `percentage` to 51%. Proposal 1 starts when there is a `total_weight` of 5. This will require 3 weight of Yes votes in order to pass. Later, the Proposal 2 starts but the `total_weight` of the group has increased to 9. That proposal will then automatically require 5 Yes of 9 to pass, rather than 3 yes of 9 as would be the case with `AbsoluteCount`.", @@ -378,7 +384,8 @@ } } } - } + }, + "additionalProperties": false }, { "description": "In addition to a `threshold`, declares a `quorum` of the total votes that must participate in the election in order for the vote to be considered at all. Within the votes that were cast, it requires `threshold` votes in favor. That is calculated by ignoring the Abstain votes (they count towards `quorum`, but do not influence `threshold`). That is, we calculate `Yes / (Yes + No + Veto)` and compare it with `threshold` to consider if the proposal was passed.\n\nIt is rather difficult for a proposal of this type to pass early. That can only happen if the required quorum has been already met, and there are already enough Yes votes for the proposal to pass.\n\n30% Yes votes, 10% No votes, and 20% Abstain would pass early if quorum <= 60% (who has cast votes) and if the threshold is <= 37.5% (the remaining 40% voting no => 30% yes + 50% no). Once the voting period has passed with no additional votes, that same proposal would be considered successful if quorum <= 60% and threshold <= 75% (percent in favor if we ignore abstain votes).\n\nThis type is more common in general elections, where participation is often expected to be low, and `AbsolutePercentage` would either be too high to pass anything, or allow low percentages to pass, independently of if there was high participation in the election or not.", @@ -408,7 +415,8 @@ } } } - } + }, + "additionalProperties": false } ] }, @@ -434,7 +442,7 @@ ], "properties": { "contract_addr": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "msg": { "description": "msg is the json-encoded ExecuteMsg struct (as raw Binary)", @@ -452,7 +460,8 @@ } } } - } + }, + "additionalProperties": false }, { "description": "Instantiates a new contracts from previously uploaded Wasm code.\n\nThis is translated to a [MsgInstantiateContract](https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto#L47-L61). `sender` is automatically filled with the current contract's address.", @@ -495,7 +504,8 @@ } } } - } + }, + "additionalProperties": false }, { "description": "Migrates a given contracts to use new wasm code. Passes a MigrateMsg to allow us to customize behavior.\n\nOnly the contract admin (as defined in wasmd), if any, is able to make this call.\n\nThis is translated to a [MsgMigrateContract](https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto#L86-L96). `sender` is automatically filled with the current contract's address.", @@ -513,7 +523,7 @@ ], "properties": { "contract_addr": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "msg": { "description": "msg is the json-encoded MigrateMsg struct that will be passed to the new code", @@ -531,7 +541,8 @@ } } } - } + }, + "additionalProperties": false } ] } diff --git a/packages/cw3/schema/query_msg.json b/packages/cw3/schema/query_msg.json index 2c2e04dc3..39c5b003e 100644 --- a/packages/cw3/schema/query_msg.json +++ b/packages/cw3/schema/query_msg.json @@ -12,7 +12,8 @@ "threshold": { "type": "object" } - } + }, + "additionalProperties": false }, { "description": "Returns details of the proposal state. Returns ProposalResponse.", @@ -34,7 +35,8 @@ } } } - } + }, + "additionalProperties": false }, { "description": "Iterate over details of all proposals from oldest to newest. Returns ProposalListResponse", @@ -64,7 +66,8 @@ } } } - } + }, + "additionalProperties": false }, { "description": "Iterate reverse over details of all proposals, this is useful to easily query only the most recent proposals (to get updates). Returns ProposalListResponse", @@ -94,7 +97,8 @@ } } } - } + }, + "additionalProperties": false }, { "description": "Query the vote made by the given voter on `proposal_id`. This should return an error if there is no such proposal. It will return a None value if the proposal exists but the voter did not vote. Returns VoteResponse", @@ -116,14 +120,15 @@ "minimum": 0.0 }, "voter": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false }, { - "description": "Iterate (with pagination) over all votes for this proposal. The ordering is arbitrary, unlikely to be sorted by HumanAddr. But ordering is consistent and pagination from the end of each page will cover all votes for the proposal. Returns VoteListResponse", + "description": "Iterate (with pagination) over all votes for this proposal. The ordering is arbitrary, unlikely to be sorted by address. But ordering is consistent and pagination from the end of each page will cover all votes for the proposal. Returns VoteListResponse", "type": "object", "required": [ "list_votes" @@ -149,18 +154,15 @@ "minimum": 0.0 }, "start_after": { - "anyOf": [ - { - "$ref": "#/definitions/HumanAddr" - }, - { - "type": "null" - } + "type": [ + "string", + "null" ] } } } - } + }, + "additionalProperties": false }, { "description": "Voter extension: Returns VoterResponse", @@ -176,11 +178,12 @@ ], "properties": { "address": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "ListVoters extension: Returns VoterListResponse", @@ -201,23 +204,15 @@ "minimum": 0.0 }, "start_after": { - "anyOf": [ - { - "$ref": "#/definitions/HumanAddr" - }, - { - "type": "null" - } + "type": [ + "string", + "null" ] } } } - } - } - ], - "definitions": { - "HumanAddr": { - "type": "string" + }, + "additionalProperties": false } - } + ] } diff --git a/packages/cw3/schema/threshold_response.json b/packages/cw3/schema/threshold_response.json index 3eed276a5..022e88bc7 100644 --- a/packages/cw3/schema/threshold_response.json +++ b/packages/cw3/schema/threshold_response.json @@ -29,7 +29,8 @@ } } } - } + }, + "additionalProperties": false }, { "description": "Declares a percentage of the total weight that must cast Yes votes, in order for a proposal to pass. The passing weight is computed over the total weight minus the weight of the abstained votes.\n\nThis is useful for similar circumstances as `AbsoluteCount`, where we have a relatively small set of voters, and participation is required. It is understood that if the voting set (group) changes between different proposals that refer to the same group, each proposal will work with a different set of voter weights (the ones snapshotted at proposal creation), and the passing weight for each proposal will be computed based on the absolute percentage, times the total weights of the members at the time of each proposal creation.\n\nExample: we set `percentage` to 51%. Proposal 1 starts when there is a `total_weight` of 5. This will require 3 weight of Yes votes in order to pass. Later, the Proposal 2 starts but the `total_weight` of the group has increased to 9. That proposal will then automatically require 5 Yes of 9 to pass, rather than 3 yes of 9 as would be the case with `AbsoluteCount`.", @@ -55,7 +56,8 @@ } } } - } + }, + "additionalProperties": false }, { "description": "In addition to a `threshold`, declares a `quorum` of the total votes that must participate in the election in order for the vote to be considered at all. Within the votes that were cast, it requires `threshold` votes in favor. That is calculated by ignoring the Abstain votes (they count towards `quorum`, but do not influence `threshold`). That is, we calculate `Yes / (Yes + No + Veto)` and compare it with `threshold` to consider if the proposal was passed.\n\nIt is rather difficult for a proposal of this type to pass early. That can only happen if the required quorum has been already met, and there are already enough Yes votes for the proposal to pass.\n\n30% Yes votes, 10% No votes, and 20% Abstain would pass early if quorum <= 60% (who has cast votes) and if the threshold is <= 37.5% (the remaining 40% voting no => 30% yes + 50% no). Once the voting period has passed with no additional votes, that same proposal would be considered successful if quorum <= 60% and threshold <= 75% (percent in favor if we ignore abstain votes).\n\nThis type is more common in general elections, where participation is often expected to be low, and `AbsolutePercentage` would either be too high to pass anything, or allow low percentages to pass, independently of if there was high participation in the election or not.", @@ -85,7 +87,8 @@ } } } - } + }, + "additionalProperties": false } ], "definitions": { diff --git a/packages/cw3/schema/vote_list_response.json b/packages/cw3/schema/vote_list_response.json index 93f7f9fb6..d0c22b6ba 100644 --- a/packages/cw3/schema/vote_list_response.json +++ b/packages/cw3/schema/vote_list_response.json @@ -14,9 +14,6 @@ } }, "definitions": { - "HumanAddr": { - "type": "string" - }, "Vote": { "type": "string", "enum": [ @@ -39,7 +36,7 @@ "$ref": "#/definitions/Vote" }, "voter": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "weight": { "type": "integer", diff --git a/packages/cw3/schema/vote_response.json b/packages/cw3/schema/vote_response.json index ea774c58c..eaf97cfee 100644 --- a/packages/cw3/schema/vote_response.json +++ b/packages/cw3/schema/vote_response.json @@ -15,9 +15,6 @@ } }, "definitions": { - "HumanAddr": { - "type": "string" - }, "Vote": { "type": "string", "enum": [ @@ -40,7 +37,7 @@ "$ref": "#/definitions/Vote" }, "voter": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "weight": { "type": "integer", diff --git a/packages/cw3/schema/voter_detail.json b/packages/cw3/schema/voter_detail.json index ac1c52360..b9543b60a 100644 --- a/packages/cw3/schema/voter_detail.json +++ b/packages/cw3/schema/voter_detail.json @@ -8,17 +8,12 @@ ], "properties": { "addr": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "weight": { "type": "integer", "format": "uint64", "minimum": 0.0 } - }, - "definitions": { - "HumanAddr": { - "type": "string" - } } } diff --git a/packages/cw3/schema/voter_list_response.json b/packages/cw3/schema/voter_list_response.json index b0d80ca28..17535bdc9 100644 --- a/packages/cw3/schema/voter_list_response.json +++ b/packages/cw3/schema/voter_list_response.json @@ -14,9 +14,6 @@ } }, "definitions": { - "HumanAddr": { - "type": "string" - }, "VoterDetail": { "type": "object", "required": [ @@ -25,7 +22,7 @@ ], "properties": { "addr": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "weight": { "type": "integer", diff --git a/packages/cw3/src/helpers.rs b/packages/cw3/src/helpers.rs index d87b19485..52ca005a1 100644 --- a/packages/cw3/src/helpers.rs +++ b/packages/cw3/src/helpers.rs @@ -1,12 +1,12 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -use cosmwasm_std::{to_binary, CosmosMsg, HumanAddr, StdResult, WasmMsg}; +use cosmwasm_std::{to_binary, Addr, CosmosMsg, StdResult, WasmMsg}; use crate::msg::{Cw3ExecuteMsg, Vote}; use cw0::Expiration; -/// Cw3Contract is a wrapper around HumanAddr that provides a lot of helpers +/// Cw3Contract is a wrapper around Addr that provides a lot of helpers /// for working with this. /// /// If you wish to persist this, convert to Cw3CanonicalContract via .canonical() @@ -14,16 +14,16 @@ use cw0::Expiration; /// FIXME: Cw3Contract currently only supports CosmosMsg. When we actually /// use this in some consuming code, we should make it generic over CosmosMsg. #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] -pub struct Cw3Contract(pub HumanAddr); +pub struct Cw3Contract(pub Addr); impl Cw3Contract { - pub fn addr(&self) -> HumanAddr { + pub fn addr(&self) -> Addr { self.0.clone() } pub fn encode_msg(&self, msg: Cw3ExecuteMsg) -> StdResult { Ok(WasmMsg::Execute { - contract_addr: self.addr(), + contract_addr: self.addr().into(), msg: to_binary(&msg)?, send: vec![], } diff --git a/packages/cw3/src/query.rs b/packages/cw3/src/query.rs index d67b918cb..9255460fd 100644 --- a/packages/cw3/src/query.rs +++ b/packages/cw3/src/query.rs @@ -2,7 +2,7 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use std::fmt; -use cosmwasm_std::{CosmosMsg, Decimal, Empty, HumanAddr}; +use cosmwasm_std::{CosmosMsg, Decimal, Empty}; use cw0::Expiration; use crate::msg::Vote; @@ -31,20 +31,20 @@ pub enum Cw3QueryMsg { /// Query the vote made by the given voter on `proposal_id`. This should /// return an error if there is no such proposal. It will return a None value /// if the proposal exists but the voter did not vote. Returns VoteResponse - Vote { proposal_id: u64, voter: HumanAddr }, + Vote { proposal_id: u64, voter: String }, /// Iterate (with pagination) over all votes for this proposal. The ordering is arbitrary, - /// unlikely to be sorted by HumanAddr. But ordering is consistent and pagination from the end + /// unlikely to be sorted by address. But ordering is consistent and pagination from the end /// of each page will cover all votes for the proposal. Returns VoteListResponse ListVotes { proposal_id: u64, - start_after: Option, + start_after: Option, limit: Option, }, /// Voter extension: Returns VoterResponse - Voter { address: HumanAddr }, + Voter { address: String }, /// ListVoters extension: Returns VoterListResponse ListVoters { - start_after: Option, + start_after: Option, limit: Option, }, } @@ -168,7 +168,7 @@ pub struct VoteListResponse { /// the address of the voter who submitted it #[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] pub struct VoteInfo { - pub voter: HumanAddr, + pub voter: String, pub vote: Vote, pub weight: u64, } @@ -190,6 +190,6 @@ pub struct VoterListResponse { #[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] pub struct VoterDetail { - pub addr: HumanAddr, + pub addr: String, pub weight: u64, } diff --git a/packages/cw4/Cargo.toml b/packages/cw4/Cargo.toml index 0b1e2cbb8..77b2c472d 100644 --- a/packages/cw4/Cargo.toml +++ b/packages/cw4/Cargo.toml @@ -10,9 +10,9 @@ homepage = "https://cosmwasm.com" documentation = "https://docs.cosmwasm.com" [dependencies] -cosmwasm-std = { version = "0.14.0-beta1" } -schemars = "0.7" +cosmwasm-std = { version = "0.14.0-beta2" } +schemars = "0.8.1" serde = { version = "1.0.103", default-features = false, features = ["derive"] } [dev-dependencies] -cosmwasm-schema = { version = "0.14.0-beta1" } +cosmwasm-schema = { version = "0.14.0-beta2" } diff --git a/packages/cw4/schema/admin_response.json b/packages/cw4/schema/admin_response.json index 71edb382e..82bf62a3a 100644 --- a/packages/cw4/schema/admin_response.json +++ b/packages/cw4/schema/admin_response.json @@ -4,19 +4,10 @@ "type": "object", "properties": { "admin": { - "anyOf": [ - { - "$ref": "#/definitions/HumanAddr" - }, - { - "type": "null" - } + "type": [ + "string", + "null" ] } - }, - "definitions": { - "HumanAddr": { - "type": "string" - } } } diff --git a/packages/cw4/schema/cw4_execute_msg.json b/packages/cw4/schema/cw4_execute_msg.json index 711d2a130..aeafc9403 100644 --- a/packages/cw4/schema/cw4_execute_msg.json +++ b/packages/cw4/schema/cw4_execute_msg.json @@ -13,18 +13,15 @@ "type": "object", "properties": { "admin": { - "anyOf": [ - { - "$ref": "#/definitions/HumanAddr" - }, - { - "type": "null" - } + "type": [ + "string", + "null" ] } } } - } + }, + "additionalProperties": false }, { "description": "Add a new hook to be informed of all membership changes. Must be called by Admin", @@ -40,11 +37,12 @@ ], "properties": { "addr": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "Remove a hook. Must be called by Admin", @@ -60,16 +58,12 @@ ], "properties": { "addr": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false } - ], - "definitions": { - "HumanAddr": { - "type": "string" - } - } + ] } diff --git a/packages/cw4/schema/cw4_query_msg.json b/packages/cw4/schema/cw4_query_msg.json index 7b1b3abc6..c5ef68d7d 100644 --- a/packages/cw4/schema/cw4_query_msg.json +++ b/packages/cw4/schema/cw4_query_msg.json @@ -12,7 +12,8 @@ "admin": { "type": "object" } - } + }, + "additionalProperties": false }, { "description": "Return TotalWeightResponse", @@ -24,7 +25,8 @@ "total_weight": { "type": "object" } - } + }, + "additionalProperties": false }, { "description": "Returns MembersListResponse", @@ -45,18 +47,15 @@ "minimum": 0.0 }, "start_after": { - "anyOf": [ - { - "$ref": "#/definitions/HumanAddr" - }, - { - "type": "null" - } + "type": [ + "string", + "null" ] } } } - } + }, + "additionalProperties": false }, { "description": "Returns MemberResponse", @@ -72,7 +71,7 @@ ], "properties": { "addr": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "at_height": { "type": [ @@ -84,7 +83,8 @@ } } } - } + }, + "additionalProperties": false }, { "description": "Shows all registered hooks. Returns HooksResponse.", @@ -96,12 +96,8 @@ "hooks": { "type": "object" } - } - } - ], - "definitions": { - "HumanAddr": { - "type": "string" + }, + "additionalProperties": false } - } + ] } diff --git a/packages/cw4/schema/member_changed_hook_msg.json b/packages/cw4/schema/member_changed_hook_msg.json index 017e13943..983f51d12 100644 --- a/packages/cw4/schema/member_changed_hook_msg.json +++ b/packages/cw4/schema/member_changed_hook_msg.json @@ -15,9 +15,6 @@ } }, "definitions": { - "HumanAddr": { - "type": "string" - }, "MemberDiff": { "description": "MemberDiff shows the old and new states for a given cw4 member They cannot both be None. old = None, new = Some -> Insert old = Some, new = Some -> Update old = Some, new = None -> Delete", "type": "object", @@ -26,7 +23,7 @@ ], "properties": { "key": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "new": { "type": [ diff --git a/packages/cw4/schema/member_list_response.json b/packages/cw4/schema/member_list_response.json index cad6cf104..ae09f9bba 100644 --- a/packages/cw4/schema/member_list_response.json +++ b/packages/cw4/schema/member_list_response.json @@ -14,9 +14,6 @@ } }, "definitions": { - "HumanAddr": { - "type": "string" - }, "Member": { "description": "A group member has a weight associated with them. This may all be equal, or may have meaning in the app that makes use of the group (eg. voting power)", "type": "object", @@ -26,7 +23,7 @@ ], "properties": { "addr": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "weight": { "type": "integer", diff --git a/packages/cw4/src/helpers.rs b/packages/cw4/src/helpers.rs index a2013b746..814e4bdf6 100644 --- a/packages/cw4/src/helpers.rs +++ b/packages/cw4/src/helpers.rs @@ -2,8 +2,8 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use cosmwasm_std::{ - from_slice, to_binary, to_vec, Binary, CanonicalAddr, ContractResult, CosmosMsg, Empty, - HumanAddr, QuerierWrapper, QueryRequest, StdError, StdResult, SystemResult, WasmMsg, WasmQuery, + from_slice, to_binary, to_vec, Addr, Binary, ContractResult, CosmosMsg, Empty, QuerierWrapper, + QueryRequest, StdError, StdResult, SystemResult, WasmMsg, WasmQuery, }; use crate::msg::Cw4ExecuteMsg; @@ -12,52 +12,51 @@ use crate::{ member_key, AdminResponse, Cw4QueryMsg, Member, MemberListResponse, MemberResponse, TOTAL_KEY, }; -/// Cw4Contract is a wrapper around HumanAddr that provides a lot of helpers +/// Cw4Contract is a wrapper around Addr that provides a lot of helpers /// for working with cw4 contracts /// /// If you wish to persist this, convert to Cw4CanonicalContract via .canonical() #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] -pub struct Cw4Contract(pub HumanAddr); +pub struct Cw4Contract(pub Addr); impl Cw4Contract { - pub fn new(addr: HumanAddr) -> Self { + pub fn new(addr: Addr) -> Self { Cw4Contract(addr) } - pub fn addr(&self) -> HumanAddr { + pub fn addr(&self) -> Addr { self.0.clone() } fn encode_msg(&self, msg: Cw4ExecuteMsg) -> StdResult { Ok(WasmMsg::Execute { - contract_addr: self.addr(), + contract_addr: self.addr().into(), msg: to_binary(&msg)?, send: vec![], } .into()) } - pub fn add_hook(&self, addr: HumanAddr) -> StdResult { - let msg = Cw4ExecuteMsg::AddHook { addr }; + pub fn add_hook>(&self, addr: T) -> StdResult { + let msg = Cw4ExecuteMsg::AddHook { addr: addr.into() }; self.encode_msg(msg) } - pub fn remove_hook(&self, addr: HumanAddr) -> StdResult { - let msg = Cw4ExecuteMsg::AddHook { addr }; + pub fn remove_hook>(&self, addr: T) -> StdResult { + let msg = Cw4ExecuteMsg::AddHook { addr: addr.into() }; self.encode_msg(msg) } - pub fn update_admin>( - &self, - admin: Option, - ) -> StdResult { - let msg = Cw4ExecuteMsg::UpdateAdmin { admin }; + pub fn update_admin>(&self, admin: Option) -> StdResult { + let msg = Cw4ExecuteMsg::UpdateAdmin { + admin: admin.map(|x| x.into()), + }; self.encode_msg(msg) } fn encode_smart_query(&self, msg: Cw4QueryMsg) -> StdResult> { Ok(WasmQuery::Smart { - contract_addr: self.addr(), + contract_addr: self.addr().into(), msg: to_binary(&msg)?, } .into()) @@ -65,14 +64,14 @@ impl Cw4Contract { fn encode_raw_query>(&self, key: T) -> QueryRequest { WasmQuery::Raw { - contract_addr: self.addr(), + contract_addr: self.addr().into(), key: key.into(), } .into() } /// Show the hooks - pub fn hooks(&self, querier: &QuerierWrapper) -> StdResult> { + pub fn hooks(&self, querier: &QuerierWrapper) -> StdResult> { let query = self.encode_smart_query(Cw4QueryMsg::Hooks {})?; let res: HooksResponse = querier.query(&query)?; Ok(res.hooks) @@ -85,12 +84,8 @@ impl Cw4Contract { } /// Check if this address is a member, and if so, with which weight - pub fn is_member( - &self, - querier: &QuerierWrapper, - addr: &CanonicalAddr, - ) -> StdResult> { - let path = member_key(addr.as_slice()); + pub fn is_member(&self, querier: &QuerierWrapper, addr: &Addr) -> StdResult> { + let path = member_key(addr.as_ref()); let query = self.encode_raw_query(path); // We have to copy the logic of Querier.query to handle the empty case, and not @@ -117,14 +112,14 @@ impl Cw4Contract { } /// Return the member's weight at the given snapshot - requires a smart query - pub fn member_at_height( + pub fn member_at_height>( &self, querier: &QuerierWrapper, - member: HumanAddr, + member: T, height: u64, ) -> StdResult> { let query = self.encode_smart_query(Cw4QueryMsg::Member { - addr: member, + addr: member.into(), at_height: Some(height), })?; let res: MemberResponse = querier.query(&query)?; @@ -134,7 +129,7 @@ impl Cw4Contract { pub fn list_members( &self, querier: &QuerierWrapper, - start_after: Option, + start_after: Option, limit: Option, ) -> StdResult> { let query = self.encode_smart_query(Cw4QueryMsg::ListMembers { start_after, limit })?; @@ -143,7 +138,7 @@ impl Cw4Contract { } /// Read the admin - pub fn admin(&self, querier: &QuerierWrapper) -> StdResult> { + pub fn admin(&self, querier: &QuerierWrapper) -> StdResult> { let query = self.encode_smart_query(Cw4QueryMsg::Admin {})?; let res: AdminResponse = querier.query(&query)?; Ok(res.admin) diff --git a/packages/cw4/src/hook.rs b/packages/cw4/src/hook.rs index c7bdfc196..517dc57ab 100644 --- a/packages/cw4/src/hook.rs +++ b/packages/cw4/src/hook.rs @@ -1,7 +1,7 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -use cosmwasm_std::{to_binary, Binary, CosmosMsg, HumanAddr, StdResult, WasmMsg}; +use cosmwasm_std::{to_binary, Binary, CosmosMsg, StdResult, WasmMsg}; /// MemberDiff shows the old and new states for a given cw4 member /// They cannot both be None. @@ -10,17 +10,13 @@ use cosmwasm_std::{to_binary, Binary, CosmosMsg, HumanAddr, StdResult, WasmMsg}; /// old = Some, new = None -> Delete #[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] pub struct MemberDiff { - pub key: HumanAddr, + pub key: String, pub old: Option, pub new: Option, } impl MemberDiff { - pub fn new>( - addr: T, - old_weight: Option, - new_weight: Option, - ) -> Self { + pub fn new>(addr: T, old_weight: Option, new_weight: Option) -> Self { MemberDiff { key: addr.into(), old: old_weight, @@ -53,10 +49,10 @@ impl MemberChangedHookMsg { } /// creates a cosmos_msg sending this struct to the named contract - pub fn into_cosmos_msg(self, contract_addr: HumanAddr) -> StdResult { + pub fn into_cosmos_msg>(self, contract_addr: T) -> StdResult { let msg = self.into_binary()?; let execute = WasmMsg::Execute { - contract_addr, + contract_addr: contract_addr.into(), msg, send: vec![], }; diff --git a/packages/cw4/src/msg.rs b/packages/cw4/src/msg.rs index c316638df..291857ce7 100644 --- a/packages/cw4/src/msg.rs +++ b/packages/cw4/src/msg.rs @@ -1,15 +1,13 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -use cosmwasm_std::HumanAddr; - #[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] #[serde(rename_all = "snake_case")] pub enum Cw4ExecuteMsg { /// Change the admin - UpdateAdmin { admin: Option }, + UpdateAdmin { admin: Option }, /// Add a new hook to be informed of all membership changes. Must be called by Admin - AddHook { addr: HumanAddr }, + AddHook { addr: String }, /// Remove a hook. Must be called by Admin - RemoveHook { addr: HumanAddr }, + RemoveHook { addr: String }, } diff --git a/packages/cw4/src/query.rs b/packages/cw4/src/query.rs index 200338f21..d82734264 100644 --- a/packages/cw4/src/query.rs +++ b/packages/cw4/src/query.rs @@ -1,8 +1,6 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -use cosmwasm_std::HumanAddr; - #[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] #[serde(rename_all = "snake_case")] pub enum Cw4QueryMsg { @@ -12,12 +10,12 @@ pub enum Cw4QueryMsg { TotalWeight {}, /// Returns MembersListResponse ListMembers { - start_after: Option, + start_after: Option, limit: Option, }, /// Returns MemberResponse Member { - addr: HumanAddr, + addr: String, at_height: Option, }, /// Shows all registered hooks. Returns HooksResponse. @@ -26,7 +24,7 @@ pub enum Cw4QueryMsg { #[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] pub struct AdminResponse { - pub admin: Option, + pub admin: Option, } /// A group member has a weight associated with them. @@ -34,7 +32,7 @@ pub struct AdminResponse { /// makes use of the group (eg. voting power) #[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] pub struct Member { - pub addr: HumanAddr, + pub addr: String, pub weight: u64, } @@ -55,7 +53,7 @@ pub struct TotalWeightResponse { #[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] pub struct HooksResponse { - pub hooks: Vec, + pub hooks: Vec, } /// TOTAL_KEY is meant for raw queries @@ -64,13 +62,10 @@ pub const MEMBERS_KEY: &str = "members"; pub const MEMBERS_CHECKPOINTS: &str = "members__checkpoints"; pub const MEMBERS_CHANGELOG: &str = "members__changelog"; -/// member_key is meant for raw queries for one member, given canonical address -pub fn member_key(address: &[u8]) -> Vec { - // FIXME?: Inlined here to avoid storage-plus import - if MEMBERS_KEY.len() > 0xFF { - panic!("only supports member keys up to length 0xFF") - } +/// member_key is meant for raw queries for one member, given address +pub fn member_key(address: &str) -> Vec { + // FIXME: Inlined here to avoid storage-plus import let mut key = [b"\x00", &[MEMBERS_KEY.len() as u8], MEMBERS_KEY.as_bytes()].concat(); - key.extend_from_slice(address); + key.extend_from_slice(address.as_bytes()); key } diff --git a/packages/cw721/Cargo.toml b/packages/cw721/Cargo.toml index 082c5f7a0..fad1c9ba3 100644 --- a/packages/cw721/Cargo.toml +++ b/packages/cw721/Cargo.toml @@ -11,9 +11,9 @@ documentation = "https://docs.cosmwasm.com" [dependencies] cw0 = { path = "../../packages/cw0", version = "0.6.0-alpha3" } -cosmwasm-std = { version = "0.14.0-beta1" } -schemars = "0.7" +cosmwasm-std = { version = "0.14.0-beta2" } +schemars = "0.8.1" serde = { version = "1.0.103", default-features = false, features = ["derive"] } [dev-dependencies] -cosmwasm-schema = { version = "0.14.0-beta1" } +cosmwasm-schema = { version = "0.14.0-beta2" } diff --git a/packages/cw721/schema/all_nft_info_response.json b/packages/cw721/schema/all_nft_info_response.json index 1a3214ed1..317248590 100644 --- a/packages/cw721/schema/all_nft_info_response.json +++ b/packages/cw721/schema/all_nft_info_response.json @@ -42,11 +42,7 @@ }, "spender": { "description": "Account that can transfer/send the token", - "allOf": [ - { - "$ref": "#/definitions/HumanAddr" - } - ] + "type": "string" } } }, @@ -65,7 +61,8 @@ "format": "uint64", "minimum": 0.0 } - } + }, + "additionalProperties": false }, { "description": "AtTime will expire when `env.block.time` >= time", @@ -79,7 +76,8 @@ "format": "uint64", "minimum": 0.0 } - } + }, + "additionalProperties": false }, { "description": "Never will never expire. Used to express the empty variant", @@ -91,13 +89,11 @@ "never": { "type": "object" } - } + }, + "additionalProperties": false } ] }, - "HumanAddr": { - "type": "string" - }, "NftInfoResponse": { "type": "object", "required": [ @@ -138,11 +134,7 @@ }, "owner": { "description": "Owner of the token", - "allOf": [ - { - "$ref": "#/definitions/HumanAddr" - } - ] + "type": "string" } } } diff --git a/packages/cw721/schema/approved_for_all_response.json b/packages/cw721/schema/approved_for_all_response.json index 5b013ee49..ce7407ba5 100644 --- a/packages/cw721/schema/approved_for_all_response.json +++ b/packages/cw721/schema/approved_for_all_response.json @@ -31,11 +31,7 @@ }, "spender": { "description": "Account that can transfer/send the token", - "allOf": [ - { - "$ref": "#/definitions/HumanAddr" - } - ] + "type": "string" } } }, @@ -54,7 +50,8 @@ "format": "uint64", "minimum": 0.0 } - } + }, + "additionalProperties": false }, { "description": "AtTime will expire when `env.block.time` >= time", @@ -68,7 +65,8 @@ "format": "uint64", "minimum": 0.0 } - } + }, + "additionalProperties": false }, { "description": "Never will never expire. Used to express the empty variant", @@ -80,12 +78,10 @@ "never": { "type": "object" } - } + }, + "additionalProperties": false } ] - }, - "HumanAddr": { - "type": "string" } } } diff --git a/packages/cw721/schema/cw721_execute_msg.json b/packages/cw721/schema/cw721_execute_msg.json index f6a884521..805e5aad7 100644 --- a/packages/cw721/schema/cw721_execute_msg.json +++ b/packages/cw721/schema/cw721_execute_msg.json @@ -17,14 +17,15 @@ ], "properties": { "recipient": { - "$ref": "#/definitions/HumanAddr" + "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.", @@ -41,7 +42,7 @@ ], "properties": { "contract": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "msg": { "anyOf": [ @@ -58,7 +59,8 @@ } } } - } + }, + "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", @@ -85,14 +87,15 @@ ] }, "spender": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "token_id": { "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "Remove previously granted Approval", @@ -109,14 +112,15 @@ ], "properties": { "spender": { - "$ref": "#/definitions/HumanAddr" + "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", @@ -142,11 +146,12 @@ ] }, "operator": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false }, { "description": "Remove previously granted ApproveAll permission", @@ -162,11 +167,12 @@ ], "properties": { "operator": { - "$ref": "#/definitions/HumanAddr" + "type": "string" } } } - } + }, + "additionalProperties": false } ], "definitions": { @@ -189,7 +195,8 @@ "format": "uint64", "minimum": 0.0 } - } + }, + "additionalProperties": false }, { "description": "AtTime will expire when `env.block.time` >= time", @@ -203,7 +210,8 @@ "format": "uint64", "minimum": 0.0 } - } + }, + "additionalProperties": false }, { "description": "Never will never expire. Used to express the empty variant", @@ -215,12 +223,10 @@ "never": { "type": "object" } - } + }, + "additionalProperties": false } ] - }, - "HumanAddr": { - "type": "string" } } } diff --git a/packages/cw721/schema/cw721_query_msg.json b/packages/cw721/schema/cw721_query_msg.json index 31416e552..32858d55a 100644 --- a/packages/cw721/schema/cw721_query_msg.json +++ b/packages/cw721/schema/cw721_query_msg.json @@ -27,7 +27,8 @@ } } } - } + }, + "additionalProperties": false }, { "description": "List all operators that can access all of the owner's tokens. Return type: `ApprovedForAllResponse`", @@ -58,21 +59,18 @@ "minimum": 0.0 }, "owner": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "start_after": { - "anyOf": [ - { - "$ref": "#/definitions/HumanAddr" - }, - { - "type": "null" - } + "type": [ + "string", + "null" ] } } } - } + }, + "additionalProperties": false }, { "description": "Total number of tokens issued", @@ -84,7 +82,8 @@ "num_tokens": { "type": "object" } - } + }, + "additionalProperties": false }, { "description": "With MetaData Extension. Returns top-level metadata about the contract: `ContractInfoResponse`", @@ -96,7 +95,8 @@ "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`", @@ -116,7 +116,8 @@ } } } - } + }, + "additionalProperties": false }, { "description": "With MetaData Extension. Returns the result of both `NftInfo` and `OwnerOf` as one query as an optimization for clients: `AllNftInfo`", @@ -143,7 +144,8 @@ } } } - } + }, + "additionalProperties": false }, { "description": "With Enumerable extension. Returns all tokens owned by the given address, [] if unset. Return type: TokensResponse.", @@ -167,7 +169,7 @@ "minimum": 0.0 }, "owner": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "start_after": { "type": [ @@ -177,7 +179,8 @@ } } } - } + }, + "additionalProperties": false }, { "description": "With Enumerable extension. Requires pagination. Lists all token_ids controlled by the contract. Return type: TokensResponse.", @@ -205,12 +208,8 @@ } } } - } - } - ], - "definitions": { - "HumanAddr": { - "type": "string" + }, + "additionalProperties": false } - } + ] } diff --git a/packages/cw721/schema/cw721_receive_msg.json b/packages/cw721/schema/cw721_receive_msg.json index eeb5af6fc..1e8e819c9 100644 --- a/packages/cw721/schema/cw721_receive_msg.json +++ b/packages/cw721/schema/cw721_receive_msg.json @@ -19,7 +19,7 @@ ] }, "sender": { - "$ref": "#/definitions/HumanAddr" + "type": "string" }, "token_id": { "type": "string" @@ -29,9 +29,6 @@ "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" - }, - "HumanAddr": { - "type": "string" } } } diff --git a/packages/cw721/schema/owner_of_response.json b/packages/cw721/schema/owner_of_response.json index 8aa467831..2e861d5e4 100644 --- a/packages/cw721/schema/owner_of_response.json +++ b/packages/cw721/schema/owner_of_response.json @@ -16,11 +16,7 @@ }, "owner": { "description": "Owner of the token", - "allOf": [ - { - "$ref": "#/definitions/HumanAddr" - } - ] + "type": "string" } }, "definitions": { @@ -41,11 +37,7 @@ }, "spender": { "description": "Account that can transfer/send the token", - "allOf": [ - { - "$ref": "#/definitions/HumanAddr" - } - ] + "type": "string" } } }, @@ -64,7 +56,8 @@ "format": "uint64", "minimum": 0.0 } - } + }, + "additionalProperties": false }, { "description": "AtTime will expire when `env.block.time` >= time", @@ -78,7 +71,8 @@ "format": "uint64", "minimum": 0.0 } - } + }, + "additionalProperties": false }, { "description": "Never will never expire. Used to express the empty variant", @@ -90,12 +84,10 @@ "never": { "type": "object" } - } + }, + "additionalProperties": false } ] - }, - "HumanAddr": { - "type": "string" } } } diff --git a/packages/cw721/src/helpers.rs b/packages/cw721/src/helpers.rs index 601692dc2..dc59e177c 100644 --- a/packages/cw721/src/helpers.rs +++ b/packages/cw721/src/helpers.rs @@ -2,8 +2,7 @@ use schemars::JsonSchema; use serde::{de::DeserializeOwned, Deserialize, Serialize}; use cosmwasm_std::{ - to_binary, Api, CanonicalAddr, CosmosMsg, HumanAddr, Querier, QuerierWrapper, StdResult, - WasmMsg, WasmQuery, + to_binary, Addr, CosmosMsg, Querier, QuerierWrapper, StdResult, WasmMsg, WasmQuery, }; use crate::{ @@ -11,28 +10,22 @@ use crate::{ Cw721QueryMsg, NftInfoResponse, NumTokensResponse, OwnerOfResponse, TokensResponse, }; -/// Cw721Contract is a wrapper around HumanAddr that provides a lot of helpers +/// Cw721Contract is a wrapper around Addr that provides a lot of helpers /// for working with this. /// /// If you wish to persist this, convert to Cw721CanonicalContract via .canonical() #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] -pub struct Cw721Contract(pub HumanAddr); +pub struct Cw721Contract(pub Addr); impl Cw721Contract { - pub fn addr(&self) -> HumanAddr { + pub fn addr(&self) -> Addr { self.0.clone() } - /// Convert this address to a form fit for storage - pub fn canonical(&self, api: &A) -> StdResult { - let canon = api.canonical_address(&self.0)?; - Ok(Cw721CanonicalContract(canon)) - } - pub fn call(&self, msg: Cw721ExecuteMsg) -> StdResult { let msg = to_binary(&msg)?; Ok(WasmMsg::Execute { - contract_addr: self.addr(), + contract_addr: self.addr().into(), msg, send: vec![], } @@ -45,7 +38,7 @@ impl Cw721Contract { req: Cw721QueryMsg, ) -> StdResult { let query = WasmQuery::Smart { - contract_addr: self.addr(), + contract_addr: self.addr().into(), msg: to_binary(&req)?, } .into(); @@ -67,12 +60,12 @@ impl Cw721Contract { self.query(querier, req) } - pub fn approved_for_all>( + pub fn approved_for_all>( &self, querier: &Q, owner: T, include_expired: bool, - start_after: Option, + start_after: Option, limit: Option, ) -> StdResult> { let req = Cw721QueryMsg::ApprovedForAll { @@ -124,7 +117,7 @@ impl Cw721Contract { } /// With enumerable extension - pub fn tokens>( + pub fn tokens>( &self, querier: &Q, owner: T, @@ -160,16 +153,3 @@ impl Cw721Contract { self.tokens(querier, self.addr(), None, Some(1)).is_ok() } } - -/// This is a respresentation of Cw721Contract for storage. -/// Don't use it directly, just translate to the Cw721Contract when needed. -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] -pub struct Cw721CanonicalContract(pub CanonicalAddr); - -impl Cw721CanonicalContract { - /// Convert this address to a form fit for usage in messages and queries - pub fn human(&self, api: &A) -> StdResult { - let human = api.human_address(&self.0)?; - Ok(Cw721Contract(human)) - } -} diff --git a/packages/cw721/src/lib.rs b/packages/cw721/src/lib.rs index 989377894..cf7f9e945 100644 --- a/packages/cw721/src/lib.rs +++ b/packages/cw721/src/lib.rs @@ -5,7 +5,7 @@ mod receiver; pub use cw0::Expiration; -pub use crate::helpers::{Cw721CanonicalContract, Cw721Contract}; +pub use crate::helpers::Cw721Contract; pub use crate::msg::Cw721ExecuteMsg; pub use crate::query::{ AllNftInfoResponse, Approval, ApprovedForAllResponse, ContractInfoResponse, Cw721QueryMsg, diff --git a/packages/cw721/src/msg.rs b/packages/cw721/src/msg.rs index 035a9f262..5bd7ed41a 100644 --- a/packages/cw721/src/msg.rs +++ b/packages/cw721/src/msg.rs @@ -1,42 +1,36 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -use cosmwasm_std::{Binary, HumanAddr}; +use cosmwasm_std::Binary; use cw0::Expiration; #[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] #[serde(rename_all = "snake_case")] pub enum Cw721ExecuteMsg { /// Transfer is a base message to move a token to another account without triggering actions - TransferNft { - recipient: HumanAddr, - token_id: String, - }, + 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: HumanAddr, + contract: String, token_id: String, msg: Option, }, /// 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: HumanAddr, + spender: String, token_id: String, expires: Option, }, /// Remove previously granted Approval - Revoke { - spender: HumanAddr, - token_id: String, - }, + 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: HumanAddr, + operator: String, expires: Option, }, /// Remove previously granted ApproveAll permission - RevokeAll { operator: HumanAddr }, + RevokeAll { operator: String }, } diff --git a/packages/cw721/src/query.rs b/packages/cw721/src/query.rs index 87e757d8e..ec3c1df85 100644 --- a/packages/cw721/src/query.rs +++ b/packages/cw721/src/query.rs @@ -1,7 +1,6 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -use cosmwasm_std::HumanAddr; use cw0::Expiration; #[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] @@ -17,10 +16,10 @@ pub enum Cw721QueryMsg { /// List all operators that can access all of the owner's tokens. /// Return type: `ApprovedForAllResponse` ApprovedForAll { - owner: HumanAddr, + owner: String, /// unset or false will filter out expired approvals, you must set to true to see them include_expired: Option, - start_after: Option, + start_after: Option, limit: Option, }, /// Total number of tokens issued @@ -46,7 +45,7 @@ pub enum Cw721QueryMsg { /// Returns all tokens owned by the given address, [] if unset. /// Return type: TokensResponse. Tokens { - owner: HumanAddr, + owner: String, start_after: Option, limit: Option, }, @@ -62,7 +61,7 @@ pub enum Cw721QueryMsg { #[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] pub struct OwnerOfResponse { /// Owner of the token - pub owner: HumanAddr, + pub owner: String, /// If set this address is approved to transfer/send the token as well pub approvals: Vec, } @@ -70,7 +69,7 @@ pub struct OwnerOfResponse { #[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] pub struct Approval { /// Account that can transfer/send the token - pub spender: HumanAddr, + pub spender: String, /// When the Approval expires (maybe Expiration::never) pub expires: Expiration, } diff --git a/packages/cw721/src/receiver.rs b/packages/cw721/src/receiver.rs index b6257c623..02c25426d 100644 --- a/packages/cw721/src/receiver.rs +++ b/packages/cw721/src/receiver.rs @@ -1,13 +1,13 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -use cosmwasm_std::{to_binary, Binary, CosmosMsg, HumanAddr, StdResult, WasmMsg}; +use cosmwasm_std::{to_binary, Binary, CosmosMsg, StdResult, WasmMsg}; /// Cw721ReceiveMsg should be de/serialized under `Receive()` variant in a ExecuteMsg #[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] #[serde(rename_all = "snake_case")] pub struct Cw721ReceiveMsg { - pub sender: HumanAddr, + pub sender: String, pub token_id: String, pub msg: Option, } @@ -20,10 +20,10 @@ impl Cw721ReceiveMsg { } /// creates a cosmos_msg sending this struct to the named contract - pub fn into_cosmos_msg(self, contract_addr: HumanAddr) -> StdResult { + pub fn into_cosmos_msg>(self, contract_addr: T) -> StdResult { let msg = self.into_binary()?; let execute = WasmMsg::Execute { - contract_addr, + contract_addr: contract_addr.into(), msg, send: vec![], }; diff --git a/packages/multi-test/Cargo.toml b/packages/multi-test/Cargo.toml index 6c6c291ef..f54fb5eb0 100644 --- a/packages/multi-test/Cargo.toml +++ b/packages/multi-test/Cargo.toml @@ -18,6 +18,6 @@ stargate = ["cosmwasm-std/stargate"] [dependencies] cw0 = { path = "../../packages/cw0", version = "0.6.0-alpha3" } cw-storage-plus = { path = "../../packages/storage-plus", version = "0.6.0-alpha3" } -cosmwasm-std = { version = "0.14.0-beta1" } -schemars = "0.7" +cosmwasm-std = { version = "0.14.0-beta2" } +schemars = "0.8.1" serde = { version = "1.0.103", default-features = false, features = ["derive"] } diff --git a/packages/multi-test/src/app.rs b/packages/multi-test/src/app.rs index a9e077130..f1c9f132f 100644 --- a/packages/multi-test/src/app.rs +++ b/packages/multi-test/src/app.rs @@ -3,9 +3,9 @@ use serde::Serialize; #[cfg(test)] use cosmwasm_std::testing::{mock_env, MockApi}; use cosmwasm_std::{ - from_slice, to_binary, to_vec, Api, Attribute, BankMsg, Binary, BlockInfo, Coin, - ContractResult, CosmosMsg, Empty, HumanAddr, MessageInfo, Querier, QuerierResult, - QuerierWrapper, QueryRequest, Response, SystemError, SystemResult, WasmMsg, + from_slice, to_binary, to_vec, Addr, Api, Attribute, BankMsg, Binary, BlockInfo, Coin, + ContractResult, CosmosMsg, Empty, MessageInfo, Querier, QuerierResult, QuerierWrapper, + QueryRequest, Response, SystemError, SystemResult, WasmMsg, }; use crate::bank::{Bank, BankCache, BankOps, BankRouter}; @@ -48,11 +48,11 @@ impl ActionResponse where C: Clone + fmt::Debug + PartialEq + JsonSchema, { - fn init(input: Response, address: HumanAddr) -> Self { + fn init(input: Response, address: Addr) -> Self { ActionResponse { messages: input.messages, attributes: input.attributes, - data: Some(address.as_bytes().into()), + data: Some(address.as_ref().as_bytes().into()), } } } @@ -127,11 +127,7 @@ where } /// This is an "admin" function to let us adjust bank accounts - pub fn set_bank_balance( - &mut self, - account: HumanAddr, - amount: Vec, - ) -> Result<(), String> { + pub fn set_bank_balance(&mut self, account: Addr, amount: Vec) -> Result<(), String> { self.bank.set_balance(account, amount) } @@ -159,14 +155,14 @@ where /// Create a contract and get the new address. /// This is just a helper around execute() - pub fn instantiate_contract, V: Into>( + pub fn instantiate_contract>( &mut self, code_id: u64, - sender: V, + sender: Addr, init_msg: &T, send_funds: &[Coin], label: U, - ) -> Result { + ) -> Result { // instantiate contract let init_msg = to_binary(init_msg).map_err(|e| e.to_string())?; let msg: CosmosMsg = WasmMsg::Instantiate { @@ -176,16 +172,16 @@ where label: label.into(), } .into(); - let res = self.execute(sender.into(), msg)?; + let res = self.execute(sender, msg)?; parse_contract_addr(&res.data) } /// Execute a contract and process all returned messages. /// This is just a helper around execute() - pub fn execute_contract>( + pub fn execute_contract( &mut self, - sender: U, - contract_addr: U, + sender: Addr, + contract_addr: Addr, msg: &T, send_funds: &[Coin], ) -> Result { @@ -196,13 +192,13 @@ where send: send_funds.to_vec(), } .into(); - self.execute(sender.into(), msg) + self.execute(sender, msg) } /// Runs arbitrary CosmosMsg. /// This will create a cache before the execution, so no state changes are persisted if this /// returns an error, but all are persisted on success. - pub fn execute(&mut self, sender: HumanAddr, msg: CosmosMsg) -> Result { + pub fn execute(&mut self, sender: Addr, msg: CosmosMsg) -> Result { let mut all = self.execute_multi(sender, vec![msg])?; let res = all.pop().unwrap(); Ok(res) @@ -213,7 +209,7 @@ where /// return an error. But all writes are persisted on success. pub fn execute_multi( &mut self, - sender: HumanAddr, + sender: Addr, msgs: Vec>, ) -> Result, String> { // we need to do some caching of storage here, once in the entry point: @@ -239,7 +235,7 @@ where /// Runs arbitrary CosmosMsg. /// This will create a cache before the execution, so no state changes are persisted if this /// returns an error, but all are persisted on success. - pub fn sudo>( + pub fn sudo>( &mut self, contract_addr: U, msg: &T, @@ -310,7 +306,7 @@ where /// /// For normal use cases, you can use Router::execute() or Router::execute_multi(). /// This is designed to be handled internally as part of larger process flows. - fn execute(&mut self, sender: HumanAddr, msg: CosmosMsg) -> Result { + fn execute(&mut self, sender: Addr, msg: CosmosMsg) -> Result { match msg { CosmosMsg::Wasm(msg) => { let (resender, res) = self.handle_wasm(sender, msg)?; @@ -335,7 +331,7 @@ where } } - fn sudo(&mut self, contract_addr: HumanAddr, msg: Vec) -> Result { + fn sudo(&mut self, contract_addr: Addr, msg: Vec) -> Result { let res = self.wasm.sudo(contract_addr.clone(), self.router, msg)?; let mut attributes = res.attributes; // recurse in all messages @@ -354,17 +350,18 @@ where // this returns the contract address as well, so we can properly resend the data fn handle_wasm( &mut self, - sender: HumanAddr, + sender: Addr, msg: WasmMsg, - ) -> Result<(HumanAddr, ActionResponse), String> { + ) -> Result<(Addr, ActionResponse), String> { match msg { WasmMsg::Execute { contract_addr, msg, send, } => { + let contract_addr = Addr::unchecked(contract_addr); // first move the cash - self.send(&sender, &contract_addr, &send)?; + self.send(sender.clone(), contract_addr.clone().into(), &send)?; // then call the contract let info = MessageInfo { sender, @@ -381,9 +378,9 @@ where send, label: _, } => { - let contract_addr = self.wasm.register_contract(code_id as usize)?; + let contract_addr = Addr::unchecked(self.wasm.register_contract(code_id as usize)?); // move the cash - self.send(&sender, &contract_addr, &send)?; + self.send(sender.clone(), contract_addr.clone().into(), &send)?; // then call the contract let info = MessageInfo { sender, @@ -402,32 +399,31 @@ where } } - fn send, U: Into>( + fn send>( &mut self, sender: T, - recipient: U, + recipient: String, amount: &[Coin], ) -> Result { if !amount.is_empty() { - let sender: HumanAddr = sender.into(); let msg = BankMsg::Send { - to_address: recipient.into(), + to_address: recipient, amount: amount.to_vec(), }; - self.bank.execute(sender, msg)?; + self.bank.execute(sender.into(), msg)?; } Ok(AppResponse::default()) } } // this parses the result from a wasm contract init -pub fn parse_contract_addr(data: &Option) -> Result { +pub fn parse_contract_addr(data: &Option) -> Result { let bin = data .as_ref() .ok_or_else(|| "No data response".to_string())? .to_vec(); let str = String::from_utf8(bin).map_err(|e| e.to_string())?; - Ok(HumanAddr::from(str)) + Ok(Addr::unchecked(str)) } #[cfg(test)] @@ -457,7 +453,7 @@ mod test { App::new(api, env.block, bank, || Box::new(MockStorage::new())) } - fn get_balance(router: &App, addr: &HumanAddr) -> Vec + fn get_balance(router: &App, addr: &Addr) -> Vec where C: Clone + fmt::Debug + PartialEq + JsonSchema, { @@ -468,8 +464,8 @@ mod test { fn send_tokens() { let mut router = mock_router(); - let owner = HumanAddr::from("owner"); - let rcpt = HumanAddr::from("receiver"); + let owner = Addr::unchecked("owner"); + let rcpt = Addr::unchecked("receiver"); let init_funds = vec![coin(20, "btc"), coin(100, "eth")]; let rcpt_funds = vec![coin(5, "btc")]; @@ -484,7 +480,7 @@ mod test { // send both tokens let to_send = vec![coin(30, "eth"), coin(5, "btc")]; let msg: CosmosMsg = BankMsg::Send { - to_address: rcpt.clone(), + to_address: rcpt.clone().into(), amount: to_send.clone(), } .into(); @@ -499,7 +495,7 @@ mod test { // cannot send too much let msg = BankMsg::Send { - to_address: rcpt.clone(), + to_address: rcpt.clone().into(), amount: coins(20, "btc"), } .into(); @@ -514,7 +510,7 @@ mod test { let mut router = mock_router(); // set personal balance - let owner = HumanAddr::from("owner"); + let owner = Addr::unchecked("owner"); let init_funds = vec![coin(20, "btc"), coin(100, "eth")]; router .set_bank_balance(owner.clone(), init_funds.clone()) @@ -526,7 +522,7 @@ mod test { payout: coin(5, "eth"), }; let contract_addr = router - .instantiate_contract(code_id, &owner, &msg, &coins(23, "eth"), "Payout") + .instantiate_contract(code_id, owner.clone(), &msg, &coins(23, "eth"), "Payout") .unwrap(); // sender funds deducted @@ -537,13 +533,13 @@ mod test { assert_eq!(funds, coins(23, "eth")); // create empty account - let random = HumanAddr::from("random"); + let random = Addr::unchecked("random"); let funds = get_balance(&router, &random); assert_eq!(funds, vec![]); // do one payout and see money coming in let res = router - .execute_contract(&random, &contract_addr, &EmptyMsg {}, &[]) + .execute_contract(random.clone(), contract_addr.clone(), &EmptyMsg {}, &[]) .unwrap(); assert_eq!(1, res.attributes.len()); assert_eq!(&attr("action", "payout"), &res.attributes[0]); @@ -561,7 +557,7 @@ mod test { let mut router = custom_router(); // set personal balance - let owner = HumanAddr::from("owner"); + let owner = Addr::unchecked("owner"); let init_funds = vec![coin(20, "btc"), coin(100, "eth")]; router .set_bank_balance(owner.clone(), init_funds.clone()) @@ -573,13 +569,13 @@ mod test { payout: coin(5, "eth"), }; let payout_addr = router - .instantiate_contract(payout_id, &owner, &msg, &coins(23, "eth"), "Payout") + .instantiate_contract(payout_id, owner.clone(), &msg, &coins(23, "eth"), "Payout") .unwrap(); // set up reflect contract let reflect_id = router.store_code(contract_reflect()); let reflect_addr = router - .instantiate_contract(reflect_id, &owner, &EmptyMsg {}, &[], "Reflect") + .instantiate_contract(reflect_id, owner.clone(), &EmptyMsg {}, &[], "Reflect") .unwrap(); // reflect account is empty @@ -594,7 +590,7 @@ mod test { // reflecting payout message pays reflect contract let msg = WasmMsg::Execute { - contract_addr: payout_addr.clone(), + contract_addr: payout_addr.clone().into(), msg: b"{}".into(), send: vec![], } @@ -603,7 +599,7 @@ mod test { messages: vec![msg], }; let res = router - .execute_contract(&HumanAddr::from("random"), &reflect_addr, &msgs, &[]) + .execute_contract(Addr::unchecked("random"), reflect_addr.clone(), &msgs, &[]) .unwrap(); // ensure the attributes were relayed from the sub-message @@ -627,7 +623,7 @@ mod test { let mut router = custom_router(); // set personal balance - let owner = HumanAddr::from("owner"); + let owner = Addr::unchecked("owner"); let init_funds = vec![coin(20, "btc"), coin(100, "eth")]; router .set_bank_balance(owner.clone(), init_funds.clone()) @@ -638,7 +634,7 @@ mod test { let reflect_addr = router .instantiate_contract( reflect_id, - &owner, + owner.clone(), &EmptyMsg {}, &coins(40, "eth"), "Reflect", @@ -648,11 +644,11 @@ mod test { // reflect has 40 eth let funds = get_balance(&router, &reflect_addr); assert_eq!(funds, coins(40, "eth")); - let random = HumanAddr::from("random"); + let random = Addr::unchecked("random"); // sending 7 eth works let msg = BankMsg::Send { - to_address: random.clone(), + to_address: random.clone().into(), amount: coins(7, "eth"), } .into(); @@ -660,7 +656,7 @@ mod test { messages: vec![msg], }; let res = router - .execute_contract(&random, &reflect_addr, &msgs, &[]) + .execute_contract(random.clone(), reflect_addr.clone(), &msgs, &[]) .unwrap(); assert_eq!(0, res.attributes.len()); // ensure random got paid @@ -676,12 +672,12 @@ mod test { // sending 8 eth, then 3 btc should fail both let msg = BankMsg::Send { - to_address: random.clone(), + to_address: random.clone().into(), amount: coins(8, "eth"), } .into(); let msg2 = BankMsg::Send { - to_address: random.clone(), + to_address: random.clone().into(), amount: coins(3, "btc"), } .into(); @@ -689,9 +685,9 @@ mod test { messages: vec![msg, msg2], }; let err = router - .execute_contract(&random, &reflect_addr, &msgs, &[]) + .execute_contract(random.clone(), reflect_addr.clone(), &msgs, &[]) .unwrap_err(); - assert_eq!("Cannot subtract 3 from 0", err.as_str()); + assert_eq!("Overflow: Cannot Sub with 0 and 3", err.as_str()); // first one should have been rolled-back on error (no second payment) let funds = get_balance(&router, &random); @@ -709,10 +705,10 @@ mod test { fn sudo_works() { let mut router = custom_router(); - let owner = HumanAddr::from("owner"); + let owner = Addr::unchecked("owner"); let reflect_id = router.store_code(contract_reflect()); let reflect_addr = router - .instantiate_contract(reflect_id, &owner, &EmptyMsg {}, &[], "Reflect") + .instantiate_contract(reflect_id, owner.clone(), &EmptyMsg {}, &[], "Reflect") .unwrap(); // count is 1 @@ -724,7 +720,7 @@ mod test { // sudo let msg = ReflectSudoMsg { set_count: 25 }; - router.sudo(&reflect_addr, &msg).unwrap(); + router.sudo(reflect_addr.clone(), &msg).unwrap(); // count is 25 let ReflectResponse { count } = router diff --git a/packages/multi-test/src/bank.rs b/packages/multi-test/src/bank.rs index 97a701345..046ec2cb4 100644 --- a/packages/multi-test/src/bank.rs +++ b/packages/multi-test/src/bank.rs @@ -1,6 +1,6 @@ use cosmwasm_std::{ - coin, from_slice, to_binary, to_vec, AllBalanceResponse, BalanceResponse, BankMsg, BankQuery, - Binary, Coin, HumanAddr, Storage, + coin, from_slice, to_binary, to_vec, Addr, AllBalanceResponse, BalanceResponse, BankMsg, + BankQuery, Binary, Coin, Storage, }; use crate::transactions::{RepLog, StorageTransaction}; @@ -9,12 +9,7 @@ use cw0::NativeBalance; /// Bank is a minimal contract-like interface that implements a bank module /// It is initialized outside of the trait pub trait Bank { - fn handle( - &self, - storage: &mut dyn Storage, - sender: HumanAddr, - msg: BankMsg, - ) -> Result<(), String>; + fn handle(&self, storage: &mut dyn Storage, sender: Addr, msg: BankMsg) -> Result<(), String>; fn query(&self, storage: &dyn Storage, request: BankQuery) -> Result; @@ -22,7 +17,7 @@ pub trait Bank { fn set_balance( &self, storage: &mut dyn Storage, - account: HumanAddr, + account: Addr, amount: Vec, ) -> Result<(), String>; @@ -43,7 +38,7 @@ impl BankRouter { } // this is an "admin" function to let us adjust bank accounts - pub fn set_balance(&mut self, account: HumanAddr, amount: Vec) -> Result<(), String> { + pub fn set_balance(&mut self, account: Addr, amount: Vec) -> Result<(), String> { self.bank .set_balance(self.storage.as_mut(), account, amount) } @@ -86,7 +81,7 @@ impl<'a> BankCache<'a> { BankOps(self.state.prepare()) } - pub fn execute(&mut self, sender: HumanAddr, msg: BankMsg) -> Result<(), String> { + pub fn execute(&mut self, sender: Addr, msg: BankMsg) -> Result<(), String> { self.router.bank.handle(&mut self.state, sender, msg) } } @@ -96,12 +91,8 @@ pub struct SimpleBank {} impl SimpleBank { // this is an "admin" function to let us adjust bank accounts - pub fn get_balance( - &self, - storage: &dyn Storage, - account: HumanAddr, - ) -> Result, String> { - let raw = storage.get(account.as_bytes()); + pub fn get_balance(&self, storage: &dyn Storage, account: Addr) -> Result, String> { + let raw = storage.get(account.as_ref().as_bytes()); match raw { Some(data) => { let balance: NativeBalance = from_slice(&data).map_err(|e| e.to_string())?; @@ -114,8 +105,8 @@ impl SimpleBank { fn send( &self, storage: &mut dyn Storage, - from_address: HumanAddr, - to_address: HumanAddr, + from_address: Addr, + to_address: Addr, amount: Vec, ) -> Result<(), String> { let a = self.get_balance(storage, from_address.clone())?; @@ -132,14 +123,11 @@ impl SimpleBank { // TODO: use storage-plus when that is on 0.12.. for now just do this by hand impl Bank for SimpleBank { - fn handle( - &self, - storage: &mut dyn Storage, - sender: HumanAddr, - msg: BankMsg, - ) -> Result<(), String> { + fn handle(&self, storage: &mut dyn Storage, sender: Addr, msg: BankMsg) -> Result<(), String> { match msg { - BankMsg::Send { to_address, amount } => self.send(storage, sender, to_address, amount), + BankMsg::Send { to_address, amount } => { + self.send(storage, sender, Addr::unchecked(to_address), amount) + } m => panic!("Unsupported bank message: {:?}", m), } } @@ -147,12 +135,12 @@ impl Bank for SimpleBank { fn query(&self, storage: &dyn Storage, request: BankQuery) -> Result { match request { BankQuery::AllBalances { address } => { - let amount = self.get_balance(storage, address)?; + let amount = self.get_balance(storage, Addr::unchecked(address))?; let res = AllBalanceResponse { amount }; Ok(to_binary(&res).map_err(|e| e.to_string())?) } BankQuery::Balance { address, denom } => { - let all_amounts = self.get_balance(storage, address)?; + let all_amounts = self.get_balance(storage, Addr::unchecked(address))?; let amount = all_amounts .into_iter() .find(|c| c.denom == denom) @@ -168,12 +156,12 @@ impl Bank for SimpleBank { fn set_balance( &self, storage: &mut dyn Storage, - account: HumanAddr, + account: Addr, amount: Vec, ) -> Result<(), String> { let mut balance = NativeBalance(amount); balance.normalize(); - let key = account.as_bytes(); + let key = account.as_ref().as_bytes(); let value = to_vec(&balance).map_err(|e| e.to_string())?; storage.set(key, &value); Ok(()) @@ -195,8 +183,8 @@ mod test { fn get_set_balance() { let mut store = MockStorage::new(); - let owner = HumanAddr::from("owner"); - let rcpt = HumanAddr::from("receiver"); + let owner = Addr::unchecked("owner"); + let rcpt = Addr::unchecked("receiver"); let init_funds = vec![coin(100, "eth"), coin(20, "btc")]; let norm = vec![coin(20, "btc"), coin(100, "eth")]; @@ -213,21 +201,21 @@ mod test { // proper queries work let req = BankQuery::AllBalances { - address: owner.clone(), + address: owner.clone().into(), }; let raw = bank.query(&store, req).unwrap(); let res: AllBalanceResponse = from_slice(&raw).unwrap(); assert_eq!(res.amount, norm); let req = BankQuery::AllBalances { - address: rcpt.clone(), + address: rcpt.clone().into(), }; let raw = bank.query(&store, req).unwrap(); let res: AllBalanceResponse = from_slice(&raw).unwrap(); assert_eq!(res.amount, vec![]); let req = BankQuery::Balance { - address: owner.clone(), + address: owner.clone().into(), denom: "eth".into(), }; let raw = bank.query(&store, req).unwrap(); @@ -235,7 +223,7 @@ mod test { assert_eq!(res.amount, coin(100, "eth")); let req = BankQuery::Balance { - address: owner.clone(), + address: owner.clone().into(), denom: "foobar".into(), }; let raw = bank.query(&store, req).unwrap(); @@ -243,7 +231,7 @@ mod test { assert_eq!(res.amount, coin(0, "foobar")); let req = BankQuery::Balance { - address: rcpt.clone(), + address: rcpt.clone().into(), denom: "eth".into(), }; let raw = bank.query(&store, req).unwrap(); @@ -255,8 +243,8 @@ mod test { fn send_coins() { let mut store = MockStorage::new(); - let owner = HumanAddr::from("owner"); - let rcpt = HumanAddr::from("receiver"); + let owner = Addr::unchecked("owner"); + let rcpt = Addr::unchecked("receiver"); let init_funds = vec![coin(20, "btc"), coin(100, "eth")]; let rcpt_funds = vec![coin(5, "btc")]; @@ -270,7 +258,7 @@ mod test { // send both tokens let to_send = vec![coin(30, "eth"), coin(5, "btc")]; let msg = BankMsg::Send { - to_address: rcpt.clone(), + to_address: rcpt.clone().into(), amount: to_send.clone(), }; bank.handle(&mut store, owner.clone(), msg.clone()).unwrap(); @@ -284,7 +272,7 @@ mod test { // cannot send too much let msg = BankMsg::Send { - to_address: rcpt.clone(), + to_address: rcpt.clone().into(), amount: coins(20, "btc"), }; bank.handle(&mut store, owner.clone(), msg.clone()) diff --git a/packages/multi-test/src/test_helpers.rs b/packages/multi-test/src/test_helpers.rs index 5f7a73c99..1ac23dec5 100644 --- a/packages/multi-test/src/test_helpers.rs +++ b/packages/multi-test/src/test_helpers.rs @@ -77,7 +77,7 @@ fn handle_payout( // always try to payout what was set originally let payout = PAYOUT.load(deps.storage)?; let msg = BankMsg::Send { - to_address: info.sender, + to_address: info.sender.into(), amount: vec![payout.payout], } .into(); diff --git a/packages/multi-test/src/transactions.rs b/packages/multi-test/src/transactions.rs index 5a6b282f2..f87316765 100644 --- a/packages/multi-test/src/transactions.rs +++ b/packages/multi-test/src/transactions.rs @@ -10,7 +10,7 @@ use std::ops::{Bound, RangeBounds}; use cosmwasm_std::Storage; #[cfg(feature = "iterator")] -use cosmwasm_std::{Order, KV}; +use cosmwasm_std::{Order, Pair}; #[cfg(feature = "iterator")] /// The BTreeMap specific key-value pair reference type, as returned by BTreeMap, T>::range. @@ -79,7 +79,7 @@ impl<'a> Storage for StorageTransaction<'a> { start: Option<&[u8]>, end: Option<&[u8]>, order: Order, - ) -> Box + 'b> { + ) -> Box + 'b> { let bounds = range_bounds(start, end); // BTreeMap.range panics if range is start > end. @@ -172,7 +172,7 @@ enum Delta { struct MergeOverlay<'a, L, R> where L: Iterator>, - R: Iterator, + R: Iterator, { left: Peekable, right: Peekable, @@ -183,7 +183,7 @@ where impl<'a, L, R> MergeOverlay<'a, L, R> where L: Iterator>, - R: Iterator, + R: Iterator, { fn new(left: L, right: R, order: Order) -> Self { MergeOverlay { @@ -193,7 +193,7 @@ where } } - fn pick_match(&mut self, lkey: Vec, rkey: Vec) -> Option { + fn pick_match(&mut self, lkey: Vec, rkey: Vec) -> Option { // compare keys - result is such that Ordering::Less => return left side let order = match self.order { Order::Ascending => lkey.cmp(&rkey), @@ -213,7 +213,7 @@ where } /// take_left must only be called when we know self.left.next() will return Some - fn take_left(&mut self) -> Option { + fn take_left(&mut self) -> Option { let (lkey, lval) = self.left.next().unwrap(); match lval { Delta::Set { value } => Some((lkey.clone(), value.clone())), @@ -226,9 +226,9 @@ where impl<'a, L, R> Iterator for MergeOverlay<'a, L, R> where L: Iterator>, - R: Iterator, + R: Iterator, { - type Item = KV; + type Item = Pair; fn next(&mut self) -> Option { let (left, right) = (self.left.peek(), self.right.peek()); @@ -352,7 +352,7 @@ mod test { // unbounded { let iter = store.range(None, None, Order::Ascending); - let elements: Vec = iter.collect(); + let elements: Vec = iter.collect(); assert_eq!( elements, vec![ @@ -366,7 +366,7 @@ mod test { // unbounded (descending) { let iter = store.range(None, None, Order::Descending); - let elements: Vec = iter.collect(); + let elements: Vec = iter.collect(); assert_eq!( elements, vec![ @@ -380,14 +380,14 @@ mod test { // bounded { let iter = store.range(Some(b"f"), Some(b"n"), Order::Ascending); - let elements: Vec = iter.collect(); + let elements: Vec = iter.collect(); assert_eq!(elements, vec![(b"foo".to_vec(), b"bar".to_vec())]); } // bounded (descending) { let iter = store.range(Some(b"air"), Some(b"loop"), Order::Descending); - let elements: Vec = iter.collect(); + let elements: Vec = iter.collect(); assert_eq!( elements, vec![ @@ -400,35 +400,35 @@ mod test { // bounded empty [a, a) { let iter = store.range(Some(b"foo"), Some(b"foo"), Order::Ascending); - let elements: Vec = iter.collect(); + let elements: Vec = iter.collect(); assert_eq!(elements, vec![]); } // bounded empty [a, a) (descending) { let iter = store.range(Some(b"foo"), Some(b"foo"), Order::Descending); - let elements: Vec = iter.collect(); + let elements: Vec = iter.collect(); assert_eq!(elements, vec![]); } // bounded empty [a, b) with b < a { let iter = store.range(Some(b"z"), Some(b"a"), Order::Ascending); - let elements: Vec = iter.collect(); + let elements: Vec = iter.collect(); assert_eq!(elements, vec![]); } // bounded empty [a, b) with b < a (descending) { let iter = store.range(Some(b"z"), Some(b"a"), Order::Descending); - let elements: Vec = iter.collect(); + let elements: Vec = iter.collect(); assert_eq!(elements, vec![]); } // right unbounded { let iter = store.range(Some(b"f"), None, Order::Ascending); - let elements: Vec = iter.collect(); + let elements: Vec = iter.collect(); assert_eq!( elements, vec![ @@ -441,7 +441,7 @@ mod test { // right unbounded (descending) { let iter = store.range(Some(b"f"), None, Order::Descending); - let elements: Vec = iter.collect(); + let elements: Vec = iter.collect(); assert_eq!( elements, vec![ @@ -454,14 +454,14 @@ mod test { // left unbounded { let iter = store.range(None, Some(b"f"), Order::Ascending); - let elements: Vec = iter.collect(); + let elements: Vec = iter.collect(); assert_eq!(elements, vec![(b"ant".to_vec(), b"hill".to_vec()),]); } // left unbounded (descending) { let iter = store.range(None, Some(b"no"), Order::Descending); - let elements: Vec = iter.collect(); + let elements: Vec = iter.collect(); assert_eq!( elements, vec![ diff --git a/packages/multi-test/src/wasm.rs b/packages/multi-test/src/wasm.rs index 41fcc135a..ea8ce8e08 100644 --- a/packages/multi-test/src/wasm.rs +++ b/packages/multi-test/src/wasm.rs @@ -5,8 +5,8 @@ use std::fmt; use std::ops::Deref; use cosmwasm_std::{ - from_slice, Api, Binary, BlockInfo, ContractInfo, CosmosMsg, Deps, DepsMut, Empty, Env, - HumanAddr, MessageInfo, Querier, QuerierWrapper, Response, Storage, SubMsg, WasmQuery, + from_slice, Addr, Api, Binary, BlockInfo, ContractInfo, CosmosMsg, Deps, DepsMut, Empty, Env, + MessageInfo, Querier, QuerierWrapper, Response, Storage, SubMsg, WasmQuery, }; use crate::transactions::{RepLog, StorageTransaction}; @@ -157,6 +157,7 @@ where id: x.id, msg: customize_msg(x.msg), gas_limit: x.gas_limit, + reply_on: Default::default(), }) .collect(), messages: resp.messages.into_iter().map(customize_msg::).collect(), @@ -260,7 +261,7 @@ where { // WasmState - cache this, pass in separate? handlers: HashMap>>, - contracts: HashMap, + contracts: HashMap, // WasmConst block: BlockInfo, api: Box, @@ -308,16 +309,18 @@ where pub fn query(&self, querier: &dyn Querier, request: WasmQuery) -> Result { match request { WasmQuery::Smart { contract_addr, msg } => { - self.query_smart(contract_addr, querier, msg.into()) + self.query_smart(Addr::unchecked(contract_addr), querier, msg.into()) + } + WasmQuery::Raw { contract_addr, key } => { + self.query_raw(Addr::unchecked(contract_addr), &key) } - WasmQuery::Raw { contract_addr, key } => self.query_raw(contract_addr, &key), q => panic!("Unsupported wasm query: {:?}", q), } } pub fn query_smart( &self, - address: HumanAddr, + address: Addr, querier: &dyn Querier, msg: Vec, ) -> Result { @@ -326,7 +329,7 @@ where }) } - pub fn query_raw(&self, address: HumanAddr, key: &[u8]) -> Result { + pub fn query_raw(&self, address: Addr, key: &[u8]) -> Result { let contract = self .contracts .get(&address) @@ -335,7 +338,7 @@ where Ok(data.into()) } - fn get_env>(&self, address: T) -> Env { + fn get_env>(&self, address: T) -> Env { Env { block: self.block.clone(), contract: ContractInfo { @@ -347,7 +350,7 @@ where fn with_storage( &self, querier: &dyn Querier, - address: HumanAddr, + address: Addr, action: F, ) -> Result where @@ -399,15 +402,15 @@ where /// while still getting an immutable reference to router. /// (We cannot take &mut WasmCache) pub struct WasmCacheState<'a> { - contracts: HashMap, - contract_diffs: HashMap>, + contracts: HashMap, + contract_diffs: HashMap>, } /// This is a set of data from the WasmCache with no external reference, /// which can be used to commit to the underlying WasmRouter. pub struct WasmOps { - new_contracts: HashMap, - contract_diffs: Vec<(HumanAddr, RepLog)>, + new_contracts: HashMap, + contract_diffs: Vec<(Addr, RepLog)>, } impl WasmOps { @@ -449,7 +452,7 @@ where /// This just creates an address and empty storage instance, returning the new address /// You must call init after this to set up the contract properly. /// These are separated into two steps to have cleaner return values. - pub fn register_contract(&mut self, code_id: usize) -> Result { + pub fn register_contract(&mut self, code_id: usize) -> Result { if !self.router.handlers.contains_key(&code_id) { return Err("Cannot init contract with unregistered code id".to_string()); } @@ -460,15 +463,15 @@ where } // TODO: better addr generation - fn next_address(&self) -> HumanAddr { + fn next_address(&self) -> Addr { let count = self.router.contracts.len() + self.state.contracts.len(); // we make this longer so it is not rejected by tests - HumanAddr::from("Contract #".to_string() + &count.to_string()) + Addr::unchecked("Contract #".to_string() + &count.to_string()) } pub fn handle( &mut self, - address: HumanAddr, + address: Addr, querier: &dyn Querier, info: MessageInfo, msg: Vec, @@ -495,7 +498,7 @@ where pub fn init( &mut self, - address: HumanAddr, + address: Addr, querier: &dyn Querier, info: MessageInfo, msg: Vec, @@ -522,7 +525,7 @@ where pub fn sudo( &mut self, - address: HumanAddr, + address: Addr, querier: &dyn Querier, msg: Vec, ) -> Result, String> { @@ -563,8 +566,8 @@ impl<'a> WasmCacheState<'a> { fn get_contract<'b>( &'b mut self, - parent: &'a HashMap, - addr: &HumanAddr, + parent: &'a HashMap, + addr: &Addr, ) -> Option<(usize, &'b mut dyn Storage)> { // if we created this transaction if let Some(x) = self.contracts.get_mut(addr) { @@ -588,8 +591,8 @@ impl<'a> WasmCacheState<'a> { fn with_storage( &mut self, querier: &dyn Querier, - parent: &'a HashMap, - address: HumanAddr, + parent: &'a HashMap, + address: Addr, env: Env, api: &dyn Api, action: F, @@ -647,7 +650,12 @@ mod test { // and the error for calling an unregistered contract let info = mock_info("foobar", &[]); let err = cache - .init("unregistered".into(), &querier, info, b"{}".to_vec()) + .init( + Addr::unchecked("unregistered"), + &querier, + info, + b"{}".to_vec(), + ) .unwrap_err(); // Default error message from router when not found assert_eq!(err, "Unregistered contract address"); @@ -660,9 +668,9 @@ mod test { fn update_block() { let mut router = mock_router(); - let BlockInfo { time, height, .. } = router.get_env("foo").block; + let BlockInfo { time, height, .. } = router.get_env(Addr::unchecked("foo")).block; router.update_block(next_block); - let next = router.get_env("foo").block; + let next = router.get_env(Addr::unchecked("foo")).block; assert_eq!(time + 5, next.time); assert_eq!(height + 1, next.height); diff --git a/packages/storage-plus/Cargo.toml b/packages/storage-plus/Cargo.toml index ad70b5e27..d2f2ff6c6 100644 --- a/packages/storage-plus/Cargo.toml +++ b/packages/storage-plus/Cargo.toml @@ -13,6 +13,6 @@ documentation = "https://docs.cosmwasm.com" iterator = ["cosmwasm-std/iterator"] [dependencies] -cosmwasm-std = { version = "0.14.0-beta1" } -schemars = "0.7" +cosmwasm-std = { version = "0.14.0-beta2" } +schemars = "0.8.1" serde = { version = "1.0.103", default-features = false, features = ["derive"] } diff --git a/packages/storage-plus/src/indexed_map.rs b/packages/storage-plus/src/indexed_map.rs index e7f5f30aa..a7744164a 100644 --- a/packages/storage-plus/src/indexed_map.rs +++ b/packages/storage-plus/src/indexed_map.rs @@ -149,7 +149,7 @@ where min: Option, max: Option, order: cosmwasm_std::Order, - ) -> Box>> + 'c> + ) -> Box>> + 'c> where T: 'c, { diff --git a/packages/storage-plus/src/indexes.rs b/packages/storage-plus/src/indexes.rs index 5491f4938..219bc3ad9 100644 --- a/packages/storage-plus/src/indexes.rs +++ b/packages/storage-plus/src/indexes.rs @@ -4,7 +4,7 @@ use serde::de::DeserializeOwned; use serde::{Deserialize, Serialize}; -use cosmwasm_std::{from_slice, Binary, Order, StdError, StdResult, Storage, KV}; +use cosmwasm_std::{from_slice, Binary, Order, Pair, StdError, StdResult, Storage}; use crate::helpers::namespaces_with_key; use crate::keys::EmptyPrefix; @@ -77,8 +77,8 @@ where fn deserialize_multi_kv( store: &dyn Storage, pk_namespace: &[u8], - kv: KV, -) -> StdResult> { + kv: Pair, +) -> StdResult> { let (key, pk_len) = kv; // Deserialize pk_len @@ -175,7 +175,7 @@ where &self, store: &'c dyn Storage, prefix: K::Prefix, - ) -> StdResult>> { + ) -> StdResult>> { self.prefix(prefix) .range(store, None, None, Order::Ascending) .collect() @@ -197,7 +197,7 @@ where min: Option, max: Option, order: Order, - ) -> Box>> + 'c> + ) -> Box>> + 'c> where T: 'c, { @@ -259,7 +259,7 @@ where } } -fn deserialize_unique_kv(kv: KV) -> StdResult> { +fn deserialize_unique_kv(kv: Pair) -> StdResult> { let (_, v) = kv; let t = from_slice::>(&v)?; Ok((t.pk.into(), t.value)) @@ -283,7 +283,7 @@ where } /// returns all items that match this secondary index, always by pk Ascending - pub fn item(&self, store: &dyn Storage, idx: K) -> StdResult>> { + pub fn item(&self, store: &dyn Storage, idx: K) -> StdResult>> { let data = self .idx_map .may_load(store, idx)? @@ -307,7 +307,7 @@ where min: Option, max: Option, order: Order, - ) -> Box>> + 'c> + ) -> Box>> + 'c> where T: 'c, { diff --git a/packages/storage-plus/src/item.rs b/packages/storage-plus/src/item.rs index 9628aa252..a35f177b5 100644 --- a/packages/storage-plus/src/item.rs +++ b/packages/storage-plus/src/item.rs @@ -79,7 +79,7 @@ mod test { use cosmwasm_std::testing::MockStorage; use serde::{Deserialize, Serialize}; - use cosmwasm_std::StdError; + use cosmwasm_std::{OverflowError, OverflowOperation, StdError}; #[derive(Serialize, Deserialize, PartialEq, Debug)] struct Config { @@ -196,9 +196,15 @@ mod test { }; CONFIG.save(&mut store, &cfg).unwrap(); - let output = CONFIG.update(&mut store, &|_c| Err(StdError::underflow(4, 7))); + let output = CONFIG.update(&mut store, &|_c| { + Err(StdError::overflow(OverflowError::new( + OverflowOperation::Sub, + 4, + 7, + ))) + }); match output.unwrap_err() { - StdError::Underflow { .. } => {} + StdError::Overflow { .. } => {} err => panic!("Unexpected error: {:?}", err), } assert_eq!(CONFIG.load(&store).unwrap(), cfg); diff --git a/packages/storage-plus/src/iter_helpers.rs b/packages/storage-plus/src/iter_helpers.rs index 4811a7244..1d6800f4a 100644 --- a/packages/storage-plus/src/iter_helpers.rs +++ b/packages/storage-plus/src/iter_helpers.rs @@ -2,12 +2,12 @@ use serde::de::DeserializeOwned; -use cosmwasm_std::KV; +use cosmwasm_std::Pair; use cosmwasm_std::{from_slice, StdResult}; use crate::helpers::encode_length; -pub(crate) fn deserialize_kv(kv: KV) -> StdResult> { +pub(crate) fn deserialize_kv(kv: Pair) -> StdResult> { let (k, v) = kv; let t = from_slice::(&v)?; Ok((k, t)) @@ -146,7 +146,7 @@ mod namespace_test { // ensure we get proper result from prefixed_range iterator let iter = range_with_prefix(&storage, &prefix, None, None, Order::Descending); - let elements: Vec = iter.collect(); + let elements: Vec = iter.collect(); assert_eq!( elements, vec![ @@ -171,14 +171,14 @@ mod namespace_test { set_with_prefix(&mut storage, &other_prefix, b"moon", b"buggy"); // make sure start and end are applied properly - let res: Vec = + let res: Vec = range_with_prefix(&storage, &prefix, Some(b"b"), Some(b"c"), Order::Ascending) .collect(); assert_eq!(res.len(), 1); assert_eq!(res[0], (b"bar".to_vec(), b"none".to_vec())); // make sure start and end are applied properly - let res: Vec = range_with_prefix( + let res: Vec = range_with_prefix( &storage, &prefix, Some(b"bas"), @@ -188,7 +188,7 @@ mod namespace_test { .collect(); assert_eq!(res.len(), 0); - let res: Vec = + let res: Vec = range_with_prefix(&storage, &prefix, Some(b"ant"), None, Order::Ascending).collect(); assert_eq!(res.len(), 2); assert_eq!(res[0], (b"bar".to_vec(), b"none".to_vec())); diff --git a/packages/storage-plus/src/keys.rs b/packages/storage-plus/src/keys.rs index 1f3240a11..483ee5276 100644 --- a/packages/storage-plus/src/keys.rs +++ b/packages/storage-plus/src/keys.rs @@ -1,3 +1,4 @@ +use cosmwasm_std::Addr; use std::marker::PhantomData; use crate::helpers::namespaces_with_key; @@ -136,6 +137,23 @@ impl<'a> Prefixer<'a> for PkOwned { } } +/// type safe version to ensure address was validated before use. +impl<'a> PrimaryKey<'a> for &'a Addr { + type Prefix = (); + type SubPrefix = (); + + fn key(&self) -> Vec<&[u8]> { + // this is simple, we don't add more prefixes + vec![self.as_ref().as_bytes()] + } +} + +impl<'a> Prefixer<'a> for &'a Addr { + fn prefix(&self) -> Vec<&[u8]> { + vec![&self.as_ref().as_bytes()] + } +} + // this auto-implements PrimaryKey for all the IntKey types (and more!) impl<'a, T: AsRef + From + Clone> PrimaryKey<'a> for T { type Prefix = (); diff --git a/packages/storage-plus/src/map.rs b/packages/storage-plus/src/map.rs index c025f12dd..43e85c1fd 100644 --- a/packages/storage-plus/src/map.rs +++ b/packages/storage-plus/src/map.rs @@ -93,7 +93,7 @@ where min: Option, max: Option, order: cosmwasm_std::Order, - ) -> Box>> + 'c> + ) -> Box>> + 'c> where T: 'c, { diff --git a/packages/storage-plus/src/prefix.rs b/packages/storage-plus/src/prefix.rs index 08d125c4d..3bc16517c 100644 --- a/packages/storage-plus/src/prefix.rs +++ b/packages/storage-plus/src/prefix.rs @@ -3,7 +3,7 @@ use serde::de::DeserializeOwned; use serde::Serialize; use std::marker::PhantomData; -use cosmwasm_std::{Order, StdResult, Storage, KV}; +use cosmwasm_std::{Order, Pair, StdResult, Storage}; use std::ops::Deref; use crate::helpers::nested_namespaces_with_key; @@ -42,7 +42,7 @@ impl Bound { } } -type DeserializeFn = fn(&dyn Storage, &[u8], KV) -> StdResult>; +type DeserializeFn = fn(&dyn Storage, &[u8], Pair) -> StdResult>; #[derive(Clone)] pub struct Prefix @@ -100,7 +100,7 @@ where min: Option, max: Option, order: Order, - ) -> Box>> + 'a> + ) -> Box>> + 'a> where T: 'a, { @@ -133,7 +133,7 @@ pub fn range_with_prefix<'a>( start: Option, end: Option, order: Order, -) -> Box + 'a> { +) -> Box + 'a> { let start = calc_start_bound(namespace, start); let end = calc_end_bound(namespace, end); diff --git a/packages/storage-plus/src/snapshot.rs b/packages/storage-plus/src/snapshot.rs index 95d1070df..d8d0b4f37 100644 --- a/packages/storage-plus/src/snapshot.rs +++ b/packages/storage-plus/src/snapshot.rs @@ -253,7 +253,7 @@ where min: Option, max: Option, order: cosmwasm_std::Order, - ) -> Box>> + 'c> + ) -> Box>> + 'c> where T: 'c, { diff --git a/scripts/publish.sh b/scripts/publish.sh index f0992514b..fd540de85 100755 --- a/scripts/publish.sh +++ b/scripts/publish.sh @@ -4,11 +4,11 @@ command -v shellcheck > /dev/null && shellcheck "$0" # these are imported by other packages BASE_PACKAGES="cw0 storage-plus" -ALL_PACKAGES="controllers cw1 cw2 cw3 cw4 cw20 cw721 multi-test" +ALL_PACKAGES="controllers cw1 cw2 cw3 cw4 cw20 cw721 cw1155 multi-test" # these are imported by other contracts BASE_CONTRACTS="cw1-whitelist cw4-group cw20-base cw721-base" -ALL_CONTRACTS="cw1-subkeys cw3-fixed-multisig cw3-flex-multisig cw4-stake cw20-atomic-swap cw20-bonding cw20-escrow cw20-ics20 cw20-staking" +ALL_CONTRACTS="cw1-subkeys cw3-fixed-multisig cw3-flex-multisig cw4-stake cw20-atomic-swap cw20-bonding cw20-escrow cw20-ics20 cw20-staking cw1155-base" SLEEP_TIME=30