diff --git a/contracts/external/cw-abc/Cargo.toml b/contracts/external/cw-abc/Cargo.toml index bd2be85fd..9a8766113 100644 --- a/contracts/external/cw-abc/Cargo.toml +++ b/contracts/external/cw-abc/Cargo.toml @@ -46,6 +46,7 @@ cw-paginate-storage = { workspace = true } speculoos = "0.11.0" anyhow = { workspace = true } cw-multi-test = { workspace = true } +osmosis-test-tube = "16.0.0" [profile.release] rpath = false diff --git a/contracts/external/cw-abc/src/integration.rs b/contracts/external/cw-abc/src/integration.rs index b7de8d3b4..d9c72c985 100644 --- a/contracts/external/cw-abc/src/integration.rs +++ b/contracts/external/cw-abc/src/integration.rs @@ -1,16 +1,19 @@ +use anyhow::Result as AnyResult; +use cosmwasm_schema::{schemars::JsonSchema, serde::de::DeserializeOwned}; use cosmwasm_std::{ coin, coins, testing::{MockApi, MockStorage}, - Addr, Api, Coin, Decimal, Empty, GovMsg, IbcMsg, IbcQuery, StdResult, Storage, Uint128, + Addr, Api, Binary, BlockInfo, Coin, CustomQuery, Decimal, Empty, GovMsg, IbcMsg, IbcQuery, + Querier, StdResult, Storage, Uint128, }; use cw_multi_test::{ custom_app, custom_handler::{CachingCustomHandler, CachingCustomHandlerState}, - App, AppBuilder, AppResponse, BankKeeper, BankSudo, Contract, ContractWrapper, - DistributionKeeper, Executor, FailingModule, Router, StakeKeeper, WasmKeeper, + next_block, App, AppBuilder, AppResponse, BankKeeper, BankSudo, BasicAppBuilder, Contract, + ContractWrapper, CosmosRouter, DistributionKeeper, Executor, FailingModule, Module, + StakeKeeper, SudoMsg, WasmKeeper, }; -use cw_utils::PaymentError; -use token_bindings::{Metadata, TokenFactoryMsg, TokenFactoryQuery}; +use token_bindings::{Metadata, TokenFactoryMsg, TokenFactoryQuery, TokenMsg}; use crate::{ abc::{ @@ -18,15 +21,104 @@ use crate::{ SupplyToken, }, msg::{CurveInfoResponse, InstantiateMsg}, - ContractError, }; +pub struct CustomHandler {} + +impl Module for CustomHandler { + type ExecT = TokenFactoryMsg; + type QueryT = TokenFactoryQuery; + type SudoT = Empty; + + fn execute( + &self, + api: &dyn Api, + storage: &mut dyn Storage, + router: &dyn CosmosRouter, + block: &BlockInfo, + _sender: Addr, + msg: Self::ExecT, + ) -> AnyResult + where + ExecC: std::fmt::Debug + Clone + PartialEq + JsonSchema + DeserializeOwned + 'static, + QueryC: CustomQuery + DeserializeOwned + 'static, + { + println!("msg {:?}", msg); + match msg { + TokenFactoryMsg::Token(TokenMsg::MintTokens { + denom, + amount, + mint_to_address, + }) => { + println!("minting tokens"); + + // mint new tokens + let mint = SudoMsg::Bank(BankSudo::Mint { + to_address: mint_to_address, + amount: vec![Coin { + denom: denom.clone(), + amount: amount.clone(), + }], + }); + return Ok(router.sudo(api, storage, block, mint)?); + } + TokenFactoryMsg::Token(TokenMsg::CreateDenom { subdenom, metadata }) => { + println!("creating denom"); + return Ok(AppResponse::default()); + } + _ => unimplemented!(), + }; + } + + fn sudo( + &self, + _api: &dyn Api, + _storage: &mut dyn Storage, + _router: &dyn CosmosRouter, + _block: &BlockInfo, + _msg: Self::SudoT, + ) -> AnyResult + where + ExecC: std::fmt::Debug + Clone + PartialEq + JsonSchema + DeserializeOwned + 'static, + QueryC: CustomQuery + DeserializeOwned + 'static, + { + unimplemented!() + } + + fn query( + &self, + _api: &dyn Api, + _storage: &dyn Storage, + _querier: &dyn Querier, + _block: &BlockInfo, + _request: Self::QueryT, + ) -> AnyResult { + unimplemented!() + } +} + +// impl CustomHandler { +// // this is a custom initialization method +// pub fn set_payout( +// &self, +// storage: &mut dyn Storage, +// lottery: Coin, +// pity: Coin, +// ) -> AnyResult<()> { +// LOTTERY.save(storage, &lottery)?; +// PITY.save(storage, &pity)?; +// Ok(()) +// } +// } + pub struct Test { pub app: App< BankKeeper, MockApi, MockStorage, - CachingCustomHandler, + // CachingCustomHandler, + // FailingModule, + CustomHandler, WasmKeeper, StakeKeeper, DistributionKeeper, @@ -47,8 +139,19 @@ impl Test { let custom_handler = CachingCustomHandler::::new(); let custom_handler_state = custom_handler.state(); - let mut app = AppBuilder::new_custom() - .with_custom(custom_handler) + // let mut app = AppBuilder::new_custom() + // .with_custom(custom_handler) + // .build(|_, _, _| {}); + + // let mut app = custom_app::(|router, _, storage| { + // router + // .bank + // .init_balance(storage, &owner, coins(10000, "ujuno")) + // .unwrap(); + // }); + + let mut app = BasicAppBuilder::::new_custom() + .with_custom(CustomHandler {}) .build(|_, _, _| {}); app.sudo(cw_multi_test::SudoMsg::Bank(BankSudo::Mint { @@ -128,6 +231,14 @@ impl Test { Ok(res) } + pub fn burn(&mut self, amount: Vec) -> Result { + let msg = crate::msg::ExecuteMsg::Burn {}; + let res = + self.app + .execute_contract(self.owner.clone(), self.addr.clone(), &msg, &amount)?; + Ok(res) + } + pub fn query_curve_info(&self) -> StdResult { let msg = crate::msg::QueryMsg::CurveInfo {}; self.app.wrap().query_wasm_smart(&self.addr, &msg) @@ -169,6 +280,9 @@ pub fn test_happy_path() { // Buy some coins test.buy(coins(100, "ujuno")).unwrap(); + // // Update block + // test.app.update_block(next_block); + // Curve has been updated let curve_info = test.query_curve_info().unwrap(); assert_eq!( @@ -183,7 +297,7 @@ pub fn test_happy_path() { } ); - // assert balance + // Assert balance let balance_after = test .app .wrap() @@ -195,4 +309,19 @@ pub fn test_happy_path() { balance_before.amount.u128(), balance_after.amount.u128() ); + + // TODO get denom + let tf_balance = test + .app + .wrap() + .query_balance(test.addr.clone(), "factory/contract0/subdenom") + .unwrap(); + // TODO how to handle this? + println!("{:?}", tf_balance); + + // // Burn some coins + // test.burn(coins(100, "ujuno")).unwrap(); + + // let curve_info = test.query_curve_info().unwrap(); + // println!("{:?}", curve_info); } diff --git a/contracts/external/cw-abc/src/lib.rs b/contracts/external/cw-abc/src/lib.rs index 599b96043..3191289c5 100644 --- a/contracts/external/cw-abc/src/lib.rs +++ b/contracts/external/cw-abc/src/lib.rs @@ -8,6 +8,8 @@ mod integration; pub mod msg; mod queries; pub mod state; +#[cfg(test)] +mod testtube; pub use crate::error::ContractError; diff --git a/contracts/external/cw-abc/src/testtube.rs b/contracts/external/cw-abc/src/testtube.rs new file mode 100644 index 000000000..d4a32c5ac --- /dev/null +++ b/contracts/external/cw-abc/src/testtube.rs @@ -0,0 +1,122 @@ +use crate::{ + abc::{ + ClosedConfig, CommonsPhaseConfig, HatchConfig, MinMax, OpenConfig, ReserveToken, + SupplyToken, + }, + msg::{CurveInfoResponse, ExecuteMsg, InstantiateMsg, QueryMsg}, +}; +use cosmwasm_std::{Coin, Decimal, Uint128}; +use osmosis_test_tube::{Account, Module, OsmosisTestApp, Wasm}; +use token_bindings::Metadata; + +#[test] +fn test_tf() { + // Atempt to write tests with test-tube: https://github.com/osmosis-labs/test-tube + let app = OsmosisTestApp::new(); + let accs = app + .init_accounts( + &[ + Coin::new(1_000_000_000_000, "uatom"), + Coin::new(1_000_000_000_000, "uosmo"), + ], + 2, + ) + .unwrap(); + let admin = &accs[0]; + let new_admin = &accs[1]; + + let wasm = Wasm::new(&app); + + let wasm_byte_code = std::fs::read("../../../artifacts/cw_abc-aarch64.wasm").unwrap(); + let code_id = wasm + .store_code(&wasm_byte_code, None, admin) + .unwrap() + .data + .code_id; + + // instantiate contract + let contract_addr = wasm + .instantiate( + code_id, + &InstantiateMsg { + supply: SupplyToken { + subdenom: "subdenom".to_string(), + metadata: Metadata { + description: None, + denom_units: vec![], + base: None, + display: None, + name: None, + symbol: None, + }, + decimals: 6, + }, + reserve: ReserveToken { + denom: "ujuno".to_string(), + decimals: 6, + }, + curve_type: crate::abc::CurveType::Linear { + slope: Uint128::new(1), + scale: 2, + }, + phase_config: CommonsPhaseConfig { + hatch: HatchConfig { + initial_raise: MinMax { + min: Uint128::new(100), + max: Uint128::new(1000), + }, + initial_price: Uint128::new(1), + initial_allocation_ratio: Decimal::percent(10), + exit_tax: Decimal::percent(10), + }, + open: OpenConfig { + allocation_percentage: Decimal::percent(10), + exit_tax: Decimal::percent(10), + }, + closed: ClosedConfig {}, + }, + hatcher_allowlist: None, + }, + None, // contract admin used for migration, not the same as cw1_whitelist admin + Some("cw-bounties"), // contract label + &[], // funds + admin, // signer + ) + .unwrap() + .data + .address; + println!("{:?}", contract_addr); + + let curve_info = wasm + .query::(&contract_addr, &QueryMsg::CurveInfo {}) + .unwrap(); + println!("{:?}", curve_info); + + // let admin_list = wasm + // .query::(&contract_addr, &QueryMsg::AdminList {}) + // .unwrap(); + + // assert_eq!(admin_list.admins, init_admins); + // assert!(admin_list.mutable); + + // // ============= NEW CODE ================ + + // // update admin list and rechec the state + // let new_admins = vec![new_admin.address()]; + // wasm.execute::( + // &contract_addr, + // &ExecuteMsg::UpdateAdmins { + // admins: new_admins.clone(), + // }, + // &[], + // admin, + // ) + // .unwrap(); + + // let admin_list = wasm + // .query::(&contract_addr, &QueryMsg::AdminList {}) + // .unwrap(); + + // assert_eq!(admin_list.admins, new_admins); + // assert!(admin_list.mutable); +}