@@ -10,6 +10,8 @@ use bitflags::bitflags;
1010use 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 ;
1315use ibc:: apps:: transfer:: types:: { Memo , PrefixedCoin , PrefixedDenom } ;
1416use ibc:: core:: host:: types:: error:: HostError ;
1517use ibc:: core:: host:: types:: identifiers:: { ChannelId , PortId } ;
@@ -22,6 +24,7 @@ use namada_core::uint::Uint;
2224use namada_tx:: event:: { MaspEvent , MaspEventKind , MaspTxRef } ;
2325
2426use super :: common:: IbcCommonContext ;
27+ use crate :: context:: middlewares:: MaspUnshieldingFeesExecutionContext ;
2528use crate :: context:: storage:: IbcStorageContext ;
2629use crate :: storage:: { load_shielding_counter, write_shielding_counter} ;
2730use 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+ }
0 commit comments