Skip to content

Commit

Permalink
test: warp route (#51)
Browse files Browse the repository at this point in the history
* Revert "revert: aggregate"

This reverts commit 00fe615.

* test(cw20): cw20 init

* test(warp): unit test for cw20

* test(warp): add query test for cw20

* test(warp): remove existing tests for native

* feat(warp): add ownable message

* wip

* test(warp): unit test for native denom

* test: use u32 directly

* fix!(ism): use parsed u32 merkle index

* test: modularize

* test: add empty warp

* test: runnable mailbox

* test: warp placeholder

* test: deployable

* fix(warp): inject minter to cw20

* fix(warp): use consistant event name

* test: warp cw20 / native denom creation

* chore: prune

* feat: aggregation

* schema

* fix: evm equivalence

* fix(hook): pass entire metadata

* fix: aggregate works

* chore: remove debugger

* fix: tests

* clippy

* use aggregate ism on integration test

* feat: migrate to aggregations (#53)
  • Loading branch information
byeongsu-hong committed Oct 23, 2023
1 parent f4027eb commit fbcc641
Show file tree
Hide file tree
Showing 54 changed files with 2,056 additions and 1,141 deletions.
42 changes: 42 additions & 0 deletions contracts/hooks/aggregate/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
[package]
name = "hpl-hook-aggregate"
version.workspace = true
authors.workspace = true
edition.workspace = true
license.workspace = true
repository.workspace = true
homepage.workspace = true
documentation.workspace = true
keywords.workspace = true

[lib]
crate-type = ["cdylib", "rlib"]

[features]
# for more explicit tests, cargo test --features=backtraces
backtraces = ["cosmwasm-std/backtraces"]
# use library feature to disable all instantiate/execute/query exports
library = []

[dependencies]
cosmwasm-std.workspace = true
cosmwasm-storage.workspace = true
cosmwasm-schema.workspace = true

cw-storage-plus.workspace = true
cw2.workspace = true
cw-utils.workspace = true

schemars.workspace = true
serde-json-wasm.workspace = true

thiserror.workspace = true

hpl-ownable.workspace = true
hpl-interface.workspace = true

[dev-dependencies]
rstest.workspace = true
ibcx-test-utils.workspace = true

anyhow.workspace = true
16 changes: 16 additions & 0 deletions contracts/hooks/aggregate/src/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
use cosmwasm_std::StdError;

#[derive(thiserror::Error, Debug, PartialEq)]
pub enum ContractError {
#[error("{0}")]
Std(#[from] StdError),

#[error("{0}")]
PaymentError(#[from] cw_utils::PaymentError),

#[error("unauthorized")]
Unauthorized {},

#[error("hook paused")]
Paused {},
}
186 changes: 186 additions & 0 deletions contracts/hooks/aggregate/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
mod error;

#[cfg(not(feature = "library"))]
use cosmwasm_std::entry_point;
use cosmwasm_std::{
ensure_eq, Addr, Coin, CosmosMsg, Deps, DepsMut, Env, Event, HexBinary, MessageInfo,
QueryResponse, Response, StdResult,
};
use cw_storage_plus::Item;
use error::ContractError;
use hpl_interface::{
hook::{
aggregate::{AggregateHookQueryMsg, ExecuteMsg, HooksResponse, InstantiateMsg, QueryMsg},
post_dispatch, HookQueryMsg, MailboxResponse, PostDispatchMsg, QuoteDispatchMsg,
QuoteDispatchResponse,
},
to_binary,
types::Message,
};
use hpl_ownable::get_owner;

// version info for migration info
pub const CONTRACT_NAME: &str = env!("CARGO_PKG_NAME");
pub const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION");

pub const HOOKS_KEY: &str = "hooks";
pub const HOOKS: Item<Vec<Addr>> = Item::new(HOOKS_KEY);

fn new_event(name: &str) -> Event {
Event::new(format!("hpl_hook_aggregate::{}", name))
}

#[cfg_attr(not(feature = "library"), entry_point)]
pub fn instantiate(
deps: DepsMut,
_env: Env,
info: MessageInfo,
msg: InstantiateMsg,
) -> Result<Response, ContractError> {
cw2::set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?;

let owner = deps.api.addr_validate(&msg.owner)?;
let hooks = msg
.hooks
.iter()
.map(|v| deps.api.addr_validate(v))
.collect::<StdResult<_>>()?;

hpl_ownable::initialize(deps.storage, &owner)?;

HOOKS.save(deps.storage, &hooks)?;

Ok(Response::new().add_event(
new_event("initialize")
.add_attribute("sender", info.sender)
.add_attribute("owner", owner)
.add_attribute("hooks", msg.hooks.join(",")),
))
}

#[cfg_attr(not(feature = "library"), entry_point)]
pub fn execute(
deps: DepsMut,
env: Env,
info: MessageInfo,
msg: ExecuteMsg,
) -> Result<Response, ContractError> {
match msg {
ExecuteMsg::Ownable(msg) => Ok(hpl_ownable::handle(deps, env, info, msg)?),
ExecuteMsg::PostDispatch(PostDispatchMsg { message, metadata }) => {
// aggregate it
let hooks = HOOKS.load(deps.storage)?;

let msgs: Vec<CosmosMsg> = hooks
.into_iter()
.map(|v| {
let quote = hpl_interface::hook::quote_dispatch(
&deps.querier,
&v,
metadata.clone(),
message.clone(),
)?;
let msg = post_dispatch(
v,
metadata.clone(),
message.clone(),
quote.gas_amount.map(|v| vec![v]),
)?
.into();

Ok(msg)
})
.collect::<StdResult<_>>()?;

let decoded_msg: Message = message.into();

// do nothing
Ok(Response::new().add_messages(msgs).add_event(
new_event("post_dispatch").add_attribute("message_id", decoded_msg.id().to_hex()),
))
}
ExecuteMsg::SetHooks { hooks } => {
ensure_eq!(
get_owner(deps.storage)?,
info.sender,
ContractError::Unauthorized {}
);

let parsed_hooks = hooks
.iter()
.map(|v| deps.api.addr_validate(v))
.collect::<StdResult<_>>()?;

HOOKS.save(deps.storage, &parsed_hooks)?;

Ok(Response::new().add_event(
new_event("set_hooks")
.add_attribute("sender", info.sender)
.add_attribute("hooks", hooks.join(",")),
))
}
}
}

#[cfg_attr(not(feature = "library"), entry_point)]
pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> Result<QueryResponse, ContractError> {
match msg {
QueryMsg::Ownable(msg) => Ok(hpl_ownable::handle_query(deps, env, msg)?),
QueryMsg::Hook(msg) => match msg {
HookQueryMsg::Mailbox {} => to_binary(get_mailbox(deps)),
HookQueryMsg::QuoteDispatch(QuoteDispatchMsg { metadata, message }) => {
to_binary(quote_dispatch(deps, metadata, message))
}
},
QueryMsg::AggregateHook(msg) => match msg {
AggregateHookQueryMsg::Hooks {} => to_binary(get_hooks(deps)),
},
}
}

fn get_mailbox(_deps: Deps) -> Result<MailboxResponse, ContractError> {
Ok(MailboxResponse {
mailbox: "unrestricted".to_string(),
})
}

fn quote_dispatch(
deps: Deps,
metadata: HexBinary,
message: HexBinary,
) -> Result<QuoteDispatchResponse, ContractError> {
let hooks = HOOKS.load(deps.storage)?;

let mut total: Option<Coin> = None;

for hook in hooks {
let res = hpl_interface::hook::quote_dispatch(
&deps.querier,
hook,
metadata.clone(),
message.clone(),
)?;

if let Some(gas_amount) = res.gas_amount {
total = match total {
Some(mut v) => {
v.amount += gas_amount.amount;
Some(v)
}
None => Some(gas_amount),
};
}
}

Ok(QuoteDispatchResponse { gas_amount: total })
}

fn get_hooks(deps: Deps) -> Result<HooksResponse, ContractError> {
Ok(HooksResponse {
hooks: HOOKS
.load(deps.storage)?
.into_iter()
.map(|v| v.into())
.collect(),
})
}
4 changes: 1 addition & 3 deletions contracts/igps/core/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use hpl_interface::igp::core::{ExecuteMsg, IgpQueryMsg, InstantiateMsg, QueryMsg
use hpl_interface::igp::oracle::IgpGasOracleQueryMsg;
use hpl_interface::to_binary;

use crate::{ContractError, BENEFICIARY, CONTRACT_NAME, CONTRACT_VERSION, GAS_TOKEN, HRP, MAILBOX};
use crate::{ContractError, BENEFICIARY, CONTRACT_NAME, CONTRACT_VERSION, GAS_TOKEN, HRP};

fn new_event(name: &str) -> Event {
Event::new(format!("hpl_igp_core::{}", name))
Expand All @@ -23,13 +23,11 @@ pub fn instantiate(
cw2::set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?;

let owner = deps.api.addr_validate(&msg.owner)?;
let mailbox = deps.api.addr_validate(&msg.mailbox)?;
let beneficiary = deps.api.addr_validate(&msg.beneficiary)?;

hpl_ownable::initialize(deps.storage, &owner)?;

BENEFICIARY.save(deps.storage, &beneficiary)?;
MAILBOX.save(deps.storage, &mailbox)?;

GAS_TOKEN.save(deps.storage, &msg.gas_token)?;
HRP.save(deps.storage, &msg.hrp)?;
Expand Down
8 changes: 1 addition & 7 deletions contracts/igps/core/src/execute.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::event::{emit_claim, emit_pay_for_gas, emit_post_dispatch, emit_set_beneficiary};
use crate::query::quote_gas_price;
use crate::{ContractError, BENEFICIARY, DEFAULT_GAS_USAGE, GAS_TOKEN, HRP, MAILBOX};
use crate::{ContractError, BENEFICIARY, DEFAULT_GAS_USAGE, GAS_TOKEN, HRP};

use cosmwasm_std::{
coins, ensure, ensure_eq, BankMsg, DepsMut, Env, HexBinary, MessageInfo, Response, Uint128,
Expand Down Expand Up @@ -55,12 +55,6 @@ pub fn post_dispatch(
info: MessageInfo,
req: PostDispatchMsg,
) -> Result<Response, ContractError> {
ensure_eq!(
info.sender,
MAILBOX.load(deps.storage)?,
ContractError::Unauthorized {}
);

let message: Message = req.message.clone().into();
let hrp = HRP.load(deps.storage)?;

Expand Down
3 changes: 0 additions & 3 deletions contracts/igps/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,6 @@ pub const DEFAULT_GAS_USAGE: u128 = 25_000;
pub const HRP_KEY: &str = "hrp";
pub const HRP: Item<String> = Item::new(HRP_KEY);

pub const MAILBOX_KEY: &str = "mailbox";
pub const MAILBOX: Item<Addr> = Item::new(MAILBOX_KEY);

pub const GAS_TOKEN_KEY: &str = "gas_token";
pub const GAS_TOKEN: Item<String> = Item::new(GAS_TOKEN_KEY);

Expand Down
8 changes: 3 additions & 5 deletions contracts/igps/core/src/query.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
use crate::error::ContractError;
use crate::{BENEFICIARY, DEFAULT_GAS_USAGE, GAS_TOKEN, MAILBOX, TOKEN_EXCHANGE_RATE_SCALE};
use crate::{BENEFICIARY, DEFAULT_GAS_USAGE, GAS_TOKEN, TOKEN_EXCHANGE_RATE_SCALE};

use cosmwasm_std::{coin, Addr, Deps, QuerierWrapper, Storage, Uint256};
use hpl_interface::hook::{MailboxResponse, QuoteDispatchMsg, QuoteDispatchResponse};
use hpl_interface::igp::core::{BeneficiaryResponse, QuoteGasPaymentResponse};
use hpl_interface::igp::oracle::{self, GetExchangeRateAndGasPriceResponse, IgpGasOracleQueryMsg};
use hpl_interface::types::{IGPMetadata, Message};

pub fn get_mailbox(deps: Deps) -> Result<MailboxResponse, ContractError> {
let mailbox = MAILBOX.load(deps.storage)?;

pub fn get_mailbox(_deps: Deps) -> Result<MailboxResponse, ContractError> {
Ok(MailboxResponse {
mailbox: mailbox.into(),
mailbox: "unrestricted".to_string(),
})
}

Expand Down
17 changes: 3 additions & 14 deletions contracts/igps/core/src/tests/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use hpl_router::get_routes;
use ibcx_test_utils::{addr, gen_bz};
use rstest::{fixture, rstest};

use crate::{BENEFICIARY, DEFAULT_GAS_USAGE, GAS_TOKEN, HRP, MAILBOX};
use crate::{BENEFICIARY, DEFAULT_GAS_USAGE, GAS_TOKEN, HRP};

use super::IGP;

Expand Down Expand Up @@ -62,22 +62,14 @@ macro_rules! arg_fixture {
arg_fixture!(deployer, Addr, addr("deployer"));
arg_fixture!(hrp, &'static str, "test");
arg_fixture!(owner, Addr, addr("owner"));
arg_fixture!(mailbox, Addr, addr("mailbox"));
arg_fixture!(gas_token, &'static str, "utest");
arg_fixture!(beneficiary, Addr, addr("beneficiary"));

#[fixture]
fn igp(
deployer: Addr,
hrp: &str,
owner: Addr,
mailbox: Addr,
gas_token: &str,
beneficiary: Addr,
) -> IGP {
fn igp(deployer: Addr, hrp: &str, owner: Addr, gas_token: &str, beneficiary: Addr) -> IGP {
let mut igp = IGP::new(mock_dependencies(), mock_env());

igp.init(&deployer, hrp, &owner, &mailbox, gas_token, &beneficiary)
igp.init(&deployer, hrp, &owner, gas_token, &beneficiary)
.unwrap();

igp
Expand All @@ -101,7 +93,6 @@ fn test_init(igp: IGP) {
assert_eq!(get_owner(storage).unwrap(), "owner");
assert_eq!(BENEFICIARY.load(storage).unwrap(), "beneficiary");
assert_eq!(GAS_TOKEN.load(storage).unwrap(), "utest");
assert_eq!(MAILBOX.load(storage).unwrap(), "mailbox");
assert_eq!(HRP.load(storage).unwrap(), "test");
}

Expand Down Expand Up @@ -249,8 +240,6 @@ fn test_pay_for_gas(
#[case(addr("mailbox"), true, Some(300_000))]
#[case(addr("mailbox"), true, None)]
#[case(addr("mailbox"), false, None)]
#[should_panic(expected = "unauthorized")]
#[case(addr("owner"), true, Some(300_000))]
fn test_post_dispatch(
#[values("osmo", "neutron")] hrp: &str,
#[with(vec![(1, "oracle/2/150".into())])] igp_routes: (IGP, Vec<(u32, String)>),
Expand Down
2 changes: 0 additions & 2 deletions contracts/igps/core/src/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ impl IGP {
sender: &Addr,
hrp: &str,
owner: &Addr,
mailbox: &Addr,
gas_token: &str,
beneficiary: &Addr,
) -> Result<Response, ContractError> {
Expand All @@ -53,7 +52,6 @@ impl IGP {
InstantiateMsg {
hrp: hrp.to_string(),
owner: owner.to_string(),
mailbox: mailbox.to_string(),
gas_token: gas_token.to_string(),
beneficiary: beneficiary.to_string(),
},
Expand Down
Loading

0 comments on commit fbcc641

Please sign in to comment.