From 96cc89a09f447d4ea38e75eccabcb2d72e771807 Mon Sep 17 00:00:00 2001 From: "shiki.takahashi" Date: Wed, 4 Nov 2020 14:14:54 +0900 Subject: [PATCH 1/2] feat: Implement token wrapper library and complete token tester --- contracts/README.md | 5 + contracts/token-tester/examples/schema.rs | 2 + contracts/token-tester/schema/handle_msg.json | 170 +++++++++++ contracts/token-tester/schema/query_msg.json | 76 ++++- contracts/token-tester/schema/state.json | 22 ++ contracts/token-tester/src/contract.rs | 278 +++++++++++++++++- contracts/token-tester/src/msg.rs | 48 ++- ...apper_for__token_route_and__token_msg.json | 227 +++++++++++--- packages/ext/src/lib.rs | 6 + packages/ext/src/msg_token.rs | 37 +++ packages/ext/src/querier_token.rs | 111 +++++++ packages/ext/src/query.rs | 42 +++ packages/ext/src/token.rs | 37 +++ 13 files changed, 1011 insertions(+), 50 deletions(-) create mode 100644 contracts/token-tester/schema/state.json create mode 100644 packages/ext/src/querier_token.rs create mode 100644 packages/ext/src/query.rs create mode 100644 packages/ext/src/token.rs diff --git a/contracts/README.md b/contracts/README.md index 9d0ed200a..0b7e5e62a 100644 --- a/contracts/README.md +++ b/contracts/README.md @@ -38,4 +38,9 @@ docker run --rm -v "$(pwd)":/code \ --mount type=volume,source="devcontract_cache_staking",target=/code/contracts/staking/target \ --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \ cosmwasm/rust-optimizer:0.9.0 ./contracts/staking + +docker run --rm -v "$(pwd)":/code \ + --mount type=volume,source="devcontract_token_tester",target=/code/contracts/staking/target \ + --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \ + cosmwasm/rust-optimizer:0.9.0 ./contracts/token-tester ``` diff --git a/contracts/token-tester/examples/schema.rs b/contracts/token-tester/examples/schema.rs index 0b9cda4a7..6e83e2fd1 100644 --- a/contracts/token-tester/examples/schema.rs +++ b/contracts/token-tester/examples/schema.rs @@ -4,6 +4,7 @@ use std::fs::create_dir_all; use cosmwasm_schema::{export_schema, remove_schemas, schema_for}; use token_tester::msg::{HandleMsg, InitMsg, QueryMsg}; +use token_tester::state::State; fn main() { let mut out_dir = current_dir().unwrap(); @@ -14,4 +15,5 @@ fn main() { export_schema(&schema_for!(InitMsg), &out_dir); export_schema(&schema_for!(HandleMsg), &out_dir); export_schema(&schema_for!(QueryMsg), &out_dir); + export_schema(&schema_for!(State), &out_dir); } diff --git a/contracts/token-tester/schema/handle_msg.json b/contracts/token-tester/schema/handle_msg.json index 220f30969..3e10b894e 100644 --- a/contracts/token-tester/schema/handle_msg.json +++ b/contracts/token-tester/schema/handle_msg.json @@ -52,6 +52,176 @@ } } } + }, + { + "type": "object", + "required": [ + "transfer" + ], + "properties": { + "transfer": { + "type": "object", + "required": [ + "amount", + "contract_id", + "from", + "to" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Uint128" + }, + "contract_id": { + "type": "string" + }, + "from": { + "$ref": "#/definitions/HumanAddr" + }, + "to": { + "$ref": "#/definitions/HumanAddr" + } + } + } + } + }, + { + "type": "object", + "required": [ + "mint" + ], + "properties": { + "mint": { + "type": "object", + "required": [ + "amount", + "contract_id", + "from", + "to" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Uint128" + }, + "contract_id": { + "type": "string" + }, + "from": { + "$ref": "#/definitions/HumanAddr" + }, + "to": { + "$ref": "#/definitions/HumanAddr" + } + } + } + } + }, + { + "type": "object", + "required": [ + "burn" + ], + "properties": { + "burn": { + "type": "object", + "required": [ + "amount", + "contract_id", + "from" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Uint128" + }, + "contract_id": { + "type": "string" + }, + "from": { + "$ref": "#/definitions/HumanAddr" + } + } + } + } + }, + { + "type": "object", + "required": [ + "grant_perm" + ], + "properties": { + "grant_perm": { + "type": "object", + "required": [ + "contract_id", + "from", + "permission", + "to" + ], + "properties": { + "contract_id": { + "type": "string" + }, + "from": { + "$ref": "#/definitions/HumanAddr" + }, + "permission": { + "type": "string" + }, + "to": { + "$ref": "#/definitions/HumanAddr" + } + } + } + } + }, + { + "type": "object", + "required": [ + "revoke_perm" + ], + "properties": { + "revoke_perm": { + "type": "object", + "required": [ + "contract_id", + "from", + "permission" + ], + "properties": { + "contract_id": { + "type": "string" + }, + "from": { + "$ref": "#/definitions/HumanAddr" + }, + "permission": { + "type": "string" + } + } + } + } + }, + { + "type": "object", + "required": [ + "modify" + ], + "properties": { + "modify": { + "type": "object", + "required": [ + "contract_id", + "owner" + ], + "properties": { + "contract_id": { + "type": "string" + }, + "owner": { + "$ref": "#/definitions/HumanAddr" + } + } + } + } } ], "definitions": { diff --git a/contracts/token-tester/schema/query_msg.json b/contracts/token-tester/schema/query_msg.json index 24261cd9c..618f08f4b 100644 --- a/contracts/token-tester/schema/query_msg.json +++ b/contracts/token-tester/schema/query_msg.json @@ -20,6 +20,80 @@ } } } + }, + { + "type": "object", + "required": [ + "get_balance" + ], + "properties": { + "get_balance": { + "type": "object", + "required": [ + "address", + "contract_id" + ], + "properties": { + "address": { + "$ref": "#/definitions/HumanAddr" + }, + "contract_id": { + "type": "string" + } + } + } + } + }, + { + "type": "object", + "required": [ + "get_total" + ], + "properties": { + "get_total": { + "type": "object", + "required": [ + "contract_id", + "target" + ], + "properties": { + "contract_id": { + "type": "string" + }, + "target": { + "type": "string" + } + } + } + } + }, + { + "type": "object", + "required": [ + "get_perm" + ], + "properties": { + "get_perm": { + "type": "object", + "required": [ + "address", + "contract_id" + ], + "properties": { + "address": { + "$ref": "#/definitions/HumanAddr" + }, + "contract_id": { + "type": "string" + } + } + } + } + } + ], + "definitions": { + "HumanAddr": { + "type": "string" } - ] + } } diff --git a/contracts/token-tester/schema/state.json b/contracts/token-tester/schema/state.json new file mode 100644 index 000000000..d4b4a3340 --- /dev/null +++ b/contracts/token-tester/schema/state.json @@ -0,0 +1,22 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "State", + "type": "object", + "required": [ + "owner" + ], + "properties": { + "owner": { + "$ref": "#/definitions/CanonicalAddr" + } + }, + "definitions": { + "Binary": { + "description": "Binary is a wrapper around Vec to add base64 de/serialization with serde. It also adds some helper methods to help encode inline.\n\nThis is only needed as serde-json-{core,wasm} has a horrible encoding for Vec", + "type": "string" + }, + "CanonicalAddr": { + "$ref": "#/definitions/Binary" + } + } +} diff --git a/contracts/token-tester/src/contract.rs b/contracts/token-tester/src/contract.rs index c08947ff6..d758d8d27 100644 --- a/contracts/token-tester/src/contract.rs +++ b/contracts/token-tester/src/contract.rs @@ -1,9 +1,14 @@ +use std::str::FromStr; + use cosmwasm_std::{ - log, Api, Binary, CosmosMsg, Env, Extern, HandleResponse, HandleResult, HumanAddr, + log, to_binary, Api, Binary, CosmosMsg, Env, Extern, HandleResponse, HandleResult, HumanAddr, InitResponse, Querier, StdResult, Storage, Uint128, }; -use cosmwasm_ext::{LinkMsgWrapper, Module, MsgData, TokenMsg, TokenRoute}; +use cosmwasm_ext::{ + Change, LinkMsgWrapper, LinkTokenQuerier, Module, MsgData, Response, Token, TokenMsg, + TokenPerm, TokenRoute, +}; use crate::msg::{HandleMsg, InitMsg, QueryMsg}; use crate::state::{config, config_read, State}; @@ -41,6 +46,35 @@ pub fn handle( } => try_issue( deps, env, owner, to, name, symbol, img_uri, meta, amount, mintable, decimals, ), + HandleMsg::Transfer { + from, + contract_id, + to, + amount, + } => try_transfer(deps, env, from, contract_id, to, amount), + HandleMsg::Mint { + from, + contract_id, + to, + amount, + } => try_mint(deps, env, from, contract_id, to, amount), + HandleMsg::Burn { + from, + contract_id, + amount, + } => try_burn(deps, env, from, contract_id, amount), + HandleMsg::GrantPerm { + from, + contract_id, + to, + permission, + } => try_grant_perm(deps, env, from, contract_id, to, permission), + HandleMsg::RevokePerm { + from, + contract_id, + permission, + } => try_revoke_perm(deps, env, from, contract_id, permission), + HandleMsg::Modify { owner, contract_id } => try_modify(deps, env, owner, contract_id), } } @@ -50,6 +84,18 @@ pub fn query( ) -> StdResult { match msg { QueryMsg::GetToken { contract_id } => query_token(deps, contract_id), + QueryMsg::GetBalance { + contract_id, + address, + } => query_balance(deps, contract_id, address), + QueryMsg::GetTotal { + contract_id, + target, + } => query_supply(deps, contract_id, target), + QueryMsg::GetPerm { + contract_id, + address, + } => query_perm(deps, contract_id, address), } } @@ -95,11 +141,231 @@ pub fn try_issue( Ok(res) } +pub fn try_transfer( + _deps: &mut Extern, + _env: Env, + from: HumanAddr, + contract_id: String, + to: HumanAddr, + amount: Uint128, +) -> HandleResult> { + // Some kind of logic. + + let msg: CosmosMsg> = LinkMsgWrapper { + module: Module::Tokenencode, + msg_data: MsgData { + route: TokenRoute::Transfer, + data: TokenMsg::Transfer { + from, + contract_id, + to, + amount, + }, + }, + } + .into(); + + let res = HandleResponse { + messages: vec![msg], + log: vec![log("action", "transfer")], + data: None, + }; + Ok(res) +} + +pub fn try_mint( + _deps: &mut Extern, + _env: Env, + from: HumanAddr, + contract_id: String, + to: HumanAddr, + amount: Uint128, +) -> HandleResult> { + let msg: CosmosMsg> = LinkMsgWrapper { + module: Module::Tokenencode, + msg_data: MsgData { + route: TokenRoute::Mint, + data: TokenMsg::Mint { + from, + contract_id, + to, + amount, + }, + }, + } + .into(); + + let res = HandleResponse { + messages: vec![msg], + log: vec![log("action", "mint")], + data: None, + }; + Ok(res) +} + +pub fn try_burn( + _deps: &mut Extern, + _env: Env, + from: HumanAddr, + contract_id: String, + amount: Uint128, +) -> HandleResult> { + let msg: CosmosMsg> = LinkMsgWrapper { + module: Module::Tokenencode, + msg_data: MsgData { + route: TokenRoute::Burn, + data: TokenMsg::Burn { + from, + contract_id, + amount, + }, + }, + } + .into(); + + let res = HandleResponse { + messages: vec![msg], + log: vec![log("action", "burn")], + data: None, + }; + Ok(res) +} + +pub fn try_grant_perm( + _deps: &mut Extern, + _env: Env, + from: HumanAddr, + contract_id: String, + to: HumanAddr, + perm_str: String, +) -> HandleResult> { + let permission = TokenPerm::from_str(&perm_str).unwrap(); + let msg: CosmosMsg> = LinkMsgWrapper { + module: Module::Tokenencode, + msg_data: MsgData { + route: TokenRoute::GrantPerm, + data: TokenMsg::GrantPerm { + from, + contract_id, + to, + permission, + }, + }, + } + .into(); + + let res = HandleResponse { + messages: vec![msg], + log: vec![log("action", "grant_perm")], + data: None, + }; + Ok(res) +} + +pub fn try_revoke_perm( + _deps: &mut Extern, + _env: Env, + from: HumanAddr, + contract_id: String, + perm_str: String, +) -> HandleResult> { + let permission = TokenPerm::from_str(&perm_str).unwrap(); + let msg: CosmosMsg> = LinkMsgWrapper { + module: Module::Tokenencode, + msg_data: MsgData { + route: TokenRoute::RevokePerm, + data: TokenMsg::RevokePerm { + from, + contract_id, + permission, + }, + }, + } + .into(); + + let res = HandleResponse { + messages: vec![msg], + log: vec![log("action", "revoke_perm")], + data: None, + }; + Ok(res) +} + +pub fn try_modify( + _deps: &mut Extern, + _env: Env, + owner: HumanAddr, + contract_id: String, +) -> HandleResult> { + let change = Change::new("meta".to_string(), "update_token_meta".to_string()); + let msg: CosmosMsg> = LinkMsgWrapper { + module: Module::Tokenencode, + msg_data: MsgData { + route: TokenRoute::Modify, + data: TokenMsg::Modify { + owner, + contract_id, + changes: vec![change], + }, + }, + } + .into(); + let res = HandleResponse { + messages: vec![msg], + log: vec![log("action", "modify")], + data: None, + }; + Ok(res) +} + fn query_token( - _deps: &Extern, - _contract_id: String, + deps: &Extern, + contract_id: String, ) -> StdResult { - unimplemented!() + let res = match LinkTokenQuerier::new(&deps.querier).query_token(contract_id)? { + Some(token_response) => token_response, + None => return to_binary(&None::>>), + }; + + let out = to_binary(&res)?; + Ok(out) +} + +fn query_balance( + deps: &Extern, + contract_id: String, + address: HumanAddr, +) -> StdResult { + let res = LinkTokenQuerier::new(&deps.querier) + .query_balance(contract_id, address) + .unwrap(); + let out = to_binary(&res)?; + Ok(out) +} + +fn query_supply( + deps: &Extern, + contract_id: String, + target: String, +) -> StdResult { + let res = LinkTokenQuerier::new(&deps.querier) + .query_supply(contract_id, target) + .unwrap(); + let out = to_binary(&res)?; + Ok(out) +} + +fn query_perm( + deps: &Extern, + contract_id: String, + address: HumanAddr, +) -> StdResult { + let res = match LinkTokenQuerier::new(&deps.querier).query_perm(contract_id, address)? { + Some(permissions) => permissions, + None => return to_binary(&None::>>), + }; + let out = to_binary(&res)?; + Ok(out) } fn _query_owner(deps: &Extern) -> StdResult { @@ -116,7 +382,7 @@ mod tests { fn create_contract(owner: String) -> (Extern, Env) { let mut deps = mock_dependencies(20, &coins(1000, "cony")); let env = mock_env(owner, &coins(1000, "cony")); - let res = init(&mut deps, env.clone(), InitMsg {}).unwrap(); + let res = init(&mut deps, env, InitMsg {}).unwrap(); assert_eq!(0, res.messages.len()); (deps, env) } diff --git a/contracts/token-tester/src/msg.rs b/contracts/token-tester/src/msg.rs index b8dce5194..e8eb7092c 100644 --- a/contracts/token-tester/src/msg.rs +++ b/contracts/token-tester/src/msg.rs @@ -20,10 +20,56 @@ pub enum HandleMsg { mintable: bool, decimals: Uint128, }, + Transfer { + from: HumanAddr, + contract_id: String, + to: HumanAddr, + amount: Uint128, + }, + Mint { + from: HumanAddr, + contract_id: String, + to: HumanAddr, + amount: Uint128, + }, + Burn { + from: HumanAddr, + contract_id: String, + amount: Uint128, + }, + GrantPerm { + from: HumanAddr, + contract_id: String, + to: HumanAddr, + permission: String, + }, + RevokePerm { + from: HumanAddr, + contract_id: String, + permission: String, + }, + Modify { + owner: HumanAddr, + contract_id: String, + }, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] #[serde(rename_all = "snake_case")] pub enum QueryMsg { - GetToken { contract_id: String }, + GetToken { + contract_id: String, + }, + GetBalance { + contract_id: String, + address: HumanAddr, + }, + GetTotal { + contract_id: String, + target: String, + }, + GetPerm { + contract_id: String, + address: HumanAddr, + }, } diff --git a/packages/ext/schema/link_msg_wrapper_for__token_route_and__token_msg.json b/packages/ext/schema/link_msg_wrapper_for__token_route_and__token_msg.json index 7bc656bdc..9de62427f 100644 --- a/packages/ext/schema/link_msg_wrapper_for__token_route_and__token_msg.json +++ b/packages/ext/schema/link_msg_wrapper_for__token_route_and__token_msg.json @@ -15,6 +15,21 @@ } }, "definitions": { + "Change": { + "type": "object", + "required": [ + "field", + "value" + ], + "properties": { + "field": { + "type": "string" + }, + "value": { + "type": "string" + } + } + }, "HumanAddr": { "type": "string" }, @@ -44,51 +59,172 @@ { "type": "object", "required": [ - "issue" + "amount", + "decimals", + "img_uri", + "meta", + "mintable", + "name", + "owner", + "symbol", + "to" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Uint128" + }, + "decimals": { + "$ref": "#/definitions/Uint128" + }, + "img_uri": { + "type": "string" + }, + "meta": { + "type": "string" + }, + "mintable": { + "type": "boolean" + }, + "name": { + "type": "string" + }, + "owner": { + "$ref": "#/definitions/HumanAddr" + }, + "symbol": { + "type": "string" + }, + "to": { + "$ref": "#/definitions/HumanAddr" + } + } + }, + { + "type": "object", + "required": [ + "amount", + "contract_id", + "from", + "to" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Uint128" + }, + "contract_id": { + "type": "string" + }, + "from": { + "$ref": "#/definitions/HumanAddr" + }, + "to": { + "$ref": "#/definitions/HumanAddr" + } + } + }, + { + "type": "object", + "required": [ + "amount", + "contract_id", + "from", + "to" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Uint128" + }, + "contract_id": { + "type": "string" + }, + "from": { + "$ref": "#/definitions/HumanAddr" + }, + "to": { + "$ref": "#/definitions/HumanAddr" + } + } + }, + { + "type": "object", + "required": [ + "amount", + "contract_id", + "from" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Uint128" + }, + "contract_id": { + "type": "string" + }, + "from": { + "$ref": "#/definitions/HumanAddr" + } + } + }, + { + "type": "object", + "required": [ + "contract_id", + "from", + "permission", + "to" ], "properties": { - "issue": { - "type": "object", - "required": [ - "amount", - "decimals", - "img_uri", - "meta", - "mintable", - "name", - "owner", - "symbol", - "to" - ], - "properties": { - "amount": { - "$ref": "#/definitions/Uint128" - }, - "decimals": { - "$ref": "#/definitions/Uint128" - }, - "img_uri": { - "type": "string" - }, - "meta": { - "type": "string" - }, - "mintable": { - "type": "boolean" - }, - "name": { - "type": "string" - }, - "owner": { - "$ref": "#/definitions/HumanAddr" - }, - "symbol": { - "type": "string" - }, - "to": { - "$ref": "#/definitions/HumanAddr" - } + "contract_id": { + "type": "string" + }, + "from": { + "$ref": "#/definitions/HumanAddr" + }, + "permission": { + "$ref": "#/definitions/permission" + }, + "to": { + "$ref": "#/definitions/HumanAddr" + } + } + }, + { + "type": "object", + "required": [ + "contract_id", + "from", + "permission" + ], + "properties": { + "contract_id": { + "type": "string" + }, + "from": { + "$ref": "#/definitions/HumanAddr" + }, + "permission": { + "$ref": "#/definitions/permission" + } + } + }, + { + "type": "object", + "required": [ + "changes", + "contract_id", + "owner" + ], + "properties": { + "changes": { + "type": "array", + "items": { + "$ref": "#/definitions/Change" } + }, + "contract_id": { + "type": "string" + }, + "owner": { + "$ref": "#/definitions/HumanAddr" } } } @@ -107,6 +243,13 @@ }, "Uint128": { "type": "string" + }, + "permission": { + "enum": [ + "mint", + "burn", + "modify" + ] } } } diff --git a/packages/ext/src/lib.rs b/packages/ext/src/lib.rs index 86571a2a9..2f4d37443 100644 --- a/packages/ext/src/lib.rs +++ b/packages/ext/src/lib.rs @@ -1,10 +1,16 @@ mod msg; mod msg_collection; mod msg_token; +mod querier_token; +mod query; +mod token; pub use msg::{Change, LinkMsgWrapper, Module, MsgData}; pub use msg_collection::{CollectionMsg, CollectionRoute}; pub use msg_token::{TokenMsg, TokenRoute}; +pub use querier_token::{LinkTokenQuerier, TokenQuery, TokenQueryRoute}; +pub use query::{LinkQueryWrapper, QueryData, Response}; +pub use token::{Token, TokenPerm}; // This export is added to all contracts that import this package, signifying that they require // "link" support on the chain they run on. diff --git a/packages/ext/src/msg_token.rs b/packages/ext/src/msg_token.rs index 2f51d241a..49c1a53b8 100644 --- a/packages/ext/src/msg_token.rs +++ b/packages/ext/src/msg_token.rs @@ -3,6 +3,9 @@ use serde::{Deserialize, Serialize}; use cosmwasm_std::{HumanAddr, Uint128}; +use crate::msg::Change; +use crate::token::TokenPerm; + #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] #[serde(rename_all = "snake_case")] pub enum TokenRoute { @@ -17,6 +20,7 @@ pub enum TokenRoute { #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] #[serde(rename_all = "snake_case")] +#[serde(untagged)] pub enum TokenMsg { Issue { owner: HumanAddr, @@ -29,6 +33,39 @@ pub enum TokenMsg { mintable: bool, decimals: Uint128, }, + Transfer { + from: HumanAddr, + contract_id: String, + to: HumanAddr, + amount: Uint128, + }, + Mint { + from: HumanAddr, + contract_id: String, + to: HumanAddr, + amount: Uint128, + }, + Burn { + from: HumanAddr, + contract_id: String, + amount: Uint128, + }, + GrantPerm { + from: HumanAddr, + contract_id: String, + to: HumanAddr, + permission: TokenPerm, + }, + RevokePerm { + from: HumanAddr, + contract_id: String, + permission: TokenPerm, + }, + Modify { + owner: HumanAddr, + contract_id: String, + changes: Vec, + }, } #[cfg(test)] diff --git a/packages/ext/src/querier_token.rs b/packages/ext/src/querier_token.rs new file mode 100644 index 000000000..02905484a --- /dev/null +++ b/packages/ext/src/querier_token.rs @@ -0,0 +1,111 @@ +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; + +use cosmwasm_std::{HumanAddr, Querier, StdResult, Uint128}; + +use crate::query::{LinkQueryWrapper, Module, QueryData, Response}; +use crate::token::{Token, TokenPerm}; + +pub struct LinkTokenQuerier<'a, Q: Querier> { + querier: &'a Q, +} + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[serde(rename_all = "snake_case")] +pub enum TokenQueryRoute { + Tokens, + Balance, + Supply, + Perms, +} + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[serde(rename_all = "snake_case")] +pub enum TokenQuery { + QueryTokenParam { + contract_id: String, + }, + QueryBalanceParam { + contract_id: String, + address: HumanAddr, + }, + QueryTotalParam { + contract_id: String, + target: String, + }, + QueryPermParam { + contract_id: String, + address: HumanAddr, + }, +} + +impl<'a, Q: Querier> LinkTokenQuerier<'a, Q> { + pub fn new(querier: &'a Q) -> Self { + LinkTokenQuerier { querier } + } + + pub fn query_token(&self, contract_id: String) -> StdResult>> { + let request = LinkQueryWrapper:: { + module: Module::Tokenencode, + query_data: QueryData { + route: TokenQueryRoute::Tokens, + data: TokenQuery::QueryTokenParam { contract_id }, + }, + }; + + let res = self.querier.custom_query(&request.into())?; + Ok(res) + } + + pub fn query_balance(&self, contract_id: String, address: HumanAddr) -> StdResult { + let request = LinkQueryWrapper:: { + module: Module::Tokenencode, + query_data: QueryData { + route: TokenQueryRoute::Balance, + data: TokenQuery::QueryBalanceParam { + contract_id, + address, + }, + }, + }; + + let res = self.querier.custom_query(&request.into())?; + Ok(res) + } + + pub fn query_supply(&self, contract_id: String, target: String) -> StdResult { + let request = LinkQueryWrapper:: { + module: Module::Tokenencode, + query_data: QueryData { + route: TokenQueryRoute::Supply, + data: TokenQuery::QueryTotalParam { + contract_id, + target, + }, + }, + }; + + let res = self.querier.custom_query(&request.into())?; + Ok(res) + } + + pub fn query_perm( + &self, + contract_id: String, + address: HumanAddr, + ) -> StdResult>> { + let request = LinkQueryWrapper:: { + module: Module::Tokenencode, + query_data: QueryData { + route: TokenQueryRoute::Perms, + data: TokenQuery::QueryPermParam { + contract_id, + address, + }, + }, + }; + + let res = self.querier.custom_query(&request.into())?; + Ok(res) + } +} diff --git a/packages/ext/src/query.rs b/packages/ext/src/query.rs new file mode 100644 index 000000000..244556bd2 --- /dev/null +++ b/packages/ext/src/query.rs @@ -0,0 +1,42 @@ +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; + +use cosmwasm_std::QueryRequest; + +use crate::querier_token::{TokenQuery, TokenQueryRoute}; + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[serde(rename_all = "snake_case")] +pub enum Module { + Tokenencode, + Collectionencode, +} + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[serde(rename_all = "snake_case")] +pub struct LinkQueryWrapper { + pub module: Module, + pub query_data: QueryData, +} + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[serde(rename_all = "snake_case")] +pub struct QueryData { + pub route: R, + pub data: D, +} + +impl Into>> + for LinkQueryWrapper +{ + fn into(self) -> QueryRequest> { + QueryRequest::Custom(self) + } +} + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +pub struct Response { + #[serde(rename = "type")] + pub key: String, + pub value: T, +} diff --git a/packages/ext/src/token.rs b/packages/ext/src/token.rs new file mode 100644 index 000000000..c15a90e90 --- /dev/null +++ b/packages/ext/src/token.rs @@ -0,0 +1,37 @@ +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; +use std::str::FromStr; + +use cosmwasm_std::Uint128; + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +pub struct Token { + pub contract_id: String, + pub name: String, + pub symbol: String, + pub meta: String, + pub img_uri: String, + pub decimals: Uint128, + pub mintable: bool, +} + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[serde(rename = "permission")] +#[serde(rename_all = "snake_case")] +pub enum TokenPerm { + Mint, + Burn, + Modify, +} + +impl FromStr for TokenPerm { + type Err = &'static str; + fn from_str(s: &str) -> Result { + match s { + "mint" => Ok(TokenPerm::Mint), + "burn" => Ok(TokenPerm::Burn), + "modify" => Ok(TokenPerm::Modify), + _ => Err("Unknown permission type"), + } + } +} From 409bc56ce644833d28cbde38caf414f2bf4a131a Mon Sep 17 00:00:00 2001 From: "shiki.takahashi" Date: Fri, 6 Nov 2020 19:58:24 +0900 Subject: [PATCH 2/2] fix: used enum for target param --- contracts/token-tester/src/contract.rs | 5 +++-- packages/ext/src/lib.rs | 2 +- packages/ext/src/querier_token.rs | 26 ++++++++++++++++++++++++-- 3 files changed, 28 insertions(+), 5 deletions(-) diff --git a/contracts/token-tester/src/contract.rs b/contracts/token-tester/src/contract.rs index d758d8d27..bbe5bed34 100644 --- a/contracts/token-tester/src/contract.rs +++ b/contracts/token-tester/src/contract.rs @@ -7,7 +7,7 @@ use cosmwasm_std::{ use cosmwasm_ext::{ Change, LinkMsgWrapper, LinkTokenQuerier, Module, MsgData, Response, Token, TokenMsg, - TokenPerm, TokenRoute, + TokenPerm, TokenRoute, TokenTarget, }; use crate::msg::{HandleMsg, InitMsg, QueryMsg}; @@ -346,8 +346,9 @@ fn query_balance( fn query_supply( deps: &Extern, contract_id: String, - target: String, + target_str: String, ) -> StdResult { + let target = TokenTarget::from_str(&target_str).unwrap(); let res = LinkTokenQuerier::new(&deps.querier) .query_supply(contract_id, target) .unwrap(); diff --git a/packages/ext/src/lib.rs b/packages/ext/src/lib.rs index 2f4d37443..918ac0ea8 100644 --- a/packages/ext/src/lib.rs +++ b/packages/ext/src/lib.rs @@ -8,7 +8,7 @@ mod token; pub use msg::{Change, LinkMsgWrapper, Module, MsgData}; pub use msg_collection::{CollectionMsg, CollectionRoute}; pub use msg_token::{TokenMsg, TokenRoute}; -pub use querier_token::{LinkTokenQuerier, TokenQuery, TokenQueryRoute}; +pub use querier_token::{LinkTokenQuerier, TokenQuery, TokenQueryRoute, TokenTarget}; pub use query::{LinkQueryWrapper, QueryData, Response}; pub use token::{Token, TokenPerm}; diff --git a/packages/ext/src/querier_token.rs b/packages/ext/src/querier_token.rs index 02905484a..fc78680ec 100644 --- a/packages/ext/src/querier_token.rs +++ b/packages/ext/src/querier_token.rs @@ -1,5 +1,6 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; +use std::str::FromStr; use cosmwasm_std::{HumanAddr, Querier, StdResult, Uint128}; @@ -10,6 +11,27 @@ pub struct LinkTokenQuerier<'a, Q: Querier> { querier: &'a Q, } +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +#[serde(rename = "target")] +#[serde(rename_all = "snake_case")] +pub enum TokenTarget { + Mint, + Burn, + Supply, +} + +impl FromStr for TokenTarget { + type Err = &'static str; + fn from_str(s: &str) -> Result { + match s { + "mint" => Ok(TokenTarget::Mint), + "burn" => Ok(TokenTarget::Burn), + "supply" => Ok(TokenTarget::Supply), + _ => Err("Unknown target type"), + } + } +} + #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] #[serde(rename_all = "snake_case")] pub enum TokenQueryRoute { @@ -31,7 +53,7 @@ pub enum TokenQuery { }, QueryTotalParam { contract_id: String, - target: String, + target: TokenTarget, }, QueryPermParam { contract_id: String, @@ -73,7 +95,7 @@ impl<'a, Q: Querier> LinkTokenQuerier<'a, Q> { Ok(res) } - pub fn query_supply(&self, contract_id: String, target: String) -> StdResult { + pub fn query_supply(&self, contract_id: String, target: TokenTarget) -> StdResult { let request = LinkQueryWrapper:: { module: Module::Tokenencode, query_data: QueryData {