Skip to content

Commit

Permalink
Merge pull request #255 from public-awesome/add-renewal-cost-to-query
Browse files Browse the repository at this point in the history
  • Loading branch information
jason-c-child authored Mar 6, 2024
2 parents 0d18873 + f908a67 commit 70e5d4e
Show file tree
Hide file tree
Showing 7 changed files with 229 additions and 4 deletions.
125 changes: 125 additions & 0 deletions contracts/marketplace/schema/name-marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -544,6 +544,35 @@
},
"additionalProperties": false
},
{
"description": "Get renewal price for multiple names",
"type": "object",
"required": [
"ask_renewal_prices"
],
"properties": {
"ask_renewal_prices": {
"type": "object",
"required": [
"current_time",
"token_ids"
],
"properties": {
"current_time": {
"$ref": "#/definitions/Timestamp"
},
"token_ids": {
"type": "array",
"items": {
"type": "string"
}
}
},
"additionalProperties": false
}
},
"additionalProperties": false
},
{
"description": "Get data for a specific bid",
"type": "object",
Expand Down Expand Up @@ -1126,6 +1155,102 @@
}
}
},
"ask_renewal_prices": {
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Array_of_AskRenewPriceResponse",
"type": "array",
"items": {
"$ref": "#/definitions/AskRenewPriceResponse"
},
"definitions": {
"Addr": {
"description": "A human readable address.\n\nIn Cosmos, this is typically bech32 encoded. But for multi-chain smart contracts no assumptions should be made other than being UTF-8 encoded and of reasonable length.\n\nThis type represents a validated address. It can be created in the following ways 1. Use `Addr::unchecked(input)` 2. Use `let checked: Addr = deps.api.addr_validate(input)?` 3. Use `let checked: Addr = deps.api.addr_humanize(canonical_addr)?` 4. Deserialize from JSON. This must only be done from JSON that was validated before such as a contract's state. `Addr` must not be used in messages sent by the user because this would result in unvalidated instances.\n\nThis type is immutable. If you really need to mutate it (Really? Are you sure?), create a mutable copy using `let mut mutable = Addr::to_string()` and operate on that `String` instance.",
"type": "string"
},
"AskRenewPriceResponse": {
"type": "object",
"required": [
"price",
"token_id"
],
"properties": {
"bid": {
"anyOf": [
{
"$ref": "#/definitions/Bid"
},
{
"type": "null"
}
]
},
"price": {
"$ref": "#/definitions/Coin"
},
"token_id": {
"type": "string"
}
},
"additionalProperties": false
},
"Bid": {
"description": "Represents a bid (offer) on the marketplace",
"type": "object",
"required": [
"amount",
"bidder",
"created_time",
"token_id"
],
"properties": {
"amount": {
"$ref": "#/definitions/Uint128"
},
"bidder": {
"$ref": "#/definitions/Addr"
},
"created_time": {
"$ref": "#/definitions/Timestamp"
},
"token_id": {
"type": "string"
}
},
"additionalProperties": false
},
"Coin": {
"type": "object",
"required": [
"amount",
"denom"
],
"properties": {
"amount": {
"$ref": "#/definitions/Uint128"
},
"denom": {
"type": "string"
}
}
},
"Timestamp": {
"description": "A point in time in nanosecond precision.\n\nThis type can represent times from 1970-01-01T00:00:00Z to 2554-07-21T23:34:33Z.\n\n## Examples\n\n``` # use cosmwasm_std::Timestamp; let ts = Timestamp::from_nanos(1_000_000_202); assert_eq!(ts.nanos(), 1_000_000_202); assert_eq!(ts.seconds(), 1); assert_eq!(ts.subsec_nanos(), 202);\n\nlet ts = ts.plus_seconds(2); assert_eq!(ts.nanos(), 3_000_000_202); assert_eq!(ts.seconds(), 3); assert_eq!(ts.subsec_nanos(), 202); ```",
"allOf": [
{
"$ref": "#/definitions/Uint64"
}
]
},
"Uint128": {
"description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```",
"type": "string"
},
"Uint64": {
"description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```",
"type": "string"
}
}
},
"asks": {
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Array_of_Ask",
Expand Down
13 changes: 13 additions & 0 deletions contracts/marketplace/src/msg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,13 @@ impl BidOffset {
}
}

#[cw_serde]
pub struct AskRenewPriceResponse {
pub token_id: TokenId,
pub price: Coin,
pub bid: Option<Bid>,
}

