diff --git a/Cargo.lock b/Cargo.lock index 635f52999..e4e6702ea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -170,7 +170,7 @@ dependencies = [ [[package]] name = "cw721" -version = "0.10.0" +version = "0.10.1" dependencies = [ "cosmwasm-schema", "cosmwasm-std", @@ -181,7 +181,7 @@ dependencies = [ [[package]] name = "cw721-base" -version = "0.10.0" +version = "0.10.1" dependencies = [ "cosmwasm-schema", "cosmwasm-std", @@ -196,7 +196,7 @@ dependencies = [ [[package]] name = "cw721-metadata-onchain" -version = "0.10.0" +version = "0.10.1" dependencies = [ "cosmwasm-schema", "cosmwasm-std", diff --git a/contracts/cw721-base/Cargo.toml b/contracts/cw721-base/Cargo.toml index 97aa72aa5..057c4e852 100644 --- a/contracts/cw721-base/Cargo.toml +++ b/contracts/cw721-base/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cw721-base" -version = "0.10.0" +version = "0.10.1" authors = ["Ethan Frey "] edition = "2018" description = "Basic implementation cw721 NFTs" @@ -27,7 +27,7 @@ library = [] [dependencies] cw0 = { version = "0.10.2" } cw2 = { version = "0.10.2" } -cw721 = { path = "../../packages/cw721", version = "0.10.0" } +cw721 = { path = "../../packages/cw721", version = "0.10.1" } cw-storage-plus = { version = "0.10.2" } cosmwasm-std = { version = "1.0.0-beta2" } schemars = "0.8.6" diff --git a/contracts/cw721-base/examples/schema.rs b/contracts/cw721-base/examples/schema.rs index 1b7b115d0..116dad786 100644 --- a/contracts/cw721-base/examples/schema.rs +++ b/contracts/cw721-base/examples/schema.rs @@ -4,8 +4,8 @@ use std::fs::create_dir_all; use cosmwasm_schema::{export_schema, export_schema_with_title, remove_schemas, schema_for}; use cw721::{ - AllNftInfoResponse, ApprovedForAllResponse, ContractInfoResponse, NftInfoResponse, - NumTokensResponse, OwnerOfResponse, TokensResponse, + AllNftInfoResponse, ApprovedForAllResponse, ApprovedResponse, ContractInfoResponse, + NftInfoResponse, NumTokensResponse, OwnerOfResponse, TokensResponse, }; use cw721_base::{ExecuteMsg, Extension, InstantiateMsg, MinterResponse, QueryMsg}; @@ -23,6 +23,7 @@ fn main() { &out_dir, "AllNftInfoResponse", ); + export_schema(&schema_for!(ApprovedResponse), &out_dir); export_schema(&schema_for!(ApprovedForAllResponse), &out_dir); export_schema(&schema_for!(ContractInfoResponse), &out_dir); export_schema(&schema_for!(MinterResponse), &out_dir); diff --git a/contracts/cw721-base/schema/approved_response.json b/contracts/cw721-base/schema/approved_response.json new file mode 100644 index 000000000..e0acd4ad9 --- /dev/null +++ b/contracts/cw721-base/schema/approved_response.json @@ -0,0 +1,94 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "ApprovedResponse", + "type": "object", + "required": [ + "approval" + ], + "properties": { + "approval": { + "$ref": "#/definitions/Approval" + } + }, + "definitions": { + "Approval": { + "type": "object", + "required": [ + "expires", + "spender" + ], + "properties": { + "expires": { + "description": "When the Approval expires (maybe Expiration::never)", + "allOf": [ + { + "$ref": "#/definitions/Expiration" + } + ] + }, + "spender": { + "description": "Account that can transfer/send the token", + "type": "string" + } + } + }, + "Expiration": { + "description": "Expiration represents a point in time when some event happens. It can compare with a BlockInfo and will return is_expired() == true once the condition is hit (and for every block in the future)", + "oneOf": [ + { + "description": "AtHeight will expire when `env.block.height` >= height", + "type": "object", + "required": [ + "at_height" + ], + "properties": { + "at_height": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + }, + "additionalProperties": false + }, + { + "description": "AtTime will expire when `env.block.time` >= time", + "type": "object", + "required": [ + "at_time" + ], + "properties": { + "at_time": { + "$ref": "#/definitions/Timestamp" + } + }, + "additionalProperties": false + }, + { + "description": "Never will never expire. Used to express the empty variant", + "type": "object", + "required": [ + "never" + ], + "properties": { + "never": { + "type": "object" + } + }, + "additionalProperties": false + } + ] + }, + "Timestamp": { + "description": "A point in time in nanosecond precision.\n\nThis type can represent times from 1970-01-01T00:00:00Z to 2554-07-21T23:34:33Z.\n\n## Examples\n\n``` # use cosmwasm_std::Timestamp; let ts = Timestamp::from_nanos(1_000_000_202); assert_eq!(ts.nanos(), 1_000_000_202); assert_eq!(ts.seconds(), 1); assert_eq!(ts.subsec_nanos(), 202);\n\nlet ts = ts.plus_seconds(2); assert_eq!(ts.nanos(), 3_000_000_202); assert_eq!(ts.seconds(), 3); assert_eq!(ts.subsec_nanos(), 202); ```", + "allOf": [ + { + "$ref": "#/definitions/Uint64" + } + ] + }, + "Uint64": { + "description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```", + "type": "string" + } + } +} diff --git a/contracts/cw721-base/schema/query_msg.json b/contracts/cw721-base/schema/query_msg.json index bcf6a51e7..01d86c8a1 100644 --- a/contracts/cw721-base/schema/query_msg.json +++ b/contracts/cw721-base/schema/query_msg.json @@ -30,6 +30,31 @@ }, "additionalProperties": false }, + { + "description": "Return operator that can access all of the owner's tokens. Return type: `ApprovedResponse`", + "type": "object", + "required": [ + "approved" + ], + "properties": { + "approved": { + "type": "object", + "required": [ + "operator", + "owner" + ], + "properties": { + "operator": { + "type": "string" + }, + "owner": { + "type": "string" + } + } + } + }, + "additionalProperties": false + }, { "description": "List all operators that can access all of the owner's tokens Return type: `ApprovedForAllResponse`", "type": "object", diff --git a/contracts/cw721-base/src/contract_tests.rs b/contracts/cw721-base/src/contract_tests.rs index db269644c..e277bd215 100644 --- a/contracts/cw721-base/src/contract_tests.rs +++ b/contracts/cw721-base/src/contract_tests.rs @@ -3,8 +3,8 @@ 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, ApprovedForAllResponse, ApprovedResponse, ContractInfoResponse, Cw721Query, + Cw721ReceiveMsg, Expiration, NftInfoResponse, OwnerOfResponse, }; use crate::{ @@ -470,7 +470,7 @@ fn approving_all_revoking_all() { }; let owner = mock_info("demeter", &[]); let res = contract - .execute(deps.as_mut(), mock_env(), owner, approve_all_msg) + .execute(deps.as_mut(), mock_env(), owner.clone(), approve_all_msg) .unwrap(); assert_eq!( res, @@ -480,6 +480,25 @@ fn approving_all_revoking_all() { .add_attribute("operator", "random") ); + // test approval query + let res = contract + .approval( + deps.as_ref(), + mock_env(), + owner.sender.into_string(), + String::from("random"), + ) + .unwrap(); + assert_eq!( + res, + ApprovedResponse { + approval: Approval { + spender: String::from("random"), + expires: Expiration::Never {} + } + } + ); + // random can now transfer let random = mock_info("random", &[]); let transfer_msg = ExecuteMsg::TransferNft { diff --git a/contracts/cw721-base/src/msg.rs b/contracts/cw721-base/src/msg.rs index 9aa27a21f..7499e4993 100644 --- a/contracts/cw721-base/src/msg.rs +++ b/contracts/cw721-base/src/msg.rs @@ -81,6 +81,14 @@ pub enum QueryMsg { /// unset or false will filter out expired approvals, you must set to true to see them include_expired: Option, }, + + /// Return operator that can access all of the owner's tokens. + /// Return type: `ApprovedResponse` + Approved { + owner: String, + operator: String, + }, + /// List all operators that can access all of the owner's tokens /// Return type: `ApprovedForAllResponse` ApprovedForAll { diff --git a/contracts/cw721-base/src/query.rs b/contracts/cw721-base/src/query.rs index bd11056d2..9c948c5a8 100644 --- a/contracts/cw721-base/src/query.rs +++ b/contracts/cw721-base/src/query.rs @@ -5,8 +5,8 @@ use cosmwasm_std::{to_binary, Binary, BlockInfo, Deps, Env, Order, Record, StdEr use cw0::maybe_addr; use cw721::{ - AllNftInfoResponse, ApprovedForAllResponse, ContractInfoResponse, CustomMsg, Cw721Query, - Expiration, NftInfoResponse, NumTokensResponse, OwnerOfResponse, TokensResponse, + AllNftInfoResponse, ApprovedForAllResponse, ApprovedResponse, ContractInfoResponse, CustomMsg, + Cw721Query, Expiration, NftInfoResponse, NumTokensResponse, OwnerOfResponse, TokensResponse, }; use cw_storage_plus::Bound; @@ -79,6 +79,29 @@ where Ok(ApprovedForAllResponse { operators: res? }) } + fn approval( + &self, + deps: Deps, + _env: Env, + owner: String, + operator: String, + ) -> StdResult { + let owner_addr = deps.api.addr_validate(&owner)?; + let operator_addr = deps.api.addr_validate(&operator)?; + + let expires = self + .operators + .key((&owner_addr, &operator_addr)) + .load(deps.storage)?; + + Ok(ApprovedResponse { + approval: cw721::Approval { + spender: operator, + expires, + }, + }) + } + fn tokens( &self, deps: Deps, @@ -197,6 +220,9 @@ where QueryMsg::AllTokens { start_after, limit } => { to_binary(&self.all_tokens(deps, start_after, limit)?) } + QueryMsg::Approved { owner, operator } => { + to_binary(&self.approval(deps, env, owner, operator)?) + } } } } diff --git a/contracts/cw721-metadata-onchain/Cargo.toml b/contracts/cw721-metadata-onchain/Cargo.toml index 4c27de571..01db272af 100644 --- a/contracts/cw721-metadata-onchain/Cargo.toml +++ b/contracts/cw721-metadata-onchain/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cw721-metadata-onchain" -version = "0.10.0" +version = "0.10.1" authors = ["Ethan Frey "] edition = "2018" description = "Example extending CW721 NFT to store metadata on chain" diff --git a/contracts/cw721-metadata-onchain/examples/schema.rs b/contracts/cw721-metadata-onchain/examples/schema.rs index 1b3c97b46..e77523412 100644 --- a/contracts/cw721-metadata-onchain/examples/schema.rs +++ b/contracts/cw721-metadata-onchain/examples/schema.rs @@ -4,8 +4,8 @@ use std::fs::create_dir_all; use cosmwasm_schema::{export_schema, export_schema_with_title, remove_schemas, schema_for}; use cw721::{ - AllNftInfoResponse, ApprovedForAllResponse, ContractInfoResponse, NftInfoResponse, - NumTokensResponse, OwnerOfResponse, TokensResponse, + AllNftInfoResponse, ApprovedForAllResponse, ApprovedResponse, ContractInfoResponse, + NftInfoResponse, NumTokensResponse, OwnerOfResponse, TokensResponse, }; use cw721_metadata_onchain::{ExecuteMsg, Extension, InstantiateMsg, MinterResponse, QueryMsg}; @@ -23,6 +23,7 @@ fn main() { &out_dir, "AllNftInfoResponse", ); + export_schema(&schema_for!(ApprovedResponse), &out_dir); export_schema(&schema_for!(ApprovedForAllResponse), &out_dir); export_schema(&schema_for!(ContractInfoResponse), &out_dir); export_schema(&schema_for!(MinterResponse), &out_dir); diff --git a/contracts/cw721-metadata-onchain/schema/approved_response.json b/contracts/cw721-metadata-onchain/schema/approved_response.json new file mode 100644 index 000000000..e0acd4ad9 --- /dev/null +++ b/contracts/cw721-metadata-onchain/schema/approved_response.json @@ -0,0 +1,94 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "ApprovedResponse", + "type": "object", + "required": [ + "approval" + ], + "properties": { + "approval": { + "$ref": "#/definitions/Approval" + } + }, + "definitions": { + "Approval": { + "type": "object", + "required": [ + "expires", + "spender" + ], + "properties": { + "expires": { + "description": "When the Approval expires (maybe Expiration::never)", + "allOf": [ + { + "$ref": "#/definitions/Expiration" + } + ] + }, + "spender": { + "description": "Account that can transfer/send the token", + "type": "string" + } + } + }, + "Expiration": { + "description": "Expiration represents a point in time when some event happens. It can compare with a BlockInfo and will return is_expired() == true once the condition is hit (and for every block in the future)", + "oneOf": [ + { + "description": "AtHeight will expire when `env.block.height` >= height", + "type": "object", + "required": [ + "at_height" + ], + "properties": { + "at_height": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + }, + "additionalProperties": false + }, + { + "description": "AtTime will expire when `env.block.time` >= time", + "type": "object", + "required": [ + "at_time" + ], + "properties": { + "at_time": { + "$ref": "#/definitions/Timestamp" + } + }, + "additionalProperties": false + }, + { + "description": "Never will never expire. Used to express the empty variant", + "type": "object", + "required": [ + "never" + ], + "properties": { + "never": { + "type": "object" + } + }, + "additionalProperties": false + } + ] + }, + "Timestamp": { + "description": "A point in time in nanosecond precision.\n\nThis type can represent times from 1970-01-01T00:00:00Z to 2554-07-21T23:34:33Z.\n\n## Examples\n\n``` # use cosmwasm_std::Timestamp; let ts = Timestamp::from_nanos(1_000_000_202); assert_eq!(ts.nanos(), 1_000_000_202); assert_eq!(ts.seconds(), 1); assert_eq!(ts.subsec_nanos(), 202);\n\nlet ts = ts.plus_seconds(2); assert_eq!(ts.nanos(), 3_000_000_202); assert_eq!(ts.seconds(), 3); assert_eq!(ts.subsec_nanos(), 202); ```", + "allOf": [ + { + "$ref": "#/definitions/Uint64" + } + ] + }, + "Uint64": { + "description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```", + "type": "string" + } + } +} diff --git a/contracts/cw721-metadata-onchain/schema/query_msg.json b/contracts/cw721-metadata-onchain/schema/query_msg.json index bcf6a51e7..01d86c8a1 100644 --- a/contracts/cw721-metadata-onchain/schema/query_msg.json +++ b/contracts/cw721-metadata-onchain/schema/query_msg.json @@ -30,6 +30,31 @@ }, "additionalProperties": false }, + { + "description": "Return operator that can access all of the owner's tokens. Return type: `ApprovedResponse`", + "type": "object", + "required": [ + "approved" + ], + "properties": { + "approved": { + "type": "object", + "required": [ + "operator", + "owner" + ], + "properties": { + "operator": { + "type": "string" + }, + "owner": { + "type": "string" + } + } + } + }, + "additionalProperties": false + }, { "description": "List all operators that can access all of the owner's tokens Return type: `ApprovedForAllResponse`", "type": "object", diff --git a/packages/cw721/Cargo.toml b/packages/cw721/Cargo.toml index ea9af7d4e..6bbf3f4ec 100644 --- a/packages/cw721/Cargo.toml +++ b/packages/cw721/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cw721" -version = "0.10.0" +version = "0.10.1" authors = ["Ethan Frey "] edition = "2018" description = "Definition and types for the CosmWasm-721 NFT interface" diff --git a/packages/cw721/examples/schema.rs b/packages/cw721/examples/schema.rs index 15b607152..071e12692 100644 --- a/packages/cw721/examples/schema.rs +++ b/packages/cw721/examples/schema.rs @@ -5,9 +5,9 @@ use cosmwasm_schema::{export_schema, export_schema_with_title, remove_schemas, s use cosmwasm_std::Empty; use cw721::{ - AllNftInfoResponse, ApprovedForAllResponse, ContractInfoResponse, Cw721ExecuteMsg, - Cw721QueryMsg, Cw721ReceiveMsg, NftInfoResponse, NumTokensResponse, OwnerOfResponse, - TokensResponse, + AllNftInfoResponse, ApprovedForAllResponse, ApprovedResponse, ContractInfoResponse, + Cw721ExecuteMsg, Cw721QueryMsg, Cw721ReceiveMsg, NftInfoResponse, NumTokensResponse, + OwnerOfResponse, TokensResponse, }; type Extension = Option; @@ -26,6 +26,7 @@ fn main() { &out_dir, "AllNftInfoResponse", ); + export_schema(&schema_for!(ApprovedResponse), &out_dir); export_schema(&schema_for!(ApprovedForAllResponse), &out_dir); export_schema(&schema_for!(ContractInfoResponse), &out_dir); export_schema(&schema_for!(OwnerOfResponse), &out_dir); diff --git a/packages/cw721/schema/approved_response.json b/packages/cw721/schema/approved_response.json new file mode 100644 index 000000000..e0acd4ad9 --- /dev/null +++ b/packages/cw721/schema/approved_response.json @@ -0,0 +1,94 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "ApprovedResponse", + "type": "object", + "required": [ + "approval" + ], + "properties": { + "approval": { + "$ref": "#/definitions/Approval" + } + }, + "definitions": { + "Approval": { + "type": "object", + "required": [ + "expires", + "spender" + ], + "properties": { + "expires": { + "description": "When the Approval expires (maybe Expiration::never)", + "allOf": [ + { + "$ref": "#/definitions/Expiration" + } + ] + }, + "spender": { + "description": "Account that can transfer/send the token", + "type": "string" + } + } + }, + "Expiration": { + "description": "Expiration represents a point in time when some event happens. It can compare with a BlockInfo and will return is_expired() == true once the condition is hit (and for every block in the future)", + "oneOf": [ + { + "description": "AtHeight will expire when `env.block.height` >= height", + "type": "object", + "required": [ + "at_height" + ], + "properties": { + "at_height": { + "type": "integer", + "format": "uint64", + "minimum": 0.0 + } + }, + "additionalProperties": false + }, + { + "description": "AtTime will expire when `env.block.time` >= time", + "type": "object", + "required": [ + "at_time" + ], + "properties": { + "at_time": { + "$ref": "#/definitions/Timestamp" + } + }, + "additionalProperties": false + }, + { + "description": "Never will never expire. Used to express the empty variant", + "type": "object", + "required": [ + "never" + ], + "properties": { + "never": { + "type": "object" + } + }, + "additionalProperties": false + } + ] + }, + "Timestamp": { + "description": "A point in time in nanosecond precision.\n\nThis type can represent times from 1970-01-01T00:00:00Z to 2554-07-21T23:34:33Z.\n\n## Examples\n\n``` # use cosmwasm_std::Timestamp; let ts = Timestamp::from_nanos(1_000_000_202); assert_eq!(ts.nanos(), 1_000_000_202); assert_eq!(ts.seconds(), 1); assert_eq!(ts.subsec_nanos(), 202);\n\nlet ts = ts.plus_seconds(2); assert_eq!(ts.nanos(), 3_000_000_202); assert_eq!(ts.seconds(), 3); assert_eq!(ts.subsec_nanos(), 202); ```", + "allOf": [ + { + "$ref": "#/definitions/Uint64" + } + ] + }, + "Uint64": { + "description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```", + "type": "string" + } + } +} diff --git a/packages/cw721/schema/cw721_query_msg.json b/packages/cw721/schema/cw721_query_msg.json index 0dafe9db1..383e1b437 100644 --- a/packages/cw721/schema/cw721_query_msg.json +++ b/packages/cw721/schema/cw721_query_msg.json @@ -30,6 +30,31 @@ }, "additionalProperties": false }, + { + "description": "Return operator that can access all of the owner's tokens. Return type: `ApprovedResponse`", + "type": "object", + "required": [ + "approved" + ], + "properties": { + "approved": { + "type": "object", + "required": [ + "operator", + "owner" + ], + "properties": { + "operator": { + "type": "string" + }, + "owner": { + "type": "string" + } + } + } + }, + "additionalProperties": false + }, { "description": "List all operators that can access all of the owner's tokens. Return type: `ApprovedForAllResponse`", "type": "object", diff --git a/packages/cw721/src/helpers.rs b/packages/cw721/src/helpers.rs index 94e1cbd35..34f6f8446 100644 --- a/packages/cw721/src/helpers.rs +++ b/packages/cw721/src/helpers.rs @@ -1,13 +1,12 @@ use schemars::JsonSchema; use serde::{de::DeserializeOwned, Deserialize, Serialize}; -use cosmwasm_std::{ - to_binary, Addr, CosmosMsg, Empty, Querier, QuerierWrapper, StdResult, WasmMsg, WasmQuery, -}; +use cosmwasm_std::{to_binary, Addr, CosmosMsg, QuerierWrapper, StdResult, WasmMsg, WasmQuery}; use crate::{ - AllNftInfoResponse, Approval, ApprovedForAllResponse, ContractInfoResponse, Cw721ExecuteMsg, - Cw721QueryMsg, NftInfoResponse, NumTokensResponse, OwnerOfResponse, TokensResponse, + AllNftInfoResponse, Approval, ApprovedForAllResponse, ApprovedResponse, ContractInfoResponse, + Cw721ExecuteMsg, Cw721QueryMsg, NftInfoResponse, NumTokensResponse, OwnerOfResponse, + TokensResponse, }; /// Cw721Contract is a wrapper around Addr that provides a lot of helpers @@ -32,9 +31,9 @@ impl Cw721Contract { .into()) } - pub fn query( + pub fn query( &self, - querier: &Q, + querier: &QuerierWrapper, req: Cw721QueryMsg, ) -> StdResult { let query = WasmQuery::Smart { @@ -42,14 +41,14 @@ impl Cw721Contract { msg: to_binary(&req)?, } .into(); - QuerierWrapper::::new(querier).query(&query) + querier.query(&query) } /*** queries ***/ - pub fn owner_of>( + pub fn owner_of>( &self, - querier: &Q, + querier: &QuerierWrapper, token_id: T, include_expired: bool, ) -> StdResult { @@ -60,9 +59,23 @@ impl Cw721Contract { self.query(querier, req) } - pub fn approved_for_all>( + pub fn approved>( + &self, + querier: &QuerierWrapper, + owner: T, + operator: T, + ) -> StdResult { + let req = Cw721QueryMsg::Approved { + owner: owner.into(), + operator: operator.into(), + }; + let res: ApprovedResponse = self.query(querier, req)?; + Ok(res) + } + + pub fn approved_for_all>( &self, - querier: &Q, + querier: &QuerierWrapper, owner: T, include_expired: bool, start_after: Option, @@ -78,22 +91,22 @@ impl Cw721Contract { Ok(res.operators) } - pub fn num_tokens(&self, querier: &Q) -> StdResult { + pub fn num_tokens(&self, querier: &QuerierWrapper) -> StdResult { let req = Cw721QueryMsg::NumTokens {}; let res: NumTokensResponse = self.query(querier, req)?; Ok(res.count) } /// With metadata extension - pub fn contract_info(&self, querier: &Q) -> StdResult { + pub fn contract_info(&self, querier: &QuerierWrapper) -> StdResult { let req = Cw721QueryMsg::ContractInfo {}; self.query(querier, req) } /// With metadata extension - pub fn nft_info, U: DeserializeOwned>( + pub fn nft_info, U: DeserializeOwned>( &self, - querier: &Q, + querier: &QuerierWrapper, token_id: T, ) -> StdResult> { let req = Cw721QueryMsg::NftInfo { @@ -103,9 +116,9 @@ impl Cw721Contract { } /// With metadata extension - pub fn all_nft_info, U: DeserializeOwned>( + pub fn all_nft_info, U: DeserializeOwned>( &self, - querier: &Q, + querier: &QuerierWrapper, token_id: T, include_expired: bool, ) -> StdResult> { @@ -117,9 +130,9 @@ impl Cw721Contract { } /// With enumerable extension - pub fn tokens>( + pub fn tokens>( &self, - querier: &Q, + querier: &QuerierWrapper, owner: T, start_after: Option, limit: Option, @@ -133,9 +146,9 @@ impl Cw721Contract { } /// With enumerable extension - pub fn all_tokens( + pub fn all_tokens( &self, - querier: &Q, + querier: &QuerierWrapper, start_after: Option, limit: Option, ) -> StdResult { @@ -144,12 +157,12 @@ impl Cw721Contract { } /// returns true if the contract supports the metadata extension - pub fn has_metadata(&self, querier: &Q) -> bool { + 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: &Q) -> bool { + pub fn has_enumerable(&self, querier: &QuerierWrapper) -> bool { self.tokens(querier, self.addr(), None, Some(1)).is_ok() } } diff --git a/packages/cw721/src/lib.rs b/packages/cw721/src/lib.rs index 5d1962919..6520d7e6e 100644 --- a/packages/cw721/src/lib.rs +++ b/packages/cw721/src/lib.rs @@ -9,8 +9,8 @@ pub use cw0::Expiration; pub use crate::helpers::Cw721Contract; pub use crate::msg::Cw721ExecuteMsg; pub use crate::query::{ - AllNftInfoResponse, Approval, ApprovedForAllResponse, ContractInfoResponse, Cw721QueryMsg, - NftInfoResponse, NumTokensResponse, OwnerOfResponse, TokensResponse, + AllNftInfoResponse, Approval, ApprovedForAllResponse, ApprovedResponse, ContractInfoResponse, + Cw721QueryMsg, NftInfoResponse, NumTokensResponse, OwnerOfResponse, TokensResponse, }; pub use crate::receiver::Cw721ReceiveMsg; pub use crate::traits::{CustomMsg, Cw721, Cw721Execute, Cw721Query}; diff --git a/packages/cw721/src/query.rs b/packages/cw721/src/query.rs index e3ada63f7..1c3d8d889 100644 --- a/packages/cw721/src/query.rs +++ b/packages/cw721/src/query.rs @@ -13,6 +13,11 @@ pub enum Cw721QueryMsg { /// unset or false will filter out expired approvals, you must set to true to see them include_expired: Option, }, + + /// Return operator that can access all of the owner's tokens. + /// Return type: `ApprovedResponse` + Approved { owner: String, operator: String }, + /// List all operators that can access all of the owner's tokens. /// Return type: `ApprovedForAllResponse` ApprovedForAll { @@ -74,6 +79,11 @@ pub struct Approval { pub expires: Expiration, } +#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] +pub struct ApprovedResponse { + pub approval: Approval, +} + #[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)] pub struct ApprovedForAllResponse { pub operators: Vec, diff --git a/packages/cw721/src/traits.rs b/packages/cw721/src/traits.rs index b2bc134a1..eccdf42f4 100644 --- a/packages/cw721/src/traits.rs +++ b/packages/cw721/src/traits.rs @@ -2,6 +2,7 @@ use schemars::JsonSchema; use serde::de::DeserializeOwned; use serde::Serialize; +use crate::query::ApprovedResponse; use crate::{ AllNftInfoResponse, ApprovedForAllResponse, ContractInfoResponse, NftInfoResponse, NumTokensResponse, OwnerOfResponse, TokensResponse, @@ -123,6 +124,14 @@ where limit: Option, ) -> StdResult; + fn approval( + &self, + deps: Deps, + env: Env, + owner: String, + spender: String, + ) -> StdResult; + fn tokens( &self, deps: Deps,