Skip to content

Commit

Permalink
Merge pull request #482 from ComposableFi/rustdev/cosmos-fee
Browse files Browse the repository at this point in the history
implement custom transfer method for ibc transfer wrapper keeper.
  • Loading branch information
RustNinja authored Apr 3, 2024
2 parents b2e0660 + fd055bc commit 43239c4
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 3 deletions.
7 changes: 4 additions & 3 deletions app/keepers/keepers.go
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,7 @@ func (appKeepers *AppKeepers) InitNormalKeepers(
appKeepers.GetSubspace(transfermiddlewaretypes.ModuleName),
appCodec,
&appKeepers.RatelimitKeeper,
&appKeepers.TransferKeeper.Keeper,
&appKeepers.TransferKeeper,
appKeepers.BankKeeper,
authorityAddress,
)
Expand All @@ -319,7 +319,7 @@ func (appKeepers *AppKeepers) InitNormalKeepers(
appCodec,
appKeepers.keys[routertypes.StoreKey],
appKeepers.GetSubspace(routertypes.ModuleName),
appKeepers.TransferKeeper.Keeper,
appKeepers.TransferKeeper,
appKeepers.IBCKeeper.ChannelKeeper,
&appKeepers.DistrKeeper,
appKeepers.BankKeeper,
Expand All @@ -337,6 +337,7 @@ func (appKeepers *AppKeepers) InitNormalKeepers(
appKeepers.BankKeeper,
appKeepers.ScopedTransferKeeper,
&appKeepers.IbcTransferMiddlewareKeeper,
&appKeepers.BankKeeper,
)

appKeepers.RouterKeeper.SetTransferKeeper(appKeepers.TransferKeeper)
Expand Down Expand Up @@ -408,7 +409,7 @@ func (appKeepers *AppKeepers) InitNormalKeepers(
appKeepers.IBCKeeper.ChannelKeeper,
&appKeepers.IBCKeeper.PortKeeper,
appKeepers.ScopedWasmKeeper,
appKeepers.TransferKeeper.Keeper,
appKeepers.TransferKeeper,
bApp.MsgServiceRouter(),
bApp.GRPCQueryRouter(),
wasmDir,
Expand Down
79 changes: 79 additions & 0 deletions custom/ibc-transfer/keeper/keeper.go
Original file line number Diff line number Diff line change
@@ -1,21 +1,28 @@
package keeper

import (
"context"
"fmt"
"time"

"github.com/cosmos/cosmos-sdk/codec"
ibctransferkeeper "github.com/cosmos/ibc-go/v7/modules/apps/transfer/keeper"

storetypes "github.com/cosmos/cosmos-sdk/store/types"
sdk "github.com/cosmos/cosmos-sdk/types"
paramtypes "github.com/cosmos/cosmos-sdk/x/params/types"
"github.com/cosmos/ibc-go/v7/modules/apps/transfer/types"
porttypes "github.com/cosmos/ibc-go/v7/modules/core/05-port/types"
"github.com/cosmos/ibc-go/v7/modules/core/exported"
custombankkeeper "github.com/notional-labs/composable/v6/custom/bank/keeper"
ibctransfermiddleware "github.com/notional-labs/composable/v6/x/ibctransfermiddleware/keeper"
)

type Keeper struct {
ibctransferkeeper.Keeper
cdc codec.BinaryCodec
IbcTransfermiddleware *ibctransfermiddleware.Keeper
bank *custombankkeeper.Keeper
}

func NewKeeper(
Expand All @@ -29,11 +36,83 @@ func NewKeeper(
bk types.BankKeeper,
scopedKeeper exported.ScopedKeeper,
ibcTransfermiddleware *ibctransfermiddleware.Keeper,
bankKeeper *custombankkeeper.Keeper,
) Keeper {
keeper := Keeper{
Keeper: ibctransferkeeper.NewKeeper(cdc, key, paramSpace, ics4Wrapper, channelKeeper, portKeeper, authKeeper, bk, scopedKeeper),
IbcTransfermiddleware: ibcTransfermiddleware,
cdc: cdc,
bank: bankKeeper,
}
return keeper
}

// Transfer is the server API around the Transfer method of the IBC transfer module.
// It checks if the sender is allowed to transfer the token and if the channel has fees.
// If the channel has fees, it will charge the sender and send the fees to the fee address.
// If the sender is not allowed to transfer the token because this tokens does not exists in the allowed tokens list, it just return without doing anything.
// If the sender is allowed to transfer the token, it will call the original transfer method.
// If the transfer amount is less than the minimum fee, it will charge the full transfer amount.
// If the transfer amount is greater than the minimum fee, it will charge the minimum fee and the percentage fee.
func (k Keeper) Transfer(goCtx context.Context, msg *types.MsgTransfer) (*types.MsgTransferResponse, error) {
ctx := sdk.UnwrapSDKContext(goCtx)
params := k.IbcTransfermiddleware.GetParams(ctx)
if params.ChannelFees != nil && len(params.ChannelFees) > 0 {
channelFee := findChannelParams(params.ChannelFees, msg.SourceChannel)
if channelFee != nil {
if channelFee.MinTimeoutTimestamp > 0 {

goCtx := sdk.UnwrapSDKContext(goCtx)
blockTime := goCtx.BlockTime()

timeoutTimeInFuture := time.Unix(0, int64(msg.TimeoutTimestamp))
if timeoutTimeInFuture.Before(blockTime) {
return nil, fmt.Errorf("incorrect timeout timestamp found during ibc transfer. timeout timestamp is in the past")
}

difference := timeoutTimeInFuture.Sub(blockTime).Nanoseconds()
if difference < channelFee.MinTimeoutTimestamp {
return nil, fmt.Errorf("incorrect timeout timestamp found during ibc transfer. too soon")
}
}
coin := findCoinByDenom(channelFee.AllowedTokens, msg.Token.Denom)
if coin == nil {
return nil, fmt.Errorf("token not allowed to be transferred in this channel")
}
minFee := coin.MinFee.Amount
charge := minFee
if charge.GT(msg.Token.Amount) {
charge = msg.Token.Amount
}

newAmount := msg.Token.Amount.Sub(charge)

if newAmount.IsPositive() {
percentageCharge := newAmount.QuoRaw(coin.Percentage)
newAmount = newAmount.Sub(percentageCharge)
charge = charge.Add(percentageCharge)
}

msgSender, err := sdk.AccAddressFromBech32(msg.Sender)
if err != nil {
return nil, err
}

feeAddress, err := sdk.AccAddressFromBech32(channelFee.FeeAddress)
if err != nil {
return nil, err
}

send_err := k.bank.SendCoins(ctx, msgSender, feeAddress, sdk.NewCoins(sdk.NewCoin(msg.Token.Denom, charge)))
if send_err != nil {
return nil, send_err
}

if newAmount.LTE(sdk.ZeroInt()) {
return &types.MsgTransferResponse{}, nil
}
msg.Token.Amount = newAmount
}
}
return k.Keeper.Transfer(goCtx, msg)
}

0 comments on commit 43239c4

Please sign in to comment.