diff --git a/.env b/.env index 999095a2f6..693a03e752 100644 --- a/.env +++ b/.env @@ -1,7 +1,7 @@ INDEXER_NETWORK_ID=teritori-testnet TERITORI_MINTER_CODE_IDS=10 TENDERMINT_WEBSOCKET_ENDPOINT=wss://rpc.testnet.teritori.com/websocket -TERITORI_COLLECTION_WHITELIST=tori122qmagdhqxr00ldp5jax08zgdumahx4h03shcy4wn9ckchfzky5q3hdylc,tori1hzz0s0ucrhdp6tue2lxk3c03nj6f60qy463we7lgx0wudd72ctmstg4wkc,tori14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s3hewys,0x43cc70bf324d716782628bed38af97e4afe92f69,0x916ad9d549907ccbbaf9ba65526826bfc3a9c0c4,tori162skshe30f43kv2q2rw6we2mu3pvz43lm2zrg4hq50jdd2fjjdjsvm8mc7,tori1zxzv4j9dxarfhxhkxm5cfnv06vy6g4l80adjwaq3dxdzmh5jm8rsrkzz65,tori18etjzrma5604af50jjklk3wlkqcsxdrvmy6jzw5naw2t7kyv4rys3kpwky,tori10z8um7u47e24rv68ghd43tspeztmqy3cc283gvc3pj48zxs5ljdqn84deq,tori1afwrcs58afaka6ltynevwcvq8zhejr3ssn703c0hky5emh890vzsry5wp5 +TERITORI_COLLECTION_WHITELIST=tori156edst4w2cjj2l7g6xezzs7hf2vpl25mrpagkgde85aj360pc22s48m2ff,tori1hzz0s0ucrhdp6tue2lxk3c03nj6f60qy463we7lgx0wudd72ctmstg4wkc,tori14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s3hewys,0x43cc70bf324d716782628bed38af97e4afe92f69,0x916ad9d549907ccbbaf9ba65526826bfc3a9c0c4,tori162skshe30f43kv2q2rw6we2mu3pvz43lm2zrg4hq50jdd2fjjdjsvm8mc7,tori1zxzv4j9dxarfhxhkxm5cfnv06vy6g4l80adjwaq3dxdzmh5jm8rsrkzz65,tori18etjzrma5604af50jjklk3wlkqcsxdrvmy6jzw5naw2t7kyv4rys3kpwky,tori10z8um7u47e24rv68ghd43tspeztmqy3cc283gvc3pj48zxs5ljdqn84deq,tori1afwrcs58afaka6ltynevwcvq8zhejr3ssn703c0hky5emh890vzsry5wp5 PUBLIC_TENOR_KEY=AIzaSyA8TpVfoyoBaDdLww6wJ1Xe0OVN-Hi8qPE diff --git a/cosmwasm-contracts/cw721-membership/Cargo.toml b/cosmwasm-contracts/cw721-membership/Cargo.toml index c716087e0c..a71a250daf 100644 --- a/cosmwasm-contracts/cw721-membership/Cargo.toml +++ b/cosmwasm-contracts/cw721-membership/Cargo.toml @@ -17,7 +17,7 @@ cw-storage-plus = "1.1.0" thiserror = "1.0.44" cw721 = "0.18.0" cw721-metadata-onchain = { version = "0.15.0", features = ["library"] } -cw2981-royalties = "0.18.0" +cw2981-royalties = { version = "0.18.0", features = ["library"] } integer-encoding = "4.0.0" base64 = "0.21.7" diff --git a/cosmwasm-contracts/cw721-membership/Makefile b/cosmwasm-contracts/cw721-membership/Makefile index 31d753ae70..fc09c84ea9 100644 --- a/cosmwasm-contracts/cw721-membership/Makefile +++ b/cosmwasm-contracts/cw721-membership/Makefile @@ -3,11 +3,11 @@ ADMIN_ADDR=$(shell teritorid keys show $(ADMIN) --keyring-backend test --output NODE_FLAG=--node https://rpc.testnet.teritori.com:443 TX_FLAGS=--from $(ADMIN) --chain-id teritori-test-6 $(NODE_FLAG) --gas auto --gas-adjustment 1.3 -y -b sync --output json --keyring-backend test -o json QUERY_FLAGS=$(NODE_FLAG) -o json -CODE_ID=53 +CODE_ID=58 CONFIG=$(shell cat config.json | jq --rawfile desc desc.txt -r '.admin_addr="$(ADMIN_ADDR)" | .description=$$desc | tojson | @sh') # only informative -CONTRACT_ADDRESS=tori122qmagdhqxr00ldp5jax08zgdumahx4h03shcy4wn9ckchfzky5q3hdylc +CONTRACT_ADDRESS=tori156edst4w2cjj2l7g6xezzs7hf2vpl25mrpagkgde85aj360pc22s48m2ff .PHONY: artifacts/cw721_membership.wasm artifacts/cw721_membership.wasm: diff --git a/cosmwasm-contracts/cw721-membership/schema/cw721-membership.json b/cosmwasm-contracts/cw721-membership/schema/cw721-membership.json index 8980aefabe..a2feea33d0 100644 --- a/cosmwasm-contracts/cw721-membership/schema/cw721-membership.json +++ b/cosmwasm-contracts/cw721-membership/schema/cw721-membership.json @@ -430,6 +430,50 @@ } ], "definitions": { + "Cw2981BorkedQueryMsg": { + "oneOf": [ + { + "description": "Should be called on sale to see if royalties are owed by the marketplace selling the NFT, if CheckRoyalties returns true See https://eips.ethereum.org/EIPS/eip-2981", + "type": "object", + "required": [ + "RoyaltyInfo" + ], + "properties": { + "RoyaltyInfo": { + "type": "object", + "required": [ + "sale_price", + "token_id" + ], + "properties": { + "sale_price": { + "$ref": "#/definitions/Uint128" + }, + "token_id": { + "type": "string" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Called against contract to determine if this NFT implements royalties. Should return a boolean as part of CheckRoyaltiesResponse - default can simply be true if royalties are implemented at token level (i.e. always check on sale)", + "type": "object", + "required": [ + "CheckRoyalties" + ], + "properties": { + "CheckRoyalties": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + } + ] + }, "QueryMsg": { "oneOf": [ { @@ -523,39 +567,23 @@ { "type": "object", "required": [ - "royalty_info" + "extension" ], "properties": { - "royalty_info": { + "extension": { "type": "object", "required": [ - "sale_price", - "token_id" + "msg" ], "properties": { - "sale_price": { - "$ref": "#/definitions/Uint128" - }, - "token_id": { - "type": "string" + "msg": { + "$ref": "#/definitions/Cw2981BorkedQueryMsg" } } } }, "additionalProperties": false }, - { - "type": "object", - "required": [ - "check_royalties" - ], - "properties": { - "check_royalties": { - "type": "object" - } - }, - "additionalProperties": false - }, { "type": "object", "required": [ @@ -1164,21 +1192,6 @@ } } }, - "check_royalties": { - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "CheckRoyaltiesResponse", - "description": "Shows if the contract implements royalties if royalty_payments is true, marketplaces should pay them", - "type": "object", - "required": [ - "royalty_payments" - ], - "properties": { - "royalty_payments": { - "type": "boolean" - } - }, - "additionalProperties": false - }, "config": { "$schema": "http://json-schema.org/draft-07/schema#", "title": "Config", @@ -1239,6 +1252,53 @@ }, "additionalProperties": false }, + "extension": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Cw2981Response", + "anyOf": [ + { + "$ref": "#/definitions/CheckRoyaltiesResponse" + }, + { + "$ref": "#/definitions/RoyaltiesInfoResponse" + } + ], + "definitions": { + "CheckRoyaltiesResponse": { + "description": "Shows if the contract implements royalties if royalty_payments is true, marketplaces should pay them", + "type": "object", + "required": [ + "royalty_payments" + ], + "properties": { + "royalty_payments": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "RoyaltiesInfoResponse": { + "type": "object", + "required": [ + "address", + "royalty_amount" + ], + "properties": { + "address": { + "type": "string" + }, + "royalty_amount": { + "$ref": "#/definitions/Uint128" + } + }, + "additionalProperties": false + }, + "Uint128": { + "description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```", + "type": "string" + } + } + }, "nft_info": { "$schema": "http://json-schema.org/draft-07/schema#", "title": "NftInfoResponse_for_Metadata", @@ -1474,30 +1534,6 @@ } } }, - "royalty_info": { - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "RoyaltiesInfoResponse", - "type": "object", - "required": [ - "address", - "royalty_amount" - ], - "properties": { - "address": { - "type": "string" - }, - "royalty_amount": { - "$ref": "#/definitions/Uint128" - } - }, - "additionalProperties": false, - "definitions": { - "Uint128": { - "description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```", - "type": "string" - } - } - }, "subscription": { "$schema": "http://json-schema.org/draft-07/schema#", "title": "SubscriptionResponse", diff --git a/cosmwasm-contracts/cw721-membership/schema/raw/query.json b/cosmwasm-contracts/cw721-membership/schema/raw/query.json index f8cd2d91dd..91c8404830 100644 --- a/cosmwasm-contracts/cw721-membership/schema/raw/query.json +++ b/cosmwasm-contracts/cw721-membership/schema/raw/query.json @@ -7,6 +7,50 @@ } ], "definitions": { + "Cw2981BorkedQueryMsg": { + "oneOf": [ + { + "description": "Should be called on sale to see if royalties are owed by the marketplace selling the NFT, if CheckRoyalties returns true See https://eips.ethereum.org/EIPS/eip-2981", + "type": "object", + "required": [ + "RoyaltyInfo" + ], + "properties": { + "RoyaltyInfo": { + "type": "object", + "required": [ + "sale_price", + "token_id" + ], + "properties": { + "sale_price": { + "$ref": "#/definitions/Uint128" + }, + "token_id": { + "type": "string" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, + { + "description": "Called against contract to determine if this NFT implements royalties. Should return a boolean as part of CheckRoyaltiesResponse - default can simply be true if royalties are implemented at token level (i.e. always check on sale)", + "type": "object", + "required": [ + "CheckRoyalties" + ], + "properties": { + "CheckRoyalties": { + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false + } + ] + }, "QueryMsg": { "oneOf": [ { @@ -100,39 +144,23 @@ { "type": "object", "required": [ - "royalty_info" + "extension" ], "properties": { - "royalty_info": { + "extension": { "type": "object", "required": [ - "sale_price", - "token_id" + "msg" ], "properties": { - "sale_price": { - "$ref": "#/definitions/Uint128" - }, - "token_id": { - "type": "string" + "msg": { + "$ref": "#/definitions/Cw2981BorkedQueryMsg" } } } }, "additionalProperties": false }, - { - "type": "object", - "required": [ - "check_royalties" - ], - "properties": { - "check_royalties": { - "type": "object" - } - }, - "additionalProperties": false - }, { "type": "object", "required": [ diff --git a/cosmwasm-contracts/cw721-membership/schema/raw/response_to_extension.json b/cosmwasm-contracts/cw721-membership/schema/raw/response_to_extension.json new file mode 100644 index 0000000000..2cf920c9d8 --- /dev/null +++ b/cosmwasm-contracts/cw721-membership/schema/raw/response_to_extension.json @@ -0,0 +1,47 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Cw2981Response", + "anyOf": [ + { + "$ref": "#/definitions/CheckRoyaltiesResponse" + }, + { + "$ref": "#/definitions/RoyaltiesInfoResponse" + } + ], + "definitions": { + "CheckRoyaltiesResponse": { + "description": "Shows if the contract implements royalties if royalty_payments is true, marketplaces should pay them", + "type": "object", + "required": [ + "royalty_payments" + ], + "properties": { + "royalty_payments": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "RoyaltiesInfoResponse": { + "type": "object", + "required": [ + "address", + "royalty_amount" + ], + "properties": { + "address": { + "type": "string" + }, + "royalty_amount": { + "$ref": "#/definitions/Uint128" + } + }, + "additionalProperties": false + }, + "Uint128": { + "description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```", + "type": "string" + } + } +} diff --git a/cosmwasm-contracts/cw721-membership/src/contract.rs b/cosmwasm-contracts/cw721-membership/src/contract.rs index ae41703df1..f98f06e4ef 100644 --- a/cosmwasm-contracts/cw721-membership/src/contract.rs +++ b/cosmwasm-contracts/cw721-membership/src/contract.rs @@ -107,6 +107,13 @@ pub struct SubscriptionResponse { pub level: u16, } +#[cw_serde] +#[serde(untagged)] +pub enum Cw2981Response { + CheckRoyaltiesResponse(cw2981_royalties::msg::CheckRoyaltiesResponse), + RoyaltiesInfoResponse(cw2981_royalties::msg::RoyaltiesInfoResponse), +} + #[entry_points] #[contract] #[error(ContractError)] @@ -772,14 +779,34 @@ impl Cw721MembershipContract { // CW2981 Royalty Queries + #[msg(query)] + pub fn extension( + &self, + ctx: QueryCtx, + msg: Cw2981BorkedQueryMsg, + ) -> Result { + match msg { + Cw2981BorkedQueryMsg::CheckRoyalties {} => { + let res = self.check_royalties()?; + Ok(Cw2981Response::CheckRoyaltiesResponse(res)) + } + Cw2981BorkedQueryMsg::RoyaltyInfo { + token_id, + sale_price, + } => { + let res = self.royalty_info(ctx, token_id, sale_price)?; + Ok(Cw2981Response::RoyaltiesInfoResponse(res)) + } + } + } + /// Should be called on sale to see if royalties are owed /// by the marketplace selling the NFT, if CheckRoyalties /// returns true /// See https://eips.ethereum.org/EIPS/eip-2981 - #[msg(query)] - pub fn royalty_info( + fn royalty_info( &self, - _ctx: QueryCtx, + ctx: QueryCtx, token_id: String, // the denom of this sale must also be the denom returned by RoyaltiesInfoResponse // this was originally implemented as a Coin @@ -791,7 +818,7 @@ impl Cw721MembershipContract { let channel = self .channels - .load(_ctx.deps.storage, channel_id) + .load(ctx.deps.storage, channel_id) .map_err(|_| ContractError::ChannelNotFound)?; let royalty_amount = sale_price @@ -809,8 +836,7 @@ impl Cw721MembershipContract { /// CheckRoyaltiesResponse - default can simply be true /// if royalties are implemented at token level /// (i.e. always check on sale) - #[msg(query)] - pub fn check_royalties(&self, _ctx: QueryCtx) -> Result { + fn check_royalties(&self) -> Result { Ok(CheckRoyaltiesResponse { royalty_payments: true, }) @@ -1094,3 +1120,39 @@ pub fn parse_token_id(token_id: &String) -> Result<(u64, u64), ContractError> { pub fn format_token_id(channel_id: u64, nft_index: u64) -> String { URL_SAFE_NO_PAD.encode([nft_index.encode_var_vec(), channel_id.encode_var_vec()].concat()) } + +#[derive( + ::cosmwasm_schema::serde::Serialize, + ::cosmwasm_schema::serde::Deserialize, + ::std::clone::Clone, + ::std::fmt::Debug, + ::std::cmp::PartialEq, + ::cosmwasm_schema::schemars::JsonSchema, +)] +#[allow(clippy::derive_partial_eq_without_eq)] // Allow users of `#[cw_serde]` to not implement Eq without clippy complaining +#[serde( + deny_unknown_fields, + rename_all = "PascalCase", // this is borked in the Cw2981 libs used in teritori vault + crate = "::cosmwasm_schema::serde" +)] +#[schemars(crate = "::cosmwasm_schema::schemars")] +pub enum Cw2981BorkedQueryMsg { + /// Should be called on sale to see if royalties are owed + /// by the marketplace selling the NFT, if CheckRoyalties + /// returns true + /// See https://eips.ethereum.org/EIPS/eip-2981 + RoyaltyInfo { + token_id: String, + // the denom of this sale must also be the denom returned by RoyaltiesInfoResponse + // this was originally implemented as a Coin + // however that would mean you couldn't buy using CW20s + // as CW20 is just mapping of addr -> balance + sale_price: Uint128, + }, + /// Called against contract to determine if this NFT + /// implements royalties. Should return a boolean as part of + /// CheckRoyaltiesResponse - default can simply be true + /// if royalties are implemented at token level + /// (i.e. always check on sale) + CheckRoyalties {}, +} diff --git a/cosmwasm-contracts/cw721-membership/src/multitest.rs b/cosmwasm-contracts/cw721-membership/src/multitest.rs index c06fbab109..f36887bf26 100644 --- a/cosmwasm-contracts/cw721-membership/src/multitest.rs +++ b/cosmwasm-contracts/cw721-membership/src/multitest.rs @@ -5,7 +5,8 @@ use cw721_metadata_onchain::{Metadata, Trait}; use sylvia::{anyhow::Error, cw_multi_test::Module, multitest::App}; use crate::contract::{ - multitest_utils::CodeId, MembershipConfig, Subscription, SubscriptionResponse, + multitest_utils::CodeId, Cw2981BorkedQueryMsg, Cw2981Response, MembershipConfig, Subscription, + SubscriptionResponse, }; #[test] @@ -208,26 +209,61 @@ fn basic_full_flow() { } ); + // ------- test borked royalty queries + + let royalties_check = contract + .extension(Cw2981BorkedQueryMsg::CheckRoyalties {}) + .unwrap(); + assert_eq!( + royalties_check, + Cw2981Response::CheckRoyaltiesResponse(CheckRoyaltiesResponse { + royalty_payments: true + }), + ); + + let royalty_info = contract + .extension(Cw2981BorkedQueryMsg::RoyaltyInfo { + token_id: token_id.to_string(), + sale_price: Uint128::from(461558079u32), + }) + .unwrap(); + assert_eq!( + royalty_info, + Cw2981Response::RoyaltiesInfoResponse(RoyaltiesInfoResponse { + address: channel_owner.to_string(), + royalty_amount: Uint128::from(23077903u32) // 5% + }), + ); + // ------- test royalty queries - let royalties_check = contract.check_royalties().unwrap(); + /* + let royalties_check = contract + .extension(Cw2981Query::Cw2981QueryMsg( + Cw2981QueryMsg::CheckRoyalties {}, + )) + .unwrap(); assert_eq!( royalties_check, - CheckRoyaltiesResponse { + Cw2981Response::CheckRoyaltiesResponse(CheckRoyaltiesResponse { royalty_payments: true - } + }), ); let royalty_info = contract - .royalty_info(token_id.to_string(), Uint128::from(461558079u32)) + .extension(Cw2981Query::Cw2981QueryMsg(Cw2981QueryMsg::RoyaltyInfo { + token_id: token_id.to_string(), + sale_price: Uint128::from(461558079u32), + })) .unwrap(); assert_eq!( royalty_info, - RoyaltiesInfoResponse { + Cw2981Response::RoyaltiesInfoResponse(RoyaltiesInfoResponse { address: channel_owner.to_string(), royalty_amount: Uint128::from(23077903u32) // 5% - } + }), ); + */ // ------- test transfer and back diff --git a/networks.json b/networks.json index c16f20c770..4cdf4aee99 100644 --- a/networks.json +++ b/networks.json @@ -10939,7 +10939,7 @@ "featureObjects": [ { "type": "CosmWasmPremiumFeed", - "membershipContractAddress": "tori122qmagdhqxr00ldp5jax08zgdumahx4h03shcy4wn9ckchfzky5q3hdylc", + "membershipContractAddress": "tori156edst4w2cjj2l7g6xezzs7hf2vpl25mrpagkgde85aj360pc22s48m2ff", "mintDenom": "utori" } ], @@ -10969,7 +10969,7 @@ "contractExplorer": "https://explorer.teritori.com/teritori-testnet/account/$address", "idPrefix": "testori", "testnet": true, - "backendEndpoint": "http://localhost:9090", + "backendEndpoint": "https://dapp-backend.testnet.teritori.com", "addressPrefix": "tori", "restEndpoint": "https://rest.testnet.teritori.com", "rpcEndpoint": "https://rpc.testnet.teritori.com", @@ -10997,7 +10997,7 @@ "distributorContractAddress": "", "riotersFooterContractAddress": "", "secondaryDuringMintList": [ - "tori122qmagdhqxr00ldp5jax08zgdumahx4h03shcy4wn9ckchfzky5q3hdylc", + "tori156edst4w2cjj2l7g6xezzs7hf2vpl25mrpagkgde85aj360pc22s48m2ff", "tori14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s3hewys", "tori1hzz0s0ucrhdp6tue2lxk3c03nj6f60qy463we7lgx0wudd72ctmstg4wkc", "" diff --git a/packages/components/nftDetails/components/NFTSellInfo.tsx b/packages/components/nftDetails/components/NFTSellInfo.tsx index ed6560a34e..51728d9090 100644 --- a/packages/components/nftDetails/components/NFTSellInfo.tsx +++ b/packages/components/nftDetails/components/NFTSellInfo.tsx @@ -27,34 +27,62 @@ const useCw2981RoyaltyInfo = ( ["cw2981-royalty-info", collectionId, tokenId], async () => { if (!collectionId || !tokenId) { - return null; + return 0; } const [network, mintContractAddress] = parseCollectionId(collectionId); if (!network) { - return null; + return 0; } const client = await mustGetNonSigningCosmWasmClient(network.id); - const queryClient = new Cw721MembershipQueryClient( - client, - mintContractAddress, - ); - try { - const checkRes = await queryClient.checkRoyalties(); - if (!checkRes.royalty_payments) { - return 0; + const getRoyaltyGain = async (contractAddress: string) => { + const cwClient = new Cw721MembershipQueryClient( + client, + contractAddress, + ); + const res = await cwClient.extension({ + msg: { + RoyaltyInfo: { + token_id: tokenId, + sale_price: royaltyQueryRange.toString(), + }, + }, + }); + if (!("royalty_amount" in res) || !res.royalty_amount) { + throw new Error("RoyaltyInfo response is invalid"); } + return +res.royalty_amount / royaltyQueryRange; + }; - const res = await queryClient.royaltyInfo({ - tokenId, - salePrice: royaltyQueryRange.toString(), + try { + const cwClient = new Cw721MembershipQueryClient( + client, + mintContractAddress, + ); + + const checkRes = await cwClient.extension({ + msg: { CheckRoyalties: {} }, }); + if (!("check_royalties" in checkRes) || !checkRes.check_royalties) { + return 0; + } - return (+res.royalty_amount || 0) / royaltyQueryRange; + return await getRoyaltyGain(mintContractAddress); } catch (err) { - console.error("Failed to fetch royalty info", err); + if ( + err instanceof Error && + err.message.includes("unknown variant `extension`") + ) { + const conf = await client.queryContractSmart(mintContractAddress, { + config: {}, + }); + + const nftContractAddr = conf.nft_addr || conf.child_contract_addr; + return await getRoyaltyGain(nftContractAddr); + } + throw err; } }, { diff --git a/packages/contracts-clients/cw721-membership/Cw721Membership.client.ts b/packages/contracts-clients/cw721-membership/Cw721Membership.client.ts index a269d63cc9..37c2589085 100644 --- a/packages/contracts-clients/cw721-membership/Cw721Membership.client.ts +++ b/packages/contracts-clients/cw721-membership/Cw721Membership.client.ts @@ -6,7 +6,7 @@ import { CosmWasmClient, SigningCosmWasmClient, ExecuteResult } from "@cosmjs/cosmwasm-stargate"; import { StdFee } from "@cosmjs/amino"; -import { InstantiateMsg, ExecuteMsg, ExecMsg, Uint64, Uint128, Binary, MembershipConfig, Coin, QueryMsg, QueryMsg1, AdminFundsResponse, Expiration, Timestamp, AllNftInfoResponseForMetadata, OwnerOfResponse, Approval, NftInfoResponseForMetadata, Metadata, Trait, TokensResponse, Addr, ChannelResponse, ChannelFundsResponse, CheckRoyaltiesResponse, Config, ContractInfoResponse, NumTokensResponse, RoyaltiesInfoResponse, SubscriptionResponse, Subscription } from "./Cw721Membership.types"; +import { InstantiateMsg, ExecuteMsg, ExecMsg, Uint64, Uint128, Binary, MembershipConfig, Coin, QueryMsg, QueryMsg1, Cw2981BorkedQueryMsg, AdminFundsResponse, Expiration, Timestamp, AllNftInfoResponseForMetadata, OwnerOfResponse, Approval, NftInfoResponseForMetadata, Metadata, Trait, TokensResponse, Addr, ChannelResponse, ChannelFundsResponse, Config, ContractInfoResponse, Cw2981Response, CheckRoyaltiesResponse, RoyaltiesInfoResponse, NumTokensResponse, SubscriptionResponse, Subscription } from "./Cw721Membership.types"; export interface Cw721MembershipReadOnlyInterface { contractAddress: string; config: () => Promise; @@ -28,14 +28,11 @@ export interface Cw721MembershipReadOnlyInterface { channelAddr: string; subAddr: string; }) => Promise; - royaltyInfo: ({ - salePrice, - tokenId + extension: ({ + msg }: { - salePrice: Uint128; - tokenId: string; - }) => Promise; - checkRoyalties: () => Promise; + msg: Cw2981BorkedQueryMsg; + }) => Promise; ownerOf: ({ includeExpired, tokenId @@ -86,8 +83,7 @@ export class Cw721MembershipQueryClient implements Cw721MembershipReadOnlyInterf this.adminFunds = this.adminFunds.bind(this); this.channelFunds = this.channelFunds.bind(this); this.subscription = this.subscription.bind(this); - this.royaltyInfo = this.royaltyInfo.bind(this); - this.checkRoyalties = this.checkRoyalties.bind(this); + this.extension = this.extension.bind(this); this.ownerOf = this.ownerOf.bind(this); this.numTokens = this.numTokens.bind(this); this.contractInfo = this.contractInfo.bind(this); @@ -143,25 +139,17 @@ export class Cw721MembershipQueryClient implements Cw721MembershipReadOnlyInterf } }); }; - royaltyInfo = async ({ - salePrice, - tokenId + extension = async ({ + msg }: { - salePrice: Uint128; - tokenId: string; - }): Promise => { + msg: Cw2981BorkedQueryMsg; + }): Promise => { return this.client.queryContractSmart(this.contractAddress, { - royalty_info: { - sale_price: salePrice, - token_id: tokenId + extension: { + msg } }); }; - checkRoyalties = async (): Promise => { - return this.client.queryContractSmart(this.contractAddress, { - check_royalties: {} - }); - }; ownerOf = async ({ includeExpired, tokenId diff --git a/packages/contracts-clients/cw721-membership/Cw721Membership.types.ts b/packages/contracts-clients/cw721-membership/Cw721Membership.types.ts index 141898a131..952a06c0d9 100644 --- a/packages/contracts-clients/cw721-membership/Cw721Membership.types.ts +++ b/packages/contracts-clients/cw721-membership/Cw721Membership.types.ts @@ -125,13 +125,8 @@ export type QueryMsg1 = { [k: string]: unknown; }; } | { - royalty_info: { - sale_price: Uint128; - token_id: string; - [k: string]: unknown; - }; -} | { - check_royalties: { + extension: { + msg: Cw2981BorkedQueryMsg; [k: string]: unknown; }; } | { @@ -173,6 +168,14 @@ export type QueryMsg1 = { [k: string]: unknown; }; }; +export type Cw2981BorkedQueryMsg = { + RoyaltyInfo: { + sale_price: Uint128; + token_id: string; + }; +} | { + CheckRoyalties: {}; +}; export interface AdminFundsResponse { funds: Coin[]; } @@ -231,9 +234,6 @@ export interface ChannelResponse { export interface ChannelFundsResponse { funds: Coin[]; } -export interface CheckRoyaltiesResponse { - royalty_payments: boolean; -} export interface Config { admin_addr: Addr; description: string; @@ -246,13 +246,17 @@ export interface ContractInfoResponse { name: string; symbol: string; } -export interface NumTokensResponse { - count: number; +export type Cw2981Response = CheckRoyaltiesResponse | RoyaltiesInfoResponse; +export interface CheckRoyaltiesResponse { + royalty_payments: boolean; } export interface RoyaltiesInfoResponse { address: string; royalty_amount: Uint128; } +export interface NumTokensResponse { + count: number; +} export interface SubscriptionResponse { level: number; subscription?: Subscription | null; diff --git a/packages/networks/teritori-testnet/index.ts b/packages/networks/teritori-testnet/index.ts index eb64d1a310..98f2c96668 100644 --- a/packages/networks/teritori-testnet/index.ts +++ b/packages/networks/teritori-testnet/index.ts @@ -8,7 +8,7 @@ const nameServiceContractAddress = const premiumFeedFeature: CosmWasmPremiumFeed = { type: NetworkFeature.CosmWasmPremiumFeed, membershipContractAddress: - "tori122qmagdhqxr00ldp5jax08zgdumahx4h03shcy4wn9ckchfzky5q3hdylc", + "tori156edst4w2cjj2l7g6xezzs7hf2vpl25mrpagkgde85aj360pc22s48m2ff", mintDenom: "utori", }; @@ -43,7 +43,7 @@ export const teritoriTestnetNetwork: NetworkInfo = { "https://explorer.teritori.com/teritori-testnet/account/$address", idPrefix: "testori", testnet: true, - backendEndpoint: "http://localhost:9090", + backendEndpoint: "https://dapp-backend.testnet.teritori.com", addressPrefix: "tori", restEndpoint: "https://rest.testnet.teritori.com", rpcEndpoint: "https://rpc.testnet.teritori.com",