Skip to content

Commit 4f57916

Browse files
crodriguezvegachattoncharleenfei
authored
ics20-v2: backwards compatibility for transfer rpc and packet callbacks (#6189)
* chore: adding proto files for ics20-v2 * chore: add newline * chore: modify MsgTransfer to accept coins instead of coin * chore: reverted unintentional comment changes * chore: reverted unintentional comment changes * chore: adding test for conversion fn * chore: fix e2e linter * chore: adding docs * chore: addressing PR feedback * chore: remove duplicate import * chore: addressing PR feedback * chore: moved extration logic into internal package * chore: commented out failing test * chore: adding link to issue * chore: remove duplicate import * chore: fix linting errors * FungibleTokenPacketData interface methods + tests * linter * wip: token validation * update trace identifier validation in Token + tests * rm Printf * update with pr review * pr review * linter * rm unused function: linter * wip pr feedback * fix test * pr review * lintttttt * wip: backwards compatibility for transfer rpc * implement changes for ics20-v2 packet data for onRecvPacket, onAcknowledgePacket and onTimeoutPacket * fix callbacks tests * lint --------- Co-authored-by: chatton <github.qpeyb@simplelogin.fr> Co-authored-by: Charly <charly@interchain.berlin>
1 parent 9bbfa1a commit 4f57916

File tree

12 files changed

+635
-381
lines changed

12 files changed

+635
-381
lines changed

modules/apps/callbacks/ibc_middleware_test.go

Lines changed: 72 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ import (
1313
"github.com/cosmos/ibc-go/modules/apps/callbacks/testing/simapp"
1414
"github.com/cosmos/ibc-go/modules/apps/callbacks/types"
1515
icacontrollertypes "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/controller/types"
16-
transfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types"
17-
multidenom "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types/v3"
16+
transferv1types "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types"
17+
transferv3types "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types/v3"
1818
clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types"
1919
channelkeeper "github.com/cosmos/ibc-go/v8/modules/core/04-channel/keeper"
2020
channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types"
@@ -94,7 +94,7 @@ func (s *CallbacksTestSuite) TestWithICS4Wrapper() {
9494
}
9595

9696
func (s *CallbacksTestSuite) TestSendPacket() {
97-
var packetData transfertypes.FungibleTokenPacketData
97+
var packetData transferv3types.FungibleTokenPacketData
9898

9999
testCases := []struct {
100100
name string
@@ -165,9 +165,17 @@ func (s *CallbacksTestSuite) TestSendPacket() {
165165

166166
transferICS4Wrapper := GetSimApp(s.chainA).TransferKeeper.GetICS4Wrapper()
167167

168-
packetData = transfertypes.NewFungibleTokenPacketData(
169-
ibctesting.TestCoin.GetDenom(), ibctesting.TestCoin.Amount.String(), ibctesting.TestAccAddress,
170-
ibctesting.TestAccAddress, fmt.Sprintf(`{"src_callback": {"address": "%s"}}`, simapp.SuccessContract),
168+
packetData = transferv3types.NewFungibleTokenPacketData(
169+
[]*transferv3types.Token{
170+
{
171+
Denom: ibctesting.TestCoin.GetDenom(),
172+
Amount: ibctesting.TestCoin.Amount.String(),
173+
Trace: []string{},
174+
},
175+
},
176+
ibctesting.TestAccAddress,
177+
ibctesting.TestAccAddress,
178+
fmt.Sprintf(`{"src_callback": {"address": "%s"}}`, simapp.SuccessContract),
171179
)
172180

173181
chanCap := s.path.EndpointA.Chain.GetChannelCapability(s.path.EndpointA.ChannelConfig.PortID, s.path.EndpointA.ChannelID)
@@ -223,7 +231,7 @@ func (s *CallbacksTestSuite) TestOnAcknowledgementPacket() {
223231
)
224232

225233
var (
226-
packetData transfertypes.FungibleTokenPacketData
234+
packetData transferv3types.FungibleTokenPacketData
227235
packet channeltypes.Packet
228236
ack []byte
229237
ctx sdk.Context
@@ -299,8 +307,16 @@ func (s *CallbacksTestSuite) TestOnAcknowledgementPacket() {
299307
s.SetupTransferTest()
300308

301309
userGasLimit = 600000
302-
packetData = transfertypes.NewFungibleTokenPacketData(
303-
ibctesting.TestCoin.GetDenom(), ibctesting.TestCoin.Amount.String(), ibctesting.TestAccAddress, ibctesting.TestAccAddress,
310+
packetData = transferv3types.NewFungibleTokenPacketData(
311+
[]*transferv3types.Token{
312+
{
313+
Denom: ibctesting.TestCoin.GetDenom(),
314+
Amount: ibctesting.TestCoin.Amount.String(),
315+
Trace: []string{},
316+
},
317+
},
318+
ibctesting.TestAccAddress,
319+
ibctesting.TestAccAddress,
304320
fmt.Sprintf(`{"src_callback": {"address":"%s", "gas_limit":"%d"}}`, simapp.SuccessContract, userGasLimit),
305321
)
306322

@@ -323,7 +339,7 @@ func (s *CallbacksTestSuite) TestOnAcknowledgementPacket() {
323339
tc.malleate()
324340

325341
// callbacks module is routed as top level middleware
326-
transferStack, ok := s.chainA.App.GetIBCKeeper().Router.GetRoute(transfertypes.ModuleName)
342+
transferStack, ok := s.chainA.App.GetIBCKeeper().Router.GetRoute(transferv1types.ModuleName)
327343
s.Require().True(ok)
328344

329345
onAcknowledgementPacket := func() error {
@@ -385,7 +401,7 @@ func (s *CallbacksTestSuite) TestOnTimeoutPacket() {
385401
)
386402

387403
var (
388-
packetData transfertypes.FungibleTokenPacketData
404+
packetData transferv3types.FungibleTokenPacketData
389405
packet channeltypes.Packet
390406
ctx sdk.Context
391407
)
@@ -408,7 +424,7 @@ func (s *CallbacksTestSuite) TestOnTimeoutPacket() {
408424
packet.Data = []byte("invalid packet data")
409425
},
410426
noExecution,
411-
ibcerrors.ErrUnknownRequest,
427+
ibcerrors.ErrInvalidType,
412428
},
413429
{
414430
"success: no-op on callback data is not valid",
@@ -462,7 +478,7 @@ func (s *CallbacksTestSuite) TestOnTimeoutPacket() {
462478
// succeed on timeout
463479
userGasLimit := 600_000
464480
timeoutTimestamp := uint64(s.chainB.GetContext().BlockTime().UnixNano())
465-
msg := transfertypes.NewMsgTransfer(
481+
msg := transferv1types.NewMsgTransfer(
466482
s.path.EndpointA.ChannelConfig.PortID, s.path.EndpointA.ChannelID,
467483
sdk.NewCoins(ibctesting.TestCoin), s.chainA.SenderAccount.GetAddress().String(),
468484
s.chainB.SenderAccount.GetAddress().String(), clienttypes.ZeroHeight(), timeoutTimestamp,
@@ -486,7 +502,7 @@ func (s *CallbacksTestSuite) TestOnTimeoutPacket() {
486502
tc.malleate()
487503

488504
// callbacks module is routed as top level middleware
489-
transferStack, ok := s.chainA.App.GetIBCKeeper().Router.GetRoute(transfertypes.ModuleName)
505+
transferStack, ok := s.chainA.App.GetIBCKeeper().Router.GetRoute(transferv1types.ModuleName)
490506
s.Require().True(ok)
491507

492508
onTimeoutPacket := func() error {
@@ -547,7 +563,7 @@ func (s *CallbacksTestSuite) TestOnRecvPacket() {
547563
)
548564

549565
var (
550-
packetData transfertypes.FungibleTokenPacketData
566+
packetData transferv3types.FungibleTokenPacketData
551567
packet channeltypes.Packet
552568
ctx sdk.Context
553569
userGasLimit uint64
@@ -624,8 +640,16 @@ func (s *CallbacksTestSuite) TestOnRecvPacket() {
624640

625641
// set user gas limit above panic level in mock contract keeper
626642
userGasLimit = 600_000
627-
packetData = transfertypes.NewFungibleTokenPacketData(
628-
ibctesting.TestCoin.GetDenom(), ibctesting.TestCoin.Amount.String(), ibctesting.TestAccAddress, s.chainB.SenderAccount.GetAddress().String(),
643+
packetData = transferv3types.NewFungibleTokenPacketData(
644+
[]*transferv3types.Token{
645+
{
646+
Denom: ibctesting.TestCoin.GetDenom(),
647+
Amount: ibctesting.TestCoin.Amount.String(),
648+
Trace: []string{},
649+
},
650+
},
651+
ibctesting.TestAccAddress,
652+
s.chainB.SenderAccount.GetAddress().String(),
629653
fmt.Sprintf(`{"dest_callback": {"address":"%s", "gas_limit":"%d"}}`, ibctesting.TestAccAddress, userGasLimit),
630654
)
631655

@@ -646,7 +670,7 @@ func (s *CallbacksTestSuite) TestOnRecvPacket() {
646670
tc.malleate()
647671

648672
// callbacks module is routed as top level middleware
649-
transferStack, ok := s.chainB.App.GetIBCKeeper().Router.GetRoute(transfertypes.ModuleName)
673+
transferStack, ok := s.chainB.App.GetIBCKeeper().Router.GetRoute(transferv1types.ModuleName)
650674
s.Require().True(ok)
651675

652676
onRecvPacket := func() ibcexported.Acknowledgement {
@@ -701,7 +725,7 @@ func (s *CallbacksTestSuite) TestOnRecvPacket() {
701725

702726
func (s *CallbacksTestSuite) TestWriteAcknowledgement() {
703727
var (
704-
packetData transfertypes.FungibleTokenPacketData
728+
packetData transferv3types.FungibleTokenPacketData
705729
packet channeltypes.Packet
706730
ctx sdk.Context
707731
ack ibcexported.Acknowledgement
@@ -748,8 +772,16 @@ func (s *CallbacksTestSuite) TestWriteAcknowledgement() {
748772
s.SetupTransferTest()
749773

750774
// set user gas limit above panic level in mock contract keeper
751-
packetData = transfertypes.NewFungibleTokenPacketData(
752-
ibctesting.TestCoin.GetDenom(), ibctesting.TestCoin.Amount.String(), ibctesting.TestAccAddress, s.chainB.SenderAccount.GetAddress().String(),
775+
packetData = transferv3types.NewFungibleTokenPacketData(
776+
[]*transferv3types.Token{
777+
{
778+
Denom: ibctesting.TestCoin.GetDenom(),
779+
Amount: ibctesting.TestCoin.Amount.String(),
780+
Trace: []string{},
781+
},
782+
},
783+
ibctesting.TestAccAddress,
784+
s.chainB.SenderAccount.GetAddress().String(),
753785
fmt.Sprintf(`{"dest_callback": {"address":"%s", "gas_limit":"600000"}}`, ibctesting.TestAccAddress),
754786
)
755787

@@ -945,37 +977,44 @@ func (s *CallbacksTestSuite) TestUnmarshalPacketData() {
945977

946978
// We will pass the function call down the transfer stack to the transfer module
947979
// transfer stack UnmarshalPacketData call order: callbacks -> fee -> transfer
948-
transferStack, ok := s.chainA.App.GetIBCKeeper().Router.GetRoute(transfertypes.ModuleName)
980+
transferStack, ok := s.chainA.App.GetIBCKeeper().Router.GetRoute(transferv1types.ModuleName)
949981
s.Require().True(ok)
950982

951983
unmarshalerStack, ok := transferStack.(types.CallbacksCompatibleModule)
952984
s.Require().True(ok)
953985

954-
initialPacketData := transfertypes.FungibleTokenPacketData{
986+
expPacketDataICS20V1 := transferv1types.FungibleTokenPacketData{
955987
Denom: ibctesting.TestCoin.Denom,
956988
Amount: ibctesting.TestCoin.Amount.String(),
957989
Sender: ibctesting.TestAccAddress,
958990
Receiver: ibctesting.TestAccAddress,
959991
Memo: fmt.Sprintf(`{"src_callback": {"address": "%s"}, "dest_callback": {"address":"%s"}}`, ibctesting.TestAccAddress, ibctesting.TestAccAddress),
960992
}
961-
data := initialPacketData.GetBytes()
962993

963-
expPacketData := multidenom.FungibleTokenPacketData{
964-
Tokens: []*multidenom.Token{
994+
expPacketDataICS20V2 := transferv3types.FungibleTokenPacketData{
995+
Tokens: []*transferv3types.Token{
965996
{
966-
Denom: initialPacketData.Denom,
967-
Amount: initialPacketData.Amount,
968-
Trace: []string{""},
997+
Denom: ibctesting.TestCoin.Denom,
998+
Amount: ibctesting.TestCoin.Amount.String(),
999+
Trace: nil,
9691000
},
9701001
},
971-
Sender: initialPacketData.Sender,
972-
Receiver: initialPacketData.Receiver,
973-
Memo: initialPacketData.Memo,
1002+
Sender: ibctesting.TestAccAddress,
1003+
Receiver: ibctesting.TestAccAddress,
1004+
Memo: fmt.Sprintf(`{"src_callback": {"address": "%s"}, "dest_callback": {"address":"%s"}}`, ibctesting.TestAccAddress, ibctesting.TestAccAddress),
9741005
}
9751006

1007+
// Unmarshal ICS20 v1 packet data
1008+
data := expPacketDataICS20V1.GetBytes()
9761009
packetData, err := unmarshalerStack.UnmarshalPacketData(data)
9771010
s.Require().NoError(err)
978-
s.Require().Equal(expPacketData, packetData)
1011+
s.Require().Equal(expPacketDataICS20V2, packetData)
1012+
1013+
// Unmarshal ICS20 v1 packet data
1014+
data = expPacketDataICS20V2.GetBytes()
1015+
packetData, err = unmarshalerStack.UnmarshalPacketData(data)
1016+
s.Require().NoError(err)
1017+
s.Require().Equal(expPacketDataICS20V2, packetData)
9791018
}
9801019

9811020
func (s *CallbacksTestSuite) TestGetAppVersion() {

modules/apps/transfer/ibc_module.go

Lines changed: 65 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -207,10 +207,8 @@ func (im IBCModule) OnRecvPacket(
207207
logger := im.keeper.Logger(ctx)
208208
ack := channeltypes.NewResultAcknowledgement([]byte{byte(1)})
209209

210-
var data types.FungibleTokenPacketData
211-
var ackErr error
212-
if err := json.Unmarshal(packet.GetData(), &data); err != nil {
213-
ackErr = errorsmod.Wrapf(ibcerrors.ErrInvalidType, "cannot unmarshal ICS-20 transfer packet data")
210+
data, ackErr := im.unmarshalPacketDataBytesToICS20V2(packet.GetData())
211+
if ackErr != nil {
214212
logger.Error(fmt.Sprintf("%s sequence %d", ackErr.Error(), packet.Sequence))
215213
ack = channeltypes.NewErrorAcknowledgement(ackErr)
216214
}
@@ -228,26 +226,32 @@ func (im IBCModule) OnRecvPacket(
228226
}
229227
}
230228

229+
events := make([]sdk.Event, 0, len(data.Tokens)+1)
230+
for _, token := range data.Tokens {
231+
events = append(events, sdk.NewEvent(
232+
types.EventTypePacket,
233+
sdk.NewAttribute(types.AttributeKeySender, data.Sender),
234+
sdk.NewAttribute(types.AttributeKeyReceiver, data.Receiver),
235+
sdk.NewAttribute(types.AttributeKeyDenom, token.GetFullDenomPath()),
236+
sdk.NewAttribute(types.AttributeKeyAmount, token.Amount),
237+
sdk.NewAttribute(types.AttributeKeyMemo, data.Memo),
238+
))
239+
}
240+
231241
eventAttributes := []sdk.Attribute{
232242
sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName),
233-
sdk.NewAttribute(sdk.AttributeKeySender, data.Sender),
234-
sdk.NewAttribute(types.AttributeKeyReceiver, data.Receiver),
235-
sdk.NewAttribute(types.AttributeKeyDenom, data.Denom),
236-
sdk.NewAttribute(types.AttributeKeyAmount, data.Amount),
237-
sdk.NewAttribute(types.AttributeKeyMemo, data.Memo),
238243
sdk.NewAttribute(types.AttributeKeyAckSuccess, fmt.Sprintf("%t", ack.Success())),
239244
}
240-
241245
if ackErr != nil {
242246
eventAttributes = append(eventAttributes, sdk.NewAttribute(types.AttributeKeyAckError, ackErr.Error()))
243247
}
244248

245-
ctx.EventManager().EmitEvent(
246-
sdk.NewEvent(
247-
types.EventTypePacket,
248-
eventAttributes...,
249-
),
250-
)
249+
events = append(events, sdk.NewEvent(
250+
sdk.EventTypeMessage,
251+
eventAttributes...,
252+
))
253+
254+
ctx.EventManager().EmitEvents(events)
251255

252256
// NOTE: acknowledgement will be written synchronously during IBC handler execution.
253257
return ack
@@ -264,27 +268,35 @@ func (im IBCModule) OnAcknowledgementPacket(
264268
if err := types.ModuleCdc.UnmarshalJSON(acknowledgement, &ack); err != nil {
265269
return errorsmod.Wrapf(ibcerrors.ErrUnknownRequest, "cannot unmarshal ICS-20 transfer packet acknowledgement: %v", err)
266270
}
267-
var data types.FungibleTokenPacketData
268-
if err := json.Unmarshal(packet.GetData(), &data); err != nil {
269-
return errorsmod.Wrapf(ibcerrors.ErrUnknownRequest, "cannot unmarshal ICS-20 transfer packet data: %s", err.Error())
271+
272+
data, err := im.unmarshalPacketDataBytesToICS20V2(packet.GetData())
273+
if err != nil {
274+
return err
270275
}
271276

272277
if err := im.keeper.OnAcknowledgementPacket(ctx, packet, data, ack); err != nil {
273278
return err
274279
}
275280

276-
ctx.EventManager().EmitEvent(
277-
sdk.NewEvent(
278-
types.EventTypePacket,
279-
sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName),
280-
sdk.NewAttribute(sdk.AttributeKeySender, data.Sender),
281-
sdk.NewAttribute(types.AttributeKeyReceiver, data.Receiver),
282-
sdk.NewAttribute(types.AttributeKeyDenom, data.Denom),
283-
sdk.NewAttribute(types.AttributeKeyAmount, data.Amount),
284-
sdk.NewAttribute(types.AttributeKeyMemo, data.Memo),
285-
sdk.NewAttribute(types.AttributeKeyAck, ack.String()),
286-
),
287-
)
281+
events := make([]sdk.Event, 0, len(data.Tokens)+1)
282+
for _, token := range data.Tokens {
283+
ctx.EventManager().EmitEvent(
284+
sdk.NewEvent(
285+
types.EventTypePacket,
286+
sdk.NewAttribute(sdk.AttributeKeySender, data.Sender),
287+
sdk.NewAttribute(types.AttributeKeyReceiver, data.Receiver),
288+
sdk.NewAttribute(types.AttributeKeyDenom, token.GetFullDenomPath()),
289+
sdk.NewAttribute(types.AttributeKeyAmount, token.Amount),
290+
sdk.NewAttribute(types.AttributeKeyMemo, data.Memo),
291+
),
292+
)
293+
}
294+
events = append(events, sdk.NewEvent(
295+
sdk.EventTypeMessage,
296+
sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName),
297+
sdk.NewAttribute(types.AttributeKeyAck, ack.String()),
298+
))
299+
ctx.EventManager().EmitEvents(events)
288300

289301
switch resp := ack.Response.(type) {
290302
case *channeltypes.Acknowledgement_Result:
@@ -312,25 +324,34 @@ func (im IBCModule) OnTimeoutPacket(
312324
packet channeltypes.Packet,
313325
relayer sdk.AccAddress,
314326
) error {
315-
var data types.FungibleTokenPacketData
316-
if err := json.Unmarshal(packet.GetData(), &data); err != nil {
317-
return errorsmod.Wrapf(ibcerrors.ErrUnknownRequest, "cannot unmarshal ICS-20 transfer packet data: %s", err.Error())
327+
data, err := im.unmarshalPacketDataBytesToICS20V2(packet.GetData())
328+
if err != nil {
329+
return err
318330
}
331+
319332
// refund tokens
320333
if err := im.keeper.OnTimeoutPacket(ctx, packet, data); err != nil {
321334
return err
322335
}
323336

324-
ctx.EventManager().EmitEvent(
325-
sdk.NewEvent(
326-
types.EventTypeTimeout,
327-
sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName),
328-
sdk.NewAttribute(types.AttributeKeyRefundReceiver, data.Sender),
329-
sdk.NewAttribute(types.AttributeKeyRefundDenom, data.Denom),
330-
sdk.NewAttribute(types.AttributeKeyRefundAmount, data.Amount),
331-
sdk.NewAttribute(types.AttributeKeyMemo, data.Memo),
332-
),
333-
)
337+
events := make([]sdk.Event, 0, len(data.Tokens)+1)
338+
for _, token := range data.Tokens {
339+
ctx.EventManager().EmitEvent(
340+
sdk.NewEvent(
341+
types.EventTypeTimeout,
342+
sdk.NewAttribute(sdk.AttributeKeySender, data.Sender),
343+
sdk.NewAttribute(types.AttributeKeyReceiver, data.Receiver),
344+
sdk.NewAttribute(types.AttributeKeyDenom, token.GetFullDenomPath()),
345+
sdk.NewAttribute(types.AttributeKeyAmount, token.Amount),
346+
sdk.NewAttribute(types.AttributeKeyMemo, data.Memo),
347+
),
348+
)
349+
}
350+
events = append(events, sdk.NewEvent(
351+
sdk.EventTypeMessage,
352+
sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName),
353+
))
354+
ctx.EventManager().EmitEvents(events)
334355

335356
return nil
336357
}

0 commit comments

Comments
 (0)