diff --git a/.changelog/unreleased/bug-fixes/4938-fix-refund-limit.md b/.changelog/unreleased/bug-fixes/4938-fix-refund-limit.md new file mode 100644 index 00000000000..5ad893baab7 --- /dev/null +++ b/.changelog/unreleased/bug-fixes/4938-fix-refund-limit.md @@ -0,0 +1,2 @@ +- Fix to enable the refund without per-epoch limit + ([\#4938](https://github.com/namada-net/namada/issues/4938)) \ No newline at end of file diff --git a/crates/ibc/src/context/token_transfer.rs b/crates/ibc/src/context/token_transfer.rs index 1f273c84866..d4d4b898584 100644 --- a/crates/ibc/src/context/token_transfer.rs +++ b/crates/ibc/src/context/token_transfer.rs @@ -27,6 +27,7 @@ where pub(crate) inner: Rc>, pub(crate) verifiers: Rc>>, is_shielded: bool, + is_refund: bool, } impl TokenTransferContext @@ -42,6 +43,7 @@ where inner, verifiers, is_shielded: false, + is_refund: false, } } @@ -55,6 +57,11 @@ where self.is_shielded = true; } + /// Set the transfer as refund + pub fn enable_refund_transfer(&mut self) { + self.is_refund = true; + } + fn validate_sent_coin(&self, coin: &PrefixedCoin) -> Result<(), HostError> { // The base denom should not be an IBC token address because an IBC // token address has been already encoded and other chains can't extract @@ -312,7 +319,9 @@ where ) -> Result<(), HostError> { let (ibc_token, amount) = self.get_token_amount(coin)?; - self.add_deposit(&ibc_token, amount)?; + if !self.is_refund { + self.add_deposit(&ibc_token, amount)?; + } self.inner .borrow_mut() @@ -329,7 +338,9 @@ where let (ibc_token, amount) = self.get_token_amount(coin)?; self.update_mint_amount(&ibc_token, amount, true)?; - self.add_deposit(&ibc_token, amount)?; + if !self.is_refund { + self.add_deposit(&ibc_token, amount)?; + } // A transfer of NUT tokens must be verified by their VP if ibc_token.is_internal() diff --git a/crates/ibc/src/context/transfer_mod.rs b/crates/ibc/src/context/transfer_mod.rs index 03c81e5353f..a84b61335d0 100644 --- a/crates/ibc/src/context/transfer_mod.rs +++ b/crates/ibc/src/context/transfer_mod.rs @@ -302,6 +302,7 @@ where acknowledgement: &Acknowledgement, relayer: &Signer, ) -> (ModuleExtras, Result<(), ChannelError>) { + self.ctx.enable_refund_transfer(); let (extras, result) = on_acknowledgement_packet_execute( &mut self.ctx, packet, @@ -325,6 +326,7 @@ where packet: &Packet, relayer: &Signer, ) -> (ModuleExtras, Result<(), ChannelError>) { + self.ctx.enable_refund_transfer(); let (extras, result) = on_timeout_packet_execute(&mut self.ctx, packet, relayer); (extras, result.map_err(into_channel_error)) diff --git a/crates/ibc/src/vp/mod.rs b/crates/ibc/src/vp/mod.rs index 81e0baa9e98..009376818cb 100644 --- a/crates/ibc/src/vp/mod.rs +++ b/crates/ibc/src/vp/mod.rs @@ -2909,16 +2909,8 @@ mod tests { .delete(&commitment_key) .expect("delete failed"); keys_changed.insert(commitment_key); - // deposit let data = serde_json::from_slice::(&packet.data) .expect("decoding packet data failed"); - let deposit_key = deposit_key(&nam()); - let bytes = amount.serialize_to_vec(); - let _ = state - .write_log_mut() - .write(&deposit_key, bytes) - .expect("write failed"); - keys_changed.insert(deposit_key); // event let timeout_event = TimeoutEvent { refund_receiver: data.sender, @@ -3068,16 +3060,8 @@ mod tests { .delete(&commitment_key) .expect("delete failed"); keys_changed.insert(commitment_key); - // deposit let data = serde_json::from_slice::(&packet.data) .expect("decoding packet data failed"); - let deposit_key = deposit_key(&nam()); - let bytes = amount.serialize_to_vec(); - let _ = state - .write_log_mut() - .write(&deposit_key, bytes) - .expect("write failed"); - keys_changed.insert(deposit_key); // event let timeout_event = TimeoutEvent { refund_receiver: data.sender, diff --git a/crates/tests/src/e2e/ibc_tests.rs b/crates/tests/src/e2e/ibc_tests.rs index 2e5873b4dd6..71674f2e647 100644 --- a/crates/tests/src/e2e/ibc_tests.rs +++ b/crates/tests/src/e2e/ibc_tests.rs @@ -1073,6 +1073,7 @@ fn ibc_upgrade_client() -> Result<()> { /// - Transfer 1 NAM in an epoch will succeed /// - Transfer 1 NAM in the same epoch will fail /// - Transfer 1 NAM in the next epoch will succeed +/// - Refund will succeed after sending 1 NAM /// 2. Test the mint limit /// - The mint limit is 1 /// - Receiving 2 samoleans from Gaia will fail @@ -1233,6 +1234,33 @@ fn ibc_rate_limit() -> Result<()> { epoch = get_epoch(&test, &rpc).unwrap(); } + // Send 1 Apfel from Namada to an invalid Gaia address to trigger a refund + transfer( + &test, + ALBERT, + "invalid_receiver", + APFEL, + 1, + Some(ALBERT_KEY), + &port_id_namada, + &channel_id_namada, + None, + None, + None, + None, + false, + None, + None, + )?; + // the per-epoch limit has reached but the refund should succeed + wait_for_packet_relay( + &hermes_dir, + &port_id_namada, + &channel_id_namada, + &test, + )?; + check_balance(&test, ALBERT, APFEL, 1_000_000)?; + // Transfer 2 samoleans from Gaia to Namada will succeed, but Namada can't // receive due to the mint limit and the packet will be timed out let namada_receiver = find_address(&test, ALBERT)?.to_string();