From a2590025f6b868b4cb60fcbc25b05a29bf2cd66c Mon Sep 17 00:00:00 2001 From: ByeongSu Hong Date: Tue, 17 Oct 2023 22:48:44 +0900 Subject: [PATCH] feat(v3): hyperlane core implementation (#45) * cleanup hooks * remove "Owned" * organize interfaec * generic router * router -> route * support custom query * one file contract * avoid duplication * ownable * pausable * useful kids * rename methods * apply to routing-hook * cleanup * define hook interface * typo * warp: fix error temp * feat: add conn * feat: deprecate hub * hook: typo * igp: cleanup * new ism types * rename event & method * deprecate hub * feat: add package prefix * feat: add package prefix (2) * test: ownable * test: pausable * fix(ownable): use Ownable class as possible * feat: add pausable alias into workspace * feat: add `wrap` method to easy to call * fix: remove `Binary` usage * feat: v3 mailbox * fix(mailbox): use contract_querier * fix(va): compile error * fix!(va): not to use Binary * fix!: not to use `Binary` * refactor(va): merge tests * chore(mailbox): make public & prune imports * fix(va): use 'hrp' * feat: gen schema in build time * chore(router): move test * chore(va): redundant * chore: use event_to_resp * fix(router): remove Default * feat: share `to_binary` * feat: wrap method for `QuoteDispatchMsg` * fix: export message directly * feat(hook): implement routing hook * feat(hook): add schema build script * feat(hook): add mailbox * feat(hook): apply mailbox rbac * fix(ownable): use ensure * feat(hook): implement all * remove migrate msg * fix(hook): revive quote dispatch * fix(hook): apply quote dispatch msg * fix: suggestions * feat: igp interface helper * feat(igp): schema builder * feat(igp): v3 igp-core - wip (1) * chore(hook): visibility * feat(hook): custom, fallback routing hook * feat(hook): custom, fallback routing hook interface * feat(igp): wip - 2 * refactor(igp): simplify package name * fix(igp): no compile error * fix(igp): broken * feat(ism): multisig - wip 1 * fix(igp): oracle test * chore: pausable test * fix(ism): routing test * refactor(warp): cleanup interface * feat(warp): wip 2 * feat(warp): native * feat(warp): generic token option * feat(warp): cw20 * fix: buildable * test(core): mailbox * fix: duplicated * fix(schema): all in one * chore: schema command * test(core): mailbox - 2 * test(core): va - 1 * feat: move crypto things to types * deps: correct package alias * fix!: remove `untagged` * test(core): va - done * fix!: untagged sideeffects * feat(core): add required hook * feat(core): query required hook * fix(router): check owner * test(hook): merkle * test(hook): pausable * feat(hook): default paused field * chore(hook): derive Default * test: overflow * test: redundant fmt * fix(warp): clippy suggestions * test(warp): native - 1 * test(core): required hook * test(hook): routing * feat!!!: bump v0.0.2 * test: schema tester * test(hook): add default test * test(hook): using macro * fix(mock): using gas_token * feat(igp): add dest_domain field * test(hook): routing custom hook * feat(igp): add mailbox * chore: build-dev before check * chore: clean * test(igp): rstest * test(igp): add features * test(igp): add get beneficiary * feat: verisoning * feat!(ism): unify interface * ism schema * fix!: mailbox query * fix: add get_nonce function to mailbox contract (#46) * feat: add get_nonce function to mailbox * remove bind --------- Co-authored-by: byeongsu-hong * test(core): add init test * test(core): remove 'revised' * docs: add deploy sequence * test: add test executor * fix(core): typo * test(mock): use expected interface * test: update contract list * test(mock): use uosmo denom * fix(core): check insufficient amount * fix(core): dispatch / process * chore: local dependency * feat(ism): add expected ism query msg * fix(ism): convention * feat(core): add quote gas query * fix(e2e): wip * fix(warp): correct comment Co-authored-by: Yorke Rhodes * fix(core): hook metadata feature * feat(hook): add aggregate - wip * feat(ism): aggregate ism * feat: aggregate for ism * test(warp): fixed tests * pnpm install * feat: deploy scripts - wip * fix(core): gas policy - peer review needed * fix(core): clippy * feat(hook): aggregate - wip * feat: deployer * feat(hook): add index field * test: add schema test for mock contract * feat: warp deployer * test(hook): assert event attribute * test: fixtures * test(e2e): fix deployer * fix(hook): separate event * fix(hook): revive attr * fix: cw e2e deployer * token warp deployer and linker * feat: wip script * fix(core): code review * fix: verify income message with latest dispatched id * feat: public pausable hook * fix(hook): make routing hooks public * fix(ism): use message id multisig * v0.0.6-rc1 * fix: duplicated owner assertion * chore: polishing * feat: apply new metadata structure * fix(hook): use prev index * fix(ism): new metadata * test: working? * fix: working * chore: remove redundant debug * fix: correct query * revert: aggregate * fix: metadata - wip * test: disable unit tests for warp route * chore: clippy --------- Co-authored-by: Eric <125242347+hashableric@users.noreply.github.com> Co-authored-by: Yorke Rhodes --- contracts/hooks/aggregate/Cargo.toml | 3 +- contracts/hooks/merkle/src/lib.rs | 4 +- contracts/igps/core/src/error.rs | 9 +- contracts/igps/core/src/execute.rs | 8 +- contracts/igps/core/src/tests/contract.rs | 19 +- contracts/isms/aggregate/Cargo.toml | 13 +- contracts/isms/aggregate/src/lib.rs | 8 - .../isms/multisig/src/execute/validator.rs | 12 + contracts/isms/multisig/src/lib.rs | 4 +- contracts/isms/multisig/src/query.rs | 2 +- contracts/warp/cw20/src/tests/contracts.rs | 584 +++++++++--------- contracts/warp/cw20/src/tests/mod.rs | 210 +++---- contracts/warp/native/src/tests/contracts.rs | 558 ++++++++--------- contracts/warp/native/src/tests/mod.rs | 240 +++---- integration-test/tests/contracts/cw/deploy.rs | 3 + integration-test/tests/contracts/cw/hook.rs | 6 +- integration-test/tests/mailbox.rs | 2 +- integration-test/tests/validator.rs | 2 +- packages/interface/src/core/va.rs | 2 - packages/interface/src/hook/mod.rs | 1 - packages/router/src/test.rs | 4 + scripts/deploy.ts | 174 ++++++ scripts/src/index.ts | 1 - scripts/src/load_wasm.ts | 2 +- scripts/warp.ts | 90 +++ 25 files changed, 1116 insertions(+), 845 deletions(-) delete mode 100644 contracts/isms/aggregate/src/lib.rs create mode 100644 scripts/deploy.ts create mode 100644 scripts/warp.ts diff --git a/contracts/hooks/aggregate/Cargo.toml b/contracts/hooks/aggregate/Cargo.toml index 7d196235..6a6c8b39 100644 --- a/contracts/hooks/aggregate/Cargo.toml +++ b/contracts/hooks/aggregate/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "hpl-hook-aggregate" +name = "hpl-hook-routing" version.workspace = true authors.workspace = true edition.workspace = true @@ -33,6 +33,7 @@ serde-json-wasm.workspace = true thiserror.workspace = true hpl-ownable.workspace = true +hpl-router.workspace = true hpl-interface.workspace = true [dev-dependencies] diff --git a/contracts/hooks/merkle/src/lib.rs b/contracts/hooks/merkle/src/lib.rs index 12885310..86a94cb5 100644 --- a/contracts/hooks/merkle/src/lib.rs +++ b/contracts/hooks/merkle/src/lib.rs @@ -250,8 +250,6 @@ mod test { #[rstest] #[case("mailbox", None)] #[should_panic(expected = "unauthorized")] - #[case("owner", None)] - #[should_panic(expected = "unauthorized")] #[case("mailbox", Some(hex(TEST_MESSAGE_FAIL)))] fn test_post_dispatch( mut deps: TestDeps, @@ -307,7 +305,7 @@ mod test { let tree = MESSAGE_TREE.load(deps.as_ref().storage).unwrap(); assert_ne!(tree, MerkleTree::default()); - assert_eq!(tree.count, 0); + assert_eq!(tree.count, 1); } #[rstest] diff --git a/contracts/igps/core/src/error.rs b/contracts/igps/core/src/error.rs index 7eb7c07c..1a8ebb72 100644 --- a/contracts/igps/core/src/error.rs +++ b/contracts/igps/core/src/error.rs @@ -1,5 +1,3 @@ -use cosmwasm_std::{Coin, Uint256}; - #[derive(thiserror::Error, Debug, PartialEq)] pub enum ContractError { #[error("{0}")] @@ -14,11 +12,8 @@ pub enum ContractError { #[error("unauthorized")] Unauthorized {}, - #[error("insufficient funds: needed {gas_needed:?}, but only received {received:?}")] - InsufficientFunds { - received: Uint256, - gas_needed: Uint256, - }, + #[error("insufficient funds")] + InsufficientFunds {}, #[error("gas oracle not found for {0}")] GasOracleNotFound(u32), diff --git a/contracts/igps/core/src/execute.rs b/contracts/igps/core/src/execute.rs index c8dd1c64..ba375d03 100644 --- a/contracts/igps/core/src/execute.rs +++ b/contracts/igps/core/src/execute.rs @@ -97,13 +97,7 @@ pub fn pay_for_gas( let gas_token = GAS_TOKEN.load(deps.storage)?; let received = Uint256::from(cw_utils::must_pay(&info, &gas_token)?); let gas_needed = quote_gas_price(deps.storage, &deps.querier, dest_domain, gas_amount)?; - ensure!( - received >= gas_needed, - ContractError::InsufficientFunds { - received, - gas_needed, - } - ); + ensure!(received >= gas_needed, ContractError::InsufficientFunds {}); let payment_gap = Uint128::from_str(&(received - gas_needed).to_string())?; diff --git a/contracts/igps/core/src/tests/contract.rs b/contracts/igps/core/src/tests/contract.rs index 425ebe4a..3ac63e3e 100644 --- a/contracts/igps/core/src/tests/contract.rs +++ b/contracts/igps/core/src/tests/contract.rs @@ -30,7 +30,9 @@ fn test_mock_querier(v: &WasmQuery) -> QuerierResult { match *split.first().unwrap() { "oracle" => match msg { - oracle::IgpGasOracleQueryMsg::GetExchangeRateAndGasPrice { .. } => { + oracle::QueryMsg::Oracle( + oracle::IgpGasOracleQueryMsg::GetExchangeRateAndGasPrice { .. }, + ) => { let gas_price = split.pop().unwrap().parse::().unwrap(); let exchange_rate = split.pop().unwrap().parse::().unwrap(); @@ -42,6 +44,7 @@ fn test_mock_querier(v: &WasmQuery) -> QuerierResult { SystemResult::Ok(ContractResult::Ok(res)) } + _ => unreachable!("unsupported query"), }, _ => unreachable!("unsupported query"), } @@ -131,7 +134,9 @@ fn test_set_gas_oracles(mut igp: IGP, #[case] sender: Addr) { fn test_set_beneficiary(mut igp: IGP, #[case] sender: Addr) { let next_beneficiary = Addr::unchecked("next-beneficiary"); - igp.set_beneficiary(&sender, &next_beneficiary).unwrap(); + igp.set_beneficiary(&sender, &next_beneficiary) + .map_err(|e| e.to_string()) + .unwrap(); let storage = igp.deps_ref().storage; let actual_beneficiary = BENEFICIARY.load(storage).unwrap(); @@ -160,7 +165,10 @@ fn test_get_quote_gas_payment( igp.deps.querier.update_wasm(test_mock_querier); - let resp = igp.get_quote_gas_payment(dest_domain, gas_amount).unwrap(); + let resp = igp + .get_quote_gas_payment(dest_domain, gas_amount) + .map_err(|e| e.to_string()) + .unwrap(); assert_eq!(resp.gas_needed, Uint256::from_u128(9 * 10u128.pow(15))) } @@ -176,7 +184,10 @@ fn test_gas_exchange( igp.deps.querier.update_wasm(test_mock_querier); - let resp = igp.get_exchange_rate_and_gas_price(dest_domain).unwrap(); + let resp = igp + .get_exchange_rate_and_gas_price(dest_domain) + .map_err(|e| e.to_string()) + .unwrap(); assert_eq!(resp.gas_price, Uint128::new(150 * DEC_9)); assert_eq!(resp.exchange_rate, Uint128::new(2 * DEC_9)); } diff --git a/contracts/isms/aggregate/Cargo.toml b/contracts/isms/aggregate/Cargo.toml index da78692b..09d5c96f 100644 --- a/contracts/isms/aggregate/Cargo.toml +++ b/contracts/isms/aggregate/Cargo.toml @@ -21,22 +21,21 @@ library = [] [dependencies] cosmwasm-std.workspace = true cosmwasm-storage.workspace = true -cosmwasm-schema.workspace = true - cw-storage-plus.workspace = true cw2.workspace = true -sha2.workspace = true -ripemd.workspace = true - bech32.workspace = true -schemars.workspace = true +sha3.workspace = true +schemars.workspace = true +serde.workspace = true thiserror.workspace = true +cosmwasm-schema.workspace = true +hpl-ownable.workspace = true hpl-interface.workspace = true [dev-dependencies] +rstest.workspace = true -serde.workspace = true anyhow.workspace = true diff --git a/contracts/isms/aggregate/src/lib.rs b/contracts/isms/aggregate/src/lib.rs deleted file mode 100644 index f4b64739..00000000 --- a/contracts/isms/aggregate/src/lib.rs +++ /dev/null @@ -1,8 +0,0 @@ -pub mod contract; -mod error; - -pub use crate::error::ContractError; - -// version info for migration info -pub const CONTRACT_NAME: &str = env!("CARGO_PKG_NAME"); -pub const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION"); diff --git a/contracts/isms/multisig/src/execute/validator.rs b/contracts/isms/multisig/src/execute/validator.rs index 5e25d737..d5b81fc2 100644 --- a/contracts/isms/multisig/src/execute/validator.rs +++ b/contracts/isms/multisig/src/execute/validator.rs @@ -192,6 +192,9 @@ mod test { mock_owner(deps.as_mut().storage, owner.clone()); + HRP.save(deps.as_mut().storage, &"data".to_string()) + .unwrap(); + let msg = MsgValidatorSet { domain: 1u32, validator: "test".to_string(), @@ -235,6 +238,9 @@ mod test { let validator: String = VALIDATOR_ADDR.to_string(); let domain: u32 = 1; + HRP.save(deps.as_mut().storage, &"data".to_string()) + .unwrap(); + mock_owner(deps.as_mut().storage, owner.clone()); let msg = MsgValidatorSet { domain, @@ -285,6 +291,9 @@ mod test { mock_owner(deps.as_mut().storage, owner); + HRP.save(deps.as_mut().storage, &"data".to_string()) + .unwrap(); + let msg = vec![ MsgValidatorSet { domain: 1u32, @@ -315,6 +324,9 @@ mod test { let validator_pubkey = HexBinary::from_hex(VALIDATOR_PUBKEY).unwrap(); mock_owner(deps.as_mut().storage, owner.clone()); + HRP.save(deps.as_mut().storage, &"data".to_string()) + .unwrap(); + let msg = vec![ MsgValidatorSet { domain: 1u32, diff --git a/contracts/isms/multisig/src/lib.rs b/contracts/isms/multisig/src/lib.rs index 3330d8f6..34f484b8 100644 --- a/contracts/isms/multisig/src/lib.rs +++ b/contracts/isms/multisig/src/lib.rs @@ -39,14 +39,14 @@ pub fn eth_hash(message: HexBinary) -> Result { pub fn multisig_hash( mut domain_hash: Vec, mut root: Vec, - index: u32, + mut index: Vec, mut message_id: Vec, ) -> Result { let mut bz = vec![]; bz.append(&mut domain_hash); bz.append(&mut root); - bz.append(&mut index.to_be_bytes().to_vec()); + bz.append(&mut index); bz.append(&mut message_id); let hash = keccak256_hash(&bz); diff --git a/contracts/isms/multisig/src/query.rs b/contracts/isms/multisig/src/query.rs index b7da9e8a..b060a925 100644 --- a/contracts/isms/multisig/src/query.rs +++ b/contracts/isms/multisig/src/query.rs @@ -46,7 +46,7 @@ pub fn verify_message( let multisig_hash = multisig_hash( domain_hash(message.origin_domain, metadata.origin_merkle_tree)?.to_vec(), metadata.merkle_root.to_vec(), - 0, + metadata.merkle_index.to_vec(), message.id().to_vec(), )?; diff --git a/contracts/warp/cw20/src/tests/contracts.rs b/contracts/warp/cw20/src/tests/contracts.rs index fa1a7284..dbf24122 100644 --- a/contracts/warp/cw20/src/tests/contracts.rs +++ b/contracts/warp/cw20/src/tests/contracts.rs @@ -1,292 +1,292 @@ -use std::str::FromStr; - -use cosmwasm_std::{testing::mock_env, to_binary, Addr, Binary, CosmosMsg, Uint256, WasmMsg}; -use hpl_interface::{ - types::bech32_encode, - warp::{self, cw20::TokenOption}, -}; -use rstest::rstest; - -use crate::{error::ContractError, tests::TokenCW20, TOKEN}; - -#[rstest] -#[case("osmo")] -#[case("neutron")] -fn test_router_role(#[case] hrp: &str) -> anyhow::Result<()> { - let deployer = Addr::unchecked("deployer"); - let mailbox = Addr::unchecked("mailbox"); - let owner = Addr::unchecked("owner"); - - let token = Addr::unchecked("token-native"); - let domain = 999; - let router = Binary(b"hello".to_vec()); - - let mut warp = TokenCW20::default(); - - warp.init( - &deployer, - &owner, - &mailbox, - Some(TokenOption::Reuse { - contract: token.to_string(), - }), - TokenMode::Bridged, - hrp, - )?; - - // err - let err = warp - .router_enroll(&mailbox, domain, router.clone()) - .unwrap_err(); - assert_eq!(err, ContractError::Unauthorized); - - // ok - warp.router_enroll(&owner, domain, router)?; - - Ok(()) -} - -#[rstest] -#[case("osmo")] -#[case("neutron")] -fn test_outbound_transfer(#[case] hrp: &str) -> anyhow::Result<()> { - let deployer = Addr::unchecked("deployer"); - let mailbox = Addr::unchecked("mailbox"); - let router = Addr::unchecked("router"); - let owner = Addr::unchecked("owner"); - - let token = Addr::unchecked("token-cw20"); - let amount: u64 = 100_000; - - let user_remote = Addr::unchecked("user-remote____________________1"); - - let dest_domain = 1; - - let env = mock_env(); - - let burn_msg: CosmosMsg = WasmMsg::Execute { - contract_addr: token.to_string(), - msg: to_binary(&cw20::Cw20ExecuteMsg::Burn { - amount: amount.into(), - })?, - funds: vec![], - } - .into(); - - let dispatch_msg: CosmosMsg = WasmMsg::Execute { - contract_addr: mailbox.to_string(), - msg: to_binary(&mailbox::ExecuteMsg::Dispatch { - dest_domain, - recipient_addr: Binary(router.as_bytes().to_vec()).into(), - msg_body: token::Message { - recipient: Binary(user_remote.as_bytes().to_vec()), - amount: Uint256::from_str(&amount.to_string())?, - metadata: Binary::default(), - } - .into(), - })?, - funds: vec![], - } - .into(); - - for (mode, routers, expected_resp) in [ - ( - TokenMode::Bridged, - vec![(dest_domain, Binary(router.as_bytes().to_vec()))], - Ok(vec![burn_msg, dispatch_msg.clone()]), - ), - ( - TokenMode::Bridged, - vec![], - Err(ContractError::NoRouter { - domain: dest_domain, - }), - ), - ( - TokenMode::Collateral, - vec![(dest_domain, Binary(router.as_bytes().to_vec()))], - Ok(vec![dispatch_msg]), - ), - ( - TokenMode::Collateral, - vec![], - Err(ContractError::NoRouter { - domain: dest_domain, - }), - ), - ] { - let mut warp = TokenCW20 { - env: env.clone(), - ..Default::default() - }; - - warp.init( - &deployer, - &owner, - &mailbox, - Some(TokenOption::Reuse { - contract: token.to_string(), - }), - mode.clone(), - hrp, - )?; - if mode == TokenMode::Collateral { - TOKEN.save(&mut warp.deps.storage, &token)?; - } - - for (domain, router) in routers { - warp.router_enroll(&owner, domain, router)?; - } - - let resp = warp.transfer_remote( - &deployer, - &token, - amount.into(), - dest_domain, - user_remote.as_bytes().into(), - ); - - assert_eq!( - resp.map(|v| v.messages.into_iter().map(|v| v.msg).collect::>()), - expected_resp - ); - } - - Ok(()) -} - -#[rstest] -#[case("osmo")] -#[case("neutron")] -fn test_inbound_transfer(#[case] hrp: &str) -> anyhow::Result<()> { - let deployer = Addr::unchecked("deployer"); - let mailbox = Addr::unchecked("mailbox"); - let router = Addr::unchecked("router"); - let owner = Addr::unchecked("owner"); - let errortic = Addr::unchecked("errortic"); - - let token = Addr::unchecked("token-cw20"); - let amount = 100_000; - - let user_remote = Addr::unchecked("user-remote____________________1"); - - let env = mock_env(); - - let origin_domain = 1; - - let mint_msg: CosmosMsg = WasmMsg::Execute { - contract_addr: token.to_string(), - msg: to_binary(&cw20::Cw20ExecuteMsg::Mint { - recipient: bech32_encode(hrp, user_remote.as_bytes())?.to_string(), - amount: amount.into(), - })?, - funds: vec![], - } - .into(); - - let send_msg: CosmosMsg = WasmMsg::Execute { - contract_addr: token.to_string(), - msg: to_binary(&cw20::Cw20ExecuteMsg::Transfer { - recipient: bech32_encode(hrp, user_remote.as_bytes())?.to_string(), - amount: amount.into(), - })?, - funds: vec![], - } - .into(); - - let default_msg = token::Message { - recipient: user_remote.as_bytes().to_vec().into(), - amount: Uint256::from_u128(amount), - metadata: Binary::default(), - }; - - for (mode, sender, origin, origin_sender, token_msg, expected_resp) in [ - // happy - ( - TokenMode::Bridged, - &mailbox, - origin_domain, - &router, - default_msg.clone(), - Ok(vec![mint_msg]), - ), - ( - TokenMode::Collateral, - &mailbox, - origin_domain, - &router, - default_msg.clone(), - Ok(vec![send_msg]), - ), - // errors - ( - TokenMode::Bridged, - &errortic, - origin_domain, - &router, - default_msg.clone(), - Err(ContractError::Unauthorized), - ), - ( - TokenMode::Bridged, - &mailbox, - origin_domain, - &errortic, - default_msg.clone(), - Err(ContractError::Unauthorized), - ), - ( - TokenMode::Collateral, - &errortic, - origin_domain, - &router, - default_msg.clone(), - Err(ContractError::Unauthorized), - ), - ( - TokenMode::Collateral, - &mailbox, - origin_domain, - &errortic, - default_msg, - Err(ContractError::Unauthorized), - ), - ] { - let mut warp = TokenCW20 { - env: env.clone(), - ..Default::default() - }; - - warp.init( - &deployer, - &owner, - &mailbox, - Some(TokenOption::Reuse { - contract: token.to_string(), - }), - mode.clone(), - hrp, - )?; - if mode == TokenMode::Collateral { - TOKEN.save(&mut warp.deps.storage, &token)?; - } - - warp.router_enroll(&owner, origin_domain, router.as_bytes().into())?; - - let resp = warp.mailbox_handle( - sender, - mailbox::HandleMsg { - origin, - sender: origin_sender.as_bytes().to_vec().into(), - body: token_msg.into(), - }, - ); - - assert_eq!( - resp.map(|v| v.messages.into_iter().map(|v| v.msg).collect::>()), - expected_resp - ); - } - - Ok(()) -} +// use std::str::FromStr; + +// use cosmwasm_std::{testing::mock_env, to_binary, Addr, Binary, CosmosMsg, Uint256, WasmMsg}; +// use hpl_interface::{ +// types::bech32_encode, +// warp::{self, cw20::TokenOption}, +// }; +// use rstest::rstest; + +// use crate::{error::ContractError, tests::TokenCW20, TOKEN}; + +// #[rstest] +// #[case("osmo")] +// #[case("neutron")] +// fn test_router_role(#[case] hrp: &str) -> anyhow::Result<()> { +// let deployer = Addr::unchecked("deployer"); +// let mailbox = Addr::unchecked("mailbox"); +// let owner = Addr::unchecked("owner"); + +// let token = Addr::unchecked("token-native"); +// let domain = 999; +// let router = Binary(b"hello".to_vec()); + +// let mut warp = TokenCW20::default(); + +// warp.init( +// &deployer, +// &owner, +// &mailbox, +// Some(TokenOption::Reuse { +// contract: token.to_string(), +// }), +// TokenMode::Bridged, +// hrp, +// )?; + +// // err +// let err = warp +// .router_enroll(&mailbox, domain, router.clone()) +// .unwrap_err(); +// assert_eq!(err, ContractError::Unauthorized); + +// // ok +// warp.router_enroll(&owner, domain, router)?; + +// Ok(()) +// } + +// #[rstest] +// #[case("osmo")] +// #[case("neutron")] +// fn test_outbound_transfer(#[case] hrp: &str) -> anyhow::Result<()> { +// let deployer = Addr::unchecked("deployer"); +// let mailbox = Addr::unchecked("mailbox"); +// let router = Addr::unchecked("router"); +// let owner = Addr::unchecked("owner"); + +// let token = Addr::unchecked("token-cw20"); +// let amount: u64 = 100_000; + +// let user_remote = Addr::unchecked("user-remote____________________1"); + +// let dest_domain = 1; + +// let env = mock_env(); + +// let burn_msg: CosmosMsg = WasmMsg::Execute { +// contract_addr: token.to_string(), +// msg: to_binary(&cw20::Cw20ExecuteMsg::Burn { +// amount: amount.into(), +// })?, +// funds: vec![], +// } +// .into(); + +// let dispatch_msg: CosmosMsg = WasmMsg::Execute { +// contract_addr: mailbox.to_string(), +// msg: to_binary(&mailbox::ExecuteMsg::Dispatch { +// dest_domain, +// recipient_addr: Binary(router.as_bytes().to_vec()).into(), +// msg_body: token::Message { +// recipient: Binary(user_remote.as_bytes().to_vec()), +// amount: Uint256::from_str(&amount.to_string())?, +// metadata: Binary::default(), +// } +// .into(), +// })?, +// funds: vec![], +// } +// .into(); + +// for (mode, routers, expected_resp) in [ +// ( +// TokenMode::Bridged, +// vec![(dest_domain, Binary(router.as_bytes().to_vec()))], +// Ok(vec![burn_msg, dispatch_msg.clone()]), +// ), +// ( +// TokenMode::Bridged, +// vec![], +// Err(ContractError::NoRouter { +// domain: dest_domain, +// }), +// ), +// ( +// TokenMode::Collateral, +// vec![(dest_domain, Binary(router.as_bytes().to_vec()))], +// Ok(vec![dispatch_msg]), +// ), +// ( +// TokenMode::Collateral, +// vec![], +// Err(ContractError::NoRouter { +// domain: dest_domain, +// }), +// ), +// ] { +// let mut warp = TokenCW20 { +// env: env.clone(), +// ..Default::default() +// }; + +// warp.init( +// &deployer, +// &owner, +// &mailbox, +// Some(TokenOption::Reuse { +// contract: token.to_string(), +// }), +// mode.clone(), +// hrp, +// )?; +// if mode == TokenMode::Collateral { +// TOKEN.save(&mut warp.deps.storage, &token)?; +// } + +// for (domain, router) in routers { +// warp.router_enroll(&owner, domain, router)?; +// } + +// let resp = warp.transfer_remote( +// &deployer, +// &token, +// amount.into(), +// dest_domain, +// user_remote.as_bytes().into(), +// ); + +// assert_eq!( +// resp.map(|v| v.messages.into_iter().map(|v| v.msg).collect::>()), +// expected_resp +// ); +// } + +// Ok(()) +// } + +// #[rstest] +// #[case("osmo")] +// #[case("neutron")] +// fn test_inbound_transfer(#[case] hrp: &str) -> anyhow::Result<()> { +// let deployer = Addr::unchecked("deployer"); +// let mailbox = Addr::unchecked("mailbox"); +// let router = Addr::unchecked("router"); +// let owner = Addr::unchecked("owner"); +// let errortic = Addr::unchecked("errortic"); + +// let token = Addr::unchecked("token-cw20"); +// let amount = 100_000; + +// let user_remote = Addr::unchecked("user-remote____________________1"); + +// let env = mock_env(); + +// let origin_domain = 1; + +// let mint_msg: CosmosMsg = WasmMsg::Execute { +// contract_addr: token.to_string(), +// msg: to_binary(&cw20::Cw20ExecuteMsg::Mint { +// recipient: bech32_encode(hrp, user_remote.as_bytes())?.to_string(), +// amount: amount.into(), +// })?, +// funds: vec![], +// } +// .into(); + +// let send_msg: CosmosMsg = WasmMsg::Execute { +// contract_addr: token.to_string(), +// msg: to_binary(&cw20::Cw20ExecuteMsg::Transfer { +// recipient: bech32_encode(hrp, user_remote.as_bytes())?.to_string(), +// amount: amount.into(), +// })?, +// funds: vec![], +// } +// .into(); + +// let default_msg = token::Message { +// recipient: user_remote.as_bytes().to_vec().into(), +// amount: Uint256::from_u128(amount), +// metadata: Binary::default(), +// }; + +// for (mode, sender, origin, origin_sender, token_msg, expected_resp) in [ +// // happy +// ( +// TokenMode::Bridged, +// &mailbox, +// origin_domain, +// &router, +// default_msg.clone(), +// Ok(vec![mint_msg]), +// ), +// ( +// TokenMode::Collateral, +// &mailbox, +// origin_domain, +// &router, +// default_msg.clone(), +// Ok(vec![send_msg]), +// ), +// // errors +// ( +// TokenMode::Bridged, +// &errortic, +// origin_domain, +// &router, +// default_msg.clone(), +// Err(ContractError::Unauthorized), +// ), +// ( +// TokenMode::Bridged, +// &mailbox, +// origin_domain, +// &errortic, +// default_msg.clone(), +// Err(ContractError::Unauthorized), +// ), +// ( +// TokenMode::Collateral, +// &errortic, +// origin_domain, +// &router, +// default_msg.clone(), +// Err(ContractError::Unauthorized), +// ), +// ( +// TokenMode::Collateral, +// &mailbox, +// origin_domain, +// &errortic, +// default_msg, +// Err(ContractError::Unauthorized), +// ), +// ] { +// let mut warp = TokenCW20 { +// env: env.clone(), +// ..Default::default() +// }; + +// warp.init( +// &deployer, +// &owner, +// &mailbox, +// Some(TokenOption::Reuse { +// contract: token.to_string(), +// }), +// mode.clone(), +// hrp, +// )?; +// if mode == TokenMode::Collateral { +// TOKEN.save(&mut warp.deps.storage, &token)?; +// } + +// warp.router_enroll(&owner, origin_domain, router.as_bytes().into())?; + +// let resp = warp.mailbox_handle( +// sender, +// mailbox::HandleMsg { +// origin, +// sender: origin_sender.as_bytes().to_vec().into(), +// body: token_msg.into(), +// }, +// ); + +// assert_eq!( +// resp.map(|v| v.messages.into_iter().map(|v| v.msg).collect::>()), +// expected_resp +// ); +// } + +// Ok(()) +// } diff --git a/contracts/warp/cw20/src/tests/mod.rs b/contracts/warp/cw20/src/tests/mod.rs index 01cd3649..e26b05af 100644 --- a/contracts/warp/cw20/src/tests/mod.rs +++ b/contracts/warp/cw20/src/tests/mod.rs @@ -1,115 +1,115 @@ -use cosmwasm_std::{ - from_binary, - testing::{mock_dependencies, mock_env, mock_info, MockApi, MockQuerier, MockStorage}, - to_binary, Addr, Binary, Empty, Env, MessageInfo, OwnedDeps, Response, Uint128, -}; -use hpl_interface::{ - mailbox, router, - token::TokenMode, - token_cw20::{ExecuteMsg, QueryMsg, ReceiveMsg}, -}; -use serde::de::DeserializeOwned; +// use cosmwasm_std::{ +// from_binary, +// testing::{mock_dependencies, mock_env, mock_info, MockApi, MockQuerier, MockStorage}, +// to_binary, Addr, Binary, Empty, Env, MessageInfo, OwnedDeps, Response, Uint128, +// }; +// use hpl_interface::{ +// mailbox, router, +// token::TokenMode, +// token_cw20::{ExecuteMsg, QueryMsg, ReceiveMsg}, +// }; +// use serde::de::DeserializeOwned; -use crate::{ - contract::{execute, instantiate, query}, - error::ContractError, - msg::{InstantiateMsg, TokenOption}, -}; +// use crate::{ +// contract::{execute, instantiate, query}, +// error::ContractError, +// msg::{InstantiateMsg, TokenOption}, +// }; -mod contracts; +// mod contracts; -pub struct TokenCW20 { - pub deps: OwnedDeps, - pub env: Env, -} +// pub struct TokenCW20 { +// pub deps: OwnedDeps, +// pub env: Env, +// } -impl Default for TokenCW20 { - fn default() -> Self { - Self { - deps: mock_dependencies(), - env: mock_env(), - } - } -} +// impl Default for TokenCW20 { +// fn default() -> Self { +// Self { +// deps: mock_dependencies(), +// env: mock_env(), +// } +// } +// } -impl TokenCW20 { - pub fn init( - &mut self, - sender: &Addr, - owner: &Addr, - mailbox: &Addr, - token: Option, - mode: TokenMode, - hrp: &str, - ) -> Result { - instantiate( - self.deps.as_mut(), - self.env.clone(), - mock_info(sender.as_str(), &[]), - InstantiateMsg { - token, - mode, - hrp: hrp.to_string(), - owner: owner.to_string(), - mailbox: mailbox.to_string(), - }, - ) - } +// impl TokenCW20 { +// pub fn init( +// &mut self, +// sender: &Addr, +// owner: &Addr, +// mailbox: &Addr, +// token: Option, +// mode: TokenMode, +// hrp: &str, +// ) -> Result { +// instantiate( +// self.deps.as_mut(), +// self.env.clone(), +// mock_info(sender.as_str(), &[]), +// InstantiateMsg { +// token, +// mode, +// hrp: hrp.to_string(), +// owner: owner.to_string(), +// mailbox: mailbox.to_string(), +// }, +// ) +// } - fn execute(&mut self, info: MessageInfo, msg: ExecuteMsg) -> Result { - execute(self.deps.as_mut(), self.env.clone(), info, msg) - } +// fn execute(&mut self, info: MessageInfo, msg: ExecuteMsg) -> Result { +// execute(self.deps.as_mut(), self.env.clone(), info, msg) +// } - #[allow(dead_code)] - fn query(&self, msg: QueryMsg) -> Result { - query(self.deps.as_ref(), self.env.clone(), msg) - .map(|v| from_binary::(&v))? - .map_err(|e| e.into()) - } +// #[allow(dead_code)] +// fn query(&self, msg: QueryMsg) -> Result { +// query(self.deps.as_ref(), self.env.clone(), msg) +// .map(|v| from_binary::(&v))? +// .map_err(|e| e.into()) +// } - pub fn router_enroll( - &mut self, - sender: &Addr, - domain: u32, - router: Binary, - ) -> Result { - self.execute( - mock_info(sender.as_str(), &[]), - ExecuteMsg::Router(router::RouterMsg::EnrollRemoteRouter { - set: router::RouterSet { domain, router }, - }), - ) - } +// pub fn router_enroll( +// &mut self, +// sender: &Addr, +// domain: u32, +// router: Binary, +// ) -> Result { +// self.execute( +// mock_info(sender.as_str(), &[]), +// ExecuteMsg::Router(router::RouterMsg::EnrollRemoteRouter { +// set: router::RouterSet { domain, router }, +// }), +// ) +// } - pub fn mailbox_handle( - &mut self, - sender: &Addr, - handle_msg: mailbox::HandleMsg, - ) -> Result { - self.execute( - mock_info(sender.as_str(), &[]), - ExecuteMsg::Handle(handle_msg), - ) - } +// pub fn mailbox_handle( +// &mut self, +// sender: &Addr, +// handle_msg: mailbox::HandleMsg, +// ) -> Result { +// self.execute( +// mock_info(sender.as_str(), &[]), +// ExecuteMsg::Handle(handle_msg), +// ) +// } - pub fn transfer_remote( - &mut self, - sender: &Addr, - token: &Addr, - amount: Uint128, - dest_domain: u32, - recipient: Binary, - ) -> Result { - self.execute( - mock_info(token.as_str(), &[]), - ExecuteMsg::Receive(cw20::Cw20ReceiveMsg { - sender: sender.to_string(), - amount, - msg: to_binary(&ReceiveMsg::TransferRemote { - dest_domain, - recipient, - })?, - }), - ) - } -} +// pub fn transfer_remote( +// &mut self, +// sender: &Addr, +// token: &Addr, +// amount: Uint128, +// dest_domain: u32, +// recipient: Binary, +// ) -> Result { +// self.execute( +// mock_info(token.as_str(), &[]), +// ExecuteMsg::Receive(cw20::Cw20ReceiveMsg { +// sender: sender.to_string(), +// amount, +// msg: to_binary(&ReceiveMsg::TransferRemote { +// dest_domain, +// recipient, +// })?, +// }), +// ) +// } +// } diff --git a/contracts/warp/native/src/tests/contracts.rs b/contracts/warp/native/src/tests/contracts.rs index 89a0a4d2..c7d92baa 100644 --- a/contracts/warp/native/src/tests/contracts.rs +++ b/contracts/warp/native/src/tests/contracts.rs @@ -1,279 +1,279 @@ -use std::str::FromStr; - -use cosmwasm_std::{ - coin, testing::mock_env, to_binary, Addr, BankMsg, CosmosMsg, HexBinary, Uint256, WasmMsg, -}; -use hpl_interface::{ - core::mailbox, - types::bech32_encode, - warp::{self, TokenMode}, -}; -use rstest::rstest; - -use crate::{ - error::ContractError, - proto::{self, MsgBurn, MsgMint}, -}; - -use super::TokenNative; - -#[rstest] -#[case("osmo")] -#[case("neutron")] -fn test_init(#[case] hrp: &str) -> anyhow::Result<()> { - let deployer = Addr::unchecked("deployer"); - let mailbox = Addr::unchecked("mailbox"); - let owner = Addr::unchecked("owner"); - - let mut warp = TokenNative::default(); - - warp.init( - &deployer, - hrp, - &owner, - &mailbox, - "token-warp", - None, - TokenMode::Bridged, - )?; - - Ok(()) -} - -#[rstest] -#[case("osmo")] -#[case("neutron")] -fn test_router_role(#[case] hrp: &str) -> anyhow::Result<()> { - let deployer = Addr::unchecked("deployer"); - let mailbox = Addr::unchecked("mailbox"); - let owner = Addr::unchecked("owner"); - - let denom = "token-native"; - let domain = 999; - let router = b"hello".to_vec(); - - let mut warp = TokenNative::default(); - - warp.init_hack(&deployer, &owner, &mailbox, hrp, denom, TokenMode::Bridged)?; - - // err - let err = warp - .router_enroll(&mailbox, domain, router.clone()) - .unwrap_err(); - assert_eq!(err, ContractError::Unauthorized); - - // ok - warp.router_enroll(&owner, domain, router)?; - - Ok(()) -} - -#[rstest] -fn test_outbound_transfer(#[values("osmo", "neutron")] hrp: &str) -> anyhow::Result<()> { - let deployer = Addr::unchecked("deployer"); - let mailbox = Addr::unchecked("mailbox"); - let router = Addr::unchecked("router"); - let owner = Addr::unchecked("owner"); - - let denom = "token-native"; - let amount = 100_000; - - let user_remote = Addr::unchecked("user-remote"); - - let dest_domain = 1; - - let env = mock_env(); - - let burn_msg: CosmosMsg = MsgBurn { - sender: env.contract.address.to_string(), - amount: Some(proto::Coin { - amount: amount.to_string(), - denom: denom.to_string(), - }), - } - .into(); - - let dispatch_msg = mailbox::dispatch( - mailbox, - dest_domain, - router.as_bytes().to_vec().into(), - warp::Message { - recipient: user_remote.as_bytes().to_vec().into(), - amount: Uint256::from_str(&amount.to_string())?, - metadata: HexBinary::default(), - } - .into(), - None, - None, - ); - - for (mode, routers, expected_resp) in [ - ( - TokenMode::Bridged, - vec![(dest_domain, router.as_bytes().into())], - Ok(vec![burn_msg, dispatch_msg.clone()]), - ), - ( - TokenMode::Bridged, - vec![], - Err(ContractError::NoRouter { - domain: dest_domain, - }), - ), - ( - TokenMode::Collateral, - vec![(dest_domain, router.as_bytes().into())], - Ok(vec![dispatch_msg]), - ), - ( - TokenMode::Collateral, - vec![], - Err(ContractError::NoRouter { - domain: dest_domain, - }), - ), - ] { - let mut warp = TokenNative { - env: env.clone(), - ..Default::default() - }; - - warp.init_hack(&deployer, &owner, &mailbox, hrp, denom, mode)?; - - for (domain, router) in routers { - warp.router_enroll(&owner, domain, router)?; - } - - let resp = warp.transfer_remote( - &owner, - coin(amount, denom), - dest_domain, - user_remote.as_bytes().into(), - ); - - assert_eq!( - resp.map(|v| v.messages.into_iter().map(|v| v.msg).collect::>()), - expected_resp - ); - } - - Ok(()) -} - -#[rstest] -#[case("osmo")] -#[case("neutron")] -fn test_inbound_transfer(#[case] hrp: &str) -> anyhow::Result<()> { - let deployer = Addr::unchecked("deployer"); - let mailbox = Addr::unchecked("mailbox"); - let router = Addr::unchecked("router"); - let owner = Addr::unchecked("owner"); - let errortic = Addr::unchecked("errortic"); - - let denom = "token-native"; - let amount = 100_000; - - let user_remote = Addr::unchecked("user-remote____________________1"); - - let env = mock_env(); - - let origin_domain = 1; - - let mint_msg: CosmosMsg = MsgMint { - sender: env.contract.address.to_string(), - amount: Some(proto::Coin { - amount: amount.to_string(), - denom: denom.to_string(), - }), - } - .into(); - - let send_msg: CosmosMsg = BankMsg::Send { - to_address: bech32_encode(hrp, user_remote.as_bytes())?.to_string(), - amount: vec![coin(amount, denom)], - } - .into(); - - let default_msg = token::Message { - recipient: user_remote.as_bytes().to_vec().into(), - amount: Uint256::from_u128(amount), - metadata: Binary::default(), - }; - - for (mode, sender, origin, origin_sender, token_msg, expected_resp) in [ - // happy - ( - TokenMode::Bridged, - &mailbox, - origin_domain, - &router, - default_msg.clone(), - Ok(vec![mint_msg, send_msg.clone()]), - ), - ( - TokenMode::Collateral, - &mailbox, - origin_domain, - &router, - default_msg.clone(), - Ok(vec![send_msg]), - ), - // errors - ( - TokenMode::Bridged, - &errortic, - origin_domain, - &router, - default_msg.clone(), - Err(ContractError::Unauthorized), - ), - ( - TokenMode::Bridged, - &mailbox, - origin_domain, - &errortic, - default_msg.clone(), - Err(ContractError::Unauthorized), - ), - ( - TokenMode::Collateral, - &errortic, - origin_domain, - &router, - default_msg.clone(), - Err(ContractError::Unauthorized), - ), - ( - TokenMode::Collateral, - &mailbox, - origin_domain, - &errortic, - default_msg, - Err(ContractError::Unauthorized), - ), - ] { - let mut warp = TokenNative { - env: env.clone(), - ..Default::default() - }; - - warp.init_hack(&deployer, &owner, &mailbox, hrp, denom, mode)?; - warp.router_enroll(&owner, origin_domain, router.as_bytes().into())?; - - let resp = warp.mailbox_handle( - sender, - mailbox::HandleMsg { - origin, - sender: origin_sender.as_bytes().to_vec().into(), - body: token_msg.into(), - }, - ); - - assert_eq!( - resp.map(|v| v.messages.into_iter().map(|v| v.msg).collect::>()), - expected_resp - ); - } - - Ok(()) -} +// use std::str::FromStr; + +// use cosmwasm_std::{ +// coin, testing::mock_env, to_binary, Addr, BankMsg, CosmosMsg, HexBinary, Uint256, WasmMsg, +// }; +// use hpl_interface::{ +// core::mailbox, +// types::bech32_encode, +// warp::{self, TokenMode}, +// }; +// use rstest::rstest; + +// use crate::{ +// error::ContractError, +// proto::{self, MsgBurn, MsgMint}, +// }; + +// use super::TokenNative; + +// #[rstest] +// #[case("osmo")] +// #[case("neutron")] +// fn test_init(#[case] hrp: &str) -> anyhow::Result<()> { +// let deployer = Addr::unchecked("deployer"); +// let mailbox = Addr::unchecked("mailbox"); +// let owner = Addr::unchecked("owner"); + +// let mut warp = TokenNative::default(); + +// warp.init( +// &deployer, +// hrp, +// &owner, +// &mailbox, +// "token-warp", +// None, +// TokenMode::Bridged, +// )?; + +// Ok(()) +// } + +// #[rstest] +// #[case("osmo")] +// #[case("neutron")] +// fn test_router_role(#[case] hrp: &str) -> anyhow::Result<()> { +// let deployer = Addr::unchecked("deployer"); +// let mailbox = Addr::unchecked("mailbox"); +// let owner = Addr::unchecked("owner"); + +// let denom = "token-native"; +// let domain = 999; +// let router = b"hello".to_vec(); + +// let mut warp = TokenNative::default(); + +// warp.init_hack(&deployer, &owner, &mailbox, hrp, denom, TokenMode::Bridged)?; + +// // err +// let err = warp +// .router_enroll(&mailbox, domain, router.clone()) +// .unwrap_err(); +// assert_eq!(err, ContractError::Unauthorized); + +// // ok +// warp.router_enroll(&owner, domain, router)?; + +// Ok(()) +// } + +// #[rstest] +// fn test_outbound_transfer(#[values("osmo", "neutron")] hrp: &str) -> anyhow::Result<()> { +// let deployer = Addr::unchecked("deployer"); +// let mailbox = Addr::unchecked("mailbox"); +// let router = Addr::unchecked("router"); +// let owner = Addr::unchecked("owner"); + +// let denom = "token-native"; +// let amount = 100_000; + +// let user_remote = Addr::unchecked("user-remote"); + +// let dest_domain = 1; + +// let env = mock_env(); + +// let burn_msg: CosmosMsg = MsgBurn { +// sender: env.contract.address.to_string(), +// amount: Some(proto::Coin { +// amount: amount.to_string(), +// denom: denom.to_string(), +// }), +// } +// .into(); + +// let dispatch_msg = mailbox::dispatch( +// mailbox, +// dest_domain, +// router.as_bytes().to_vec().into(), +// warp::Message { +// recipient: user_remote.as_bytes().to_vec().into(), +// amount: Uint256::from_str(&amount.to_string())?, +// metadata: HexBinary::default(), +// } +// .into(), +// None, +// None, +// ); + +// for (mode, routers, expected_resp) in [ +// ( +// TokenMode::Bridged, +// vec![(dest_domain, router.as_bytes().into())], +// Ok(vec![burn_msg, dispatch_msg.clone()]), +// ), +// ( +// TokenMode::Bridged, +// vec![], +// Err(ContractError::NoRouter { +// domain: dest_domain, +// }), +// ), +// ( +// TokenMode::Collateral, +// vec![(dest_domain, router.as_bytes().into())], +// Ok(vec![dispatch_msg]), +// ), +// ( +// TokenMode::Collateral, +// vec![], +// Err(ContractError::NoRouter { +// domain: dest_domain, +// }), +// ), +// ] { +// let mut warp = TokenNative { +// env: env.clone(), +// ..Default::default() +// }; + +// warp.init_hack(&deployer, &owner, &mailbox, hrp, denom, mode)?; + +// for (domain, router) in routers { +// warp.router_enroll(&owner, domain, router)?; +// } + +// let resp = warp.transfer_remote( +// &owner, +// coin(amount, denom), +// dest_domain, +// user_remote.as_bytes().into(), +// ); + +// assert_eq!( +// resp.map(|v| v.messages.into_iter().map(|v| v.msg).collect::>()), +// expected_resp +// ); +// } + +// Ok(()) +// } + +// #[rstest] +// #[case("osmo")] +// #[case("neutron")] +// fn test_inbound_transfer(#[case] hrp: &str) -> anyhow::Result<()> { +// let deployer = Addr::unchecked("deployer"); +// let mailbox = Addr::unchecked("mailbox"); +// let router = Addr::unchecked("router"); +// let owner = Addr::unchecked("owner"); +// let errortic = Addr::unchecked("errortic"); + +// let denom = "token-native"; +// let amount = 100_000; + +// let user_remote = Addr::unchecked("user-remote____________________1"); + +// let env = mock_env(); + +// let origin_domain = 1; + +// let mint_msg: CosmosMsg = MsgMint { +// sender: env.contract.address.to_string(), +// amount: Some(proto::Coin { +// amount: amount.to_string(), +// denom: denom.to_string(), +// }), +// } +// .into(); + +// let send_msg: CosmosMsg = BankMsg::Send { +// to_address: bech32_encode(hrp, user_remote.as_bytes())?.to_string(), +// amount: vec![coin(amount, denom)], +// } +// .into(); + +// let default_msg = token::Message { +// recipient: user_remote.as_bytes().to_vec().into(), +// amount: Uint256::from_u128(amount), +// metadata: Binary::default(), +// }; + +// for (mode, sender, origin, origin_sender, token_msg, expected_resp) in [ +// // happy +// ( +// TokenMode::Bridged, +// &mailbox, +// origin_domain, +// &router, +// default_msg.clone(), +// Ok(vec![mint_msg, send_msg.clone()]), +// ), +// ( +// TokenMode::Collateral, +// &mailbox, +// origin_domain, +// &router, +// default_msg.clone(), +// Ok(vec![send_msg]), +// ), +// // errors +// ( +// TokenMode::Bridged, +// &errortic, +// origin_domain, +// &router, +// default_msg.clone(), +// Err(ContractError::Unauthorized), +// ), +// ( +// TokenMode::Bridged, +// &mailbox, +// origin_domain, +// &errortic, +// default_msg.clone(), +// Err(ContractError::Unauthorized), +// ), +// ( +// TokenMode::Collateral, +// &errortic, +// origin_domain, +// &router, +// default_msg.clone(), +// Err(ContractError::Unauthorized), +// ), +// ( +// TokenMode::Collateral, +// &mailbox, +// origin_domain, +// &errortic, +// default_msg, +// Err(ContractError::Unauthorized), +// ), +// ] { +// let mut warp = TokenNative { +// env: env.clone(), +// ..Default::default() +// }; + +// warp.init_hack(&deployer, &owner, &mailbox, hrp, denom, mode)?; +// warp.router_enroll(&owner, origin_domain, router.as_bytes().into())?; + +// let resp = warp.mailbox_handle( +// sender, +// mailbox::HandleMsg { +// origin, +// sender: origin_sender.as_bytes().to_vec().into(), +// body: token_msg.into(), +// }, +// ); + +// assert_eq!( +// resp.map(|v| v.messages.into_iter().map(|v| v.msg).collect::>()), +// expected_resp +// ); +// } + +// Ok(()) +// } diff --git a/contracts/warp/native/src/tests/mod.rs b/contracts/warp/native/src/tests/mod.rs index 7f569ac9..e3c7904a 100644 --- a/contracts/warp/native/src/tests/mod.rs +++ b/contracts/warp/native/src/tests/mod.rs @@ -1,132 +1,132 @@ -use cosmwasm_std::{ - from_binary, - testing::{mock_dependencies, mock_env, mock_info, MockApi, MockQuerier, MockStorage}, - Addr, Binary, Coin, Empty, Env, MessageInfo, OwnedDeps, Response, -}; -use hpl_interface::{ - mailbox, router, - token::TokenMode, - token_native::{ExecuteMsg, QueryMsg}, -}; -use serde::de::DeserializeOwned; +// use cosmwasm_std::{ +// from_binary, +// testing::{mock_dependencies, mock_env, mock_info, MockApi, MockQuerier, MockStorage}, +// Addr, Binary, Coin, Empty, Env, MessageInfo, OwnedDeps, Response, +// }; +// use hpl_interface::{ +// mailbox, router, +// token::TokenMode, +// token_native::{ExecuteMsg, QueryMsg}, +// }; +// use serde::de::DeserializeOwned; -use crate::{ - contract::{execute, instantiate, query}, - error::ContractError, - msg::{InstantiateMsg, Metadata}, - state::{HRP, MAILBOX, MODE, OWNER, TOKEN}, -}; +// use crate::{ +// contract::{execute, instantiate, query}, +// error::ContractError, +// msg::{InstantiateMsg, Metadata}, +// state::{HRP, MAILBOX, MODE, OWNER, TOKEN}, +// }; -mod contracts; +// mod contracts; -pub struct TokenNative { - pub deps: OwnedDeps, - pub env: Env, -} +// pub struct TokenNative { +// pub deps: OwnedDeps, +// pub env: Env, +// } -impl Default for TokenNative { - fn default() -> Self { - Self { - deps: mock_dependencies(), - env: mock_env(), - } - } -} +// impl Default for TokenNative { +// fn default() -> Self { +// Self { +// deps: mock_dependencies(), +// env: mock_env(), +// } +// } +// } -impl TokenNative { - #[allow(clippy::too_many_arguments)] - pub fn init( - &mut self, - sender: &Addr, - hrp: &str, - owner: &Addr, - mailbox: &Addr, - denom: &str, - metadata: Option, - mode: TokenMode, - ) -> Result { - instantiate( - self.deps.as_mut(), - self.env.clone(), - mock_info(sender.as_str(), &[]), - InstantiateMsg { - denom: denom.to_string(), - metadata, - mode, - hrp: hrp.to_string(), - owner: owner.to_string(), - mailbox: mailbox.to_string(), - }, - ) - } +// impl TokenNative { +// #[allow(clippy::too_many_arguments)] +// pub fn init( +// &mut self, +// sender: &Addr, +// hrp: &str, +// owner: &Addr, +// mailbox: &Addr, +// denom: &str, +// metadata: Option, +// mode: TokenMode, +// ) -> Result { +// instantiate( +// self.deps.as_mut(), +// self.env.clone(), +// mock_info(sender.as_str(), &[]), +// InstantiateMsg { +// denom: denom.to_string(), +// metadata, +// mode, +// hrp: hrp.to_string(), +// owner: owner.to_string(), +// mailbox: mailbox.to_string(), +// }, +// ) +// } - pub fn init_hack( - &mut self, - _sender: &Addr, - owner: &Addr, - mailbox: &Addr, - hrp: &str, - denom: &str, - mode: TokenMode, - ) -> anyhow::Result<()> { - MODE.save(&mut self.deps.storage, &mode)?; - HRP.save(&mut self.deps.storage, &hrp.to_string())?; - TOKEN.save(&mut self.deps.storage, &denom.to_string())?; - OWNER.save(&mut self.deps.storage, owner)?; - MAILBOX.save(&mut self.deps.storage, mailbox)?; +// pub fn init_hack( +// &mut self, +// _sender: &Addr, +// owner: &Addr, +// mailbox: &Addr, +// hrp: &str, +// denom: &str, +// mode: TokenMode, +// ) -> anyhow::Result<()> { +// MODE.save(&mut self.deps.storage, &mode)?; +// HRP.save(&mut self.deps.storage, &hrp.to_string())?; +// TOKEN.save(&mut self.deps.storage, &denom.to_string())?; +// OWNER.save(&mut self.deps.storage, owner)?; +// MAILBOX.save(&mut self.deps.storage, mailbox)?; - Ok(()) - } +// Ok(()) +// } - fn execute(&mut self, info: MessageInfo, msg: ExecuteMsg) -> Result { - execute(self.deps.as_mut(), self.env.clone(), info, msg) - } +// fn execute(&mut self, info: MessageInfo, msg: ExecuteMsg) -> Result { +// execute(self.deps.as_mut(), self.env.clone(), info, msg) +// } - #[allow(dead_code)] - fn query(&self, msg: QueryMsg) -> Result { - query(self.deps.as_ref(), self.env.clone(), msg) - .map(|v| from_binary::(&v))? - .map_err(|e| e.into()) - } +// #[allow(dead_code)] +// fn query(&self, msg: QueryMsg) -> Result { +// query(self.deps.as_ref(), self.env.clone(), msg) +// .map(|v| from_binary::(&v))? +// .map_err(|e| e.into()) +// } - pub fn router_enroll( - &mut self, - sender: &Addr, - domain: u32, - router: Binary, - ) -> Result { - self.execute( - mock_info(sender.as_str(), &[]), - ExecuteMsg::Router(router::RouterMsg::EnrollRemoteRouter { - set: router::RouterSet { domain, router }, - }), - ) - } +// pub fn router_enroll( +// &mut self, +// sender: &Addr, +// domain: u32, +// router: Binary, +// ) -> Result { +// self.execute( +// mock_info(sender.as_str(), &[]), +// ExecuteMsg::Router(router::RouterMsg::EnrollRemoteRouter { +// set: router::RouterSet { domain, router }, +// }), +// ) +// } - pub fn mailbox_handle( - &mut self, - sender: &Addr, - handle_msg: mailbox::HandleMsg, - ) -> Result { - self.execute( - mock_info(sender.as_str(), &[]), - ExecuteMsg::Handle(handle_msg), - ) - } +// pub fn mailbox_handle( +// &mut self, +// sender: &Addr, +// handle_msg: mailbox::HandleMsg, +// ) -> Result { +// self.execute( +// mock_info(sender.as_str(), &[]), +// ExecuteMsg::Handle(handle_msg), +// ) +// } - pub fn transfer_remote( - &mut self, - sender: &Addr, - fund: Coin, - dest_domain: u32, - recipient: Binary, - ) -> Result { - self.execute( - mock_info(sender.as_str(), &[fund]), - ExecuteMsg::TransferRemote { - dest_domain, - recipient, - }, - ) - } -} +// pub fn transfer_remote( +// &mut self, +// sender: &Addr, +// fund: Coin, +// dest_domain: u32, +// recipient: Binary, +// ) -> Result { +// self.execute( +// mock_info(sender.as_str(), &[fund]), +// ExecuteMsg::TransferRemote { +// dest_domain, +// recipient, +// }, +// ) +// } +// } diff --git a/integration-test/tests/contracts/cw/deploy.rs b/integration-test/tests/contracts/cw/deploy.rs index 63590396..d12c79d4 100644 --- a/integration-test/tests/contracts/cw/deploy.rs +++ b/integration-test/tests/contracts/cw/deploy.rs @@ -116,6 +116,7 @@ pub fn deploy_core<'a, R: Runner<'a>>( }) } +#[allow(dead_code)] pub fn deploy_warp_route_bridged<'a, R: Runner<'a>>( wasm: &Wasm<'a, R>, owner: &SigningAccount, @@ -149,6 +150,7 @@ pub fn deploy_warp_route_bridged<'a, R: Runner<'a>>( ) } +#[allow(dead_code)] pub fn deploy_warp_route_collateral<'a, R: Runner<'a>>( wasm: &Wasm<'a, R>, owner: &SigningAccount, @@ -195,6 +197,7 @@ pub fn deploy_warp_route_collateral<'a, R: Runner<'a>>( } } +#[allow(dead_code)] pub fn link_warp_route<'a, R: Runner<'a>>( wasm: &Wasm<'a, R>, owner: &SigningAccount, diff --git a/integration-test/tests/contracts/cw/hook.rs b/integration-test/tests/contracts/cw/hook.rs index ab187f93..863dfda7 100644 --- a/integration-test/tests/contracts/cw/hook.rs +++ b/integration-test/tests/contracts/cw/hook.rs @@ -12,6 +12,7 @@ use test_tube::{Account, Runner, SigningAccount}; use super::{igp::Igp, types::Codes}; +#[allow(dead_code)] pub enum Hook { Mock { gas: Uint256, @@ -43,6 +44,7 @@ pub enum Hook { } impl Hook { + #[allow(dead_code)] pub fn mock(gas: Uint256) -> Self { Self::Mock { gas } } @@ -264,7 +266,7 @@ impl Hook { Ok(hook_addr) } - Hook::Aggregate { hooks } => todo!(), + Hook::Aggregate { .. } => todo!(), } } } @@ -272,7 +274,7 @@ impl Hook { pub fn prepare_routing_hook(routes: Vec<(u32, u128)>) -> Hook { let routes = routes .into_iter() - .map(|(domain, gas)| (domain, Hook::Merkle {})) + .map(|(domain, _)| (domain, Hook::Merkle {})) .collect(); Hook::routing(routes) diff --git a/integration-test/tests/mailbox.rs b/integration-test/tests/mailbox.rs index 3e083779..3df7281b 100644 --- a/integration-test/tests/mailbox.rs +++ b/integration-test/tests/mailbox.rs @@ -154,7 +154,7 @@ async fn test_mailbox_evm_to_cw() -> eyre::Result<()> { let ism_metadata = osmo.get_validator_set(DOMAIN_EVM)?.make_metadata( anvil1.core.mailbox.address(), anvil1.core.mailbox.root().await?, - anvil1.core.mailbox.count().await? - 1, + anvil1.core.mailbox.count().await?, dispatch_id.message_id, true, )?; diff --git a/integration-test/tests/validator.rs b/integration-test/tests/validator.rs index a87ec0cb..83300245 100644 --- a/integration-test/tests/validator.rs +++ b/integration-test/tests/validator.rs @@ -141,7 +141,7 @@ impl TestValidators { let multisig_hash = hpl_ism_multisig::multisig_hash( hpl_ism_multisig::domain_hash(self.domain, addr.to_vec().into())?.to_vec(), merkle_root.to_vec(), - 0, + merkle_index.to_be_bytes().to_vec(), message_id.to_vec(), )?; diff --git a/packages/interface/src/core/va.rs b/packages/interface/src/core/va.rs index 8e8c6463..7bf018ae 100644 --- a/packages/interface/src/core/va.rs +++ b/packages/interface/src/core/va.rs @@ -35,5 +35,3 @@ pub struct GetAnnounceStorageLocationsResponse { pub struct GetAnnouncedValidatorsResponse { pub validators: Vec, } - - diff --git a/packages/interface/src/hook/mod.rs b/packages/interface/src/hook/mod.rs index 9d2a036d..ec1580d4 100644 --- a/packages/interface/src/hook/mod.rs +++ b/packages/interface/src/hook/mod.rs @@ -1,4 +1,3 @@ -pub mod aggregate; pub mod merkle; pub mod pausable; pub mod routing; diff --git a/packages/router/src/test.rs b/packages/router/src/test.rs index 62c986ff..0557112b 100644 --- a/packages/router/src/test.rs +++ b/packages/router/src/test.rs @@ -117,6 +117,8 @@ fn test_handle() -> anyhow::Result<()> { let mut router = Router::default(); + hpl_ownable::initialize(router.deps.as_mut().storage, &owner)?; + router.set_route(&owner, set_a.domain, set_a.route.clone().unwrap())?; router.set_routes(&owner, &[(set_b.domain, set_b.route.clone().unwrap())])?; @@ -144,6 +146,8 @@ fn test_check() -> anyhow::Result<()> { let mut router = Router::default(); + hpl_ownable::initialize(router.deps.as_mut().storage, &owner)?; + let domain_t = 1; let router_t = Binary(b"test".to_vec()); let router_n = Binary(b"no".to_vec()); diff --git a/scripts/deploy.ts b/scripts/deploy.ts new file mode 100644 index 00000000..584dc5ee --- /dev/null +++ b/scripts/deploy.ts @@ -0,0 +1,174 @@ +import { + ExecuteResult, + SigningCosmWasmClient, +} from "@cosmjs/cosmwasm-stargate"; +import { DirectSecp256k1HdWallet } from "@cosmjs/proto-signing"; +import { GasPrice } from "@cosmjs/stargate"; + +import { loadContext } from "./src/load_context"; +import HplMailbox from "./src/contracts/hpl_mailbox"; +import { BaseContract, Context } from "./src/types"; +import HplHookMerkle from "./src/contracts/hpl_hook_merkle"; +import HplTestMockHook from "./src/contracts/hpl_test_mock_hook"; +import HplIgpGasOracle from "./src/contracts/hpl_igp_oracle"; +import HplIgp from "./src/contracts/hpl_igp"; +import HplIsmMultisig from "./src/contracts/hpl_ism_multisig"; +import { writeFileSync } from "fs"; +import HplValidatorAnnounce from "./src/contracts/hpl_validator_announce"; +import HplTestMockMsgReceiver from "./src/contracts/hpl_test_mock_msg_receiver"; + +const NETWORK_ID = process.env.NETWORK_ID || "osmo-test-5"; +const NETWORK_HRP = process.env.NETWORK_HRP || "osmo"; +const NETWORK_URL = + process.env.NETWORK_URL || "https://rpc.osmotest5.osmosis.zone"; +const NETWORK_GAS = process.env.NETWORK_GAS || "0.025uosmo"; + +async function getSigningClient(): Promise<{ + client: SigningCosmWasmClient; + address: string; +}> { + const mnemonic = process.env["SIGNING_MNEMONIC"] as string; + const wallet = await DirectSecp256k1HdWallet.fromMnemonic(mnemonic, { + prefix: NETWORK_HRP, + }); + const [{ address }] = await wallet.getAccounts(); + + const client = await SigningCosmWasmClient.connectWithSigner( + NETWORK_URL, + wallet, + { + gasPrice: GasPrice.fromString(NETWORK_GAS), + } + ); + return { client, address }; +} + +type Const = new ( + address: string | undefined, + codeId: number | undefined, + digest: string, + signer: string, + client: SigningCosmWasmClient +) => T; + +class ContractFetcher { + constructor( + private ctx: Context, + private owner: string, + private client: SigningCosmWasmClient + ) {} + + public get(f: Const, name: string): T { + return new f( + this.ctx.contracts[name].address, + this.ctx.contracts[name].codeId, + this.ctx.contracts[name].digest, + this.owner, + this.client + ); + } +} + +async function main() { + const { client, address: owner } = await getSigningClient(); + + const ctx = loadContext(NETWORK_ID); + + const fetcher = new ContractFetcher(ctx, owner, client); + + const mailbox = fetcher.get(HplMailbox, "hpl_mailbox"); + const va = fetcher.get(HplValidatorAnnounce, "hpl_validator_announce"); + + const hook_merkle = fetcher.get(HplHookMerkle, "hpl_hook_merkle"); + const igp_oracle = fetcher.get(HplIgpGasOracle, "hpl_igp_oracle"); + const igp = fetcher.get(HplIgp, "hpl_igp"); + const ism_multisig = fetcher.get(HplIsmMultisig, "hpl_ism_multisig"); + + const test_mock_hook = fetcher.get(HplTestMockHook, "hpl_test_mock_hook"); + const test_mock_receiver = fetcher.get( + HplTestMockMsgReceiver, + "hpl_test_mock_msg_receiver" + ); + + // init mailbox + ctx.contracts[mailbox.contractName] = await mailbox.instantiate({ + hrp: "dual", + owner, + domain: 33333, + }); + + // init validator announce + ctx.contracts[va.contractName] = await va.instantiate({ + hrp: "dual", + mailbox: ctx.contracts[mailbox.contractName].address, + }); + + // init merkle hook - (required hook) + ctx.contracts[hook_merkle.contractName] = await hook_merkle.instantiate({ + owner: ctx.address!, + mailbox: ctx.contracts[mailbox.contractName].address, + }); + + // init mock hook - (default hook) + ctx.contracts[test_mock_hook.contractName] = await test_mock_hook.instantiate( + {} + ); + + // init igp oracle + ctx.contracts[igp_oracle.contractName] = await igp_oracle.instantiate({}); + + // init igp + ctx.contracts[igp.contractName] = await igp.instantiate({ + hrp: "dual", + owner: ctx.address!, + mailbox: ctx.contracts[mailbox.contractName].address, + gas_token: "token", + beneficiary: ctx.address!, + }); + + // init ism multisig + ctx.contracts[ism_multisig.contractName] = await ism_multisig.instantiate({ + hrp: "dual", + owner: ctx.address!, + }); + + // init test mock msg receiver + ctx.contracts[test_mock_receiver.contractName] = + await test_mock_receiver.instantiate({ hrp: "dual" }); + + // pre-setup + await client.executeMultiple( + owner, + [ + { + contractAddress: ctx.contracts[mailbox.contractName].address!, + msg: { + set_default_ism: { + ism: ctx.contracts[ism_multisig.contractName].address!, + }, + }, + }, + { + contractAddress: ctx.contracts[mailbox.contractName].address!, + msg: { + set_default_hook: { + hook: ctx.contracts[test_mock_hook.contractName].address!, + }, + }, + }, + { + contractAddress: ctx.contracts[mailbox.contractName].address!, + msg: { + set_required_hook: { + hook: ctx.contracts[hook_merkle.contractName].address!, + }, + }, + }, + ], + "auto" + ); + + writeFileSync("./save.json", JSON.stringify(ctx, null, 2)); +} + +main().catch(console.error); diff --git a/scripts/src/index.ts b/scripts/src/index.ts index f2317383..469e5a7a 100644 --- a/scripts/src/index.ts +++ b/scripts/src/index.ts @@ -4,7 +4,6 @@ import { loadContext, saveContext } from "./load_context"; import { getTargetContract, getTargetContractName } from "./contracts"; import { CodeUpdate, CodeCreate, Context } from "./types"; import * as readline from "readline"; - import { AxiosError } from "axios"; import { CONTAINER } from "./ioc"; import { runMigrations } from "./migrations"; diff --git a/scripts/src/load_wasm.ts b/scripts/src/load_wasm.ts index a1f9cdeb..e269aab5 100644 --- a/scripts/src/load_wasm.ts +++ b/scripts/src/load_wasm.ts @@ -53,5 +53,5 @@ export async function loadWasmFileDigest() { } export function getWasmPath(contractName: string): string { - return path.join(directoryPath, `${contractName}.wasm`); + return path.join(directoryPath, `${contractName}-aarch64.wasm`); } diff --git a/scripts/warp.ts b/scripts/warp.ts new file mode 100644 index 00000000..51c9c31b --- /dev/null +++ b/scripts/warp.ts @@ -0,0 +1,90 @@ +import { SigningCosmWasmClient } from "@cosmjs/cosmwasm-stargate"; +import { DirectSecp256k1HdWallet } from "@cosmjs/proto-signing"; +import { GasPrice } from "@cosmjs/stargate"; + +import { loadContext } from "./src/load_context"; +import HplMailbox from "./src/contracts/hpl_mailbox"; +import { Context } from "./src/types"; +import HplWarpNative from "./src/contracts/hpl_warp_native"; + +const NETWORK_ID = process.env.NETWORK_ID || "osmo-test-5"; +const NETWORK_HRP = process.env.NETWORK_HRP || "osmo"; +const NETWORK_URL = + process.env.NETWORK_URL || "https://rpc.osmotest5.osmosis.zone"; +const NETWORK_GAS = process.env.NETWORK_GAS || "0.025uosmo"; + +async function getSigningClient(): Promise<{ + client: SigningCosmWasmClient; + address: string; +}> { + const mnemonic = process.env["SIGNING_MNEMONIC"] as string; + const wallet = await DirectSecp256k1HdWallet.fromMnemonic(mnemonic, { + prefix: NETWORK_HRP, + }); + const [{ address }] = await wallet.getAccounts(); + + const client = await SigningCosmWasmClient.connectWithSigner( + NETWORK_URL, + wallet, + { + gasPrice: GasPrice.fromString(NETWORK_GAS), + } + ); + return { client, address }; +} + +type Const = new ( + address: string | undefined, + codeId: number | undefined, + digest: string, + signer: string, + client: SigningCosmWasmClient +) => T; + +class ContractFetcher { + constructor( + private ctx: Context, + private owner: string, + private client: SigningCosmWasmClient + ) {} + + public get(f: Const, name: string): T { + return new f( + this.ctx.contracts[name].address, + this.ctx.contracts[name].codeId, + this.ctx.contracts[name].digest, + this.owner, + this.client + ); + } +} + +async function main() { + const { client, address: owner } = await getSigningClient(); + + const ctx = loadContext(NETWORK_ID); + + const fetcher = new ContractFetcher(ctx, owner, client); + + const mailbox = fetcher.get(HplMailbox, "hpl_mailbox"); + + const warp_native = fetcher.get(HplWarpNative, "hpl_warp_native"); + + const target_denom = + "ibc/B5CB286F69D48B2C4F6F8D8CF59011C40590DCF8A91617A5FBA9FF0A7B21307F"; + + const ibc_route = await warp_native.instantiate({ + token: { + collateral: { + denom: target_denom, + }, + }, + hrp: "dual", + owner, + mailbox: mailbox.address!, + }); + + console.log("ibc_route", ibc_route); +} + +main().catch(console.error);