#[cw_serde]
#[derive(QueryResponses)]
pub enum QueryMsg {
Expand Down Expand Up @@ -159,6 +166,12 @@ pub enum QueryMsg {
current_time: Timestamp,
token_id: TokenId,
},
/// Get renewal price for multiple names
#[returns(Vec<AskRenewPriceResponse>)]
AskRenewalPrices {
current_time: Timestamp,
token_ids: Vec<TokenId>,
},
/// Get data for a specific bid
#[returns(Option<Bid>)]
Bid { token_id: TokenId, bidder: Bidder },
Expand Down
27 changes: 25 additions & 2 deletions contracts/marketplace/src/query.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::helpers::get_renewal_price_and_bid;
use crate::msg::{BidOffset, Bidder, ConfigResponse, QueryMsg};
use crate::msg::{AskRenewPriceResponse, BidOffset, Bidder, ConfigResponse, QueryMsg};
use crate::state::{
ask_key, asks, bid_key, bids, legacy_bids, Ask, AskKey, Bid, Id, SudoParams, TokenId,
ASK_COUNT, ASK_HOOKS, BID_HOOKS, NAME_COLLECTION, NAME_MINTER, RENEWAL_QUEUE, SALE_HOOKS,
Expand Down Expand Up @@ -51,6 +51,10 @@ pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult<Binary> {
current_time,
token_id,
} => to_binary(&query_ask_renew_price(deps, current_time, token_id)?),
QueryMsg::AskRenewalPrices {
current_time,
token_ids,
} => to_binary(&query_ask_renew_prices(deps, current_time, token_ids)?),
QueryMsg::AskCount {} => to_binary(&query_ask_count(deps)?),
QueryMsg::Bid { token_id, bidder } => {
to_binary(&query_bid(deps, token_id, api.addr_validate(&bidder)?)?)
Expand Down Expand Up @@ -207,7 +211,7 @@ pub fn query_ask_renew_price(
let name_minter = NAME_MINTER.load(deps.storage)?;
let name_minter_params = deps
.querier
.query_wasm_smart::<NameMinterParams>(name_minter, &SgNameMinterQueryMsg::Params {})?;
.query_wasm_smart::<NameMinterParams>(name_minter, &(SgNameMinterQueryMsg::Params {}))?;

let (renewal_price, valid_bid) = get_renewal_price_and_bid(
deps,
Expand All @@ -221,6 +225,25 @@ pub fn query_ask_renew_price(
Ok((Some(coin(renewal_price.u128(), NATIVE_DENOM)), valid_bid))
}

pub fn query_ask_renew_prices(
deps: Deps,
current_time: Timestamp,
token_ids: Vec<String>,
) -> StdResult<Vec<AskRenewPriceResponse>> {
token_ids
.iter()
.map(|token_id| {
let (coin_option, bid_option) =
query_ask_renew_price(deps, current_time, token_id.to_string())?;
Ok(AskRenewPriceResponse {
token_id: token_id.to_string(),
price: coin_option.unwrap_or_default(),
bid: bid_option,
})
})
.collect::<StdResult<Vec<_>>>()
}

pub fn query_ask(deps: Deps, token_id: TokenId) -> StdResult<Option<Ask>> {
asks().may_load(deps.storage, ask_key(&token_id))
}
Expand Down
31 changes: 31 additions & 0 deletions contracts/name-minter/src/integration_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ const BIDDER2: &str = "bidder2";
const ADMIN: &str = "admin";
const ADMIN2: &str = "admin2";
const NAME: &str = "bobo";
const NAME2: &str = "mccool";
const VERIFIER: &str = "verifier";
const OPERATOR: &str = "operator";

Expand Down Expand Up @@ -861,6 +862,7 @@ mod query {
use cosmwasm_std::coin;
use cosmwasm_std::Coin;
use cosmwasm_std::StdResult;
use name_marketplace::msg::AskRenewPriceResponse;
use name_marketplace::msg::BidOffset;
use name_marketplace::state::Ask;
use sg721_base::msg::CollectionInfoResponse;
Expand Down Expand Up @@ -1191,6 +1193,35 @@ mod query {
assert_eq!(renewal_price.unwrap().amount, expect_price);
}

#[test]
fn multiple_renew_prices() {
// test that QueryRenewPrices returns multiple entires
let mut app = instantiate_contracts(None, None, None);

mint_and_list(&mut app, NAME, USER, None).unwrap();
mint_and_list(&mut app, NAME2, USER, None).unwrap();

// Amount to make it just above the char price
let bid_amount = 1_000_000_000u128 * 201u128;

update_block_time(&mut app, SECONDS_PER_YEAR - (60 * 60 * 24 * 31));

bid(&mut app, NAME, BIDDER, bid_amount);
bid(&mut app, NAME2, BIDDER, bid_amount);

update_block_time(&mut app, 60 * 60 * 24 * 31);

let result = app.wrap().query_wasm_smart::<Vec<AskRenewPriceResponse>>(
MKT,
&MarketplaceQueryMsg::AskRenewalPrices {
current_time: app.block_info().time,
token_ids: vec![NAME.to_string(), NAME2.to_string()],
},
);
println!("{:?}", result);
assert!(result.is_ok());
}

#[test]
fn renew_execute_msg() {
let mut app = instantiate_contracts(None, None, None);
Expand Down
24 changes: 23 additions & 1 deletion ts/src/NameMarketplace.client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

import { CosmWasmClient, SigningCosmWasmClient, ExecuteResult } from "@cosmjs/cosmwasm-stargate";
import { StdFee } from "@cosmjs/amino";
import { Uint128, Decimal, InstantiateMsg, ExecuteMsg, QueryMsg, Timestamp, Uint64, Addr, BidOffset, NullableAsk, Ask, HooksResponse, TupleOfNullable_CoinAndNullable_Bid, Coin, Bid, ArrayOfAsk, NullableBid, ArrayOfBid, ConfigResponse, SudoParams } from "./NameMarketplace.types";
import { Uint128, Decimal, InstantiateMsg, ExecuteMsg, QueryMsg, Timestamp, Uint64, Addr, BidOffset, NullableAsk, Ask, HooksResponse, TupleOfNullable_CoinAndNullable_Bid, Coin, Bid, ArrayOfAskRenewPriceResponse, AskRenewPriceResponse, ArrayOfAsk, NullableBid, ArrayOfBid, ConfigResponse, SudoParams } from "./NameMarketplace.types";
export interface NameMarketplaceReadOnlyInterface {
contractAddress: string;
ask: ({
Expand Down Expand Up @@ -47,6 +47,13 @@ export interface NameMarketplaceReadOnlyInterface {
currentTime: Timestamp;
tokenId: string;
}) => Promise<TupleOfNullableCoinAndNullableBid>;
askRenewalPrices: ({
currentTime,
tokenIds
}: {
currentTime: Timestamp;
tokenIds: string[];
}) => Promise<ArrayOfAskRenewPriceResponse>;
bid: ({
bidder,
tokenId
Expand Down Expand Up @@ -131,6 +138,7 @@ export class NameMarketplaceQueryClient implements NameMarketplaceReadOnlyInterf
this.asksBySeller = this.asksBySeller.bind(this);
this.asksByRenewTime = this.asksByRenewTime.bind(this);
this.askRenewPrice = this.askRenewPrice.bind(this);
this.askRenewalPrices = this.askRenewalPrices.bind(this);
this.bid = this.bid.bind(this);
this.bidsByBidder = this.bidsByBidder.bind(this);
this.bids = this.bids.bind(this);
Expand Down Expand Up @@ -225,6 +233,20 @@ export class NameMarketplaceQueryClient implements NameMarketplaceReadOnlyInterf
}
});
};
askRenewalPrices = async ({
currentTime,
tokenIds
}: {
currentTime: Timestamp;
tokenIds: string[];
}): Promise<ArrayOfAskRenewPriceResponse> => {
return this.client.queryContractSmart(this.contractAddress, {
ask_renewal_prices: {
current_time: currentTime,
token_ids: tokenIds
}
});
};
bid = async ({
bidder,
tokenId
Expand Down
2 changes: 1 addition & 1 deletion ts/src/NameMarketplace.message-composer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import { MsgExecuteContractEncodeObject } from "cosmwasm";
import { MsgExecuteContract } from "cosmjs-types/cosmwasm/wasm/v1/tx";
import { toUtf8 } from "@cosmjs/encoding";
import { Uint128, Decimal, InstantiateMsg, ExecuteMsg, QueryMsg, Timestamp, Uint64, Addr, BidOffset, NullableAsk, Ask, HooksResponse, TupleOfNullable_CoinAndNullable_Bid, Coin, Bid, ArrayOfAsk, NullableBid, ArrayOfBid, ConfigResponse, SudoParams } from "./NameMarketplace.types";
import { Uint128, Decimal, InstantiateMsg, ExecuteMsg, QueryMsg, Timestamp, Uint64, Addr, BidOffset, NullableAsk, Ask, HooksResponse, TupleOfNullable_CoinAndNullable_Bid, Coin, Bid, ArrayOfAskRenewPriceResponse, AskRenewPriceResponse, ArrayOfAsk, NullableBid, ArrayOfBid, ConfigResponse, SudoParams } from "./NameMarketplace.types";
export interface NameMarketplaceMessage {
contractAddress: string;
sender: string;
Expand Down
11 changes: 11 additions & 0 deletions ts/src/NameMarketplace.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,11 @@ export type QueryMsg = {
current_time: Timestamp;
token_id: string;
};
} | {
ask_renewal_prices: {
current_time: Timestamp;
token_ids: string[];
};
} | {
bid: {
bidder: string;
Expand Down Expand Up @@ -185,6 +190,12 @@ export interface Bid {
created_time: Timestamp;
token_id: string;
}
export type ArrayOfAskRenewPriceResponse = AskRenewPriceResponse[];
export interface AskRenewPriceResponse {
bid?: Bid | null;
price: Coin;
token_id: string;
}
export type ArrayOfAsk = Ask[];
export type NullableBid = Bid | null;
export type ArrayOfBid = Bid[];
Expand Down

0 comments on commit 70e5d4e

Please sign in to comment.