Skip to content

Commit 168ccc8

Browse files
committed
Change IBC unshielding fee taking mechanism
1 parent bba7ff5 commit 168ccc8

File tree

3 files changed

+132
-63
lines changed

3 files changed

+132
-63
lines changed

crates/ibc/src/context/middlewares.rs

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@ use std::collections::BTreeSet;
88
use std::fmt::Debug;
99
use std::rc::Rc;
1010

11+
use ibc::apps::transfer::context::TokenTransferExecutionContext;
12+
use ibc::apps::transfer::handler::send_transfer_execute as send_transfer_execute_base;
13+
use ibc::apps::transfer::types::error::TokenTransferError;
14+
use ibc::apps::transfer::types::msgs::transfer::MsgTransfer;
15+
use ibc::core::channel::context::SendPacketExecutionContext;
1116
use ibc::core::host::types::identifiers::PortId;
1217
use ibc::core::router::module::Module;
1318
use ibc::core::router::types::module::ModuleId;
@@ -74,3 +79,61 @@ where
7479
PortId::transfer()
7580
}
7681
}
82+
83+
/// Executes an ICS-20 token transfer.
84+
pub fn send_transfer_execute<SendPacketCtx, TokenCtx>(
85+
send_packet_ctx_a: &mut SendPacketCtx,
86+
token_ctx_a: &mut TokenCtx,
87+
msg: MsgTransfer,
88+
) -> Result<(), TokenTransferError>
89+
where
90+
SendPacketCtx: SendPacketExecutionContext,
91+
TokenCtx:
92+
TokenTransferExecutionContext + MaspUnshieldingFeesExecutionContext,
93+
{
94+
macro_rules! assemble_middlewares {
95+
($base:expr) => { $base };
96+
($head:expr, $($tail:expr),*) => { $head(assemble_middlewares!($($tail),*)) };
97+
}
98+
99+
// NOTE: exeuction order of the middlewares is from top to bottom
100+
let transfer = assemble_middlewares!(
101+
ibc_unshielding_fees_middleware,
102+
send_transfer_execute_base
103+
);
104+
105+
transfer(send_packet_ctx_a, token_ctx_a, msg)
106+
}
107+
108+
/// Context that handles ICS-20 MASP unshielding fees.
109+
pub trait MaspUnshieldingFeesExecutionContext {
110+
/// Apply a MASP unshielding fee over the given ICS-20 packet.
111+
fn apply_masp_unshielding_fee(
112+
&mut self,
113+
msg: &mut MsgTransfer,
114+
) -> Result<(), TokenTransferError>;
115+
}
116+
117+
fn ibc_unshielding_fees_middleware<Next, SendPacketCtx, TokenCtx>(
118+
next: Next,
119+
) -> impl FnOnce(
120+
&mut SendPacketCtx,
121+
&mut TokenCtx,
122+
MsgTransfer,
123+
) -> Result<(), TokenTransferError>
124+
where
125+
Next: FnOnce(
126+
&mut SendPacketCtx,
127+
&mut TokenCtx,
128+
MsgTransfer,
129+
) -> Result<(), TokenTransferError>,
130+
SendPacketCtx: SendPacketExecutionContext,
131+
TokenCtx:
132+
TokenTransferExecutionContext + MaspUnshieldingFeesExecutionContext,
133+
{
134+
|send_packet_ctx_a, token_ctx_a, mut msg| {
135+
token_ctx_a.apply_masp_unshielding_fee(&mut msg)?;
136+
137+
next(send_packet_ctx_a, token_ctx_a, msg)
138+
}
139+
}

crates/ibc/src/context/token_transfer.rs

Lines changed: 67 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ use bitflags::bitflags;
1010
use ibc::apps::transfer::context::{
1111
TokenTransferExecutionContext, TokenTransferValidationContext,
1212
};
13+
use ibc::apps::transfer::types::error::TokenTransferError;
14+
use ibc::apps::transfer::types::msgs::transfer::MsgTransfer;
1315
use ibc::apps::transfer::types::{Memo, PrefixedCoin, PrefixedDenom};
1416
use ibc::core::host::types::error::HostError;
1517
use ibc::core::host::types::identifiers::{ChannelId, PortId};
@@ -22,6 +24,7 @@ use namada_core::uint::Uint;
2224
use namada_tx::event::{MaspEvent, MaspEventKind, MaspTxRef};
2325

2426
use super::common::IbcCommonContext;
27+
use crate::context::middlewares::MaspUnshieldingFeesExecutionContext;
2528
use crate::context::storage::IbcStorageContext;
2629
use crate::storage::{load_shielding_counter, write_shielding_counter};
2730
use crate::{IBC_ESCROW_ADDRESS, IbcAccountId, trace};
@@ -245,48 +248,24 @@ where
245248
}
246249

