@@ -19,13 +19,15 @@ import (
1919
2020// IBCTransfer performs the IBC transfer by the given params
2121func (k Keeper ) IBCTransfer (ctx sdk.Context , sender string , recipient string , token sdk.Coin , channelId string ) (uint64 , error ) {
22- clientHeight , err := k .GetClientHeight (ctx , k .IBCPortId (ctx ), channelId )
22+ portId := k .ibctransferKeeper .GetPort (ctx )
23+
24+ clientHeight , err := k .GetClientHeight (ctx , portId , channelId )
2325 if err != nil {
2426 return 0 , err
2527 }
2628
2729 msg := & transfertypes.MsgTransfer {
28- SourcePort : k . IBCPortId ( ctx ) ,
30+ SourcePort : portId ,
2931 SourceChannel : channelId ,
3032 Token : token ,
3133 Sender : sender ,
@@ -35,8 +37,20 @@ func (k Keeper) IBCTransfer(ctx sdk.Context, sender string, recipient string, to
3537 Memo : types .DefaultMemo ,
3638 }
3739
40+ // total escrow before transfer
41+ totalEscrowBefore := k .ibctransferKeeper .GetTotalEscrowForDenom (ctx , token .Denom )
42+
3843 resp , err := k .ibctransferKeeper .Transfer (ctx , msg )
3944 if err != nil {
45+ // total escrow after transfer
46+ totalEscrowAfter := k .ibctransferKeeper .GetTotalEscrowForDenom (ctx , token .Denom )
47+ if totalEscrowBefore .IsLT (totalEscrowAfter ) {
48+ // unescrow token
49+ if err := k .UnescrowToken (ctx , portId , channelId , sender , token ); err != nil {
50+ panic (err )
51+ }
52+ }
53+
4054 return 0 , err
4155 }
4256
@@ -141,6 +155,21 @@ func (k Keeper) GetClientHeight(ctx sdk.Context, sourcePort string, sourceChanne
141155 return clientState .GetLatestHeight (), nil
142156}
143157
158+ // UnescrowToken unescrows the given token from the IBC transfer module
159+ // NOTE: This method is called only if the IBC transfer failed while the token is escrowed
160+ func (k Keeper ) UnescrowToken (ctx sdk.Context , portId string , channelId string , recipient string , token sdk.Coin ) error {
161+ escrowAddress := transfertypes .GetEscrowAddress (portId , channelId )
162+ if err := k .bankKeeper .SendCoins (ctx , escrowAddress , sdk .MustAccAddressFromBech32 (recipient ), sdk .NewCoins (token )); err != nil {
163+ return errorsmod .Wrap (err , "failed to unescrow token" )
164+ }
165+
166+ currentTotalEscrow := k .ibctransferKeeper .GetTotalEscrowForDenom (ctx , token .Denom )
167+ newTotalEscrow := currentTotalEscrow .Sub (token )
168+ k .ibctransferKeeper .SetTotalEscrowForDenom (ctx , newTotalEscrow )
169+
170+ return nil
171+ }
172+
144173// IBCSendPacketCallback implements IBC callbacks
145174func (k Keeper ) IBCSendPacketCallback (
146175 ctx sdk.Context ,
0 commit comments