diff --git a/cw20/base/.cargo/config b/cw20/base/.cargo/config index 336b618..7d1a066 100644 --- a/cw20/base/.cargo/config +++ b/cw20/base/.cargo/config @@ -1,4 +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/cw20/base/.gitignore b/cw20/base/.gitignore index dfdaaa6..f9b9a83 100644 --- a/cw20/base/.gitignore +++ b/cw20/base/.gitignore @@ -1,5 +1,6 @@ # Build results /target +/artifacts # Cargo+Git helper file (https://github.com/rust-lang/cargo/blob/0.44.1/src/cargo/sources/git/utils.rs#L320-L327) .cargo-ok diff --git a/cw20/base/Cargo.toml b/cw20/base/Cargo.toml index 15a4735..dc07e42 100644 --- a/cw20/base/Cargo.toml +++ b/cw20/base/Cargo.toml @@ -33,21 +33,22 @@ library = [] [package.metadata.scripts] optimize = """docker run --rm -v "$(pwd)":/code \ + -e CARGO_TERM_COLOR=always \ --mount type=volume,source="$(basename "$(pwd)")_cache",target=/code/target \ --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \ - cosmwasm/rust-optimizer:0.12.3 + cosmwasm/rust-optimizer:0.12.5 """ [dependencies] -cosmwasm-std = "0.16.2" -cosmwasm-storage = "0.16.2" -cw-storage-plus = "0.9.1" -cw0 = "0.9.1" -cw2 = "0.9.1" -cw20 = "0.9.1" -schemars = "0.8.8" -serde = { version = "1.0.130", default-features = false, features = ["derive"] } -thiserror = "1.0.26" +cosmwasm-std = "1.0.0-beta" +cosmwasm-storage = "1.0.0-beta" +cw-storage-plus = "0.12" +cw0 = "0.10" +cw2 = "0.12" +cw20 = "0.12" +schemars = "0.8" +serde = { version = "1.0", default-features = false, features = ["derive"] } +thiserror = "1.0" [dev-dependencies] -cosmwasm-schema = "0.16.2" +cosmwasm-schema = "1.0.0-beta" diff --git a/cw20/base/examples/schema.rs b/cw20/base/examples/schema.rs index 95ad0df..c13d8b6 100644 --- a/cw20/base/examples/schema.rs +++ b/cw20/base/examples/schema.rs @@ -3,11 +3,11 @@ use std::fs::create_dir_all; use cosmwasm_schema::{export_schema, remove_schemas, schema_for}; -use {{crate_name}}::msg::{ExecuteMsg, InstantiateMsg, QueryMsg}; use cw20::{ AllAccountsResponse, AllAllowancesResponse, AllowanceResponse, BalanceResponse, TokenInfoResponse, }; +use {{crate_name}}::msg::{ExecuteMsg, InstantiateMsg, QueryMsg}; fn main() { let mut out_dir = current_dir().unwrap(); diff --git a/cw20/base/schema/all_allowances_response.json b/cw20/base/schema/all_allowances_response.json index 6bb2291..a8a11a5 100644 --- a/cw20/base/schema/all_allowances_response.json +++ b/cw20/base/schema/all_allowances_response.json @@ -35,7 +35,7 @@ }, "Expiration": { "description": "Expiration represents a point in time when some event happens. It can compare with a BlockInfo and will return is_expired() == true once the condition is hit (and for every block in the future)", - "oneOf": [ + "anyOf": [ { "description": "AtHeight will expire when `env.block.height` >= height", "type": "object", diff --git a/cw20/base/schema/allowance_response.json b/cw20/base/schema/allowance_response.json index c4f98d6..71b49ad 100644 --- a/cw20/base/schema/allowance_response.json +++ b/cw20/base/schema/allowance_response.json @@ -17,7 +17,7 @@ "definitions": { "Expiration": { "description": "Expiration represents a point in time when some event happens. It can compare with a BlockInfo and will return is_expired() == true once the condition is hit (and for every block in the future)", - "oneOf": [ + "anyOf": [ { "description": "AtHeight will expire when `env.block.height` >= height", "type": "object", diff --git a/cw20/base/schema/contract_info_response.json b/cw20/base/schema/contract_info_response.json deleted file mode 100644 index a167125..0000000 --- a/cw20/base/schema/contract_info_response.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "ContractInfoResponse", - "type": "object", - "required": [ - "name", - "symbol" - ], - "properties": { - "name": { - "type": "string" - }, - "symbol": { - "type": "string" - } - } -} diff --git a/cw20/base/schema/cw20_execute_msg.json b/cw20/base/schema/cw20_execute_msg.json index e4bc559..4dd7b8a 100644 --- a/cw20/base/schema/cw20_execute_msg.json +++ b/cw20/base/schema/cw20_execute_msg.json @@ -1,7 +1,7 @@ { "$schema": "http://json-schema.org/draft-07/schema#", "title": "Cw20ExecuteMsg", - "oneOf": [ + "anyOf": [ { "description": "Transfer is a base message to move tokens to another account without triggering actions", "type": "object", @@ -316,7 +316,7 @@ }, "EmbeddedLogo": { "description": "This is used to store the logo on the blockchain in an accepted format. Enforce maximum size of 5KB on all variants.", - "oneOf": [ + "anyOf": [ { "description": "Store the Logo as an SVG file. The content must conform to the spec at https://en.wikipedia.org/wiki/Scalable_Vector_Graphics (The contract should do some light-weight sanity-check validation)", "type": "object", @@ -347,7 +347,7 @@ }, "Expiration": { "description": "Expiration represents a point in time when some event happens. It can compare with a BlockInfo and will return is_expired() == true once the condition is hit (and for every block in the future)", - "oneOf": [ + "anyOf": [ { "description": "AtHeight will expire when `env.block.height` >= height", "type": "object", @@ -393,7 +393,7 @@ }, "Logo": { "description": "This is used for uploading logo data, or setting it in InstantiateData", - "oneOf": [ + "anyOf": [ { "description": "A reference to an externally hosted logo. Must be a valid HTTP or HTTPS URL.", "type": "object", diff --git a/cw20/base/schema/execute_msg.json b/cw20/base/schema/execute_msg.json deleted file mode 100644 index 348e00d..0000000 --- a/cw20/base/schema/execute_msg.json +++ /dev/null @@ -1,368 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "ExecuteMsg", - "description": "This is like Cw721ExecuteMsg but we add a Mint command for an owner to make this stand-alone. You will likely want to remove mint and use other control logic in any contract that inherits this.", - "oneOf": [ - { - "description": "Transfer is a base message to move a token to another account without triggering actions", - "type": "object", - "required": [ - "transfer_nft" - ], - "properties": { - "transfer_nft": { - "type": "object", - "required": [ - "recipient", - "token_id" - ], - "properties": { - "recipient": { - "type": "string" - }, - "token_id": { - "type": "string" - } - } - } - }, - "additionalProperties": false - }, - { - "description": "Send is a base message to transfer a token to a contract and trigger an action on the receiving contract.", - "type": "object", - "required": [ - "send_nft" - ], - "properties": { - "send_nft": { - "type": "object", - "required": [ - "contract", - "msg", - "token_id" - ], - "properties": { - "contract": { - "type": "string" - }, - "msg": { - "$ref": "#/definitions/Binary" - }, - "token_id": { - "type": "string" - } - } - } - }, - "additionalProperties": false - }, - { - "description": "Allows operator to transfer / send the token from the owner's account. If expiration is set, then this allowance has a time/height limit", - "type": "object", - "required": [ - "approve" - ], - "properties": { - "approve": { - "type": "object", - "required": [ - "spender", - "token_id" - ], - "properties": { - "expires": { - "anyOf": [ - { - "$ref": "#/definitions/Expiration" - }, - { - "type": "null" - } - ] - }, - "spender": { - "type": "string" - }, - "token_id": { - "type": "string" - } - } - } - }, - "additionalProperties": false - }, - { - "description": "Remove previously granted Approval", - "type": "object", - "required": [ - "revoke" - ], - "properties": { - "revoke": { - "type": "object", - "required": [ - "spender", - "token_id" - ], - "properties": { - "spender": { - "type": "string" - }, - "token_id": { - "type": "string" - } - } - } - }, - "additionalProperties": false - }, - { - "description": "Allows operator to transfer / send any token from the owner's account. If expiration is set, then this allowance has a time/height limit", - "type": "object", - "required": [ - "approve_all" - ], - "properties": { - "approve_all": { - "type": "object", - "required": [ - "operator" - ], - "properties": { - "expires": { - "anyOf": [ - { - "$ref": "#/definitions/Expiration" - }, - { - "type": "null" - } - ] - }, - "operator": { - "type": "string" - } - } - } - }, - "additionalProperties": false - }, - { - "description": "Remove previously granted ApproveAll permission", - "type": "object", - "required": [ - "revoke_all" - ], - "properties": { - "revoke_all": { - "type": "object", - "required": [ - "operator" - ], - "properties": { - "operator": { - "type": "string" - } - } - } - }, - "additionalProperties": false - }, - { - "description": "Mint a new NFT, can only be called by the contract minter", - "type": "object", - "required": [ - "mint" - ], - "properties": { - "mint": { - "$ref": "#/definitions/MintMsg_for_Nullable_Metadata" - } - }, - "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)", - "oneOf": [ - { - "description": "AtHeight will expire when `env.block.height` >= height", - "type": "object", - "required": [ - "at_height" - ], - "properties": { - "at_height": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 - } - }, - "additionalProperties": false - }, - { - "description": "AtTime will expire when `env.block.time` >= time", - "type": "object", - "required": [ - "at_time" - ], - "properties": { - "at_time": { - "$ref": "#/definitions/Timestamp" - } - }, - "additionalProperties": false - }, - { - "description": "Never will never expire. Used to express the empty variant", - "type": "object", - "required": [ - "never" - ], - "properties": { - "never": { - "type": "object" - } - }, - "additionalProperties": false - } - ] - }, - "Metadata": { - "type": "object", - "properties": { - "animation_url": { - "type": [ - "string", - "null" - ] - }, - "attributes": { - "type": [ - "array", - "null" - ], - "items": { - "$ref": "#/definitions/Trait" - } - }, - "background_color": { - "type": [ - "string", - "null" - ] - }, - "description": { - "type": [ - "string", - "null" - ] - }, - "external_url": { - "type": [ - "string", - "null" - ] - }, - "image": { - "type": [ - "string", - "null" - ] - }, - "image_data": { - "type": [ - "string", - "null" - ] - }, - "name": { - "type": [ - "string", - "null" - ] - }, - "youtube_url": { - "type": [ - "string", - "null" - ] - } - } - }, - "MintMsg_for_Nullable_Metadata": { - "type": "object", - "required": [ - "owner", - "token_id" - ], - "properties": { - "extension": { - "description": "Any custom extension used by this contract", - "anyOf": [ - { - "$ref": "#/definitions/Metadata" - }, - { - "type": "null" - } - ] - }, - "owner": { - "description": "The owner of the newly minter NFT", - "type": "string" - }, - "token_id": { - "description": "Unique ID of the NFT", - "type": "string" - }, - "token_uri": { - "description": "Universal resource identifier for this NFT Should point to a JSON file that conforms to the ERC721 Metadata JSON Schema", - "type": [ - "string", - "null" - ] - } - } - }, - "Timestamp": { - "description": "A point in time in nanosecond precision.\n\nThis type can represent times from 1970-01-01T00:00:00Z to 2554-07-21T23:34:33Z.\n\n## Examples\n\n``` # use cosmwasm_std::Timestamp; let ts = Timestamp::from_nanos(1_000_000_202); assert_eq!(ts.nanos(), 1_000_000_202); assert_eq!(ts.seconds(), 1); assert_eq!(ts.subsec_nanos(), 202);\n\nlet ts = ts.plus_seconds(2); assert_eq!(ts.nanos(), 3_000_000_202); assert_eq!(ts.seconds(), 3); assert_eq!(ts.subsec_nanos(), 202); ```", - "allOf": [ - { - "$ref": "#/definitions/Uint64" - } - ] - }, - "Trait": { - "type": "object", - "required": [ - "trait_type", - "value" - ], - "properties": { - "display_type": { - "type": [ - "string", - "null" - ] - }, - "trait_type": { - "type": "string" - }, - "value": { - "type": "string" - } - } - }, - "Uint64": { - "description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```", - "type": "string" - } - } -} diff --git a/cw20/base/schema/instantiate_msg.json b/cw20/base/schema/instantiate_msg.json index 7b9aa1e..c8a3fca 100644 --- a/cw20/base/schema/instantiate_msg.json +++ b/cw20/base/schema/instantiate_msg.json @@ -69,7 +69,7 @@ }, "EmbeddedLogo": { "description": "This is used to store the logo on the blockchain in an accepted format. Enforce maximum size of 5KB on all variants.", - "oneOf": [ + "anyOf": [ { "description": "Store the Logo as an SVG file. The content must conform to the spec at https://en.wikipedia.org/wiki/Scalable_Vector_Graphics (The contract should do some light-weight sanity-check validation)", "type": "object", @@ -133,7 +133,7 @@ }, "Logo": { "description": "This is used for uploading logo data, or setting it in InstantiateData", - "oneOf": [ + "anyOf": [ { "description": "A reference to an externally hosted logo. Must be a valid HTTP or HTTPS URL.", "type": "object", diff --git a/cw20/base/schema/minter_response.json b/cw20/base/schema/minter_response.json deleted file mode 100644 index a20e0d7..0000000 --- a/cw20/base/schema/minter_response.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "MinterResponse", - "description": "Shows who can mint these tokens", - "type": "object", - "required": [ - "minter" - ], - "properties": { - "minter": { - "type": "string" - } - } -} diff --git a/cw20/base/schema/nft_info_response.json b/cw20/base/schema/nft_info_response.json deleted file mode 100644 index fbd9b9b..0000000 --- a/cw20/base/schema/nft_info_response.json +++ /dev/null @@ -1,110 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "NftInfoResponse", - "type": "object", - "properties": { - "extension": { - "description": "You can add any custom metadata here when you extend cw721-base", - "anyOf": [ - { - "$ref": "#/definitions/Metadata" - }, - { - "type": "null" - } - ] - }, - "token_uri": { - "description": "Universal resource identifier for this NFT Should point to a JSON file that conforms to the ERC721 Metadata JSON Schema", - "type": [ - "string", - "null" - ] - } - }, - "definitions": { - "Metadata": { - "type": "object", - "properties": { - "animation_url": { - "type": [ - "string", - "null" - ] - }, - "attributes": { - "type": [ - "array", - "null" - ], - "items": { - "$ref": "#/definitions/Trait" - } - }, - "background_color": { - "type": [ - "string", - "null" - ] - }, - "description": { - "type": [ - "string", - "null" - ] - }, - "external_url": { - "type": [ - "string", - "null" - ] - }, - "image": { - "type": [ - "string", - "null" - ] - }, - "image_data": { - "type": [ - "string", - "null" - ] - }, - "name": { - "type": [ - "string", - "null" - ] - }, - "youtube_url": { - "type": [ - "string", - "null" - ] - } - } - }, - "Trait": { - "type": "object", - "required": [ - "trait_type", - "value" - ], - "properties": { - "display_type": { - "type": [ - "string", - "null" - ] - }, - "trait_type": { - "type": "string" - }, - "value": { - "type": "string" - } - } - } - } -} diff --git a/cw20/base/schema/num_tokens_response.json b/cw20/base/schema/num_tokens_response.json deleted file mode 100644 index 4647c23..0000000 --- a/cw20/base/schema/num_tokens_response.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "NumTokensResponse", - "type": "object", - "required": [ - "count" - ], - "properties": { - "count": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 - } - } -} diff --git a/cw20/base/schema/query_msg.json b/cw20/base/schema/query_msg.json index 369e21f..60aac9e 100644 --- a/cw20/base/schema/query_msg.json +++ b/cw20/base/schema/query_msg.json @@ -1,7 +1,7 @@ { "$schema": "http://json-schema.org/draft-07/schema#", "title": "QueryMsg", - "oneOf": [ + "anyOf": [ { "description": "Returns the current balance of the given address, 0 if unset. Return type: BalanceResponse.", "type": "object", diff --git a/cw20/base/schema/tokens_response.json b/cw20/base/schema/tokens_response.json deleted file mode 100644 index b8e3d75..0000000 --- a/cw20/base/schema/tokens_response.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "TokensResponse", - "type": "object", - "required": [ - "tokens" - ], - "properties": { - "tokens": { - "description": "Contains all token_ids in lexicographical ordering If there are more than `limit`, use `start_from` in future queries to achieve pagination.", - "type": "array", - "items": { - "type": "string" - } - } - } -} diff --git a/cw20/base/src/allowances.rs b/cw20/base/src/allowances.rs index 12a4dc2..663d808 100644 --- a/cw20/base/src/allowances.rs +++ b/cw20/base/src/allowances.rs @@ -243,7 +243,7 @@ pub fn query_allowance(deps: Deps, owner: String, spender: String) -> StdResult< mod tests { use super::*; - use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info}; + use cosmwasm_std::testing::{mock_dependencies_with_balance, mock_env, mock_info}; use cosmwasm_std::{coins, CosmosMsg, SubMsg, Timestamp, WasmMsg}; use cw20::{Cw20Coin, TokenInfoResponse}; @@ -279,7 +279,7 @@ mod tests { #[test] fn increase_decrease_allowances() { - let mut deps = mock_dependencies(&coins(2, "token")); + let mut deps = mock_dependencies_with_balance(&coins(2, "token")); let owner = String::from("addr0001"); let spender = String::from("addr0002"); @@ -361,7 +361,7 @@ mod tests { #[test] fn allowances_independent() { - let mut deps = mock_dependencies(&coins(2, "token")); + let mut deps = mock_dependencies_with_balance(&coins(2, "token")); let owner = String::from("addr0001"); let spender = String::from("addr0002"); @@ -456,7 +456,7 @@ mod tests { #[test] fn no_self_allowance() { - let mut deps = mock_dependencies(&coins(2, "token")); + let mut deps = mock_dependencies_with_balance(&coins(2, "token")); let owner = String::from("addr0001"); let info = mock_info(owner.as_ref(), &[]); @@ -484,7 +484,7 @@ mod tests { #[test] fn transfer_from_respects_limits() { - let mut deps = mock_dependencies(&[]); + let mut deps = mock_dependencies_with_balance(&[]); let owner = String::from("addr0001"); let spender = String::from("addr0002"); let rcpt = String::from("addr0003"); @@ -565,7 +565,7 @@ mod tests { #[test] fn burn_from_respects_limits() { - let mut deps = mock_dependencies(&[]); + let mut deps = mock_dependencies_with_balance(&[]); let owner = String::from("addr0001"); let spender = String::from("addr0002"); @@ -641,7 +641,7 @@ mod tests { #[test] fn send_from_respects_limits() { - let mut deps = mock_dependencies(&[]); + let mut deps = mock_dependencies_with_balance(&[]); let owner = String::from("addr0001"); let spender = String::from("addr0002"); let contract = String::from("cool-dex"); diff --git a/cw20/base/src/contract.rs b/cw20/base/src/contract.rs index 1ba949c..7e999fd 100644 --- a/cw20/base/src/contract.rs +++ b/cw20/base/src/contract.rs @@ -521,7 +521,9 @@ pub fn query_download_logo(deps: Deps) -> StdResult { #[cfg(test)] mod tests { - use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info}; + use cosmwasm_std::testing::{ + mock_dependencies, mock_dependencies_with_balance, mock_env, mock_info, + }; use cosmwasm_std::{coins, from_binary, Addr, CosmosMsg, StdError, SubMsg, WasmMsg}; use super::*; @@ -600,7 +602,7 @@ mod tests { #[test] fn basic() { - let mut deps = mock_dependencies(&[]); + let mut deps = mock_dependencies(); let amount = Uint128::from(11223344u128); let instantiate_msg = InstantiateMsg { name: "Cash Token".to_string(), @@ -635,7 +637,7 @@ mod tests { #[test] fn mintable() { - let mut deps = mock_dependencies(&[]); + let mut deps = mock_dependencies(); let amount = Uint128::new(11223344); let minter = String::from("asmodat"); let limit = Uint128::new(511223344); @@ -682,7 +684,7 @@ mod tests { #[test] fn mintable_over_cap() { - let mut deps = mock_dependencies(&[]); + let mut deps = mock_dependencies(); let amount = Uint128::new(11223344); let minter = String::from("asmodat"); let limit = Uint128::new(11223300); @@ -714,7 +716,7 @@ mod tests { #[test] fn basic() { - let mut deps = mock_dependencies(&[]); + let mut deps = mock_dependencies(); let instantiate_msg = InstantiateMsg { name: "Cash Token".to_string(), symbol: "CASH".to_string(), @@ -754,7 +756,7 @@ mod tests { #[test] fn invalid_marketing() { - let mut deps = mock_dependencies(&[]); + let mut deps = mock_dependencies(); let instantiate_msg = InstantiateMsg { name: "Cash Token".to_string(), symbol: "CASH".to_string(), @@ -785,7 +787,7 @@ mod tests { #[test] fn can_mint_by_minter() { - let mut deps = mock_dependencies(&[]); + let mut deps = mock_dependencies(); let genesis = String::from("genesis"); let amount = Uint128::new(11223344); @@ -832,7 +834,7 @@ mod tests { #[test] fn others_cannot_mint() { - let mut deps = mock_dependencies(&[]); + let mut deps = mock_dependencies(); do_instantiate_with_minter( deps.as_mut(), &String::from("genesis"), @@ -853,7 +855,7 @@ mod tests { #[test] fn no_one_mints_if_minter_unset() { - let mut deps = mock_dependencies(&[]); + let mut deps = mock_dependencies(); do_instantiate(deps.as_mut(), &String::from("genesis"), Uint128::new(1234)); let msg = ExecuteMsg::Mint { @@ -868,7 +870,7 @@ mod tests { #[test] fn instantiate_multiple_accounts() { - let mut deps = mock_dependencies(&[]); + let mut deps = mock_dependencies(); let amount1 = Uint128::from(11223344u128); let addr1 = String::from("addr0001"); let amount2 = Uint128::from(7890987u128); @@ -910,7 +912,7 @@ mod tests { #[test] fn queries_work() { - let mut deps = mock_dependencies(&coins(2, "token")); + let mut deps = mock_dependencies_with_balance(&coins(2, "token")); let addr1 = String::from("addr0001"); let amount1 = Uint128::from(12340000u128); @@ -947,7 +949,7 @@ mod tests { #[test] fn transfer() { - let mut deps = mock_dependencies(&coins(2, "token")); + let mut deps = mock_dependencies_with_balance(&coins(2, "token")); let addr1 = String::from("addr0001"); let addr2 = String::from("addr0002"); let amount1 = Uint128::from(12340000u128); @@ -1007,7 +1009,7 @@ mod tests { #[test] fn burn() { - let mut deps = mock_dependencies(&coins(2, "token")); + let mut deps = mock_dependencies_with_balance(&coins(2, "token")); let addr1 = String::from("addr0001"); let amount1 = Uint128::from(12340000u128); let burn = Uint128::from(76543u128); @@ -1056,7 +1058,7 @@ mod tests { #[test] fn send() { - let mut deps = mock_dependencies(&coins(2, "token")); + let mut deps = mock_dependencies_with_balance(&coins(2, "token")); let addr1 = String::from("addr0001"); let contract = String::from("addr0002"); let amount1 = Uint128::from(12340000u128); @@ -1133,7 +1135,7 @@ mod tests { #[test] fn update_unauthorised() { - let mut deps = mock_dependencies(&[]); + let mut deps = mock_dependencies(); let instantiate_msg = InstantiateMsg { name: "Cash Token".to_string(), symbol: "CASH".to_string(), @@ -1187,7 +1189,7 @@ mod tests { #[test] fn update_project() { - let mut deps = mock_dependencies(&[]); + let mut deps = mock_dependencies(); let instantiate_msg = InstantiateMsg { name: "Cash Token".to_string(), symbol: "CASH".to_string(), @@ -1240,7 +1242,7 @@ mod tests { #[test] fn clear_project() { - let mut deps = mock_dependencies(&[]); + let mut deps = mock_dependencies(); let instantiate_msg = InstantiateMsg { name: "Cash Token".to_string(), symbol: "CASH".to_string(), @@ -1293,7 +1295,7 @@ mod tests { #[test] fn update_description() { - let mut deps = mock_dependencies(&[]); + let mut deps = mock_dependencies(); let instantiate_msg = InstantiateMsg { name: "Cash Token".to_string(), symbol: "CASH".to_string(), @@ -1346,7 +1348,7 @@ mod tests { #[test] fn clear_description() { - let mut deps = mock_dependencies(&[]); + let mut deps = mock_dependencies(); let instantiate_msg = InstantiateMsg { name: "Cash Token".to_string(), symbol: "CASH".to_string(), @@ -1399,7 +1401,7 @@ mod tests { #[test] fn update_marketing() { - let mut deps = mock_dependencies(&[]); + let mut deps = mock_dependencies(); let instantiate_msg = InstantiateMsg { name: "Cash Token".to_string(), symbol: "CASH".to_string(), @@ -1452,7 +1454,7 @@ mod tests { #[test] fn update_marketing_invalid() { - let mut deps = mock_dependencies(&[]); + let mut deps = mock_dependencies(); let instantiate_msg = InstantiateMsg { name: "Cash Token".to_string(), symbol: "CASH".to_string(), @@ -1509,7 +1511,7 @@ mod tests { #[test] fn clear_marketing() { - let mut deps = mock_dependencies(&[]); + let mut deps = mock_dependencies(); let instantiate_msg = InstantiateMsg { name: "Cash Token".to_string(), symbol: "CASH".to_string(), @@ -1562,7 +1564,7 @@ mod tests { #[test] fn update_logo_url() { - let mut deps = mock_dependencies(&[]); + let mut deps = mock_dependencies(); let instantiate_msg = InstantiateMsg { name: "Cash Token".to_string(), symbol: "CASH".to_string(), @@ -1611,7 +1613,7 @@ mod tests { #[test] fn update_logo_png() { - let mut deps = mock_dependencies(&[]); + let mut deps = mock_dependencies(); let instantiate_msg = InstantiateMsg { name: "Cash Token".to_string(), symbol: "CASH".to_string(), @@ -1661,7 +1663,7 @@ mod tests { #[test] fn update_logo_svg() { - let mut deps = mock_dependencies(&[]); + let mut deps = mock_dependencies(); let instantiate_msg = InstantiateMsg { name: "Cash Token".to_string(), symbol: "CASH".to_string(), @@ -1712,7 +1714,7 @@ mod tests { #[test] fn update_logo_png_oversized() { - let mut deps = mock_dependencies(&[]); + let mut deps = mock_dependencies(); let instantiate_msg = InstantiateMsg { name: "Cash Token".to_string(), symbol: "CASH".to_string(), @@ -1762,7 +1764,7 @@ mod tests { #[test] fn update_logo_svg_oversized() { - let mut deps = mock_dependencies(&[]); + let mut deps = mock_dependencies(); let instantiate_msg = InstantiateMsg { name: "Cash Token".to_string(), symbol: "CASH".to_string(), @@ -1819,7 +1821,7 @@ mod tests { #[test] fn update_logo_png_invalid() { - let mut deps = mock_dependencies(&[]); + let mut deps = mock_dependencies(); let instantiate_msg = InstantiateMsg { name: "Cash Token".to_string(), symbol: "CASH".to_string(), @@ -1869,7 +1871,7 @@ mod tests { #[test] fn update_logo_svg_invalid() { - let mut deps = mock_dependencies(&[]); + let mut deps = mock_dependencies(); let instantiate_msg = InstantiateMsg { name: "Cash Token".to_string(), symbol: "CASH".to_string(), diff --git a/cw20/base/src/enumerable.rs b/cw20/base/src/enumerable.rs index cf61d46..7f7991c 100644 --- a/cw20/base/src/enumerable.rs +++ b/cw20/base/src/enumerable.rs @@ -16,24 +16,21 @@ pub fn query_all_allowances( ) -> StdResult { let owner_addr = deps.api.addr_validate(&owner)?; let limit = limit.unwrap_or(DEFAULT_LIMIT).min(MAX_LIMIT) as usize; - let start = start_after.map(Bound::exclusive); + let start = start_after.map(|s| Bound::ExclusiveRaw(s.into_bytes())); - let allowances: StdResult> = ALLOWANCES + let allowances = ALLOWANCES .prefix(&owner_addr) .range(deps.storage, start, None, Order::Ascending) .take(limit) .map(|item| { - let (k, v) = item?; - Ok(AllowanceInfo { - spender: String::from_utf8(k)?, - allowance: v.allowance, - expires: v.expires, + item.map(|(addr, allow)| AllowanceInfo { + spender: addr.into(), + allowance: allow.allowance, + expires: allow.expires, }) }) - .collect(); - Ok(AllAllowancesResponse { - allowances: allowances?, - }) + .collect::>()?; + Ok(AllAllowancesResponse { allowances }) } pub fn query_all_accounts( @@ -42,24 +39,22 @@ pub fn query_all_accounts( limit: Option, ) -> StdResult { let limit = limit.unwrap_or(DEFAULT_LIMIT).min(MAX_LIMIT) as usize; - let start = start_after.map(Bound::exclusive); + let start = start_after.map(|s| Bound::ExclusiveRaw(s.into())); - let accounts: Result, _> = BALANCES + let accounts = BALANCES .keys(deps.storage, start, None, Order::Ascending) - .map(String::from_utf8) .take(limit) - .collect(); + .map(|item| item.map(Into::into)) + .collect::>()?; - Ok(AllAccountsResponse { - accounts: accounts?, - }) + Ok(AllAccountsResponse { accounts }) } #[cfg(test)] mod tests { use super::*; - use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info}; + use cosmwasm_std::testing::{mock_dependencies_with_balance, mock_env, mock_info}; use cosmwasm_std::{coins, DepsMut, Uint128}; use cw20::{Cw20Coin, Expiration, TokenInfoResponse}; @@ -87,7 +82,7 @@ mod tests { #[test] fn query_all_allowances_works() { - let mut deps = mock_dependencies(&coins(2, "token")); + let mut deps = mock_dependencies_with_balance(&coins(2, "token")); let owner = String::from("owner"); // these are in alphabetical order same than insert order @@ -150,7 +145,7 @@ mod tests { #[test] fn query_all_accounts_works() { - let mut deps = mock_dependencies(&coins(2, "token")); + let mut deps = mock_dependencies_with_balance(&coins(2, "token")); // insert order and lexicographical order are different let acct1 = String::from("acct01"); diff --git a/cw721/off-chain-metadata/.cargo/config b/cw721/off-chain-metadata/.cargo/config index 336b618..7d1a066 100644 --- a/cw721/off-chain-metadata/.cargo/config +++ b/cw721/off-chain-metadata/.cargo/config @@ -1,4 +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/cw721/off-chain-metadata/.gitignore b/cw721/off-chain-metadata/.gitignore index dfdaaa6..f9b9a83 100644 --- a/cw721/off-chain-metadata/.gitignore +++ b/cw721/off-chain-metadata/.gitignore @@ -1,5 +1,6 @@ # Build results /target +/artifacts # Cargo+Git helper file (https://github.com/rust-lang/cargo/blob/0.44.1/src/cargo/sources/git/utils.rs#L320-L327) .cargo-ok diff --git a/cw721/off-chain-metadata/Cargo.toml b/cw721/off-chain-metadata/Cargo.toml index 24a3d52..2cb464b 100644 --- a/cw721/off-chain-metadata/Cargo.toml +++ b/cw721/off-chain-metadata/Cargo.toml @@ -34,21 +34,21 @@ library = [] [package.metadata.scripts] optimize = """docker run --rm -v "$(pwd)":/code \ + -e CARGO_TERM_COLOR=always \ --mount type=volume,source="$(basename "$(pwd)")_cache",target=/code/target \ --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \ - cosmwasm/rust-optimizer:0.12.3 + cosmwasm/rust-optimizer:0.12.5 """ [dependencies] -cosmwasm-std = "0.16.2" -cosmwasm-storage = "0.16.2" -cw-storage-plus = "0.9.1" -cw0 = "0.9.1" -cw2 = "0.9.1" -cw721 = "0.9.2" -schemars = "0.8.8" -serde = { version = "1.0.130", default-features = false, features = ["derive"] } -thiserror = "1.0.26" +cosmwasm-std = "1.0.0-beta" +cw-storage-plus = "0.11" +cw-utils = "0.11" +cw2 = "0.11" +cw721 = "0.11" +schemars = "0.8" +serde = { version = "1.0", default-features = false, features = ["derive"] } +thiserror = "1.0" [dev-dependencies] -cosmwasm-schema = "0.16.2" +cosmwasm-schema = "1.0.0-beta" diff --git a/cw721/off-chain-metadata/examples/schema.rs b/cw721/off-chain-metadata/examples/schema.rs index 3166121..764f1bc 100644 --- a/cw721/off-chain-metadata/examples/schema.rs +++ b/cw721/off-chain-metadata/examples/schema.rs @@ -3,11 +3,11 @@ use std::fs::create_dir_all; use cosmwasm_schema::{export_schema, export_schema_with_title, remove_schemas, schema_for}; -use {{crate_name}}::{ExecuteMsg, Extension, InstantiateMsg, MinterResponse, QueryMsg}; use cw721::{ - AllNftInfoResponse, ApprovedForAllResponse, ContractInfoResponse, NftInfoResponse, - NumTokensResponse, OwnerOfResponse, TokensResponse, + AllNftInfoResponse, ApprovalResponse, ApprovalsResponse, ContractInfoResponse, NftInfoResponse, + NumTokensResponse, OperatorsResponse, OwnerOfResponse, TokensResponse, }; +use {{crate_name}}::{ExecuteMsg, Extension, InstantiateMsg, MinterResponse, QueryMsg}; fn main() { let mut out_dir = current_dir().unwrap(); @@ -23,7 +23,9 @@ fn main() { &out_dir, "AllNftInfoResponse", ); - export_schema(&schema_for!(ApprovedForAllResponse), &out_dir); + export_schema(&schema_for!(ApprovalResponse), &out_dir); + export_schema(&schema_for!(ApprovalsResponse), &out_dir); + export_schema(&schema_for!(OperatorsResponse), &out_dir); export_schema(&schema_for!(ContractInfoResponse), &out_dir); export_schema(&schema_for!(MinterResponse), &out_dir); export_schema_with_title( diff --git a/cw20/base/schema/all_nft_info_response.json b/cw721/off-chain-metadata/schema/approval_response.json similarity index 50% rename from cw20/base/schema/all_nft_info_response.json rename to cw721/off-chain-metadata/schema/approval_response.json index 152c3cf..4f45b42 100644 --- a/cw20/base/schema/all_nft_info_response.json +++ b/cw721/off-chain-metadata/schema/approval_response.json @@ -1,27 +1,13 @@ { "$schema": "http://json-schema.org/draft-07/schema#", - "title": "AllNftInfoResponse", + "title": "ApprovalResponse", "type": "object", "required": [ - "access", - "info" + "approval" ], "properties": { - "access": { - "description": "Who can transfer the token", - "allOf": [ - { - "$ref": "#/definitions/OwnerOfResponse" - } - ] - }, - "info": { - "description": "Data on the token itself,", - "allOf": [ - { - "$ref": "#/definitions/NftInfoResponse_for_Nullable_Metadata" - } - ] + "approval": { + "$ref": "#/definitions/Approval" } }, "definitions": { @@ -92,111 +78,6 @@ } ] }, - "Metadata": { - "type": "object", - "properties": { - "animation_url": { - "type": [ - "string", - "null" - ] - }, - "attributes": { - "type": [ - "array", - "null" - ], - "items": { - "$ref": "#/definitions/Trait" - } - }, - "background_color": { - "type": [ - "string", - "null" - ] - }, - "description": { - "type": [ - "string", - "null" - ] - }, - "external_url": { - "type": [ - "string", - "null" - ] - }, - "image": { - "type": [ - "string", - "null" - ] - }, - "image_data": { - "type": [ - "string", - "null" - ] - }, - "name": { - "type": [ - "string", - "null" - ] - }, - "youtube_url": { - "type": [ - "string", - "null" - ] - } - } - }, - "NftInfoResponse_for_Nullable_Metadata": { - "type": "object", - "properties": { - "extension": { - "description": "You can add any custom metadata here when you extend cw721-base", - "anyOf": [ - { - "$ref": "#/definitions/Metadata" - }, - { - "type": "null" - } - ] - }, - "token_uri": { - "description": "Universal resource identifier for this NFT Should point to a JSON file that conforms to the ERC721 Metadata JSON Schema", - "type": [ - "string", - "null" - ] - } - } - }, - "OwnerOfResponse": { - "type": "object", - "required": [ - "approvals", - "owner" - ], - "properties": { - "approvals": { - "description": "If set this address is approved to transfer/send the token as well", - "type": "array", - "items": { - "$ref": "#/definitions/Approval" - } - }, - "owner": { - "description": "Owner of the token", - "type": "string" - } - } - }, "Timestamp": { "description": "A point in time in nanosecond precision.\n\nThis type can represent times from 1970-01-01T00:00:00Z to 2554-07-21T23:34:33Z.\n\n## Examples\n\n``` # use cosmwasm_std::Timestamp; let ts = Timestamp::from_nanos(1_000_000_202); assert_eq!(ts.nanos(), 1_000_000_202); assert_eq!(ts.seconds(), 1); assert_eq!(ts.subsec_nanos(), 202);\n\nlet ts = ts.plus_seconds(2); assert_eq!(ts.nanos(), 3_000_000_202); assert_eq!(ts.seconds(), 3); assert_eq!(ts.subsec_nanos(), 202); ```", "allOf": [ @@ -205,27 +86,6 @@ } ] }, - "Trait": { - "type": "object", - "required": [ - "trait_type", - "value" - ], - "properties": { - "display_type": { - "type": [ - "string", - "null" - ] - }, - "trait_type": { - "type": "string" - }, - "value": { - "type": "string" - } - } - }, "Uint64": { "description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```", "type": "string" diff --git a/cw20/base/schema/owner_of_response.json b/cw721/off-chain-metadata/schema/approvals_response.json similarity index 93% rename from cw20/base/schema/owner_of_response.json rename to cw721/off-chain-metadata/schema/approvals_response.json index 1258d67..8d8e39e 100644 --- a/cw20/base/schema/owner_of_response.json +++ b/cw721/off-chain-metadata/schema/approvals_response.json @@ -1,22 +1,16 @@ { "$schema": "http://json-schema.org/draft-07/schema#", - "title": "OwnerOfResponse", + "title": "ApprovalsResponse", "type": "object", "required": [ - "approvals", - "owner" + "approvals" ], "properties": { "approvals": { - "description": "If set this address is approved to transfer/send the token as well", "type": "array", "items": { "$ref": "#/definitions/Approval" } - }, - "owner": { - "description": "Owner of the token", - "type": "string" } }, "definitions": { diff --git a/cw721/off-chain-metadata/schema/execute_msg.json b/cw721/off-chain-metadata/schema/execute_msg.json index 9d82723..5cdf660 100644 --- a/cw721/off-chain-metadata/schema/execute_msg.json +++ b/cw721/off-chain-metadata/schema/execute_msg.json @@ -181,6 +181,27 @@ } }, "additionalProperties": false + }, + { + "description": "Burn an NFT the sender has access to", + "type": "object", + "required": [ + "burn" + ], + "properties": { + "burn": { + "type": "object", + "required": [ + "token_id" + ], + "properties": { + "token_id": { + "type": "string" + } + } + } + }, + "additionalProperties": false } ], "definitions": { diff --git a/cw20/base/schema/approved_for_all_response.json b/cw721/off-chain-metadata/schema/operators_response.json similarity index 98% rename from cw20/base/schema/approved_for_all_response.json rename to cw721/off-chain-metadata/schema/operators_response.json index 453f17b..5370307 100644 --- a/cw20/base/schema/approved_for_all_response.json +++ b/cw721/off-chain-metadata/schema/operators_response.json @@ -1,6 +1,6 @@ { "$schema": "http://json-schema.org/draft-07/schema#", - "title": "ApprovedForAllResponse", + "title": "OperatorsResponse", "type": "object", "required": [ "operators" diff --git a/cw721/off-chain-metadata/schema/query_msg.json b/cw721/off-chain-metadata/schema/query_msg.json index bcf6a51..cd3a956 100644 --- a/cw721/off-chain-metadata/schema/query_msg.json +++ b/cw721/off-chain-metadata/schema/query_msg.json @@ -31,13 +31,71 @@ "additionalProperties": false }, { - "description": "List all operators that can access all of the owner's tokens Return type: `ApprovedForAllResponse`", + "description": "Return operator that can access all of the owner's tokens. Return type: `ApprovalResponse`", "type": "object", "required": [ - "approved_for_all" + "approval" ], "properties": { - "approved_for_all": { + "approval": { + "type": "object", + "required": [ + "spender", + "token_id" + ], + "properties": { + "include_expired": { + "type": [ + "boolean", + "null" + ] + }, + "spender": { + "type": "string" + }, + "token_id": { + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "Return approvals that a token has Return type: `ApprovalsResponse`", + "type": "object", + "required": [ + "approvals" + ], + "properties": { + "approvals": { + "type": "object", + "required": [ + "token_id" + ], + "properties": { + "include_expired": { + "type": [ + "boolean", + "null" + ] + }, + "token_id": { + "type": "string" + } + } + } + }, + "additionalProperties": false + }, + { + "description": "List all operators that can access all of the owner's tokens Return type: `OperatorsResponse`", + "type": "object", + "required": [ + "all_operators" + ], + "properties": { + "all_operators": { "type": "object", "required": [ "owner" diff --git a/cw721/off-chain-metadata/src/error.rs b/cw721/off-chain-metadata/src/error.rs index b665db5..db1ceaa 100644 --- a/cw721/off-chain-metadata/src/error.rs +++ b/cw721/off-chain-metadata/src/error.rs @@ -14,4 +14,7 @@ pub enum ContractError { #[error("Cannot set approval that is already expired")] Expired {}, + + #[error("Approval not found for: {spender}")] + ApprovalNotFound { spender: String }, } diff --git a/cw721/off-chain-metadata/src/execute.rs b/cw721/off-chain-metadata/src/execute.rs index 51c2819..d029332 100644 --- a/cw721/off-chain-metadata/src/execute.rs +++ b/cw721/off-chain-metadata/src/execute.rs @@ -68,6 +68,7 @@ where token_id, msg, } => self.send_nft(deps, env, info, contract, token_id, msg), + ExecuteMsg::Burn { token_id } => self.burn(deps, env, info, token_id), } } } @@ -240,6 +241,25 @@ where .add_attribute("sender", info.sender) .add_attribute("operator", operator)) } + + fn burn( + &self, + deps: DepsMut, + env: Env, + info: MessageInfo, + token_id: String, + ) -> Result, ContractError> { + let token = self.tokens.load(deps.storage, &token_id)?; + self.check_can_send(deps.as_ref(), &env, &info, &token)?; + + self.tokens.remove(deps.storage, &token_id)?; + self.decrement_tokens(deps.storage)?; + + Ok(Response::new() + .add_attribute("action", "burn") + .add_attribute("sender", info.sender) + .add_attribute("token_id", token_id)) + } } // helpers @@ -338,7 +358,7 @@ where } /// returns true iff the sender can transfer ownership of the token - fn check_can_send( + pub fn check_can_send( &self, deps: Deps, env: &Env, diff --git a/cw721/off-chain-metadata/src/helpers.rs b/cw721/off-chain-metadata/src/helpers.rs new file mode 100644 index 0000000..437132f --- /dev/null +++ b/cw721/off-chain-metadata/src/helpers.rs @@ -0,0 +1,179 @@ +use crate::{ExecuteMsg, QueryMsg}; +use cosmwasm_std::{to_binary, Addr, CosmosMsg, QuerierWrapper, StdResult, WasmMsg, WasmQuery}; +use cw721::{ + AllNftInfoResponse, Approval, ApprovalResponse, ApprovalsResponse, ContractInfoResponse, + NftInfoResponse, NumTokensResponse, OperatorsResponse, OwnerOfResponse, TokensResponse, +}; +use serde::de::DeserializeOwned; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] +pub struct Cw721Contract(pub Addr); + +#[allow(dead_code)] +impl Cw721Contract { + pub fn addr(&self) -> Addr { + self.0.clone() + } + + pub fn call(&self, msg: ExecuteMsg) -> StdResult { + let msg = to_binary(&msg)?; + Ok(WasmMsg::Execute { + contract_addr: self.addr().into(), + msg, + funds: vec![], + } + .into()) + } + + pub fn query( + &self, + querier: &QuerierWrapper, + req: QueryMsg, + ) -> StdResult { + let query = WasmQuery::Smart { + contract_addr: self.addr().into(), + msg: to_binary(&req)?, + } + .into(); + querier.query(&query) + } + + /*** queries ***/ + + pub fn owner_of>( + &self, + querier: &QuerierWrapper, + token_id: T, + include_expired: bool, + ) -> StdResult { + let req = QueryMsg::OwnerOf { + token_id: token_id.into(), + include_expired: Some(include_expired), + }; + self.query(querier, req) + } + + pub fn approval>( + &self, + querier: &QuerierWrapper, + token_id: T, + spender: T, + include_expired: Option, + ) -> StdResult { + let req = QueryMsg::Approval { + token_id: token_id.into(), + spender: spender.into(), + include_expired, + }; + let res: ApprovalResponse = self.query(querier, req)?; + Ok(res) + } + + pub fn approvals>( + &self, + querier: &QuerierWrapper, + token_id: T, + include_expired: Option, + ) -> StdResult { + let req = QueryMsg::Approvals { + token_id: token_id.into(), + include_expired, + }; + let res: ApprovalsResponse = self.query(querier, req)?; + Ok(res) + } + + pub fn all_operators>( + &self, + querier: &QuerierWrapper, + owner: T, + include_expired: bool, + start_after: Option, + limit: Option, + ) -> StdResult> { + let req = QueryMsg::AllOperators { + owner: owner.into(), + include_expired: Some(include_expired), + start_after, + limit, + }; + let res: OperatorsResponse = self.query(querier, req)?; + Ok(res.operators) + } + + pub fn num_tokens(&self, querier: &QuerierWrapper) -> StdResult { + let req = QueryMsg::NumTokens {}; + let res: NumTokensResponse = self.query(querier, req)?; + Ok(res.count) + } + + /// With metadata extension + pub fn contract_info(&self, querier: &QuerierWrapper) -> StdResult { + let req = QueryMsg::ContractInfo {}; + self.query(querier, req) + } + + /// With metadata extension + pub fn nft_info, U: DeserializeOwned>( + &self, + querier: &QuerierWrapper, + token_id: T, + ) -> StdResult> { + let req = QueryMsg::NftInfo { + token_id: token_id.into(), + }; + self.query(querier, req) + } + + /// With metadata extension + pub fn all_nft_info, U: DeserializeOwned>( + &self, + querier: &QuerierWrapper, + token_id: T, + include_expired: bool, + ) -> StdResult> { + let req = QueryMsg::AllNftInfo { + token_id: token_id.into(), + include_expired: Some(include_expired), + }; + self.query(querier, req) + } + + /// With enumerable extension + pub fn tokens>( + &self, + querier: &QuerierWrapper, + owner: T, + start_after: Option, + limit: Option, + ) -> StdResult { + let req = QueryMsg::Tokens { + owner: owner.into(), + start_after, + limit, + }; + self.query(querier, req) + } + + /// With enumerable extension + pub fn all_tokens( + &self, + querier: &QuerierWrapper, + start_after: Option, + limit: Option, + ) -> StdResult { + let req = QueryMsg::AllTokens { start_after, limit }; + self.query(querier, req) + } + + /// returns true if the contract supports the metadata extension + pub fn has_metadata(&self, querier: &QuerierWrapper) -> bool { + self.contract_info(querier).is_ok() + } + + /// returns true if the contract supports the enumerable extension + pub fn has_enumerable(&self, querier: &QuerierWrapper) -> bool { + self.tokens(querier, self.addr(), None, Some(1)).is_ok() + } +} diff --git a/cw721/off-chain-metadata/src/lib.rs b/cw721/off-chain-metadata/src/lib.rs index 3bd71c3..5028832 100644 --- a/cw721/off-chain-metadata/src/lib.rs +++ b/cw721/off-chain-metadata/src/lib.rs @@ -1,5 +1,6 @@ mod error; mod execute; +pub mod helpers; pub mod msg; mod query; pub mod state; diff --git a/cw721/off-chain-metadata/src/msg.rs b/cw721/off-chain-metadata/src/msg.rs index 6ff881e..6d2994e 100644 --- a/cw721/off-chain-metadata/src/msg.rs +++ b/cw721/off-chain-metadata/src/msg.rs @@ -25,7 +25,6 @@ pub struct InstantiateMsg { pub enum ExecuteMsg { /// Transfer is a base message to move a token to another account without triggering actions TransferNft { recipient: String, token_id: String }, - /// Send is a base message to transfer a token to a contract and trigger an action /// on the receiving contract. SendNft { @@ -33,7 +32,6 @@ pub enum ExecuteMsg { token_id: String, msg: Binary, }, - /// Allows operator to transfer / send the token from the owner's account. /// If expiration is set, then this allowance has a time/height limit Approve { @@ -41,22 +39,22 @@ pub enum ExecuteMsg { token_id: String, expires: Option, }, - /// Remove previously granted Approval Revoke { spender: String, token_id: String }, - /// Allows operator to transfer / send any token from the owner's account. /// If expiration is set, then this allowance has a time/height limit ApproveAll { operator: String, expires: Option, }, - /// Remove previously granted ApproveAll permission RevokeAll { operator: String }, /// Mint a new NFT, can only be called by the contract minter Mint(MintMsg), + + /// Burn an NFT the sender has access to + Burn { token_id: String }, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] @@ -84,30 +82,42 @@ pub enum QueryMsg { include_expired: Option, }, + /// Return operator that can access all of the owner's tokens. + /// Return type: `ApprovalResponse` + Approval { + token_id: String, + spender: String, + include_expired: Option, + }, + + /// Return approvals that a token has + /// Return type: `ApprovalsResponse` + Approvals { + token_id: String, + include_expired: Option, + }, + /// List all operators that can access all of the owner's tokens - /// Return type: `ApprovedForAllResponse` - ApprovedForAll { + /// Return type: `OperatorsResponse` + AllOperators { owner: String, /// unset or false will filter out expired items, you must set to true to see them include_expired: Option, start_after: Option, limit: Option, }, - /// Total number of tokens issued NumTokens {}, /// With MetaData Extension. /// Returns top-level metadata about the contract: `ContractInfoResponse` ContractInfo {}, - /// With MetaData Extension. /// Returns metadata about one particular token, based on *ERC721 Metadata JSON Schema* /// but directly from the contract: `NftInfoResponse` NftInfo { token_id: String, }, - /// With MetaData Extension. /// Returns the result of both `NftInfo` and `OwnerOf` as one query as an optimization /// for clients: `AllNftInfo` @@ -125,7 +135,6 @@ pub enum QueryMsg { start_after: Option, limit: Option, }, - /// With Enumerable extension. /// Requires pagination. Lists all token_ids controlled by the contract. /// Return type: TokensResponse. diff --git a/cw721/off-chain-metadata/src/query.rs b/cw721/off-chain-metadata/src/query.rs index b9c9bb6..885afcd 100644 --- a/cw721/off-chain-metadata/src/query.rs +++ b/cw721/off-chain-metadata/src/query.rs @@ -1,14 +1,15 @@ use serde::de::DeserializeOwned; use serde::Serialize; -use cosmwasm_std::{to_binary, Binary, BlockInfo, Deps, Env, Order, Pair, StdError, StdResult}; +use cosmwasm_std::{to_binary, Addr, Binary, BlockInfo, Deps, Env, Order, StdError, StdResult}; -use cw0::maybe_addr; use cw721::{ - AllNftInfoResponse, ApprovedForAllResponse, ContractInfoResponse, CustomMsg, Cw721Query, - Expiration, NftInfoResponse, NumTokensResponse, OwnerOfResponse, TokensResponse, + AllNftInfoResponse, ApprovalResponse, ApprovalsResponse, ContractInfoResponse, CustomMsg, + Cw721Query, Expiration, NftInfoResponse, NumTokensResponse, OperatorsResponse, OwnerOfResponse, + TokensResponse, }; use cw_storage_plus::Bound; +use cw_utils::maybe_addr; use crate::msg::{MinterResponse, QueryMsg}; use crate::state::{Approval, Cw721Contract, TokenInfo}; @@ -52,7 +53,8 @@ where }) } - fn all_approvals( + /// operators returns all operators owner given access to + fn operators( &self, deps: Deps, env: Env, @@ -60,7 +62,7 @@ where include_expired: bool, start_after: Option, limit: Option, - ) -> StdResult { + ) -> StdResult { let limit = limit.unwrap_or(DEFAULT_LIMIT).min(MAX_LIMIT) as usize; let start_addr = maybe_addr(deps.api, start_after)?; let start = start_addr.map(|addr| Bound::exclusive(addr.as_ref())); @@ -76,7 +78,68 @@ where .take(limit) .map(parse_approval) .collect(); - Ok(ApprovedForAllResponse { operators: res? }) + Ok(OperatorsResponse { operators: res? }) + } + + fn approval( + &self, + deps: Deps, + env: Env, + token_id: String, + spender: String, + include_expired: bool, + ) -> StdResult { + let token = self.tokens.load(deps.storage, &token_id)?; + + // token owner has absolute approval + if token.owner == spender { + let approval = cw721::Approval { + spender: token.owner.to_string(), + expires: Expiration::Never {}, + }; + return Ok(ApprovalResponse { approval }); + } + + let filtered: Vec<_> = token + .approvals + .into_iter() + .filter(|t| t.spender == spender) + .filter(|t| include_expired || !t.is_expired(&env.block)) + .map(|a| cw721::Approval { + spender: a.spender.into_string(), + expires: a.expires, + }) + .collect(); + + if filtered.is_empty() { + return Err(StdError::not_found("Approval not found")); + } + // we expect only one item + let approval = filtered[0].clone(); + + Ok(ApprovalResponse { approval }) + } + + /// approvals returns all approvals owner given access to + fn approvals( + &self, + deps: Deps, + env: Env, + token_id: String, + include_expired: bool, + ) -> StdResult { + let token = self.tokens.load(deps.storage, &token_id)?; + let approvals: Vec<_> = token + .approvals + .into_iter() + .filter(|t| include_expired || !t.is_expired(&env.block)) + .map(|a| cw721::Approval { + spender: a.spender.into_string(), + expires: a.expires, + }) + .collect(); + + Ok(ApprovalsResponse { approvals }) } fn tokens( @@ -90,17 +153,16 @@ where let start = start_after.map(Bound::exclusive); let owner_addr = deps.api.addr_validate(&owner)?; - let pks: Vec<_> = self + let tokens: Vec = self .tokens .idx .owner .prefix(owner_addr) .keys(deps.storage, start, None, Order::Ascending) .take(limit) - .collect(); + .map(|x| x.map(|addr| addr.to_string())) + .collect::>>()?; - let res: Result, _> = pks.iter().map(|v| String::from_utf8(v.to_vec())).collect(); - let tokens = res.map_err(StdError::invalid_utf8)?; Ok(TokensResponse { tokens }) } @@ -111,15 +173,15 @@ where limit: Option, ) -> StdResult { let limit = limit.unwrap_or(DEFAULT_LIMIT).min(MAX_LIMIT) as usize; - let start_addr = maybe_addr(deps.api, start_after)?; - let start = start_addr.map(|addr| Bound::exclusive(addr.as_ref())); + let start = start_after.map(Bound::exclusive); let tokens: StdResult> = self .tokens .range(deps.storage, start, None, Order::Ascending) .take(limit) - .map(|item| item.map(|(k, _)| String::from_utf8_lossy(&k).to_string())) + .map(|item| item.map(|(k, _)| k)) .collect(); + Ok(TokensResponse { tokens: tokens? }) } @@ -176,12 +238,12 @@ where token_id, include_expired.unwrap_or(false), )?), - QueryMsg::ApprovedForAll { + QueryMsg::AllOperators { owner, include_expired, start_after, limit, - } => to_binary(&self.all_approvals( + } => to_binary(&self.operators( deps, env, owner, @@ -198,14 +260,31 @@ where QueryMsg::AllTokens { start_after, limit } => { to_binary(&self.all_tokens(deps, start_after, limit)?) } + QueryMsg::Approval { + token_id, + spender, + include_expired, + } => to_binary(&self.approval( + deps, + env, + token_id, + spender, + include_expired.unwrap_or(false), + )?), + QueryMsg::Approvals { + token_id, + include_expired, + } => { + to_binary(&self.approvals(deps, env, token_id, include_expired.unwrap_or(false))?) + } } } } -fn parse_approval(item: StdResult>) -> StdResult { - item.and_then(|(k, expires)| { - let spender = String::from_utf8(k)?; - Ok(cw721::Approval { spender, expires }) +fn parse_approval(item: StdResult<(Addr, Expiration)>) -> StdResult { + item.map(|(spender, expires)| cw721::Approval { + spender: spender.to_string(), + expires, }) } diff --git a/cw721/off-chain-metadata/src/state.rs b/cw721/off-chain-metadata/src/state.rs index 698bdf4..37af500 100644 --- a/cw721/off-chain-metadata/src/state.rs +++ b/cw721/off-chain-metadata/src/state.rs @@ -41,7 +41,7 @@ where "num_tokens", "operators", "tokens", - "tokens_owner", + "tokens__owner", ) } } @@ -80,6 +80,12 @@ where self.token_count.save(storage, &val)?; Ok(val) } + + pub fn decrement_tokens(&self, storage: &mut dyn Storage) -> StdResult { + let val = self.token_count(storage)? - 1; + self.token_count.save(storage, &val)?; + Ok(val) + } } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] @@ -116,8 +122,7 @@ pub struct TokenIndexes<'a, T> where T: Serialize + DeserializeOwned + Clone, { - // pk goes to second tuple element - pub owner: MultiIndex<'a, (Addr, Vec), TokenInfo>, + pub owner: MultiIndex<'a, Addr, TokenInfo, Addr>, } impl<'a, T> IndexList> for TokenIndexes<'a, T> @@ -130,6 +135,6 @@ where } } -pub fn token_owner_idx(d: &TokenInfo, k: Vec) -> (Addr, Vec) { - (d.owner.clone(), k) +pub fn token_owner_idx(d: &TokenInfo) -> Addr { + d.owner.clone() } diff --git a/cw721/off-chain-metadata/src/tests.rs b/cw721/off-chain-metadata/src/tests.rs index 1da5078..2b84024 100644 --- a/cw721/off-chain-metadata/src/tests.rs +++ b/cw721/off-chain-metadata/src/tests.rs @@ -3,17 +3,17 @@ use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info}; use cosmwasm_std::{from_binary, to_binary, CosmosMsg, DepsMut, Empty, Response, WasmMsg}; use cw721::{ - ApprovedForAllResponse, ContractInfoResponse, Cw721Query, Cw721ReceiveMsg, Expiration, - NftInfoResponse, OwnerOfResponse, + Approval, ApprovalResponse, ContractInfoResponse, Cw721Query, Cw721ReceiveMsg, Expiration, + NftInfoResponse, OperatorsResponse, OwnerOfResponse, }; use crate::{ ContractError, Cw721Contract, ExecuteMsg, Extension, InstantiateMsg, MintMsg, QueryMsg, }; -const MINTER: &str = "augusto"; -const CONTRACT_NAME: &str = "Archway NFT Demo"; -const SYMBOL: &str = "MYNFT"; +const MINTER: &str = "merlin"; +const CONTRACT_NAME: &str = "Magic Power"; +const SYMBOL: &str = "MGK"; fn setup_contract(deps: DepsMut<'_>) -> Cw721Contract<'static, Extension, Empty> { let contract = Cw721Contract::default(); @@ -30,7 +30,7 @@ fn setup_contract(deps: DepsMut<'_>) -> Cw721Contract<'static, Extension, Empty> #[test] fn proper_instantiation() { - let mut deps = mock_dependencies(&[]); + let mut deps = mock_dependencies(); let contract = Cw721Contract::::default(); let msg = InstantiateMsg { @@ -68,7 +68,7 @@ fn proper_instantiation() { #[test] fn minting() { - let mut deps = mock_dependencies(&[]); + let mut deps = mock_dependencies(); let contract = setup_contract(deps.as_mut()); let token_id = "petrify".to_string(); @@ -145,9 +145,58 @@ fn minting() { assert_eq!(vec![token_id], tokens.tokens); } +#[test] +fn burning() { + let mut deps = mock_dependencies(); + let contract = setup_contract(deps.as_mut()); + + let token_id = "petrify".to_string(); + let token_uri = "https://www.merriam-webster.com/dictionary/petrify".to_string(); + + let mint_msg = ExecuteMsg::Mint(MintMsg:: { + token_id: token_id.clone(), + owner: MINTER.to_string(), + token_uri: Some(token_uri), + extension: None, + }); + + let burn_msg = ExecuteMsg::Burn { token_id }; + + // mint some NFT + let allowed = mock_info(MINTER, &[]); + let _ = contract + .execute(deps.as_mut(), mock_env(), allowed.clone(), mint_msg) + .unwrap(); + + // random not allowed to burn + let random = mock_info("random", &[]); + let err = contract + .execute(deps.as_mut(), mock_env(), random, burn_msg.clone()) + .unwrap_err(); + + assert_eq!(err, ContractError::Unauthorized {}); + + let _ = contract + .execute(deps.as_mut(), mock_env(), allowed, burn_msg) + .unwrap(); + + // ensure num tokens decreases + let count = contract.num_tokens(deps.as_ref()).unwrap(); + assert_eq!(0, count.count); + + // trying to get nft returns error + let _ = contract + .nft_info(deps.as_ref(), "petrify".to_string()) + .unwrap_err(); + + // list the token_ids + let tokens = contract.all_tokens(deps.as_ref(), None, None).unwrap(); + assert!(tokens.tokens.is_empty()); +} + #[test] fn transferring_nft() { - let mut deps = mock_dependencies(&[]); + let mut deps = mock_dependencies(); let contract = setup_contract(deps.as_mut()); // Mint a token @@ -201,7 +250,7 @@ fn transferring_nft() { #[test] fn sending_nft() { - let mut deps = mock_dependencies(&[]); + let mut deps = mock_dependencies(); let contract = setup_contract(deps.as_mut()); // Mint a token @@ -267,7 +316,7 @@ fn sending_nft() { #[test] fn approving_revoking() { - let mut deps = mock_dependencies(&[]); + let mut deps = mock_dependencies(); let contract = setup_contract(deps.as_mut()); // Mint a token @@ -286,6 +335,26 @@ fn approving_revoking() { .execute(deps.as_mut(), mock_env(), minter, mint_msg) .unwrap(); + // token owner shows in approval query + let res = contract + .approval( + deps.as_ref(), + mock_env(), + token_id.clone(), + String::from("demeter"), + false, + ) + .unwrap(); + assert_eq!( + res, + ApprovalResponse { + approval: Approval { + spender: String::from("demeter"), + expires: Expiration::Never {} + } + } + ); + // Give random transferring power let approve_msg = ExecuteMsg::Approve { spender: String::from("random"), @@ -305,6 +374,26 @@ fn approving_revoking() { .add_attribute("token_id", token_id.clone()) ); + // test approval query + let res = contract + .approval( + deps.as_ref(), + mock_env(), + token_id.clone(), + String::from("random"), + true, + ) + .unwrap(); + assert_eq!( + res, + ApprovalResponse { + approval: Approval { + spender: String::from("random"), + expires: Expiration::Never {} + } + } + ); + // random can now transfer let random = mock_info("random", &[]); let transfer_msg = ExecuteMsg::TransferNft { @@ -371,7 +460,7 @@ fn approving_revoking() { #[test] fn approving_all_revoking_all() { - let mut deps = mock_dependencies(&[]); + let mut deps = mock_dependencies(); let contract = setup_contract(deps.as_mut()); // Mint a couple tokens (from the same owner) @@ -470,7 +559,7 @@ fn approving_all_revoking_all() { .unwrap(); let res = contract - .all_approvals( + .operators( deps.as_ref(), mock_env(), String::from("person"), @@ -481,7 +570,7 @@ fn approving_all_revoking_all() { .unwrap(); assert_eq!( res, - ApprovedForAllResponse { + OperatorsResponse { operators: vec![cw721::Approval { spender: String::from("operator"), expires: Expiration::Never {} @@ -502,7 +591,7 @@ fn approving_all_revoking_all() { // and paginate queries let res = contract - .all_approvals( + .operators( deps.as_ref(), mock_env(), String::from("person"), @@ -513,7 +602,7 @@ fn approving_all_revoking_all() { .unwrap(); assert_eq!( res, - ApprovedForAllResponse { + OperatorsResponse { operators: vec![cw721::Approval { spender: String::from("buddy"), expires: buddy_expires, @@ -521,7 +610,7 @@ fn approving_all_revoking_all() { } ); let res = contract - .all_approvals( + .operators( deps.as_ref(), mock_env(), String::from("person"), @@ -532,7 +621,7 @@ fn approving_all_revoking_all() { .unwrap(); assert_eq!( res, - ApprovedForAllResponse { + OperatorsResponse { operators: vec![cw721::Approval { spender: String::from("operator"), expires: Expiration::Never {} @@ -549,7 +638,7 @@ fn approving_all_revoking_all() { // Approvals are removed / cleared without affecting others let res = contract - .all_approvals( + .operators( deps.as_ref(), mock_env(), String::from("person"), @@ -560,7 +649,7 @@ fn approving_all_revoking_all() { .unwrap(); assert_eq!( res, - ApprovedForAllResponse { + OperatorsResponse { operators: vec![cw721::Approval { spender: String::from("buddy"), expires: buddy_expires, @@ -572,7 +661,7 @@ fn approving_all_revoking_all() { let mut late_env = mock_env(); late_env.block.height = 1234568; //expired let res = contract - .all_approvals( + .operators( deps.as_ref(), late_env, String::from("person"), @@ -586,7 +675,7 @@ fn approving_all_revoking_all() { #[test] fn query_tokens_by_owner() { - let mut deps = mock_dependencies(&[]); + let mut deps = mock_dependencies(); let contract = setup_contract(deps.as_mut()); let minter = mock_info(MINTER, &[]); diff --git a/cw721/on-chain-metadata/.cargo/config b/cw721/on-chain-metadata/.cargo/config index 336b618..7d1a066 100644 --- a/cw721/on-chain-metadata/.cargo/config +++ b/cw721/on-chain-metadata/.cargo/config @@ -1,4 +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/cw721/on-chain-metadata/.gitignore b/cw721/on-chain-metadata/.gitignore index dfdaaa6..f9b9a83 100644 --- a/cw721/on-chain-metadata/.gitignore +++ b/cw721/on-chain-metadata/.gitignore @@ -1,5 +1,6 @@ # Build results /target +/artifacts # Cargo+Git helper file (https://github.com/rust-lang/cargo/blob/0.44.1/src/cargo/sources/git/utils.rs#L320-L327) .cargo-ok diff --git a/cw721/on-chain-metadata/Cargo.toml b/cw721/on-chain-metadata/Cargo.toml index 0046ba0..1bf98d7 100644 --- a/cw721/on-chain-metadata/Cargo.toml +++ b/cw721/on-chain-metadata/Cargo.toml @@ -33,19 +33,20 @@ library = [] [package.metadata.scripts] optimize = """docker run --rm -v "$(pwd)":/code \ + -e CARGO_TERM_COLOR=always \ --mount type=volume,source="$(basename "$(pwd)")_cache",target=/code/target \ --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \ - cosmwasm/rust-optimizer:0.12.3 + cosmwasm/rust-optimizer:0.12.5 """ [dependencies] -cosmwasm-std = "0.16.2" -cw2 = "0.9.1" -cw721 = "0.9.2" -cw721-base = { version = "0.9.2", features = ["library"] } -schemars = "0.8.8" -serde = { version = "1.0.130", default-features = false, features = ["derive"] } -thiserror = "1.0.26" +cosmwasm-std = "1.0.0-beta" +cw2 = "0.11" +cw721 = "0.11" +cw721-base = { version = "0.11", features = ["library"] } +schemars = "0.8" +serde = { version = "1.0", default-features = false, features = ["derive"] } +thiserror = "1.0" [dev-dependencies] -cosmwasm-schema = "0.16.2" +cosmwasm-schema = "1.0.0-beta" diff --git a/cw721/on-chain-metadata/examples/schema.rs b/cw721/on-chain-metadata/examples/schema.rs index 63fbf80..0516b42 100644 --- a/cw721/on-chain-metadata/examples/schema.rs +++ b/cw721/on-chain-metadata/examples/schema.rs @@ -3,11 +3,11 @@ use std::fs::create_dir_all; use cosmwasm_schema::{export_schema, export_schema_with_title, remove_schemas, schema_for}; -use {{crate_name}}::{ExecuteMsg, Extension, InstantiateMsg, MinterResponse, QueryMsg}; use cw721::{ - AllNftInfoResponse, ApprovedForAllResponse, ContractInfoResponse, NftInfoResponse, - NumTokensResponse, OwnerOfResponse, TokensResponse, + AllNftInfoResponse, ApprovalResponse, ApprovalsResponse, ContractInfoResponse, NftInfoResponse, + NumTokensResponse, OperatorsResponse, OwnerOfResponse, TokensResponse, }; +use {{crate_name}}::{ExecuteMsg, Extension, InstantiateMsg, MinterResponse, QueryMsg}; fn main() { let mut out_dir = current_dir().unwrap(); @@ -23,7 +23,9 @@ fn main() { &out_dir, "AllNftInfoResponse", ); - export_schema(&schema_for!(ApprovedForAllResponse), &out_dir); + export_schema(&schema_for!(ApprovalResponse), &out_dir); + export_schema(&schema_for!(ApprovalsResponse), &out_dir); + export_schema(&schema_for!(OperatorsResponse), &out_dir); export_schema(&schema_for!(ContractInfoResponse), &out_dir); export_schema(&schema_for!(MinterResponse), &out_dir); export_schema_with_title( diff --git a/cw721/on-chain-metadata/src/lib.rs b/cw721/on-chain-metadata/src/lib.rs index a8dc626..40e2440 100644 --- a/cw721/on-chain-metadata/src/lib.rs +++ b/cw721/on-chain-metadata/src/lib.rs @@ -95,7 +95,7 @@ mod tests { #[test] fn use_metadata_extension() { - let mut deps = mock_dependencies(&[]); + let mut deps = mock_dependencies(); let contract = Cw721MetadataContract::default(); let info = mock_info(CREATOR, &[]); diff --git a/default/.cargo/config b/default/.cargo/config index 336b618..7d1a066 100644 --- a/default/.cargo/config +++ b/default/.cargo/config @@ -1,4 +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/default/.gitignore b/default/.gitignore index dfdaaa6..f9b9a83 100644 --- a/default/.gitignore +++ b/default/.gitignore @@ -1,5 +1,6 @@ # Build results /target +/artifacts # Cargo+Git helper file (https://github.com/rust-lang/cargo/blob/0.44.1/src/cargo/sources/git/utils.rs#L320-L327) .cargo-ok diff --git a/default/Cargo.toml b/default/Cargo.toml index 6ad4c4a..5c4b426 100644 --- a/default/Cargo.toml +++ b/default/Cargo.toml @@ -34,19 +34,20 @@ library = [] [package.metadata.scripts] optimize = """docker run --rm -v "$(pwd)":/code \ + -e CARGO_TERM_COLOR=always \ --mount type=volume,source="$(basename "$(pwd)")_cache",target=/code/target \ --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \ - cosmwasm/rust-optimizer:0.12.3 + cosmwasm/rust-optimizer:0.12.5 """ [dependencies] -cosmwasm-std = { version = "0.16.2" } -cosmwasm-storage = { version = "0.16.0" } -cw-storage-plus = "0.8.0" -cw2 = "0.8.1" -schemars = "0.8.3" -serde = { version = "1.0.127", default-features = false, features = ["derive"] } -thiserror = { version = "1.0.26" } +cosmwasm-std = "1.0.0-beta" +cosmwasm-storage = "1.0.0-beta" +cw-storage-plus = "0.12" +cw2 = "0.12" +schemars = "0.8" +serde = { version = "1.0", default-features = false, features = ["derive"] } +thiserror = "1.0" [dev-dependencies] -cosmwasm-schema = { version = "0.16.0" } +cosmwasm-schema = "1.0.0-beta" diff --git a/default/src/contract.rs b/default/src/contract.rs index 1f98206..0c5d416 100644 --- a/default/src/contract.rs +++ b/default/src/contract.rs @@ -64,12 +64,14 @@ fn hello_world() -> StdResult { #[cfg(test)] mod tests { use super::*; - use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info}; + use cosmwasm_std::testing::{ + mock_dependencies, mock_dependencies_with_balance, mock_env, mock_info, + }; use cosmwasm_std::{coins, from_binary}; #[test] fn can_instantiate() { - let mut deps = mock_dependencies(&[]); + let mut deps = mock_dependencies(); let res = instantiate_contract(deps.as_mut()); assert_eq!(0, res.messages.len()); @@ -85,7 +87,7 @@ mod tests { #[test] fn can_execute() { - let mut deps = mock_dependencies(&coins(2, "token")); + let mut deps = mock_dependencies_with_balance(&coins(2, "token")); instantiate_contract(deps.as_mut()); @@ -104,7 +106,7 @@ mod tests { #[test] fn can_query() { - let mut deps = mock_dependencies(&coins(2, "token")); + let mut deps = mock_dependencies_with_balance(&coins(2, "token")); instantiate_contract(deps.as_mut()); diff --git a/increment/.cargo/config b/increment/.cargo/config index 336b618..7d1a066 100644 --- a/increment/.cargo/config +++ b/increment/.cargo/config @@ -1,4 +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/increment/.gitignore b/increment/.gitignore index dfdaaa6..f9b9a83 100644 --- a/increment/.gitignore +++ b/increment/.gitignore @@ -1,5 +1,6 @@ # Build results /target +/artifacts # Cargo+Git helper file (https://github.com/rust-lang/cargo/blob/0.44.1/src/cargo/sources/git/utils.rs#L320-L327) .cargo-ok diff --git a/increment/Cargo.toml b/increment/Cargo.toml index 6ad4c4a..0d03aeb 100644 --- a/increment/Cargo.toml +++ b/increment/Cargo.toml @@ -34,19 +34,20 @@ library = [] [package.metadata.scripts] optimize = """docker run --rm -v "$(pwd)":/code \ + -e CARGO_TERM_COLOR=always \ --mount type=volume,source="$(basename "$(pwd)")_cache",target=/code/target \ --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \ - cosmwasm/rust-optimizer:0.12.3 + cosmwasm/rust-optimizer:0.12.5 """ [dependencies] -cosmwasm-std = { version = "0.16.2" } -cosmwasm-storage = { version = "0.16.0" } -cw-storage-plus = "0.8.0" -cw2 = "0.8.1" -schemars = "0.8.3" -serde = { version = "1.0.127", default-features = false, features = ["derive"] } -thiserror = { version = "1.0.26" } +cosmwasm-std = "1.0.0-beta5" +cosmwasm-storage = "1.0.0-beta5" +cw-storage-plus = "0.12" +cw2 = "0.12" +schemars = "0.8" +serde = { version = "1.0", default-features = false, features = ["derive"] } +thiserror = "1.0" [dev-dependencies] -cosmwasm-schema = { version = "0.16.0" } +cosmwasm-schema = "1.0.0-beta5" diff --git a/increment/src/contract.rs b/increment/src/contract.rs index 91540c3..b602654 100644 --- a/increment/src/contract.rs +++ b/increment/src/contract.rs @@ -78,12 +78,14 @@ fn query_count(deps: Deps) -> StdResult { #[cfg(test)] mod tests { use super::*; - use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info}; + use cosmwasm_std::testing::{ + mock_dependencies, mock_dependencies_with_balance, mock_env, mock_info, + }; use cosmwasm_std::{coins, from_binary}; #[test] fn proper_initialization() { - let mut deps = mock_dependencies(&[]); + let mut deps = mock_dependencies(); let msg = InstantiateMsg { count: 17 }; let info = mock_info("creator", &coins(1000, "earth")); @@ -100,7 +102,7 @@ mod tests { #[test] fn increment() { - let mut deps = mock_dependencies(&coins(2, "token")); + let mut deps = mock_dependencies_with_balance(&coins(2, "token")); let msg = InstantiateMsg { count: 17 }; let info = mock_info("creator", &coins(2, "token")); @@ -119,7 +121,7 @@ mod tests { #[test] fn reset() { - let mut deps = mock_dependencies(&coins(2, "token")); + let mut deps = mock_dependencies_with_balance(&coins(2, "token")); let msg = InstantiateMsg { count: 17 }; let info = mock_info("creator", &coins(2, "token"));