cw20/
helpers.rs

1use cosmwasm_schema::cw_serde;
2use cosmwasm_std::{
3    to_json_binary, Addr, CosmosMsg, CustomQuery, QuerierWrapper, QueryRequest, StdResult, Uint128,
4    WasmMsg, WasmQuery,
5};
6
7use crate::{
8    AllowanceResponse, BalanceResponse, Cw20ExecuteMsg, Cw20QueryMsg, MinterResponse,
9    TokenInfoResponse,
10};
11
12/// Cw20Contract is a wrapper around Addr that provides a lot of helpers
13/// for working with this.
14///
15/// If you wish to persist this, convert to Cw20CanonicalContract via .canonical()
16#[cw_serde]
17pub struct Cw20Contract(pub Addr);
18
19impl Cw20Contract {
20    pub fn addr(&self) -> Addr {
21        self.0.clone()
22    }
23
24    pub fn call<T: Into<Cw20ExecuteMsg>>(&self, msg: T) -> StdResult<CosmosMsg> {
25        let msg = to_json_binary(&msg.into())?;
26        Ok(WasmMsg::Execute {
27            contract_addr: self.addr().into(),
28            msg,
29            funds: vec![],
30        }
31        .into())
32    }
33
34    fn encode_smart_query<CQ: CustomQuery>(
35        &self,
36        msg: Cw20QueryMsg,
37    ) -> StdResult<QueryRequest<CQ>> {
38        Ok(WasmQuery::Smart {
39            contract_addr: self.addr().into(),
40            msg: to_json_binary(&msg)?,
41        }
42        .into())
43    }
44
45    /// Get token balance for the given address
46    pub fn balance<T, CQ>(&self, querier: &QuerierWrapper<CQ>, address: T) -> StdResult<Uint128>
47    where
48        T: Into<String>,
49        CQ: CustomQuery,
50    {
51        let query = self.encode_smart_query(Cw20QueryMsg::Balance {
52            address: address.into(),
53        })?;
54        let res: BalanceResponse = querier.query(&query)?;
55        Ok(res.balance)
56    }
57
58    /// Get metadata from the contract. This is a good check that the address
59    /// is a valid Cw20 contract.
60    pub fn meta<CQ: CustomQuery>(
61        &self,
62        querier: &QuerierWrapper<CQ>,
63    ) -> StdResult<TokenInfoResponse> {
64        let query = self.encode_smart_query(Cw20QueryMsg::TokenInfo {})?;
65        querier.query(&query)
66    }
67
68    /// Get allowance of spender to use owner's account
69    pub fn allowance<T, U, CQ>(
70        &self,
71        querier: &QuerierWrapper<CQ>,
72        owner: T,
73        spender: U,
74    ) -> StdResult<AllowanceResponse>
75    where
76        T: Into<String>,
77        U: Into<String>,
78        CQ: CustomQuery,
79    {
80        let query = self.encode_smart_query(Cw20QueryMsg::Allowance {
81            owner: owner.into(),
82            spender: spender.into(),
83        })?;
84        querier.query(&query)
85    }
86
87    /// Find info on who can mint, and how much
88    pub fn minter<CQ: CustomQuery>(
89        &self,
90        querier: &QuerierWrapper<CQ>,
91    ) -> StdResult<Option<MinterResponse>> {
92        let query = self.encode_smart_query(Cw20QueryMsg::Minter {})?;
93        querier.query(&query)
94    }
95
96    /// returns true if the contract supports the allowance extension
97    pub fn has_allowance<CQ: CustomQuery>(&self, querier: &QuerierWrapper<CQ>) -> bool {
98        self.allowance(querier, self.addr(), self.addr()).is_ok()
99    }
100
101    /// returns true if the contract supports the mintable extension
102    pub fn is_mintable<CQ: CustomQuery>(&self, querier: &QuerierWrapper<CQ>) -> bool {
103        self.minter(querier).is_ok()
104    }
105}