boot_cw_plus/
cw20.rs

1use boot_core::*;
2use cosmwasm_std::{Addr, Binary, Empty, Uint128};
3use cw20::{BalanceResponse, Cw20Coin, Expiration, MinterResponse};
4use cw20_base::msg::{ExecuteMsg, InstantiateMsg, QueryMsg};
5use cw_multi_test::ContractWrapper;
6use serde::Serialize;
7
8#[boot_contract(InstantiateMsg, ExecuteMsg, QueryMsg, Empty)]
9pub struct Cw20;
10
11// implement chain-generic functions
12impl<Chain: BootEnvironment> Cw20<Chain> {
13    pub fn new(id: &str, chain: Chain) -> Self {
14        let crate_path = env!("CARGO_MANIFEST_DIR");
15        let file_path = &format!("{}{}", crate_path, "/cw-artifacts/cw20_base.wasm");
16        Self(
17            Contract::new(id, chain)
18                .with_mock(Box::new(ContractWrapper::new_with_empty(
19                    cw20_base::contract::execute,
20                    cw20_base::contract::instantiate,
21                    cw20_base::contract::query,
22                )))
23                .with_wasm_path(file_path),
24        )
25    }
26
27    // Find a way to generate these functions with a macro!!!
28    pub fn send(
29        &self,
30        msg: &impl Serialize,
31        amount: u128,
32        contract: String,
33    ) -> Result<TxResponse<Chain>, BootError> {
34        let msg = ExecuteMsg::Send {
35            contract,
36            amount: Uint128::new(amount),
37            msg: cosmwasm_std::to_binary(msg)?,
38        };
39
40        self.execute(&msg, None)
41    }
42    pub fn transfer(
43        &self,
44        amount: u128,
45        recipient: String,
46    ) -> Result<TxResponse<Chain>, BootError> {
47        let msg = ExecuteMsg::Transfer {
48            recipient,
49            amount: amount.into(),
50        };
51        self.execute(&msg, None)
52    }
53
54    pub fn create_new<T: Into<Uint128>>(
55        &self,
56        minter: &Addr,
57        balance: T,
58    ) -> Result<TxResponse<Chain>, BootError> {
59        let msg = InstantiateMsg {
60            decimals: 6,
61            mint: Some(MinterResponse {
62                cap: None,
63                minter: minter.to_string(),
64            }),
65            symbol: "TEST".into(),
66            name: self.0.id.to_string(),
67            initial_balances: vec![Cw20Coin {
68                address: minter.to_string(),
69                amount: balance.into(),
70            }],
71            marketing: None,
72        };
73
74        self.instantiate(&msg, Some(minter), None)
75    }
76
77    pub fn balance(&self, address: &Addr) -> Result<u128, BootError> {
78        let bal: BalanceResponse = self.query(&QueryMsg::Balance {
79            address: address.to_string(),
80        })?;
81        Ok(bal.balance.u128())
82    }
83
84    pub fn mint(
85        &self,
86        recipient: impl Into<String>,
87        amount: u128,
88    ) -> Result<TxResponse<Chain>, BootError> {
89        let msg = ExecuteMsg::Mint {
90            recipient: recipient.into(),
91            amount: Uint128::new(amount),
92        };
93        self.execute(&msg, None)
94    }
95
96    pub fn increase_allowance(
97        &self,
98        spender: impl Into<String>,
99        amount: u128,
100        expires: Option<Expiration>,
101    ) -> Result<TxResponse<Chain>, BootError> {
102        let msg = ExecuteMsg::IncreaseAllowance {
103            spender: spender.into(),
104            amount: Uint128::new(amount),
105            expires,
106        };
107        self.execute(&msg, None)
108    }
109}
110// Todo: make into derive macro
111pub trait Cw20Send<Chain: BootEnvironment>: BootExecute<Chain, ExecuteMsg = ExecuteMsg> {
112    fn send(
113        &self,
114        msg: Binary,
115        amount: u128,
116        contract: String,
117    ) -> Result<TxResponse<Chain>, BootError>;
118}
119
120impl<T, Chain: BootEnvironment> Cw20Send<Chain> for T
121where
122    T: BootExecute<Chain, ExecuteMsg = ExecuteMsg>,
123{
124    fn send(
125        &self,
126        msg: Binary,
127        amount: u128,
128        contract: String,
129    ) -> Result<TxResponse<Chain>, BootError> {
130        let msg = ExecuteMsg::Send {
131            contract,
132            amount: Uint128::new(amount),
133            msg,
134        };
135        self.execute(&msg, None)
136    }
137}