Skip to content

Commit

Permalink
feat: default-hook (#34)
Browse files Browse the repository at this point in the history
* feat: route hook

* add .DS_Store into gitignore

* fix: whole contract without any warnings

* feat: default-hook

* [HPL-716]: apply v3 for igp and mailbox (#35)

* feat: fix existance

* feat: pass unit test for mailbox

* feat: cw-hyperlante test

* feat: add gitignore idea
  • Loading branch information
hashableric authored Sep 14, 2023
1 parent 7f9a666 commit 0dc02ce
Show file tree
Hide file tree
Showing 41 changed files with 1,050 additions and 214 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,4 @@ Cargo.lock
**/state.local.json
.idea/
.DS_Store
.idea/
38 changes: 38 additions & 0 deletions contracts/default-hook/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
[package]
name = "hpl-default-hook"
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 }
cw-storage-plus = { workspace = true }
cw2 = { workspace = true }
cw-utils = { workspace = true }
schemars = { workspace = true }
serde = { workspace = true }
thiserror = { workspace = true }
cosmwasm-schema = { workspace = true }
serde_json = { workspace = true }
serde-json-wasm = { workspace = true }

hpl-ownable = { workspace = true }
hpl-interface = { workspace = true }

[dev-dependencies]
anyhow = { workspace = true }
18 changes: 18 additions & 0 deletions contracts/default-hook/src/bin/schema.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
use std::{env::current_dir, fs::remove_dir_all};

use cosmwasm_schema::write_api;

use hpl_interface::domain_routing_hook::{ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg};

fn main() {
write_api! {
instantiate: InstantiateMsg,
migrate: MigrateMsg,
execute: ExecuteMsg,
query: QueryMsg,
}

let mut raw_dir = current_dir().unwrap();
raw_dir.push("schema");
remove_dir_all(raw_dir.join("raw")).unwrap();
}
82 changes: 82 additions & 0 deletions contracts/default-hook/src/contract.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
#[cfg(not(feature = "library"))]
use cosmwasm_std::entry_point;
use cosmwasm_std::{Binary, Deps, DepsMut, Env, MessageInfo, Response};
use cw2::set_contract_version;
use hpl_interface::default_hook::ExecuteMsg;
use hpl_interface::domain_routing_hook::{
ExecuteMsg as DomainRoutingExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg,
};

use crate::{
event::emit_instantiated,
query::{get_owner_info, get_pause_info, quote_dispatch},
state::{MAILBOX, PAUSE},
ContractError, CONTRACT_NAME, CONTRACT_VERSION,
};

#[cfg_attr(not(feature = "library"), entry_point)]
pub fn instantiate(
deps: DepsMut,
_env: Env,
_info: MessageInfo,
msg: InstantiateMsg,
) -> Result<Response, ContractError> {
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)?;
hpl_ownable::OWNER.save(deps.storage, &owner)?;
MAILBOX.save(deps.storage, &mailbox)?;
PAUSE.save(deps.storage, &false)?;

Ok(Response::new().add_event(emit_instantiated(owner, mailbox)))
}

#[cfg_attr(not(feature = "library"), entry_point)]
pub fn migrate(_deps: DepsMut, _env: Env, _msg: MigrateMsg) -> Result<Response, ContractError> {
Ok(Response::default())
}

#[cfg_attr(not(feature = "library"), entry_point)]
pub fn execute(
deps: DepsMut,
env: Env,
info: MessageInfo,
msg: ExecuteMsg,
) -> Result<Response, ContractError> {
use crate::execute::{dispatch, gov, hook};

match msg {
ExecuteMsg::DomainRoutingHookMsg(msg) => match msg {
DomainRoutingExecuteMsg::Ownership(msg) => {
Ok(hpl_ownable::handle(deps, env, info, msg)?)
}
DomainRoutingExecuteMsg::Pause {} => gov::pause(deps, env, info),
DomainRoutingExecuteMsg::Unpause {} => gov::unpause(deps, env, info),
DomainRoutingExecuteMsg::UpdateMailbox { mailbox } => {
gov::update_mailbox(deps, env, info, mailbox)
}
DomainRoutingExecuteMsg::SetHook { destination, hook } => {
hook::set_hook(deps, env, info, destination, hook)
}
DomainRoutingExecuteMsg::SetHooks { hooks } => hook::set_hooks(deps, env, info, hooks),
DomainRoutingExecuteMsg::PostDispatch { metadata, message } => {
dispatch::dispatch(deps, env, info, metadata, message)
}
},
ExecuteMsg::ConfigCustomHook {
destination_domain,
recipient,
hook,
} => hook::config_custom_hook(deps, env, info, destination_domain, recipient, hook),
}
}

