Skip to content

Commit d6ecea7

Browse files
colin-axnermergify[bot]
authored andcommitted
fix: prevent blocked addresses from sending ICS 20 transfers (#1907)
* fix bug, add test Ensures that a sender account isn't a blocked address Added test cases for MsgTransfer handling * update documentation * move blocked address check to SendTransfer * add changelog entry (cherry picked from commit f891c29) # Conflicts: # modules/apps/transfer/keeper/relay_test.go
1 parent c60104f commit d6ecea7

File tree

6 files changed

+104
-2
lines changed

6 files changed

+104
-2
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
4545

4646
### State Machine Breaking
4747

48+
* (apps/transfer) [\#1907](https://github.com/cosmos/ibc-go/pull/1907) Blocked module account addresses are no longer allowed to send IBC transfers.
4849
* (apps/27-interchain-accounts) [\#1882](https://github.com/cosmos/ibc-go/pull/1882) Explicitly check length of interchain account packet data in favour of nil check.
4950

5051
### Improvements

modules/apps/transfer/keeper/msg_server.go

+1-2
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@ import (
1010

1111
var _ types.MsgServer = Keeper{}
1212

13-
// See createOutgoingPacket in spec:https://github.com/cosmos/ibc/tree/master/spec/app/ics-020-fungible-token-transfer#packet-relay
14-
1513
// Transfer defines a rpc handler method for MsgTransfer.
1614
func (k Keeper) Transfer(goCtx context.Context, msg *types.MsgTransfer) (*types.MsgTransferResponse, error) {
1715
ctx := sdk.UnwrapSDKContext(goCtx)
@@ -20,6 +18,7 @@ func (k Keeper) Transfer(goCtx context.Context, msg *types.MsgTransfer) (*types.
2018
if err != nil {
2119
return nil, err
2220
}
21+
2322
if err := k.SendTransfer(
2423
ctx, msg.SourcePort, msg.SourceChannel, msg.Token, sender, msg.Receiver, msg.TimeoutHeight, msg.TimeoutTimestamp,
2524
); err != nil {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package keeper_test
2+
3+
import (
4+
sdk "github.com/cosmos/cosmos-sdk/types"
5+
6+
"github.com/cosmos/ibc-go/v5/modules/apps/transfer/types"
7+
)
8+
9+
func (suite *KeeperTestSuite) TestMsgTransfer() {
10+
var msg *types.MsgTransfer
11+
12+
testCases := []struct {
13+
name string
14+
malleate func()
15+
expPass bool
16+
}{
17+
{
18+
"success",
19+
func() {},
20+
true,
21+
},
22+
{
23+
"invalid sender",
24+
func() {
25+
msg.Sender = "address"
26+
},
27+
false,
28+
},
29+
{
30+
"sender is a blocked address",
31+
func() {
32+
msg.Sender = suite.chainA.GetSimApp().AccountKeeper.GetModuleAddress(types.ModuleName).String()
33+
},
34+
false,
35+
},
36+
{
37+
"channel does not exist",
38+
func() {
39+
msg.SourceChannel = "channel-100"
40+
},
41+
false,
42+
},
43+
}
44+
45+
for _, tc := range testCases {
46+
suite.SetupTest()
47+
48+
path := NewTransferPath(suite.chainA, suite.chainB)
49+
suite.coordinator.Setup(path)
50+
51+
coin := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100))
52+
msg = types.NewMsgTransfer(
53+
path.EndpointA.ChannelConfig.PortID,
54+
path.EndpointA.ChannelID,
55+
coin, suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(),
56+
suite.chainB.GetTimeoutHeight(), 0, // only use timeout height
57+
)
58+
59+
tc.malleate()
60+
61+
res, err := suite.chainA.GetSimApp().TransferKeeper.Transfer(sdk.WrapSDKContext(suite.chainA.GetContext()), msg)
62+
63+
if tc.expPass {
64+
suite.Require().NoError(err)
65+
suite.Require().NotNil(res)
66+
} else {
67+
suite.Require().Error(err)
68+
suite.Require().Nil(res)
69+
}
70+
}
71+
}

modules/apps/transfer/keeper/relay.go

+6
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ import (
4848
// 4. A -> C : sender chain is sink zone. Denom upon receiving: 'C/B/denom'
4949
// 5. C -> B : sender chain is sink zone. Denom upon receiving: 'B/denom'
5050
// 6. B -> A : sender chain is sink zone. Denom upon receiving: 'denom'
51+
//
52+
// Note: An IBC Transfer must be initiated using a MsgTransfer via the Transfer rpc handler
5153
func (k Keeper) SendTransfer(
5254
ctx sdk.Context,
5355
sourcePort,
@@ -63,6 +65,10 @@ func (k Keeper) SendTransfer(
6365
return types.ErrSendDisabled
6466
}
6567

68+
if k.bankKeeper.BlockedAddr(sender) {
69+
return sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "%s is not allowed to send funds", sender)
70+
}
71+
6672
sourceChannelEnd, found := k.channelKeeper.GetChannel(ctx, sourcePort, sourceChannel)
6773
if !found {
6874
return sdkerrors.Wrapf(channeltypes.ErrChannelNotFound, "port ID (%s) channel ID (%s)", sourcePort, sourceChannel)

modules/apps/transfer/keeper/relay_test.go

+19
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ func (suite *KeeperTestSuite) TestSendTransfer() {
1919
var (
2020
amount sdk.Coin
2121
path *ibctesting.Path
22+
sender sdk.AccAddress
2223
err error
2324
)
2425

@@ -58,8 +59,21 @@ func (suite *KeeperTestSuite) TestSendTransfer() {
5859
)
5960
suite.chainA.CreateChannelCapability(suite.chainA.GetSimApp().ScopedIBCMockKeeper, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)
6061
amount = sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100))
62+
<<<<<<< HEAD
6163
}, true, false},
6264

65+
=======
66+
}, true, false,
67+
},
68+
{
69+
"transfer failed - sender account is blocked",
70+
func() {
71+
suite.coordinator.CreateTransferChannels(path)
72+
amount = sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100))
73+
sender = suite.chainA.GetSimApp().AccountKeeper.GetModuleAddress(types.ModuleName)
74+
}, true, false,
75+
},
76+
>>>>>>> f891c29 (fix: prevent blocked addresses from sending ICS 20 transfers (#1907))
6377
// createOutgoingPacket tests
6478
// - source chain
6579
{"send coin failed",
@@ -91,6 +105,7 @@ func (suite *KeeperTestSuite) TestSendTransfer() {
91105
suite.SetupTest() // reset
92106
path = NewTransferPath(suite.chainA, suite.chainB)
93107
suite.coordinator.SetupConnections(path)
108+
sender = suite.chainA.SenderAccount.GetAddress()
94109

95110
tc.malleate()
96111

@@ -118,7 +133,11 @@ func (suite *KeeperTestSuite) TestSendTransfer() {
118133

119134
err = suite.chainA.GetSimApp().TransferKeeper.SendTransfer(
120135
suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, amount,
136+
<<<<<<< HEAD
121137
suite.chainA.SenderAccount.GetAddress(), suite.chainB.SenderAccount.GetAddress().String(), clienttypes.NewHeight(0, 110), 0,
138+
=======
139+
sender, suite.chainB.SenderAccount.GetAddress().String(), suite.chainB.GetTimeoutHeight(), 0,
140+
>>>>>>> f891c29 (fix: prevent blocked addresses from sending ICS 20 transfers (#1907))
122141
)
123142

124143
if tc.expPass {

testing/chain.go

+6
Original file line numberDiff line numberDiff line change
@@ -575,3 +575,9 @@ func (chain *TestChain) GetChannelCapability(portID, channelID string) *capabili
575575

576576
return cap
577577
}
578+
579+
// GetTimeoutHeight is a convenience function which returns a IBC packet timeout height
580+
// to be used for testing. It returns the current IBC height + 100 blocks
581+
func (chain *TestChain) GetTimeoutHeight() clienttypes.Height {
582+
return clienttypes.NewHeight(clienttypes.ParseChainID(chain.ChainID), uint64(chain.GetContext().BlockHeight())+100)
583+
}

0 commit comments

Comments
 (0)