247250
#[inline]
248-
fn maybe_handle_masp_unshielding<F>(
251+
fn maybe_handle_masp_unshielding(
249252
&self,
250253
from_account: &IbcAccountId,
251-
token: &Address,
252-
amount: &Amount,
253-
transfer: F,
254-
) -> Result<Amount, HostError>
255-
where
256-
F: FnOnce(Amount) -> Result<(), HostError>,
257-
Params:
258-
namada_systems::parameters::Read<<C as IbcStorageContext>::Storage>,
259-
{
260-
let mut amount = *amount;
254+
) -> Result<(), HostError> {
261255
let has_masp_tx = self
262256
.config
263257
.contains(TokenTransferContextConfig::HAS_MASP_TX);
264258

265-
if !has_masp_tx {
266-
return if from_account.is_transparent() {
267-
Ok(amount)
268-
} else {
269-
Err(HostError::Other {
270-
description: format!(
271-
"Set refund address {from_account} without including \
272-
an IBC unshielding MASP transaction"
273-
),
274-
})
275-
};
276-
}
277-
278-
if let Some(fee) = self.get_masp_unshielding_fee(token, &amount)? {
279-
amount =
280-
amount.checked_sub(fee).ok_or_else(|| HostError::Other {
281-
description: "Unshielding fee greater than withdrawn \
282-
amount"
283-
.to_string(),
284-
})?;
285-
286-
transfer(fee)?;
259+
if !has_masp_tx && from_account.is_shielded() {
260+
return Err(HostError::Other {
261+
description: format!(
262+
"Set refund address {from_account} without including an \
263+
IBC unshielding MASP transaction"
264+
),
265+
});
287266
}
288267

289-
Ok(amount)
268+
Ok(())
290269
}
291270

292271
fn get_masp_shielding_fee(
@@ -646,18 +625,8 @@ where
646625
} else {
647626
from_account.to_address()
648627
};
649-
let amount = self.maybe_handle_masp_unshielding(
650-
from_account,
651-
&ibc_token,
652-
&amount,
653-
|fee| {
654-
self.insert_verifier(&PGF);
655-
self.inner
656-
.borrow_mut()
657-
.transfer_token(&from_trans_account, &PGF, &ibc_token, fee)
658-
.map_err(HostError::from)
659-
},
660-
)?;
628+
629+
self.maybe_handle_masp_unshielding(from_account)?;
661630

662631
self.increment_per_epoch_withdraw_limits(&ibc_token, amount)?;
663632

@@ -776,21 +745,9 @@ where
776745
} else {
777746
account.to_address()
778747
};
779-
let amount = self.maybe_handle_masp_unshielding(
780-
account,
781-
&ibc_token,
782-
&amount,
783-
|fee| {
784-
self.insert_verifier(&PGF);
785-
self.inner
786-
.borrow_mut()
787-
.transfer_token(&trans_account, &PGF, &ibc_token, fee)
788-
.map_err(HostError::from)
789-
},
790-
)?;
791748

792-
// NOTE: update the burned amount after paying for
793-
// unshielding fees, since the fees aren't burned
749+
self.maybe_handle_masp_unshielding(account)?;
750+
794751
self.update_mint_amount(&ibc_token, amount, false)?;
795752

796753
self.increment_per_epoch_withdraw_limits(&ibc_token, amount)?;
@@ -809,3 +766,53 @@ where
809766
.map_err(HostError::from)
810767
}
811768
}
769+
770+
impl<C, Params, Token, ShieldedToken> MaspUnshieldingFeesExecutionContext
771+
for TokenTransferContext<C, Params, Token, ShieldedToken>
772+
where
773+
C: IbcCommonContext,
774+
Params: namada_systems::parameters::Read<<C as IbcStorageContext>::Storage>,
775+
{
776+
fn apply_masp_unshielding_fee(
777+
&mut self,
778+
msg: &mut MsgTransfer,
779+
) -> Result<(), TokenTransferError> {
780+
// no fee is taken if this is not a masp unshielding op
781+
let has_masp_tx = self
782+
.config
783+
.contains(TokenTransferContextConfig::HAS_MASP_TX);
784+
if !has_masp_tx {
785+
return Ok(());
786+
}
787+
788+
let (ibc_token, mut amount) = self
789+
.get_token_amount(&msg.packet_data.token)
790+
.map_err(TokenTransferError::Host)?;
791+
792+
if let Some(fee) = self
793+
.get_masp_unshielding_fee(&ibc_token, &amount)
794+
.map_err(TokenTransferError::Host)?
795+
.filter(|fee| !fee.is_zero())
796+
{
797+
amount =
798+
amount.checked_sub(fee).ok_or_else(|| HostError::Other {
799+
description: "Unshielding fee greater than withdrawn \
800+
amount"
801+
.to_string(),
802+
})?;
803+
804+
// commit the updated amount to the packet
805+
msg.packet_data.token.amount = amount.into();
806+
807+
// transfer the fee to PGF, and trigger its vp
808+
self.insert_verifier(&PGF);
809+
self.inner
810+
.borrow_mut()
811+
.transfer_token(&MASP, &PGF, &ibc_token, fee)
812+
.map_err(HostError::from)
813+
.map_err(TokenTransferError::Host)?;
814+
}
815+
816+
Ok(())
817+
}
818+
}

crates/ibc/src/lib.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,7 @@ use ibc::apps::nft_transfer::types::{
6060
TracePrefix as NftTracePrefix, ack_success_b64,
6161
is_receiver_chain_source as is_nft_receiver_chain_source,
6262
};
63-
use ibc::apps::transfer::handler::{
64-
send_transfer_execute, send_transfer_validate,
65-
};
63+
use ibc::apps::transfer::handler::send_transfer_validate;
6664
use ibc::apps::transfer::types::error::TokenTransferError;
6765
use ibc::apps::transfer::types::msgs::transfer::MsgTransfer as IbcMsgTransfer;
6866
use ibc::apps::transfer::types::{
@@ -115,6 +113,7 @@ use trace::{
115113
is_sender_chain_source,
116114
};
117115

116+
use crate::context::middlewares::send_transfer_execute;
118117
use crate::storage::{
119118
channel_counter_key, client_counter_key, connection_counter_key,
120119
deposit_prefix, nft_class_key, nft_metadata_key, withdraw_prefix,

0 commit comments

Comments
 (0)