#[cfg_attr(not(feature = "library"), entry_point)]
pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> Result<Binary, ContractError> {
match msg {
QueryMsg::QuoteDispatch(dispatch_msg) => quote_dispatch(deps, env, dispatch_msg),
QueryMsg::PauseInfo {} => get_pause_info(deps),
QueryMsg::Owner {} => get_owner_info(deps),
}
}
29 changes: 29 additions & 0 deletions contracts/default-hook/src/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
use cosmwasm_std::StdError;
use thiserror::Error;

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

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

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

#[error("Ownership transfer not started")]
OwnershipTransferNotStarted,

#[error("Ownership transfer already started")]
OwnershipTransferAlreadyStarted,

#[error("Paused")]
Paused {},

#[error("Not paused")]
NotPaused {},

#[error("Hook not registered for dest: {0}")]
HookNotRegistered(u32),
}
33 changes: 33 additions & 0 deletions contracts/default-hook/src/event.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
use cosmwasm_std::{Addr, Event, HexBinary};
use hpl_interface::domain_routing_hook::HookConfig;

pub fn emit_instantiated(owner: Addr, mailbox: Addr) -> Event {
Event::new("domain_routing_hook_instantiated")
.add_attribute("owner", owner.to_string())
.add_attribute("mailbox", mailbox.to_string())
}

pub fn emit_set_hook(destination: u32, hook: Addr) -> Event {
Event::new("domain_routing_hook_set_hook")
.add_attribute("destination", destination.to_string())
.add_attribute("hook", hook.to_string())
}

pub fn emit_set_hooks(hooks: Vec<HookConfig>) -> Event {
Event::new("domain_rouitng_hook_set_hooks")
.add_attribute("hooks", serde_json::to_string(&hooks).unwrap())
}

pub fn emit_post_dispatch(addr: Addr, metadata: HexBinary, message: HexBinary) -> Event {
Event::new("domain_routing_hook_post_dispatch")
.add_attribute("addr", addr.to_string())
.add_attribute("metadata", metadata.to_string())
.add_attribute("message", message.to_string())
}

pub fn emit_config_custom_hook(destination: u32, recipient: HexBinary, hook: Addr) -> Event {
Event::new("domain_routing_hook_config_custom_hook")
.add_attribute("destination", destination.to_string())
.add_attribute("recipient", recipient.to_string())
.add_attribute("hook", hook.to_string())
}
41 changes: 41 additions & 0 deletions contracts/default-hook/src/execute/dispatch.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
use cosmwasm_std::{to_binary, DepsMut, Env, HexBinary, MessageInfo, Response, WasmMsg};
use hpl_interface::types::message::Message;

use crate::{
event::emit_post_dispatch,
state::{generate_hook_key, CUSTOM_HOOK_CONFIG, HOOK_CONFIG},
ContractError,
};

pub fn dispatch(
deps: DepsMut,
_env: Env,
_info: MessageInfo,
metadata: HexBinary,
message: HexBinary,
) -> Result<Response, ContractError> {
let hpl_msg: Message = message.clone().into();
let hook_key = generate_hook_key(hpl_msg.dest_domain, hpl_msg.recipient);

let target_contract = match CUSTOM_HOOK_CONFIG.has(deps.storage, hook_key.clone()) {
true => CUSTOM_HOOK_CONFIG.load(deps.storage, hook_key)?,
false => HOOK_CONFIG
.load(deps.storage, hpl_msg.dest_domain)
.map_err(|_| ContractError::HookNotRegistered(hpl_msg.dest_domain))?,
};

let wasm_msg = WasmMsg::Execute {
contract_addr: target_contract.hook.to_string(),
msg: to_binary(
&hpl_interface::post_dispatch_hook::PostDispatchMsg::PostDispatch {
metadata: metadata.clone(),
message: message.clone(),
},
)?,
funds: vec![],
};

Ok(Response::new()
.add_message(wasm_msg)
.add_event(emit_post_dispatch(target_contract.hook, metadata, message)))
}
47 changes: 47 additions & 0 deletions contracts/default-hook/src/execute/gov.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
use cosmwasm_std::{ensure, ensure_eq, DepsMut, Env, Event, MessageInfo, Response};

use crate::{
state::{MAILBOX, PAUSE},
ContractError,
};

