From b86a6a8ef94d2e1cd8ef1e7a44beb6aebf923330 Mon Sep 17 00:00:00 2001 From: udit-gulati Date: Thu, 2 May 2024 19:12:13 +0530 Subject: [PATCH 1/2] add hooks, metadata optional values to transferRemote in cw20 and native warps --- .gitignore | 1 + contracts/warp/cw20/src/contract.rs | 16 ++++++++++++---- contracts/warp/native/src/contract.rs | 16 ++++++++++++---- packages/interface/src/warp/cw20.rs | 2 ++ packages/interface/src/warp/native.rs | 2 ++ 5 files changed, 29 insertions(+), 8 deletions(-) diff --git a/.gitignore b/.gitignore index 1ce1d55d..eec0f302 100644 --- a/.gitignore +++ b/.gitignore @@ -40,3 +40,4 @@ context/*.config.json tmp/ dist/ node_modules/ +wasm_codes.zip \ No newline at end of file diff --git a/contracts/warp/cw20/src/contract.rs b/contracts/warp/cw20/src/contract.rs index 785be875..31268b4c 100644 --- a/contracts/warp/cw20/src/contract.rs +++ b/contracts/warp/cw20/src/contract.rs @@ -99,7 +99,9 @@ pub fn execute( dest_domain, recipient, amount, - } => transfer_remote(deps, env, info, dest_domain, recipient, amount), + hook, + metadata, + } => transfer_remote(deps, env, info, dest_domain, recipient, amount, hook, metadata), } } @@ -177,6 +179,8 @@ fn transfer_remote( dest_domain: u32, recipient: HexBinary, transfer_amount: Uint128, + hook: Option, + metadata: Option, ) -> Result { let token = TOKEN.load(deps.storage)?; let mode = MODE.load(deps.storage)?; @@ -218,8 +222,8 @@ fn transfer_remote( metadata: HexBinary::default(), } .into(), - get_hook(deps.storage)?.map(|v| v.into()), - None, + hook.clone().or(get_hook(deps.storage)?.map(|v| v.into())), + metadata.clone(), info.funds, )?); @@ -229,7 +233,9 @@ fn transfer_remote( .add_attribute("dest_domain", dest_domain.to_string()) .add_attribute("recipient", recipient.to_hex()) .add_attribute("token", token) - .add_attribute("amount", transfer_amount), + .add_attribute("amount", transfer_amount) + .add_attribute("hook", hook.unwrap_or_default()) + .add_attribute("metadata", metadata.unwrap_or_default().to_string()), )) } @@ -536,6 +542,8 @@ mod test { dest_domain: domain, recipient: recipient.clone(), amount: Uint128::new(100), + hook: None, + metadata: None, }, vec![], ); diff --git a/contracts/warp/native/src/contract.rs b/contracts/warp/native/src/contract.rs index d9181be2..6c98872e 100644 --- a/contracts/warp/native/src/contract.rs +++ b/contracts/warp/native/src/contract.rs @@ -103,7 +103,9 @@ pub fn execute( dest_domain, recipient, amount, - } => transfer_remote(deps, env, info, dest_domain, recipient, amount), + hook, + metadata, + } => transfer_remote(deps, env, info, dest_domain, recipient, amount, hook, metadata), } } @@ -190,6 +192,8 @@ fn transfer_remote( dest_domain: u32, recipient: HexBinary, transfer_amount: Uint128, + hook: Option, + metadata: Option, ) -> Result { let token = TOKEN.load(deps.storage)?; let mode = MODE.load(deps.storage)?; @@ -232,8 +236,8 @@ fn transfer_remote( dest_domain, dest_router, dispatch_payload.into(), - get_hook(deps.storage)?.map(|v| v.into()), - None, + hook.clone().or(get_hook(deps.storage)?.map(|v| v.into())), + metadata.clone(), funds, )?); @@ -242,7 +246,9 @@ fn transfer_remote( .add_attribute("sender", info.sender) .add_attribute("recipient", recipient.to_hex()) .add_attribute("token", token) - .add_attribute("amount", transfer_amount.to_string()), + .add_attribute("amount", transfer_amount.to_string()) + .add_attribute("hook", hook.unwrap_or_default()) + .add_attribute("metadata", metadata.unwrap_or_default().to_string()), )) } @@ -540,6 +546,8 @@ mod test { dest_domain, recipient: dest_recipient.clone(), amount: Uint128::new(50), + hook: None, + metadata: None, }, funds.clone(), ); diff --git a/packages/interface/src/warp/cw20.rs b/packages/interface/src/warp/cw20.rs index 914cc1fc..ff5cae61 100644 --- a/packages/interface/src/warp/cw20.rs +++ b/packages/interface/src/warp/cw20.rs @@ -58,6 +58,8 @@ pub enum ExecuteMsg { dest_domain: u32, recipient: HexBinary, amount: Uint128, + hook: Option, + metadata: Option, }, } diff --git a/packages/interface/src/warp/native.rs b/packages/interface/src/warp/native.rs index 254516e3..9e82f0b0 100644 --- a/packages/interface/src/warp/native.rs +++ b/packages/interface/src/warp/native.rs @@ -66,6 +66,8 @@ pub enum ExecuteMsg { dest_domain: u32, recipient: HexBinary, amount: Uint128, + hook: Option, + metadata: Option, }, } From b5ecd54b6dc53ff53f5d3a2d86426175e75d0dee Mon Sep 17 00:00:00 2001 From: udit-gulati Date: Fri, 3 May 2024 00:06:36 +0530 Subject: [PATCH 2/2] add custom hook addr validation; add unit tests for custom hook and custom metadata --- contracts/warp/cw20/src/contract.rs | 29 ++++++++++++++++++++------- contracts/warp/native/src/contract.rs | 26 +++++++++++++++--------- 2 files changed, 39 insertions(+), 16 deletions(-) diff --git a/contracts/warp/cw20/src/contract.rs b/contracts/warp/cw20/src/contract.rs index 31268b4c..c2f8b56c 100644 --- a/contracts/warp/cw20/src/contract.rs +++ b/contracts/warp/cw20/src/contract.rs @@ -190,6 +190,11 @@ fn transfer_remote( .route .expect("route not found"); + // validate hook if present + if let Some(ref custom_hook) = hook { + let _ = deps.api.addr_validate(&custom_hook)?; + } + let mut msgs: Vec = vec![]; // push token transfer msg @@ -298,6 +303,7 @@ mod test { const OWNER: &str = "owner"; const MAILBOX: &str = "mailbox"; const TOKEN: &str = "token"; + const CUSTOM_HOOK: &str = "custom_hook"; const CW20_BRIDGED_CODE_ID: u64 = 1; const CW20_BRIDGED_NAME: &str = "cw20-created"; @@ -515,15 +521,17 @@ mod test { } #[rstest] - #[case(1, gen_bz(32), token_mode_bridged())] - #[case(1, gen_bz(32), token_mode_collateral())] + #[case(1, gen_bz(32), token_mode_bridged(), Some(CUSTOM_HOOK), None)] + #[case(1, gen_bz(32), token_mode_collateral(), None, Some(gen_bz(100)))] #[should_panic(expected = "route not found")] - #[case(2, gen_bz(32), token_mode_collateral())] + #[case(2, gen_bz(32), token_mode_collateral(), None, None)] fn test_transfer_remote( #[values("osmo", "neutron")] hrp: &str, #[case] domain: u32, #[case] route: HexBinary, #[case] token_mode: Cw20TokenMode, + #[case] custom_hook: Option<&str>, + #[case] custom_metadata: Option, ) { let (mut deps, _) = deps( vec![(1, route.clone())], @@ -542,8 +550,8 @@ mod test { dest_domain: domain, recipient: recipient.clone(), amount: Uint128::new(100), - hook: None, - metadata: None, + hook: custom_hook.map(|h| h.to_string()), + metadata: custom_metadata.clone(), }, vec![], ); @@ -566,8 +574,15 @@ mod test { metadata: HexBinary::default(), }; - let dispatch_msg = - mailbox::dispatch(MAILBOX, domain, route, warp_msg.into(), None, None, vec![]).unwrap(); + let dispatch_msg = mailbox::dispatch( + MAILBOX, + domain, + route, + warp_msg.into(), + custom_hook.map(|h| h.to_string()), + custom_metadata, + vec![], + ).unwrap(); match token_mode { TokenModeMsg::Bridged(_) => { diff --git a/contracts/warp/native/src/contract.rs b/contracts/warp/native/src/contract.rs index 6c98872e..0981bf99 100644 --- a/contracts/warp/native/src/contract.rs +++ b/contracts/warp/native/src/contract.rs @@ -217,6 +217,11 @@ fn transfer_remote( .route .expect("route not found"); + // validate hook if present + if let Some(ref custom_hook) = hook { + let _ = deps.api.addr_validate(&custom_hook)?; + } + let mut msgs: Vec = vec![]; if mode == TokenMode::Bridged { @@ -320,6 +325,7 @@ mod test { const OWNER: &str = "owner"; const MAILBOX: &str = "mailbox"; const DENOM: &str = "utest"; + const CUSTOM_HOOK: &str = "custom_hook"; #[fixture] fn metadata(#[default(true)] empty: bool) -> Option { @@ -514,20 +520,22 @@ mod test { } #[rstest] - #[case(1, gen_bz(32), gen_bz(32), vec![coin(100, DENOM)])] - #[case(1, gen_bz(32), gen_bz(32), vec![coin(100, DENOM), coin(100, "uatom")])] + #[case(1, gen_bz(32), gen_bz(32), vec![coin(100, DENOM)], Some(CUSTOM_HOOK), None)] + #[case(1, gen_bz(32), gen_bz(32), vec![coin(100, DENOM), coin(100, "uatom")], None, Some(gen_bz(100)))] #[should_panic(expected = "route not found")] - #[case(2, gen_bz(32), gen_bz(32), vec![coin(100, DENOM)])] + #[case(2, gen_bz(32), gen_bz(32), vec![coin(100, DENOM)], None, None)] #[should_panic(expected = "no funds sent")] - #[case(1, gen_bz(32), gen_bz(32), vec![])] + #[case(1, gen_bz(32), gen_bz(32), vec![], None, None)] #[should_panic(expected = "no funds sent")] - #[case(1, gen_bz(32), gen_bz(32), vec![coin(100, "uatom")])] + #[case(1, gen_bz(32), gen_bz(32), vec![coin(100, "uatom")], None, None)] fn test_transfer_remote( mut deps: TestDeps, #[case] dest_domain: u32, #[case] dest_router: HexBinary, #[case] dest_recipient: HexBinary, #[case] funds: Vec, + #[case] custom_hook: Option<&str>, + #[case] custom_metadata: Option, ) { set_route( deps.as_mut().storage, @@ -546,8 +554,8 @@ mod test { dest_domain, recipient: dest_recipient.clone(), amount: Uint128::new(50), - hook: None, - metadata: None, + hook: custom_hook.map(|h| h.to_string()), + metadata: custom_metadata.clone(), }, funds.clone(), ); @@ -567,8 +575,8 @@ mod test { metadata: HexBinary::default(), } .into(), - None, - None, + custom_hook.map(|h| h.to_string()), + custom_metadata, [ vec![coin(50, DENOM)], funds.into_iter().filter(|v| v.denom != DENOM).collect()