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
11impl<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 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}
110pub 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}