Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions x/ibc/transfer/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ type Keeper struct {
bankKeeper types.BankKeeper
erc20Keeper types.ERC20Keeper
accountKeeper types.AccountKeeper

ics4Wrapper porttypes.ICS4Wrapper
scopedKeeper capabilitykeeper.ScopedKeeper
}

// NewKeeper creates a new IBC transfer Keeper instance
Expand Down Expand Up @@ -54,5 +57,7 @@ func NewKeeper(
bankKeeper: bankKeeper,
erc20Keeper: erc20Keeper,
accountKeeper: accountKeeper,
ics4Wrapper: ics4Wrapper,
scopedKeeper: scopedKeeper,
}
}
4 changes: 4 additions & 0 deletions x/ibc/transfer/keeper/msg_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ func (k Keeper) Transfer(goCtx context.Context, msg *types.MsgTransfer) (*types.
WithTransientKVGasConfig(transientKVGasCfg)
}()

if msg.Sender == k.GetAuthority() {
return k.forceIBCTransfer(ctx, msg)
}

// use native denom or contract address
denom := strings.TrimPrefix(msg.Token.Denom, erc20types.ModuleName+"/")

Expand Down
22 changes: 22 additions & 0 deletions x/ibc/transfer/keeper/msg_server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ func (suite *KeeperTestSuite) TestTransfer() {
mockChannelKeeper.On("GetChannel", mock.Anything, mock.Anything, mock.Anything).Return(channeltypes.Channel{Counterparty: channeltypes.NewCounterparty("transfer", "channel-1")}, true)
mockICS4Wrapper.On("SendPacket", mock.Anything, mock.Anything, mock.Anything).Return(nil)
authAddr := authtypes.NewModuleAddress(govtypes.ModuleName).String()
denomTrace := types.ParseDenomTrace("transfer/channel-0/uatom")

testCases := []struct {
name string
Expand Down Expand Up @@ -279,6 +280,26 @@ func (suite *KeeperTestSuite) TestTransfer() {
},
false,
},
{
"error - invalid ibc denom (sudo)",
func() *types.MsgTransfer {
denom := "aevmos"
sender := authAddr
transferMsg := types.NewMsgTransfer("transfer", "channel-0", sdk.NewCoin(denom, math.NewInt(10)), sender, "", timeoutHeight, 0, "")
return transferMsg
},
false,
},
{
"pass - valid transfer (sudo)",
func() *types.MsgTransfer {
denom := denomTrace.IBCDenom()
sender := authAddr
transferMsg := types.NewMsgTransfer("transfer", "channel-0", sdk.NewCoin(denom, math.NewInt(10)), sender, "", timeoutHeight, 0, "")
return transferMsg
},
true,
},
}
for _, tc := range testCases {
suite.Run(fmt.Sprintf("Case %s", tc.name), func() {
Expand All @@ -294,6 +315,7 @@ func (suite *KeeperTestSuite) TestTransfer() {
suite.network.App.Erc20Keeper, // Add ERC20 Keeper for ERC20 transfers
authAddr,
)
suite.network.App.TransferKeeper.SetDenomTrace(ctx, denomTrace)
msg := tc.malleate()

// get updated context with the latest changes
Expand Down
44 changes: 44 additions & 0 deletions x/ibc/transfer/keeper/sudo_ibc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package keeper

import (
"strings"

errorsmod "cosmossdk.io/errors"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types"
host "github.com/cosmos/ibc-go/v8/modules/core/24-host"

"github.com/cosmos/ibc-go/v8/modules/apps/transfer/types"
)

func (k Keeper) forceIBCTransfer(ctx sdk.Context, msg *types.MsgTransfer) (*types.MsgTransferResponse, error) {
if !strings.HasPrefix(msg.Token.Denom, "ibc/") {
return nil, sdkerrors.ErrInvalidCoins.Wrap(
"only remote tokens (ibc/..) are allowed",
)
}

fullDenomPath, err := k.DenomPathFromHash(ctx, msg.Token.Denom)
if err != nil {
return nil, errorsmod.Wrapf(
err, "failed to found denom path: %s", msg.Token.Denom,
)
}

channelCap, ok := k.scopedKeeper.GetCapability(ctx, host.ChannelCapabilityPath(msg.SourcePort, msg.SourceChannel))
if !ok {
return nil, errorsmod.Wrap(channeltypes.ErrChannelCapabilityNotFound, "module does not own channel capability")
}

packetData := types.NewFungibleTokenPacketData(
fullDenomPath, msg.Token.Amount.String(), msg.Sender, msg.Receiver, msg.Memo,
)

sequence, err := k.ics4Wrapper.SendPacket(ctx, channelCap, msg.SourcePort, msg.SourceChannel, msg.TimeoutHeight, msg.TimeoutTimestamp, packetData.GetBytes())
if err != nil {
return nil, err
}

return &types.MsgTransferResponse{Sequence: sequence}, nil
}
Loading