Skip to content

Commit

Permalink
Merge pull request #1 from hyperlane-xyz/pausable-ism
Browse files Browse the repository at this point in the history
Add pausable ISM
  • Loading branch information
yorhodes authored Jan 16, 2024
2 parents 9cda304 + ef9c6f3 commit 7973533
Show file tree
Hide file tree
Showing 12 changed files with 272 additions and 29 deletions.
2 changes: 0 additions & 2 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ name: test

on:
pull_request:
branches:
- "main"
push:
branches:
- "main"
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ grcov . -s . --binary-path ./target/debug/ -t lcov --branch --ignore-not-existin

- [aggregate ism](./contracts/isms/aggregate)

- [pausable](./contracts/isms/pausable)

- For testing: [mock ism](./contracts/mocks/mock-ism)

5. Set deployed hooks and isms to Mailbox
Expand Down
43 changes: 43 additions & 0 deletions contracts/isms/pausable/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
[package]
name = "hpl-ism-pausable"
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-pausable.workspace = true
hpl-interface.workspace = true

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

anyhow.workspace = true
164 changes: 164 additions & 0 deletions contracts/isms/pausable/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
#[cfg(not(feature = "library"))]
use cosmwasm_std::entry_point;
use cosmwasm_std::{
ensure, to_json_binary, Deps, DepsMut, Env, Event, MessageInfo, QueryResponse, Response,
StdError,
};
use hpl_interface::ism::{
pausable::{ExecuteMsg, InstantiateMsg, QueryMsg},
IsmQueryMsg, IsmType, ModuleTypeResponse, VerifyResponse,
};

#[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 {},
}

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

fn new_event(name: &str) -> Event {
Event::new(format!("hpl_hook_pausable::{}", 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)?;

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

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

#[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::Pausable(msg) => Ok(hpl_pausable::handle(deps, env, info, msg)?),
}
}

#[cfg_attr(not(feature = "library"), entry_point)]
pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> Result<QueryResponse, ContractError> {
use IsmQueryMsg::*;

match msg {
QueryMsg::Pausable(msg) => Ok(hpl_pausable::handle_query(deps, env, msg)?),
QueryMsg::Ownable(msg) => Ok(hpl_ownable::handle_query(deps, env, msg)?),
QueryMsg::Ism(msg) => match msg {
ModuleType {} => Ok(to_json_binary(&ModuleTypeResponse { typ: IsmType::Null })?),
Verify {
metadata: _,
message: _,
} => {
ensure!(
!hpl_pausable::get_pause_info(deps.storage)?,
ContractError::Paused {}
);
Ok(to_json_binary(&VerifyResponse { verified: true })?)
}
_ => unimplemented!(),
},
}
}

#[cfg(test)]
mod test {
use cosmwasm_std::{
from_json,
testing::{mock_dependencies, mock_env, mock_info, MockApi, MockQuerier, MockStorage},
to_json_binary, Addr, OwnedDeps,
};
use hpl_ownable::get_owner;
use hpl_pausable::get_pause_info;
use ibcx_test_utils::{addr, hex};
use rstest::{fixture, rstest};

use super::*;

type TestDeps = OwnedDeps<MockStorage, MockApi, MockQuerier>;

fn query(deps: Deps, msg: crate::QueryMsg) -> Result<QueryResponse, ContractError> {
let req: QueryMsg = from_json(to_json_binary(&msg).unwrap()).unwrap();
crate::query(deps, mock_env(), req)
}

#[fixture]
fn deps(
#[default(addr("deployer"))] sender: Addr,
#[default(addr("owner"))] owner: Addr,
#[default(false)] paused: bool,
) -> TestDeps {
let mut deps = mock_dependencies();

instantiate(
deps.as_mut(),
mock_env(),
mock_info(sender.as_str(), &[]),
InstantiateMsg {
owner: owner.to_string(),
paused,
},
)
.unwrap();

deps
}

#[rstest]
fn test_init(deps: TestDeps) {
assert!(!get_pause_info(deps.as_ref().storage).unwrap());
assert_eq!("owner", get_owner(deps.as_ref().storage).unwrap().as_str());
}

#[rstest]
#[case(false)]
#[should_panic(expected = "hook paused")]
#[case(true)]
fn test_query(mut deps: TestDeps, #[case] paused: bool) {
if paused {
hpl_pausable::pause(deps.as_mut().storage, &addr("owner")).unwrap();
}

let raw_message = hex("0000000000000068220000000000000000000000000d1255b09d94659bb0888e0aa9fca60245ce402a0000682155208cd518cffaac1b5d8df216a9bd050c9a03f0d4f3ba88e5268ac4cd12ee2d68656c6c6f");
let raw_metadata = raw_message.clone();

query(
deps.as_ref(),
QueryMsg::Ism(IsmQueryMsg::Verify {
metadata: raw_metadata,
message: raw_message,
}),
)
.map_err(|e| e.to_string())
.unwrap();
}
}
1 change: 1 addition & 0 deletions packages/interface/src/ism/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
pub mod aggregate;
pub mod multisig;
pub mod routing;
pub mod pausable;

use cosmwasm_schema::{cw_serde, QueryResponses};
use cosmwasm_std::{Addr, CustomQuery, HexBinary, QuerierWrapper, StdResult};
Expand Down
26 changes: 26 additions & 0 deletions packages/interface/src/ism/pausable.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
use cosmwasm_schema::{cw_serde, QueryResponses};

use crate::{ownable::{OwnableMsg, OwnableQueryMsg}, pausable::{PausableMsg, PausableQueryMsg}};

