Skip to content

Commit

Permalink
[SG-975] Adds queries for text records and Twitter verification (#249)
Browse files Browse the repository at this point in the history
* Query name text records

* Add test

* Add helper

* Is twitter verified helper

* Add twitter verified query

* Update types
  • Loading branch information
shanev authored Jun 1, 2023
1 parent 24718ce commit 1866028
Show file tree
Hide file tree
Showing 9 changed files with 223 additions and 4 deletions.
81 changes: 81 additions & 0 deletions contracts/sg721-name/schema/sg721-name.json
Original file line number Diff line number Diff line change
Expand Up @@ -927,6 +927,50 @@
},
"additionalProperties": false
},
{
"description": "Returns the text records for a name",
"type": "object",
"required": [
"text_records"
],
"properties": {
"text_records": {
"type": "object",
"required": [
"name"
],
"properties": {
"name": {
"type": "string"
}
},
"additionalProperties": false
}
},
"additionalProperties": false
},
{
"description": "Returns if Twitter is verified for a name",
"type": "object",
"required": [
"is_twitter_verified"
],
"properties": {
"is_twitter_verified": {
"type": "object",
"required": [
"name"
],
"properties": {
"name": {
"type": "string"
}
},
"additionalProperties": false
}
},
"additionalProperties": false
},
{
"description": "Returns the verification oracle address",
"type": "object",
Expand Down Expand Up @@ -1922,6 +1966,11 @@
}
}
},
"is_twitter_verified": {
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Boolean",
"type": "boolean"
},
"minter": {
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "MinterResponse",
Expand Down Expand Up @@ -2182,6 +2231,38 @@
},
"additionalProperties": false
},
"text_records": {
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Array_of_TextRecord",
"type": "array",
"items": {
"$ref": "#/definitions/TextRecord"
},
"definitions": {
"TextRecord": {
"type": "object",
"required": [
"name",
"value"
],
"properties": {
"name": {
"type": "string"
},
"value": {
"type": "string"
},
"verified": {
"type": [
"boolean",
"null"
]
}
},
"additionalProperties": false
}
}
},
"tokens": {
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "TokensResponse",
Expand Down
23 changes: 23 additions & 0 deletions contracts/sg721-name/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -534,6 +534,29 @@ pub fn query_image_nft(deps: Deps, name: &str) -> StdResult<Option<NFT>> {
.image_nft)
}

pub fn query_text_records(deps: Deps, name: &str) -> StdResult<Vec<TextRecord>> {
Ok(Sg721NameContract::default()
.tokens
.load(deps.storage, name)?
.extension
.records)
}
pub fn query_is_twitter_verified(deps: Deps, name: &str) -> StdResult<bool> {
let records = Sg721NameContract::default()
.tokens
.load(deps.storage, name)?
.extension
.records;

for record in records {
if record.name == "twitter" {
return Ok(record.verified.unwrap_or(false));
}
}

Ok(false)
}

