Skip to content

Commit 24b29e5

Browse files
authored
imp(transfer,rate-limiting,pfm)!: use AddressCodec instead of Bech32 (#8573)
* imp: added address codec to transfer * imp: address codec used in transfer * fix: tests * imp: test passing * imp: added addressCodec to PFM * imp: added receiver test * test: transfer cov * test: added cases * test: more cov * test: more cov * style: single line func def * test: new test works * imp: add basic test * imp: added migration guide * doc: added changelog * refactor: address codec moved
1 parent bc8d007 commit 24b29e5

File tree

25 files changed

+638
-121
lines changed

25 files changed

+638
-121
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
3737
## [Unreleased]
3838

3939
### Features
40-
40+
* [\#8573](https://github.com/cosmos/ibc-go/pull/8573) Support custom address codecs in transfer, PFM, and rate limiting.
4141
* [\#8285](https://github.com/cosmos/ibc-go/pull/8285) Packet forward middleware.
4242
* [\#8545](https://github.com/cosmos/ibc-go/pull/8545) Support sending multiple payloads in the same packet for atomic payload execution.
4343
* [\#8473](https://github.com/cosmos/ibc-go/pull/8473) Support sending v2 packets on v1 channel identifiers using aliasing.

docs/docs/05-migrations/14-v10-to-v11.md

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,41 @@ Diff examples are shown after the list of overall changes:
2424
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
2525
)
2626
```
27+
28+
The transfer module, the packet forward middleware, and the rate limiting middleware support custom address codecs. This feature is primarily added to support Cosmos EVM for IBC transfers. In a standard Cosmos SDK app, they are wired as follows:
29+
30+
```diff
31+
app.TransferKeeper = ibctransferkeeper.NewKeeper(
32+
appCodec,
33+
+ app.AccountKeeper.AddressCodec(),
34+
runtime.NewKVStoreService(keys[ibctransfertypes.StoreKey]),
35+
app.IBCKeeper.ChannelKeeper,
36+
app.MsgServiceRouter(),
37+
app.AccountKeeper, app.BankKeeper,
38+
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
39+
)
40+
```
41+
42+
```diff
43+
app.RateLimitKeeper = ratelimitkeeper.NewKeeper(
44+
appCodec,
45+
+ app.AccountKeeper.AddressCodec(),
46+
runtime.NewKVStoreService(keys[ratelimittypes.StoreKey]),
47+
app.IBCKeeper.ChannelKeeper,
48+
app.IBCKeeper.ClientKeeper,
49+
app.BankKeeper,
50+
authtypes.NewModuleAddress(govtypes.ModuleName).String()
51+
)
52+
```
53+
54+
```diff
55+
app.PFMKeeper = packetforwardkeeper.NewKeeper(
56+
appCodec,
57+
+ app.AccountKeeper.AddressCodec(),
58+
runtime.NewKVStoreService(keys[packetforwardtypes.StoreKey]),
59+
app.TransferKeeper,
60+
app.IBCKeeper.ChannelKeeper,
61+
app.BankKeeper,
62+
authtypes.NewModuleAddress(govtypes.ModuleName).String()
63+
)
64+
```

modules/apps/callbacks/testing/simapp/app.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -356,7 +356,9 @@ func NewSimApp(
356356
// Create Transfer Keeper
357357
// NOTE: the Transfer Keeper's ICS4Wrapper can later be replaced.
358358
app.TransferKeeper = ibctransferkeeper.NewKeeper(
359-
appCodec, runtime.NewKVStoreService(keys[ibctransfertypes.StoreKey]),
359+
appCodec,
360+
app.AccountKeeper.AddressCodec(),
361+
runtime.NewKVStoreService(keys[ibctransfertypes.StoreKey]),
360362
app.IBCKeeper.ChannelKeeper,
361363
app.MsgServiceRouter(),
362364
app.AccountKeeper, app.BankKeeper,

modules/apps/packet-forward-middleware/keeper/keeper.go

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77

88
"github.com/hashicorp/go-metrics"
99

10+
"cosmossdk.io/core/address"
1011
corestore "cosmossdk.io/core/store"
1112
errorsmod "cosmossdk.io/errors"
1213
"cosmossdk.io/log"
@@ -39,6 +40,7 @@ var (
3940
type Keeper struct {
4041
storeService corestore.KVStoreService
4142
cdc codec.BinaryCodec
43+
addressCodec address.Codec
4244

4345
transferKeeper types.TransferKeeper
4446
channelKeeper types.ChannelKeeper
@@ -51,9 +53,11 @@ type Keeper struct {
5153
}
5254

5355
// NewKeeper creates a new forward Keeper instance
54-
func NewKeeper(cdc codec.BinaryCodec, storeService corestore.KVStoreService, transferKeeper types.TransferKeeper, channelKeeper types.ChannelKeeper, bankKeeper types.BankKeeper, authority string) *Keeper {
56+
func NewKeeper(cdc codec.BinaryCodec, addressCodec address.Codec, storeService corestore.KVStoreService, transferKeeper types.TransferKeeper, channelKeeper types.ChannelKeeper, bankKeeper types.BankKeeper, authority string,
57+
) *Keeper {
5558
return &Keeper{
5659
cdc: cdc,
60+
addressCodec: addressCodec,
5761
storeService: storeService,
5862
transferKeeper: transferKeeper,
5963
// Defaults to using the channel keeper as the ICS4Wrapper
@@ -102,7 +106,7 @@ func (k *Keeper) moveFundsToUserRecoverableAccount(ctx sdk.Context, packet chann
102106
denom := token.GetDenom()
103107
coin := sdk.NewCoin(denom.IBCDenom(), amount)
104108

105-
userAccount, err := userRecoverableAccount(inFlightPacket)
109+
userAccount, err := k.userRecoverableAccount(inFlightPacket)
106110
if err != nil {
107111
return fmt.Errorf("failed to get user recoverable account: %w", err)
108112
}
@@ -135,11 +139,11 @@ func (k *Keeper) moveFundsToUserRecoverableAccount(ctx sdk.Context, packet chann
135139
// If the destination receiver of the original packet is a valid bech32 address for this chain, we use that address.
136140
// Otherwise, if the sender of the original packet is a valid bech32 address for another chain, we translate that address to this chain.
137141
// Note that for the fallback, the coin type of the source chain sender account must be compatible with this chain.
138-
func userRecoverableAccount(inFlightPacket *types.InFlightPacket) (sdk.AccAddress, error) {
142+
func (k *Keeper) userRecoverableAccount(inFlightPacket *types.InFlightPacket) (sdk.AccAddress, error) {
139143
var originalData transfertypes.FungibleTokenPacketData
140144
err := transfertypes.ModuleCdc.UnmarshalJSON(inFlightPacket.PacketData, &originalData)
141145
if err == nil { // if NO error
142-
sender, err := sdk.AccAddressFromBech32(originalData.Receiver)
146+
sender, err := k.addressCodec.StringToBytes(originalData.Receiver)
143147
if err == nil { // if NO error
144148
return sender, nil
145149
}

modules/apps/packet-forward-middleware/keeper/keeper_test.go

Lines changed: 78 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package keeper_test
33
import (
44
"bytes"
55
"context"
6+
"encoding/hex"
67
"fmt"
78
"testing"
89
"time"
@@ -21,6 +22,7 @@ import (
2122
clienttypes "github.com/cosmos/ibc-go/v10/modules/core/02-client/types"
2223
channeltypes "github.com/cosmos/ibc-go/v10/modules/core/04-channel/types"
2324
ibctesting "github.com/cosmos/ibc-go/v10/testing"
25+
ibcmock "github.com/cosmos/ibc-go/v10/testing/mock"
2426
)
2527

2628
type KeeperTestSuite struct {
@@ -161,70 +163,100 @@ func (s *KeeperTestSuite) TestWriteAcknowledgementForForwardedPacket() {
161163
}
162164

163165
func (s *KeeperTestSuite) TestForwardTransferPacket() {
164-
s.SetupTest()
165-
path := ibctesting.NewTransferPath(s.chainA, s.chainB)
166-
path.Setup()
167-
168-
pfmKeeper := keeper.NewKeeper(s.chainA.GetSimApp().AppCodec(), runtime.NewKVStoreService(s.chainA.GetSimApp().GetKey(pfmtypes.StoreKey)), &transferMock{}, s.chainA.GetSimApp().IBCKeeper.ChannelKeeper, s.chainA.GetSimApp().BankKeeper, "authority")
166+
var (
167+
pfmKeeper *keeper.Keeper
168+
initialSender string
169+
finalReceiver string
170+
)
171+
tests := []struct {
172+
name string
173+
malleate func()
174+
}{
175+
{
176+
name: "success: standard cosmos address",
177+
malleate: func() {},
178+
},
179+
{
180+
name: "success: with hex address codec",
181+
malleate: func() {
182+
pfmKeeper = keeper.NewKeeper(s.chainA.GetSimApp().AppCodec(), ibcmock.TestAddressCodec{}, runtime.NewKVStoreService(s.chainA.GetSimApp().GetKey(pfmtypes.StoreKey)), &transferMock{}, s.chainA.GetSimApp().IBCKeeper.ChannelKeeper, s.chainA.GetSimApp().BankKeeper, "authority")
169183

170-
ctx := s.chainA.GetContext()
171-
srcPacket := channeltypes.Packet{
172-
Data: []byte{1},
173-
Sequence: 1,
174-
SourcePort: path.EndpointA.ChannelConfig.PortID,
175-
SourceChannel: path.EndpointA.ChannelID,
176-
DestinationPort: path.EndpointB.ChannelConfig.PortID,
177-
DestinationChannel: path.EndpointB.ChannelID,
178-
TimeoutHeight: clienttypes.Height{
179-
RevisionNumber: 10,
180-
RevisionHeight: 100,
184+
initialSender = hex.EncodeToString(s.chainA.SenderAccount.GetAddress().Bytes())
185+
finalReceiver = hex.EncodeToString(s.chainB.SenderAccount.GetAddress().Bytes())
186+
},
181187
},
182-
TimeoutTimestamp: 10101001,
183188
}
184189

185-
retries := uint8(2)
186-
timeout := time.Duration(1010101010)
187-
nonRefundable := false
190+
for _, tc := range tests {
191+
s.Run(tc.name, func() {
192+
s.SetupTest()
193+
path := ibctesting.NewTransferPath(s.chainA, s.chainB)
194+
path.Setup()
188195

189-
metadata := pfmtypes.ForwardMetadata{
190-
Receiver: "first-receiver",
191-
Port: path.EndpointA.ChannelConfig.PortID,
192-
Channel: path.EndpointA.ChannelID,
193-
Timeout: timeout,
194-
Retries: &retries,
195-
Next: nil,
196-
}
196+
pfmKeeper = keeper.NewKeeper(s.chainA.GetSimApp().AppCodec(), s.chainA.GetSimApp().AccountKeeper.AddressCodec(), runtime.NewKVStoreService(s.chainA.GetSimApp().GetKey(pfmtypes.StoreKey)), &transferMock{}, s.chainA.GetSimApp().IBCKeeper.ChannelKeeper, s.chainA.GetSimApp().BankKeeper, "authority")
197197

198-
initialSender := s.chainA.SenderAccount.GetAddress()
199-
finalReceiver := s.chainB.SenderAccount.GetAddress()
198+
ctx := s.chainA.GetContext()
199+
srcPacket := channeltypes.Packet{
200+
Data: []byte{1},
201+
Sequence: 1,
202+
SourcePort: path.EndpointA.ChannelConfig.PortID,
203+
SourceChannel: path.EndpointA.ChannelID,
204+
DestinationPort: path.EndpointB.ChannelConfig.PortID,
205+
DestinationChannel: path.EndpointB.ChannelID,
206+
TimeoutHeight: clienttypes.Height{
207+
RevisionNumber: 10,
208+
RevisionHeight: 100,
209+
},
210+
TimeoutTimestamp: 10101001,
211+
}
200212

201-
err := pfmKeeper.ForwardTransferPacket(ctx, nil, srcPacket, initialSender.String(), finalReceiver.String(), metadata, sdk.NewInt64Coin("denom", 1000), 2, timeout, nil, nonRefundable)
202-
s.Require().NoError(err)
213+
retries := uint8(2)
214+
timeout := time.Duration(1010101010)
215+
nonRefundable := false
203216

204-
// Get the inflight packer
205-
inflightPacket, err := pfmKeeper.GetInflightPacket(ctx, srcPacket)
206-
s.Require().NoError(err)
217+
metadata := pfmtypes.ForwardMetadata{
218+
Receiver: "first-receiver",
219+
Port: path.EndpointA.ChannelConfig.PortID,
220+
Channel: path.EndpointA.ChannelID,
221+
Timeout: timeout,
222+
Retries: &retries,
223+
Next: nil,
224+
}
207225

208-
s.Require().Equal(inflightPacket.RetriesRemaining, int32(retries))
226+
initialSender = s.chainA.SenderAccount.GetAddress().String()
227+
finalReceiver = s.chainB.SenderAccount.GetAddress().String()
209228

210-
// Call the same function again with inflight packet. Num retries should decrease.
211-
err = pfmKeeper.ForwardTransferPacket(ctx, inflightPacket, srcPacket, initialSender.String(), finalReceiver.String(), metadata, sdk.NewInt64Coin("denom", 1000), 2, timeout, nil, nonRefundable)
212-
s.Require().NoError(err)
229+
tc.malleate()
213230

214-
// Get the inflight packer
215-
inflightPacket2, err := pfmKeeper.GetInflightPacket(ctx, srcPacket)
216-
s.Require().NoError(err)
231+
err := pfmKeeper.ForwardTransferPacket(ctx, nil, srcPacket, initialSender, finalReceiver, metadata, sdk.NewInt64Coin("denom", 1000), 2, timeout, nil, nonRefundable)
232+
s.Require().NoError(err)
217233

218-
s.Require().Equal(inflightPacket.RetriesRemaining, inflightPacket2.RetriesRemaining)
219-
s.Require().Equal(int32(retries-1), inflightPacket.RetriesRemaining)
234+
// Get the inflight packer
235+
inflightPacket, err := pfmKeeper.GetInflightPacket(ctx, srcPacket)
236+
s.Require().NoError(err)
237+
238+
s.Require().Equal(inflightPacket.RetriesRemaining, int32(retries))
239+
240+
// Call the same function again with inflight packet. Num retries should decrease.
241+
err = pfmKeeper.ForwardTransferPacket(ctx, inflightPacket, srcPacket, initialSender, finalReceiver, metadata, sdk.NewInt64Coin("denom", 1000), 2, timeout, nil, nonRefundable)
242+
s.Require().NoError(err)
243+
244+
// Get the inflight packer
245+
inflightPacket2, err := pfmKeeper.GetInflightPacket(ctx, srcPacket)
246+
s.Require().NoError(err)
247+
248+
s.Require().Equal(inflightPacket.RetriesRemaining, inflightPacket2.RetriesRemaining)
249+
s.Require().Equal(int32(retries-1), inflightPacket.RetriesRemaining)
250+
})
251+
}
220252
}
221253

222254
func (s *KeeperTestSuite) TestForwardTransferPacketWithNext() {
223255
s.SetupTest()
224256
path := ibctesting.NewTransferPath(s.chainA, s.chainB)
225257
path.Setup()
226258

227-
pfmKeeper := keeper.NewKeeper(s.chainA.GetSimApp().AppCodec(), runtime.NewKVStoreService(s.chainA.GetSimApp().GetKey(pfmtypes.StoreKey)), &transferMock{}, s.chainA.GetSimApp().IBCKeeper.ChannelKeeper, s.chainA.GetSimApp().BankKeeper, "authority")
259+
pfmKeeper := keeper.NewKeeper(s.chainA.GetSimApp().AppCodec(), s.chainA.GetSimApp().AccountKeeper.AddressCodec(), runtime.NewKVStoreService(s.chainA.GetSimApp().GetKey(pfmtypes.StoreKey)), &transferMock{}, s.chainA.GetSimApp().IBCKeeper.ChannelKeeper, s.chainA.GetSimApp().BankKeeper, "authority")
228260
ctx := s.chainA.GetContext()
229261
srcPacket := channeltypes.Packet{
230262
Data: []byte{1},
@@ -283,7 +315,7 @@ func (s *KeeperTestSuite) TestRetryTimeoutErrorGettingNext() {
283315
path := ibctesting.NewTransferPath(s.chainA, s.chainB)
284316
path.Setup()
285317

286-
pfmKeeper := keeper.NewKeeper(s.chainA.GetSimApp().AppCodec(), runtime.NewKVStoreService(s.chainA.GetSimApp().GetKey(pfmtypes.StoreKey)), &transferMock{}, s.chainA.GetSimApp().IBCKeeper.ChannelKeeper, s.chainA.GetSimApp().BankKeeper, "authority")
318+
pfmKeeper := keeper.NewKeeper(s.chainA.GetSimApp().AppCodec(), s.chainA.GetSimApp().AccountKeeper.AddressCodec(), runtime.NewKVStoreService(s.chainA.GetSimApp().GetKey(pfmtypes.StoreKey)), &transferMock{}, s.chainA.GetSimApp().IBCKeeper.ChannelKeeper, s.chainA.GetSimApp().BankKeeper, "authority")
287319
ctx := s.chainA.GetContext()
288320

289321
// Create a transfer detail with invalid memo that will cause GetPacketMetadataFromPacketdata to fail

modules/apps/rate-limiting/keeper/keeper.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"fmt"
66
"strings"
77

8+
"cosmossdk.io/core/address"
89
corestore "cosmossdk.io/core/store"
910
"cosmossdk.io/log"
1011

@@ -19,6 +20,7 @@ import (
1920
type Keeper struct {
2021
storeService corestore.KVStoreService
2122
cdc codec.BinaryCodec
23+
addressCodec address.Codec
2224

2325
ics4Wrapper porttypes.ICS4Wrapper
2426
channelKeeper types.ChannelKeeper
@@ -29,13 +31,14 @@ type Keeper struct {
2931
}
3032

3133
// NewKeeper creates a new rate-limiting Keeper instance
32-
func NewKeeper(cdc codec.BinaryCodec, storeService corestore.KVStoreService, channelKeeper types.ChannelKeeper, clientKeeper types.ClientKeeper, bankKeeper types.BankKeeper, authority string) *Keeper {
34+
func NewKeeper(cdc codec.BinaryCodec, addressCodec address.Codec, storeService corestore.KVStoreService, channelKeeper types.ChannelKeeper, clientKeeper types.ClientKeeper, bankKeeper types.BankKeeper, authority string) *Keeper {
3335
if strings.TrimSpace(authority) == "" {
3436
panic(errors.New("authority must be non-empty"))
3537
}
3638

3739
return &Keeper{
3840
cdc: cdc,
41+
addressCodec: addressCodec,
3942
storeService: storeService,
4043
// Defaults to using the channel keeper as the ICS4Wrapper
4144
// This can be overridden later with WithICS4Wrapper (e.g. by the middleware stack wiring)

modules/apps/rate-limiting/keeper/keeper_test.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"github.com/cosmos/ibc-go/v10/modules/apps/rate-limiting/keeper"
1111
ratelimittypes "github.com/cosmos/ibc-go/v10/modules/apps/rate-limiting/types"
1212
ibctesting "github.com/cosmos/ibc-go/v10/testing"
13+
ibcmock "github.com/cosmos/ibc-go/v10/testing/mock"
1314
)
1415

1516
type KeeperTestSuite struct {
@@ -44,6 +45,22 @@ func (s *KeeperTestSuite) TestNewKeeper() {
4445
instantiateFn: func() {
4546
keeper.NewKeeper(
4647
s.chainA.GetSimApp().AppCodec(),
48+
s.chainA.GetSimApp().AccountKeeper.AddressCodec(),
49+
runtime.NewKVStoreService(s.chainA.GetSimApp().GetKey(ratelimittypes.StoreKey)),
50+
s.chainA.GetSimApp().IBCKeeper.ChannelKeeper,
51+
s.chainA.GetSimApp().IBCKeeper.ClientKeeper, // Add clientKeeper
52+
s.chainA.GetSimApp().BankKeeper,
53+
s.chainA.GetSimApp().ICAHostKeeper.GetAuthority(),
54+
)
55+
},
56+
panicMsg: "",
57+
},
58+
{
59+
name: "success: custom address codec",
60+
instantiateFn: func() {
61+
keeper.NewKeeper(
62+
s.chainA.GetSimApp().AppCodec(),
63+
ibcmock.TestAddressCodec{},
4764
runtime.NewKVStoreService(s.chainA.GetSimApp().GetKey(ratelimittypes.StoreKey)),
4865
s.chainA.GetSimApp().IBCKeeper.ChannelKeeper,
4966
s.chainA.GetSimApp().IBCKeeper.ClientKeeper, // Add clientKeeper
@@ -58,6 +75,7 @@ func (s *KeeperTestSuite) TestNewKeeper() {
5875
instantiateFn: func() {
5976
keeper.NewKeeper(
6077
s.chainA.GetSimApp().AppCodec(),
78+
s.chainA.GetSimApp().AccountKeeper.AddressCodec(),
6179
runtime.NewKVStoreService(s.chainA.GetSimApp().GetKey(ratelimittypes.StoreKey)),
6280
s.chainA.GetSimApp().IBCKeeper.ChannelKeeper,
6381
s.chainA.GetSimApp().IBCKeeper.ClientKeeper, // clientKeeper

0 commit comments

Comments
 (0)