use super::IsmQueryMsg;

#[cw_serde]
pub struct InstantiateMsg {
pub owner: String,
pub paused: bool
}

#[cw_serde]
pub enum ExecuteMsg {
Ownable(OwnableMsg),
Pausable(PausableMsg)
}

#[cw_serde]
#[derive(QueryResponses)]
#[query_responses(nested)]
pub enum QueryMsg {
Ownable(OwnableQueryMsg),
Ism(IsmQueryMsg),
Pausable(PausableQueryMsg)
}
14 changes: 7 additions & 7 deletions scripts/action/ism.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import { Command } from "commander";
import { ExecuteResult } from "@cosmjs/cosmwasm-stargate";
import { Command } from "commander";

import { version } from "../package.json";
import { config, getSigningClient } from "../src/config";
import { loadContext } from "../src/load_context";
import { ContractFetcher } from "./fetch";
import {
HplMailbox,
HplIgp,
HplIgpGasOracle,
HplHookMerkle,
HplIgp,
HplIgpOracle,
HplIsmAggregate,
HplMailbox,
} from "../src/contracts";
import { loadContext } from "../src/load_context";
import { ContractFetcher } from "./fetch";

const program = new Command();

Expand Down Expand Up @@ -51,7 +51,7 @@ function makeHandler(
const fetcher = new ContractFetcher(ctx, client);
const mailbox = fetcher.get(HplMailbox, "hpl_mailbox");
const igp = fetcher.get(HplIgp, "hpl_igp");
const igp_oracle = fetcher.get(HplIgpGasOracle, "hpl_igp_oracle");
const igp_oracle = fetcher.get(HplIgpOracle, "hpl_igp_oracle");
const hook_merkle = fetcher.get(HplHookMerkle, "hpl_hook_merkle");
const hook_aggregate = fetcher.get(HplIsmAggregate, "hpl_hook_aggregate");

Expand Down
18 changes: 9 additions & 9 deletions scripts/action/mailbox.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import { Command } from "commander";
import { ExecuteResult } from "@cosmjs/cosmwasm-stargate";
import { Command } from "commander";

import { version } from "../package.json";
import { config, getSigningClient } from "../src/config";
import {
HplHookMerkle,
HplIgp,
HplIgpOracle,
HplIsmAggregate,
HplMailbox,
} from "../src/contracts";
import { addPad } from "../src/conv";
import { loadContext } from "../src/load_context";
import { ContractFetcher } from "./fetch";
import {
HplMailbox,
HplIgp,
HplIgpGasOracle,
HplHookMerkle,
HplIsmAggregate,
} from "../src/contracts";

const program = new Command();

Expand Down Expand Up @@ -54,7 +54,7 @@ function makeHandler(
const fetcher = new ContractFetcher(ctx, client);
const mailbox = fetcher.get(HplMailbox, "hpl_mailbox");
const igp = fetcher.get(HplIgp, "hpl_igp");
const igp_oracle = fetcher.get(HplIgpGasOracle, "hpl_igp_oracle");
const igp_oracle = fetcher.get(HplIgpOracle, "hpl_igp_oracle");
const hook_merkle = fetcher.get(HplHookMerkle, "hpl_hook_merkle");
const hook_aggregate = fetcher.get(HplIsmAggregate, "hpl_hook_aggregate");

Expand Down
7 changes: 7 additions & 0 deletions scripts/src/contracts/hpl_ism_pausable.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { injectable } from "inversify";
import { BaseContract } from "../types";

@injectable()
export class HplIsmPausable extends BaseContract {
contractName: string = "hpl_ism_pausable";
}
5 changes: 3 additions & 2 deletions scripts/src/contracts/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export * from "./hpl_igp";
export * from "./hpl_igp_oracle";
export * from "./hpl_ism_aggregate";
export * from "./hpl_ism_multisig";
export * from "./hpl_ism_pausable";
export * from "./hpl_ism_routing";
export * from "./hpl_mailbox";
export * from "./hpl_test_mock_hook";
Expand All @@ -16,10 +17,10 @@ export * from "./hpl_validator_announce";
export * from "./hpl_warp_cw20";
export * from "./hpl_warp_native";

import { readdirSync } from "fs";
import { Context, Contract, ContractConstructor } from "../types";
import { SigningCosmWasmClient } from "@cosmjs/cosmwasm-stargate";
import { readdirSync } from "fs";
import { Container } from "inversify";
import { Context, Contract, ContractConstructor } from "../types";

const contractNames: string[] = readdirSync(__dirname)
.filter((f) => f !== "index.ts")
Expand Down
9 changes: 5 additions & 4 deletions scripts/src/migrations/InitializeStandalone.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { injectable } from "inversify";
import { Context, Migration } from "../types";
import {
HplMailbox,
HplHookMerkle,
HplIgpGasOracle,
HplIgp,
HplIgpOracle,
HplIsmMultisig,
HplMailbox,
HplTestMockHook,
} from "../contracts";
import { Context, Migration } from "../types";

@injectable()
export default class InitializeStandalone implements Migration {
Expand All @@ -18,7 +19,7 @@ export default class InitializeStandalone implements Migration {
private mailbox: HplMailbox,
private hook_merkle: HplHookMerkle,
private igp: HplIgp,
private igp_oracle: HplIgpGasOracle,
private igp_oracle: HplIgpOracle,
private ism_multisig: HplIsmMultisig,
private test_mock_hook: HplTestMockHook
) {}
Expand Down
Loading

0 comments on commit 7973533

Please sign in to comment.