pub fn transcode(address: &str) -> StdResult<String> {
let (_, data) =
bech32::decode(address).map_err(|_| StdError::generic_err("Invalid bech32 address"))?;
Expand Down
47 changes: 47 additions & 0 deletions contracts/sg721-name/src/helpers.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
use crate::msg::QueryMsg;
use cosmwasm_schema::cw_serde;
use cosmwasm_std::{to_binary, Addr, QuerierWrapper, QueryRequest, StdResult, WasmQuery};
use sg_name::{TextRecord, NFT};

/// NameCollectionContract is a wrapper around Addr that provides a lot of helpers
#[cw_serde]
pub struct NameCollectionContract(pub Addr);

impl NameCollectionContract {
pub fn addr(&self) -> Addr {
self.0.clone()
}

pub fn image_nft(&self, querier: &QuerierWrapper, name: &str) -> StdResult<Option<NFT>> {
let res: Option<NFT> = querier.query(&QueryRequest::Wasm(WasmQuery::Smart {
contract_addr: self.addr().into(),
msg: to_binary(&QueryMsg::ImageNFT {
name: name.to_string(),
})?,
}))?;

Ok(res)
}

pub fn text_records(&self, querier: &QuerierWrapper, name: &str) -> StdResult<Vec<TextRecord>> {
let res: Vec<TextRecord> = querier.query(&QueryRequest::Wasm(WasmQuery::Smart {
contract_addr: self.addr().into(),
msg: to_binary(&QueryMsg::TextRecords {
name: name.to_string(),
})?,
}))?;

Ok(res)
}

pub fn is_twitter_verified(&self, querier: &QuerierWrapper, name: &str) -> StdResult<bool> {
let res: bool = querier.query(&QueryRequest::Wasm(WasmQuery::Smart {
contract_addr: self.addr().into(),
msg: to_binary(&QueryMsg::IsTwitterVerified {
name: name.to_string(),
})?,
}))?;

Ok(res)
}
}
12 changes: 11 additions & 1 deletion contracts/sg721-name/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,13 @@ use sg_name::Metadata;

pub mod contract;
mod error;
mod helpers;
pub mod msg;
pub mod state;
pub mod sudo;

pub use helpers::NameCollectionContract;

#[cfg(test)]
pub mod unit_tests;

Expand All @@ -23,7 +26,10 @@ pub type QueryMsg = crate::msg::QueryMsg;

pub mod entry {
use crate::{
contract::{execute_verify_text_record, query_image_nft},
contract::{
execute_verify_text_record, query_image_nft, query_is_twitter_verified,
query_text_records,
},
msg::InstantiateMsg,
state::{SudoParams, SUDO_PARAMS, VERIFIER},
};
Expand Down Expand Up @@ -136,6 +142,10 @@ pub mod entry {
to_binary(&query_associated_address(deps, &name)?)
}
QueryMsg::ImageNFT { name } => to_binary(&query_image_nft(deps, &name)?),
QueryMsg::TextRecords { name } => to_binary(&query_text_records(deps, &name)?),
QueryMsg::IsTwitterVerified { name } => {
to_binary(&query_is_twitter_verified(deps, &name)?)
}
_ => Sg721NameContract::default().query(deps, env, msg.into()),
}
}
Expand Down
6 changes: 6 additions & 0 deletions contracts/sg721-name/src/msg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,12 @@ pub enum QueryMsg {
/// Returns the image NFT for a name
#[returns(Option<NFT>)]
ImageNFT { name: String },
/// Returns the text records for a name
#[returns(Vec<TextRecord>)]
TextRecords { name: String },
/// Returns if Twitter is verified for a name
#[returns(bool)]
IsTwitterVerified { name: String },
/// Returns the verification oracle address
#[returns(Option<String>)]
Verifier {},
Expand Down
10 changes: 9 additions & 1 deletion contracts/sg721-name/src/unit_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use sg721_base::ContractError::Unauthorized;
use sg_name::{Metadata, TextRecord, NFT};
use std::marker::PhantomData;

use crate::contract::{query_name, transcode};
use crate::contract::{query_is_twitter_verified, query_name, query_text_records, transcode};
use crate::entry::{execute, instantiate, query};
use crate::msg::InstantiateMsg;
use crate::state::SudoParams;
Expand Down Expand Up @@ -163,6 +163,14 @@ fn mint_and_update() {
let record: TextRecord = from_slice(&record_value).unwrap();
assert_eq!(record, new_record);

let records = query_text_records(deps.as_ref(), token_id).unwrap();
assert_eq!(records.len(), 1);
assert_eq!(records[0].name, "test");
assert_eq!(records[0].value, "test");

let is_twitter_verified = query_is_twitter_verified(deps.as_ref(), token_id).unwrap();
assert!(!is_twitter_verified);

// trigger too many records error
for i in 1..=(max_record_count) {
let new_record = TextRecord {
Expand Down
36 changes: 35 additions & 1 deletion ts/src/Sg721Name.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 { Coin, StdFee } from "@cosmjs/amino";
import { Decimal, Timestamp, Uint64, InstantiateMsg, CollectionInfoForRoyaltyInfoResponse, RoyaltyInfoResponse, ExecuteMsg, Addr, Binary, Expiration, NFT, TextRecord, MintMsgForMetadata, Metadata, UpdateCollectionInfoMsgForRoyaltyInfoResponse, QueryMsg, AllNftInfoResponseForMetadata, OwnerOfResponse, Approval, NftInfoResponseForMetadata, OperatorsResponse, TokensResponse, ApprovalResponse, ApprovalsResponse, CollectionInfoResponse, ContractInfoResponse, NullableNFT, MinterResponse, String, NumTokensResponse, SudoParams, NullableString } from "./Sg721Name.types";
import { Decimal, Timestamp, Uint64, InstantiateMsg, CollectionInfoForRoyaltyInfoResponse, RoyaltyInfoResponse, ExecuteMsg, Addr, Binary, Expiration, NFT, TextRecord, MintMsgForMetadata, Metadata, UpdateCollectionInfoMsgForRoyaltyInfoResponse, QueryMsg, AllNftInfoResponseForMetadata, OwnerOfResponse, Approval, NftInfoResponseForMetadata, OperatorsResponse, TokensResponse, ApprovalResponse, ApprovalsResponse, CollectionInfoResponse, ContractInfoResponse, NullableNFT, Boolean, MinterResponse, String, NumTokensResponse, SudoParams, ArrayOfTextRecord, NullableString } from "./Sg721Name.types";
export interface Sg721NameReadOnlyInterface {
contractAddress: string;
params: () => Promise<SudoParams>;
Expand All @@ -26,6 +26,16 @@ export interface Sg721NameReadOnlyInterface {
}: {
name: string;
}) => Promise<NullableNFT>;
textRecords: ({
name
}: {
name: string;
}) => Promise<ArrayOfTextRecord>;
isTwitterVerified: ({
name
}: {
name: string;
}) => Promise<Boolean>;
verifier: () => Promise<NullableString>;
ownerOf: ({
includeExpired,
Expand Down Expand Up @@ -106,6 +116,8 @@ export class Sg721NameQueryClient implements Sg721NameReadOnlyInterface {
this.nameMarketplace = this.nameMarketplace.bind(this);
this.associatedAddress = this.associatedAddress.bind(this);
this.imageNFT = this.imageNFT.bind(this);
this.textRecords = this.textRecords.bind(this);
this.isTwitterVerified = this.isTwitterVerified.bind(this);
this.verifier = this.verifier.bind(this);
this.ownerOf = this.ownerOf.bind(this);
this.approval = this.approval.bind(this);
Expand Down Expand Up @@ -164,6 +176,28 @@ export class Sg721NameQueryClient implements Sg721NameReadOnlyInterface {
}
});
};
textRecords = async ({
name
}: {
name: string;
}): Promise<ArrayOfTextRecord> => {
return this.client.queryContractSmart(this.contractAddress, {
text_records: {
name
}
});
};
isTwitterVerified = async ({
name
}: {
name: string;
}): Promise<Boolean> => {
return this.client.queryContractSmart(this.contractAddress, {
is_twitter_verified: {
name
}
});
};
verifier = async (): Promise<NullableString> => {
return this.client.queryContractSmart(this.contractAddress, {
verifier: {}
Expand Down
2 changes: 1 addition & 1 deletion ts/src/Sg721Name.message-composer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { Coin } from "@cosmjs/amino";
import { MsgExecuteContractEncodeObject } from "cosmwasm";
import { MsgExecuteContract } from "cosmjs-types/cosmwasm/wasm/v1/tx";
import { toUtf8 } from "@cosmjs/encoding";
import { Decimal, Timestamp, Uint64, InstantiateMsg, CollectionInfoForRoyaltyInfoResponse, RoyaltyInfoResponse, ExecuteMsg, Addr, Binary, Expiration, NFT, TextRecord, MintMsgForMetadata, Metadata, UpdateCollectionInfoMsgForRoyaltyInfoResponse, QueryMsg, AllNftInfoResponseForMetadata, OwnerOfResponse, Approval, NftInfoResponseForMetadata, OperatorsResponse, TokensResponse, ApprovalResponse, ApprovalsResponse, CollectionInfoResponse, ContractInfoResponse, NullableNFT, MinterResponse, String, NumTokensResponse, SudoParams, NullableString } from "./Sg721Name.types";
import { Decimal, Timestamp, Uint64, InstantiateMsg, CollectionInfoForRoyaltyInfoResponse, RoyaltyInfoResponse, ExecuteMsg, Addr, Binary, Expiration, NFT, TextRecord, MintMsgForMetadata, Metadata, UpdateCollectionInfoMsgForRoyaltyInfoResponse, QueryMsg, AllNftInfoResponseForMetadata, OwnerOfResponse, Approval, NftInfoResponseForMetadata, OperatorsResponse, TokensResponse, ApprovalResponse, ApprovalsResponse, CollectionInfoResponse, ContractInfoResponse, NullableNFT, Boolean, MinterResponse, String, NumTokensResponse, SudoParams, ArrayOfTextRecord, NullableString } from "./Sg721Name.types";
export interface Sg721NameMessage {
contractAddress: string;
sender: string;
Expand Down
10 changes: 10 additions & 0 deletions ts/src/Sg721Name.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,14 @@ export type QueryMsg = {
image_n_f_t: {
name: string;
};
} | {
text_records: {
name: string;
};
} | {
is_twitter_verified: {
name: string;
};
} | {
verifier: {};
} | {
Expand Down Expand Up @@ -258,6 +266,7 @@ export interface ContractInfoResponse {
symbol: string;
}
export type NullableNFT = NFT | null;
export type Boolean = boolean;
export interface MinterResponse {
minter: string;
}
Expand All @@ -268,4 +277,5 @@ export interface NumTokensResponse {
export interface SudoParams {
max_record_count: number;
}
export type ArrayOfTextRecord = TextRecord[];
export type NullableString = string | null;

0 comments on commit 1866028

Please sign in to comment.