pub fn pause(deps: DepsMut, _env: Env, info: MessageInfo) -> Result<Response, ContractError> {
ensure_eq!(
info.sender,
hpl_ownable::OWNER.load(deps.storage)?,
ContractError::Unauthorized {}
);
ensure!(!PAUSE.load(deps.storage)?, ContractError::Paused {});

PAUSE.save(deps.storage, &true)?;
Ok(Response::new().add_event(Event::new("pause")))
}

pub fn unpause(deps: DepsMut, _env: Env, info: MessageInfo) -> Result<Response, ContractError> {
ensure_eq!(
info.sender,
hpl_ownable::OWNER.load(deps.storage)?,
ContractError::Unauthorized {}
);
ensure!(PAUSE.load(deps.storage)?, ContractError::NotPaused {});

PAUSE.save(deps.storage, &false)?;
Ok(Response::new().add_event(Event::new("unpause")))
}

pub fn update_mailbox(
deps: DepsMut,
_env: Env,
info: MessageInfo,
mailbox: String,
) -> Result<Response, ContractError> {
ensure_eq!(
info.sender,
hpl_ownable::OWNER.load(deps.storage)?,
ContractError::Unauthorized {}
);
ensure!(!PAUSE.load(deps.storage)?, ContractError::Paused {});

MAILBOX.save(deps.storage, &deps.api.addr_validate(&mailbox)?)?;
Ok(Response::new().add_event(Event::new("update-mailbox").add_attribute("mailbox", mailbox)))
}
92 changes: 92 additions & 0 deletions contracts/default-hook/src/execute/hook.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
use cosmwasm_std::{ensure, ensure_eq, DepsMut, Env, HexBinary, MessageInfo, Response};
use hpl_interface::{domain_routing_hook::HookConfig, types::keccak256_hash};

use crate::{
event::{emit_config_custom_hook, emit_set_hook, emit_set_hooks},
state::{CUSTOM_HOOK_CONFIG, HOOK_CONFIG, PAUSE},
ContractError,
};

pub fn set_hook(
deps: DepsMut,
_env: Env,
info: MessageInfo,
destination: u32,
hook_value: String,
) -> Result<Response, ContractError> {
ensure_eq!(
info.sender,
hpl_ownable::OWNER.load(deps.storage)?,
ContractError::Unauthorized {}
);
ensure!(!PAUSE.load(deps.storage)?, ContractError::Paused {});

let hook = deps.api.addr_validate(&hook_value)?;
HOOK_CONFIG.save(
deps.storage,
destination,
&HookConfig {
destination,
hook: hook.clone(),
},
)?;

Ok(Response::new().add_event(emit_set_hook(destination, hook)))
}

pub fn set_hooks(
deps: DepsMut,
_env: Env,
info: MessageInfo,
hooks: Vec<HookConfig>,
) -> Result<Response, ContractError> {
ensure_eq!(
info.sender,
hpl_ownable::OWNER.load(deps.storage)?,
ContractError::Unauthorized {}
);
ensure!(!PAUSE.load(deps.storage)?, ContractError::Paused {});

for hook in hooks.iter() {
HOOK_CONFIG.save(deps.storage, hook.destination, hook)?;
}

Ok(Response::new().add_event(emit_set_hooks(hooks)))
}

pub fn config_custom_hook(
deps: DepsMut,
_env: Env,
info: MessageInfo,
destination: u32,
recipient: HexBinary,
hook: String,
) -> Result<Response, ContractError> {
ensure_eq!(
info.sender,
hpl_ownable::OWNER.load(deps.storage)?,
ContractError::Unauthorized {}
);
ensure!(!PAUSE.load(deps.storage)?, ContractError::Paused {});

let hook_key = keccak256_hash(
destination
.to_be_bytes()
.iter()
.chain(recipient.as_slice().iter())
.cloned()
.collect::<Vec<u8>>()
.as_slice(),
);
let hook_addr = deps.api.addr_validate(&hook)?;

CUSTOM_HOOK_CONFIG.save(
deps.storage,
hook_key.to_vec(),
&HookConfig {
destination,
hook: hook_addr.clone(),
},
)?;
Ok(Response::new().add_event(emit_config_custom_hook(destination, recipient, hook_addr)))
}
3 changes: 3 additions & 0 deletions contracts/default-hook/src/execute/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pub mod dispatch;
pub mod gov;
pub mod hook;
Loading

0 comments on commit 0dc02ce

Please sign in to comment.