Skip to content

Instantly share code, notes, and snippets.

@drewstaylor
Last active October 6, 2023 19:26
Show Gist options
  • Save drewstaylor/088af645dd36c013c02a2b4d05110479 to your computer and use it in GitHub Desktop.
Save drewstaylor/088af645dd36c013c02a2b4d05110479 to your computer and use it in GitHub Desktop.
ArchID 3rd party integration examples
// You can check if domain name already exists by querying the
// `ResolveRecord` entry point of the Registry contract; however,
// it should be noted this query will return an error for domain
// names that are available, and a DNS record for domains that do
use cosmwasm_std::{to_binary, QueryRequest, WasmQuery,};
use crate::archid_registry;
let registry_contract = "Registry contract address goes here";
let desired_domain_name = "archid.arch";
let query_msg: archid_registry::QueryMsg = archid_registry::ResolveRecord {
name: desired_domain_name.into(),
};
let query_req = QueryRequest::Wasm(WasmQuery::Smart {
contract_addr: registry_contract.into(),
msg: to_binary(&query_msg).unwrap(),
});
let query_resp = deps.querier.query(&query_req)?;
if query_resp.is_ok() {
// The desired domain has already been taken
}
if query_resp.is_err() {
// The desired domain is available
}
/**
* Fetch an array of domain names that resolve to a specific `account` address
* returns an empty array, for the `names` member, if no valid domains resolve
* resolve to the `account` address
* @param {String} contract : contract address string for registry contract
* @param {String} account : account address to be queried
* @param {SigningCosmWasmClient} client : instance of signing client
* @returns {QueryResult}
*/
async function DomainsOf(contract = null, account = null, client = null) {
try {
let entrypoint = {
resolve_address: {
address: account
}
};
let namesQuery = await client.queryClient.wasm.queryContractSmart(
contract,
entrypoint
);
return namesQuery;
} catch(e) {
console.error(e);
return {};
}
}
// You can check if an address has one or more domains that
// resolve to it, using the `ResolveAddress` entry point
use cosmwasm_std::{Addr, to_binary, QueryRequest, WasmQuery,};
use crate::archid_registry;
let registry_contract = "Registry contract address goes here";
let address_to_be_checked: Addr = "archway1f395p0gg67mmfd5zcqvpnp9cxnu0hg6r9hfczq";
let query_msg: archid_registry::QueryMsg = archid_registry::ResolveAddress {
address: address_to_be_checked,
};
let query_req = QueryRequest::Wasm(WasmQuery::Smart {
contract_addr: registry_contract.into(),
msg: to_binary(&query_msg).unwrap(),
});
let query_resp = deps.querier.query(&query_req)?;
if query_resp.names.unwrap().is_none() {
// The address has no valid domain names
} else {
// query_resp.names is a vector of valid domain names that
// resolve to `address_to_be_checked`
}
/**
* Loads token ids owned by a specific address
* @param {String} contract : contract address string for token contract
* @param {String} account : owner account address to be queried
* @param {SigningCosmWasmClient} client : (Optional) instance of signing client
* @param {Number} limit? : (Optional) max amount of tokens to be loaded; defaults to 100
* @param {String} start_after? : (Optional) `tokenId` for pagination, begin loading tokens beginning after a specific `tokenId`
* @returns {QueryResult}
*/
async function TokensOf(contract = null, account = null, client = null, limit = 100, start_after = null) {
try {
let entrypoint = {
tokens: {
owner: account,
limit: limit,
}
};
if (start_after) entrypoint.tokens["start_after"] = start_after;
let tokenQuery = await client.queryClient.wasm.queryContractSmart(
contract,
entrypoint
);
return tokenQuery;
} catch(e) {
console.error(e);
return {};
}
}
// These types are also needed if you are importing the Registry
// contract types (e.g. in order to integrate contract-to-contract
// calls to the Registry contract)
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)]
pub struct Subdomain {
pub name: Option<String>,
pub resolver: Option<Addr>,
pub minted: Option<bool>,
pub created: Option<u64>,
pub expiry: Option<u64>,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)]
pub struct Account {
pub username: Option<String>,
pub profile: Option<String>,
pub account_type: Option<String>,
pub verfication_hash: Option<String>,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)]
pub struct Website {
pub url: Option<String>,
pub domain: Option<String>,
pub verfication_hash: Option<String>,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug)]
pub struct Metadata {
pub name: Option<String>, // e.g. for interoperability with external marketplaces
pub description: Option<String>, // e.g. ibid.
pub image: Option<String>, // e.g. ibid.
pub created: Option<u64>,
pub expiry: Option<u64>,
pub domain: Option<String>,
pub subdomains: Option<Vec<Subdomain>>,
pub accounts: Option<Vec<Account>>,
pub websites: Option<Vec<Website>>,
}
const REGISTRY_CONTRACT = "Registry contract address goes here";
/**
* Read the contract Config;
* Use this to get the base_cost (cost per year) of registering a domain
* @param {SigningCosmWasmClient} client? : (Optional) instance of signing client
* @returns {QueryResult}
*/
async function Config(client = null) {
try {
let entrypoint = {
config: {}
};
let query = await client.queryClient.wasm.queryContractSmart(
REGISTRY_CONTRACT,
entrypoint
);
return query;
} catch(e) {
console.error(e);
return {error: e};
}
}
/*
Example return:
Config(cwClient)l
//returns:
{
"admin":"archway1f395p0gg67mmfd5zcqvpnp9cxnu0hg6r9hfczq",
"wallet":"archway1f395p0gg67mmfd5zcqvpnp9cxnu0hg6r9hfczq",
"cw721":"archway1ll9jnzdnge45w56tas3m2z08hhevwykj8hmgxpa4mfppdrx2ztfsxmj0fl",
"base_cost":"50000",
"base_expiration":10000000
}
*/
// Get the per year cost of registering a domain name
// by querying the `Config` entry point of the Registry
// contract. This query entry point takes no parameters
// as arguments (e.g. `{}`). Domains can be registered
// for 1, 2 or 3 years. Paying more than 3 x the base per
// year cost, will result in a registration of 3 years.
use cosmwasm_std::{to_binary, QueryRequest, WasmQuery,};
use crate::archid_registry;
let registry_contract = "Registry contract address goes here";
let desired_domain_name = "archid.arch";
let query_msg: archid_registry::QueryMsg = archid_registry::Config {};
let query_req = QueryRequest::Wasm(WasmQuery::Smart {
contract_addr: registry_contract.into(),
msg: to_binary(&query_msg).unwrap(),
});
let query_resp = deps.querier.query(&query_req)?;
let cost_per_year = query_resp.base_cost.unwrap();
// Note: `cost_per_year` will be a string value in `aarch` (or `aconst` if using testnet)
// You'll need to convert it to int to do math on it (e.g. to register for multiple
// years) or to register the domain using the `Register` entry point. Example conversion:
// `let integer_cost_per_year = cost_per_year.parse::<u128>().unwrap()`
import { coin } from "@cosmjs/stargate";
const REGISTRY_CONTRACT = "Registry contract address goes here";
/**
* Register a new ArchID domain
* @param {String} name : Domain name to be registered
* @param {Number} base_cost: The `base_cost` value as defined in the Registry contract storage
* @param {Number} years : Number of years to be registered; an integer between 1 and 3, impacts cost
* @param {String} sender : The address of the party registering the domain
* @param {SigningCosmWasmClient} client? : instance of signing client
* @see {Config()}
* @returns {ExecuteResult}
*/
async function Register(name, years = 1, base_cost = 0, sender = null, client = null) {
try {
let entrypoint = {
register: {
name: name
}
};
// Purchase cost
let denom = "aconst"; // "aconst" is for `constantine-3`; for `constantine-2` use "uconst"
let funds = [coin((base_cost * years), denom)];
// Broadcast tx
let tx = await client.execute(
sender,
REGISTRY_CONTRACT,
entrypoint,
client.fees,
"Registering domain",
funds
);
// Tx result
return tx;
} catch (e) {
return {error: e};
}
}
// Register a domain name
use cosmwasm_std::{CosmosMsg, WasmMsg, Coin, to_binary, Uint128,};
use archid_registry::{
ExecuteMsg as ArchIdExecuteMsg,
};
let registry_contract = "Registry contract address goes here";
let desired_domain_name = "archid"; // XXX: Do not add the `.arch` suffix when registering a domain
// XXX: Remember to get the actual cost per year by querying the `Config` entry point (see above example)
let cost_per_year: u128 = 250000000000000000;
let denom = "aarch"; // (Or "aconst" for testnet)
let register_msg: archid_registry::ExecuteMsg = ArchIdExecuteMsg::Register {
name: desired_domain_name.into(),
};
let register_resp: CosmosMsg = WasmMsg::Execute {
contract_addr: registry_contract.into(),
msg: to_binary(&register_msg)?,
funds: &[Coin {
denom: denom.into(),
amount: Uint128::from(cost_per_year),
}],
}
.into();
let messages = vec![register_resp];
Ok(Response::new().add_messages(messages))
// You'll need to import these types if you want to make contract-to-contract
// calls to the ArchID Registry contract
use archid_token::{Account, Website};
use cosmwasm_std::{Addr, Uint128};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
// The following types come from `src/state.rs` in the Registry project
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
pub struct Config {
pub admin: Addr,
pub wallet: Addr,
pub cw721: Addr,
pub base_cost: Uint128,
pub base_expiration: u64,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
pub enum SubDomainStatus {
//if subdomain in acive mint domain owner can only extend expiration up to domain expiration
ExistingMintActive,
// if subdomain expired owner can remint which will first burn existing nft
ExistingMintExpired,
// if new subdomain owner can register and mint / not mint
NewSubdomain
}
// The following types come from `src/msg.rs` in the Registry project
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
pub struct InstantiateMsg {
pub admin: Addr,
pub wallet: Addr,
pub cw721: Addr,
pub base_cost: Uint128,
pub base_expiration: u64,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub struct MetaDataUpdateMsg {
pub description: Option<String>,
pub image: Option<String>,
pub accounts: Option<Vec<Account>>,
pub websites: Option<Vec<Website>>,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum ExecuteMsg {
Register {
name: String,
},
Withdraw {
amount: Uint128,
},
RenewRegistration {
name: String,
},
ExtendSubdomainExpiry {
domain: String,
subdomain: String,
expiration: u64,
},
UpdateResolver {
name: String,
new_resolver: Addr,
},
RegisterSubdomain {
domain: String,
subdomain: String,
new_resolver: Addr,
new_owner: Addr,
expiration: u64,
},
RemoveSubdomain {
domain: String,
subdomain: String,
},
UpdateConfig {
config: Config,
},
UpdateUserDomainData {
name: String,
metadata_update: MetaDataUpdateMsg,
},
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum QueryMsg {
ResolveRecord { name: String },
RecordExpiration { name: String },
ResolveAddress { address: Addr },
Config {},
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
pub struct ResolveRecordResponse {
pub address: Option<String>,
pub expiration: u64,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
pub struct ResolveAddressResponse {
pub names: Option<Vec<String>>,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
pub struct RecordExpirationResponse {
pub created: u64,
pub expiration: u64,
}
const REGISTRY_CONTRACT = "Registry contract address goes here";
/**
* Resolve a Domain name record from the registry contract
* @param {String} name : Domain name to be resolved
* @param {SigningCosmWasmClient} client? : instance of signing client
* @returns {QueryResult}
*/
async function ResolveRecord(name, client = null) {
try {
let entrypoint = {
resolve_record: {
name: name
}
};
let query = await client.queryClient.wasm.queryContractSmart(
REGISTRY_CONTRACT,
entrypoint
);
return query;
} catch(e) {
return {error: e};
}
}
/*
Example return:
ResolveRecord('nft.arch', cwClient);
//returns:
{ address: "archway1h3mqe7elgk0ndjc5yfw8kv92m449y4e3k84pa2", expiration: 1693037996 }
*/
/**
* Load token metadata from token contract for a valid token ID
* @param {String} tokenId : The domain name / token ID to be fetched
* @param {String} contract : contract address string for token contract
* @param {SigningCosmWasmClient} client : instance of signing client
* @returns {QueryResult}
*/
async function Token (tokenId = null, contract = null, client = null) {
try {
let entrypoint = {
nft_info: {
token_id: tokenId
}
};
let tokenQuery = await client.queryClient.wasm.queryContractSmart(
contract,
entrypoint
);
return tokenQuery;
} catch(e) {
return {error: e};
}
}
/*
Example return:
const cw721ContractAddress = "nft contract address goes here";
Token('archid.arch', cw721ContractAddress, cwClient);
//returns:
{
"token_uri": null,
"extension": {
"name": "archid.arch",
"description": "A decentralized name service with support for domains, subdomains, and web2 identity verifcation",
"image": "ipfs://QmNoMUgTM82EGaTCTnuEUJDusV21UEGSgKM5RhM1C9N3WE",
"created": 1680023536,
"expiry": 1710023536,
"domain": "archid.arch",
"subdomains": [
{
"name": "dapp",
"resolver": "archway100vemsuja6h7k5ygve3xz3yzgapdj6zpe00ffg8d95hpwj9d8v5q8zc9zh",
"minted": true,
"created": 1680023944,
"expiry": 1705788708
},
{
"name": "token",
"resolver": "archway1ll9jnzdnge45w56tas3m2z08hhevwykj8hmgxpa4mfppdrx2ztfsxmj0fl",
"minted": true,
"created": 1682367218,
"expiry": 1710023536
}
],
"accounts": [
{
"username": "@archidapp",
"profile": "https://twitter.com/archidapp",
"account_type": "twitter",
"verfication_hash": null
},
{
"username": "archid-protocol",
"profile": "https://github.com/archid-protocol",
"account_type": "github",
"verfication_hash": null
}
],
"websites": [
{
"url": "https://archid.app",
"domain": "dapp.archid.arch",
"verfication_hash": null
}
]
}
}
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment