Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
- Allow bech32 encoding of MASP address in shielded receive middleware.
([\#4722](https://github.com/anoma/namada/pull/4722))
47 changes: 34 additions & 13 deletions crates/ibc/src/context/middlewares/shielded_recv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ use ibc_middleware_module::MiddlewareModule;
use ibc_middleware_module_macros::from_middleware;
use ibc_middleware_overflow_receive::OverflowRecvContext;
use ibc_middleware_packet_forward::PacketForwardMiddleware;
use namada_core::address::{Address, MASP, MULTITOKEN};
use namada_core::address::{Address, InternalAddress, MULTITOKEN};
use namada_core::token;
use serde_json::{Map, Value};

Expand Down Expand Up @@ -127,21 +127,42 @@ where
return self.next.on_recv_packet_execute(packet, relayer);
};

if data.receiver.as_ref() != MASP.to_string() {
let ack = AcknowledgementStatus::error(
AckStatusValue::new(format!(
"Shielded receive error: Address {:?} is not the MASP",
data.receiver.as_ref()
))
.expect("Ack is not empty"),
);
return (ModuleExtras::empty(), Some(ack.into()));
}

// NB: add shielded receiver as a tx verifier, since we
// have confirmed this packet should be handled by the
// shielded recv middleware
self.insert_verifier(memo.namada.osmosis_swap.overflow_receiver);

// NB: probably not needed to add the multitoken as a verifier
// again, but we do it anyway, for good measure
self.insert_verifier(MULTITOKEN);

self.next.on_recv_packet_execute(packet, relayer)
let result: Result<Address, _> = data.receiver.as_ref().parse();
match result {
Err(err) => {
let ack = AcknowledgementStatus::error(
AckStatusValue::new(format!(
"Address {:?} is not the MASP: Failed to parse MASP \
address: {err}",
data.receiver.as_ref()
))
.expect("Ack is not empty"),
);
(ModuleExtras::empty(), Some(ack.into()))
}
Ok(Address::Internal(InternalAddress::Masp)) => {
self.next.on_recv_packet_execute(packet, relayer)
}
Ok(addr) => {
let ack = AcknowledgementStatus::error(
AckStatusValue::new(format!(
"Shielded receive error: Address {addr} is not the \
MASP",
))
.expect("Ack is not empty"),
);
(ModuleExtras::empty(), Some(ack.into()))
}
}
}
}

Expand Down
111 changes: 66 additions & 45 deletions crates/tests/src/e2e/ibc_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2080,65 +2080,86 @@ fn ibc_shielded_recv_middleware_happy_flow() -> Result<()> {
let hermes = run_hermes(&hermes_dir)?;
let _bg_hermes = hermes.background();

// 1. Shield 10 NAM to AA_PAYMENT_ADDRESS
// 1. Shield 20 NAM to AA_PAYMENT_ADDRESS
transfer_on_chain(
&test,
"shield",
ALBERT,
AA_PAYMENT_ADDRESS,
NAM,
10,
20,
ALBERT_KEY,
&[],
)?;
check_shielded_balance(&test, AA_VIEWING_KEY, NAM, 10)?;
check_shielded_balance(&test, AA_VIEWING_KEY, NAM, 20)?;

// 2. Unshield from A_SPENDING_KEY to B_SPENDING_KEY,
// using the packet forward and shielded receive
// middlewares
let nam_addr = find_address(&test, NAM)?;
let overflow_addr = "tnam1qrqzqa0l0rzzrlr20n487l6n865t8ndv6uhseulq";
let ibc_denom_on_gaia = format!("transfer/{channel_id_gaia}/{nam_addr}");
let memo_path = gen_ibc_shielding_data(
&test,
AB_PAYMENT_ADDRESS,
&ibc_denom_on_gaia,
8,
&port_id_namada,
&channel_id_namada,
)?;
let memo = packet_forward_memo(
MASP.to_string().into(),
&PortId::transfer(),
&channel_id_namada,
None,
Some(shielded_recv_memo_value(
&memo_path,
Amount::native_whole(8),
overflow_addr.parse().unwrap(),
)),
);
transfer(
&test,
A_SPENDING_KEY,
"PacketForwardMiddleware",
NAM,
10,
Some(ALBERT_KEY),
&PortId::transfer(),
&channel_id_namada,
None,
None,
None,
Some(&memo),
true,
)?;
wait_for_packet_relay(&hermes_dir, &port_id_gaia, &channel_id_gaia, &test)?;
for iter in 1..=2u64 {
let nam_addr = find_address(&test, NAM)?;
let overflow_addr = "tnam1qrqzqa0l0rzzrlr20n487l6n865t8ndv6uhseulq";
let ibc_denom_on_gaia =
format!("transfer/{channel_id_gaia}/{nam_addr}");
let memo_path = gen_ibc_shielding_data(
&test,
AB_PAYMENT_ADDRESS,
&ibc_denom_on_gaia,
8,
&port_id_namada,
&channel_id_namada,
)?;
let masp_receiver = match iter {
// Test addresses encoded using `bech32m`...
1 => MASP.encode(),
// ...as well as addresses encoded using `bech32`
2 => {
let bech32 = "tnam1pcqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqh8f9c4";
let addr: namada_core::address::Address =
bech32.parse().unwrap();
assert_eq!(addr, MASP);
bech32.to_owned()
}
_ => unreachable!("there are only 2 iters"),
};
let memo = packet_forward_memo(
masp_receiver.into(),
&PortId::transfer(),
&channel_id_namada,
None,
Some(shielded_recv_memo_value(
&memo_path,
Amount::native_whole(8),
overflow_addr.parse().unwrap(),
)),
);
transfer(
&test,
A_SPENDING_KEY,
"PacketForwardMiddleware",
NAM,
10,
Some(ALBERT_KEY),
&PortId::transfer(),
&channel_id_namada,
None,
None,
None,
Some(&memo),
true,
)?;
wait_for_packet_relay(
&hermes_dir,
&port_id_gaia,
&channel_id_gaia,
&test,
)?;

// Check the token on Namada
check_shielded_balance(&test, AA_VIEWING_KEY, NAM, 0)?;
check_shielded_balance(&test, AB_VIEWING_KEY, NAM, 8)?;
check_balance(&test, overflow_addr, NAM, 2)?;
// Check the token on Namada
check_shielded_balance(&test, AA_VIEWING_KEY, NAM, 20 - iter * 10)?;
check_shielded_balance(&test, AB_VIEWING_KEY, NAM, 8 * iter)?;
check_balance(&test, overflow_addr, NAM, 2 * iter)?;
}

Ok(())
}
Expand Down
Loading