Skip to content

Commit 68a4941

Browse files
authored
Merge pull request #42 from sei-protocol/ibc-port-1
Port ibc PR
2 parents c42136a + 0799ebb commit 68a4941

File tree

6 files changed

+432
-5
lines changed

6 files changed

+432
-5
lines changed

.github/workflows/test.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ jobs:
2121
- uses: actions/checkout@v4
2222
- uses: actions/setup-go@v4
2323
with:
24-
go-version: 1.18
24+
go-version: 1.21
2525
- uses: technote-space/get-diff-action@v6.1.0
2626
id: git_diff
2727
with:
@@ -69,7 +69,7 @@ jobs:
6969
- uses: actions/checkout@v4
7070
- uses: actions/setup-go@v4
7171
with:
72-
go-version: 1.18
72+
go-version: 1.21
7373
- uses: technote-space/get-diff-action@v6.1.0
7474
with:
7575
PATTERNS: |

modules/apps/transfer/ibc_module.go

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package transfer
22

33
import (
4+
"bytes"
45
"fmt"
56
"math"
67

@@ -218,7 +219,10 @@ func (im IBCModule) OnAcknowledgementPacket(
218219
if err := types.ModuleCdc.UnmarshalJSON(packet.GetData(), &data); err != nil {
219220
return sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "cannot unmarshal ICS-20 transfer packet data: %s", err.Error())
220221
}
221-
222+
bz := types.ModuleCdc.MustMarshalJSON(&ack)
223+
if !bytes.Equal(bz, acknowledgement) {
224+
return sdkerrors.Wrapf(sdkerrors.ErrInvalidType, "acknowledgement did not marshal to expected bytes: %X ≠ %X", bz, acknowledgement)
225+
}
222226
if err := im.keeper.OnAcknowledgementPacket(ctx, packet, data, ack); err != nil {
223227
return err
224228
}

modules/apps/transfer/ibc_module_test.go

+343
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
package transfer_test
22

33
import (
4+
"errors"
45
"math"
56

7+
sdk "github.com/cosmos/cosmos-sdk/types"
8+
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
9+
"github.com/cosmos/ibc-go/v3/modules/core/exported"
10+
611
capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types"
712

813
"github.com/cosmos/ibc-go/v3/modules/apps/transfer/types"
@@ -233,3 +238,341 @@ func (suite *TransferTestSuite) TestOnChanOpenAck() {
233238
})
234239
}
235240
}
241+
242+
func (suite *TransferTestSuite) TestOnRecvPacket() {
243+
var (
244+
packet channeltypes.Packet
245+
expectedAttributes []sdk.Attribute
246+
path *ibctesting.Path
247+
packetData types.FungibleTokenPacketData
248+
)
249+
testCases := []struct {
250+
name string
251+
malleate func()
252+
expAck exported.Acknowledgement
253+
expEventErrorMsg string
254+
}{
255+
{
256+
"success",
257+
func() {
258+
coin := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100))
259+
packetData = types.NewFungibleTokenPacketData(
260+
coin.Denom,
261+
coin.Amount.String(),
262+
suite.chainA.SenderAccount.GetAddress().String(),
263+
suite.chainB.SenderAccount.GetAddress().String(),
264+
)
265+
expectedAttributes = []sdk.Attribute{
266+
sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName),
267+
sdk.NewAttribute(sdk.AttributeKeySender, packetData.Sender),
268+
sdk.NewAttribute(types.AttributeKeyReceiver, packetData.Receiver),
269+
sdk.NewAttribute(types.AttributeKeyDenom, packetData.Denom),
270+
sdk.NewAttribute(types.AttributeKeyAmount, packetData.Amount),
271+
sdk.NewAttribute(types.AttributeKeyMemo, ""),
272+
sdk.NewAttribute(types.AttributeKeyAckSuccess, "true"),
273+
}
274+
},
275+
channeltypes.NewResultAcknowledgement([]byte{byte(1)}),
276+
"",
277+
},
278+
{
279+
"failure: invalid packet data bytes",
280+
func() {
281+
packet.Data = []byte("invalid data")
282+
expectedAttributes = []sdk.Attribute{
283+
sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName),
284+
sdk.NewAttribute(sdk.AttributeKeySender, ""),
285+
sdk.NewAttribute(types.AttributeKeyReceiver, ""),
286+
sdk.NewAttribute(types.AttributeKeyDenom, ""),
287+
sdk.NewAttribute(types.AttributeKeyAmount, ""),
288+
sdk.NewAttribute(types.AttributeKeyMemo, ""),
289+
sdk.NewAttribute(types.AttributeKeyAckSuccess, "false"),
290+
}
291+
},
292+
channeltypes.NewErrorAcknowledgement("cannot unmarshal ICS-20 transfer packet data"),
293+
"cannot unmarshal ICS-20 transfer packet data",
294+
},
295+
{
296+
"failure: receive disabled",
297+
func() {
298+
suite.chainB.GetSimApp().TransferKeeper.SetParams(suite.chainB.GetContext(), types.Params{ReceiveEnabled: false})
299+
expectedAttributes = []sdk.Attribute{
300+
sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName),
301+
sdk.NewAttribute(sdk.AttributeKeySender, packetData.Sender),
302+
sdk.NewAttribute(types.AttributeKeyReceiver, packetData.Receiver),
303+
sdk.NewAttribute(types.AttributeKeyDenom, packetData.Denom),
304+
sdk.NewAttribute(types.AttributeKeyAmount, packetData.Amount),
305+
sdk.NewAttribute(types.AttributeKeyMemo, ""),
306+
sdk.NewAttribute(types.AttributeKeyAckSuccess, "false"),
307+
}
308+
},
309+
channeltypes.NewErrorAcknowledgement("ABCI code: 8: error handling packet on destination chain: see events for details"),
310+
"ABCI code: 8: error handling packet on destination chain: see events for details",
311+
},
312+
}
313+
314+
for _, tc := range testCases {
315+
suite.Run(tc.name, func() {
316+
suite.SetupTest() // reset
317+
318+
path = NewTransferPath(suite.chainA, suite.chainB)
319+
suite.coordinator.Setup(path)
320+
321+
coin := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100))
322+
packetData = types.NewFungibleTokenPacketData(
323+
coin.Denom,
324+
coin.Amount.String(),
325+
suite.chainA.SenderAccount.GetAddress().String(),
326+
suite.chainB.SenderAccount.GetAddress().String(),
327+
)
328+
329+
expectedAttributes = []sdk.Attribute{
330+
sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName),
331+
sdk.NewAttribute(sdk.AttributeKeySender, packetData.Sender),
332+
sdk.NewAttribute(types.AttributeKeyReceiver, packetData.Receiver),
333+
sdk.NewAttribute(types.AttributeKeyDenom, packetData.Denom),
334+
sdk.NewAttribute(types.AttributeKeyAmount, packetData.Amount),
335+
sdk.NewAttribute(types.AttributeKeyMemo, packetData.Memo),
336+
}
337+
if tc.expAck == nil || tc.expAck.Success() {
338+
expectedAttributes = append(expectedAttributes, sdk.NewAttribute(types.AttributeKeyAckSuccess, "true"))
339+
} else {
340+
expectedAttributes = append(expectedAttributes,
341+
sdk.NewAttribute(types.AttributeKeyAckSuccess, "false"),
342+
sdk.NewAttribute(types.AttributeKeyAckError, tc.expEventErrorMsg),
343+
)
344+
}
345+
346+
seq := uint64(1)
347+
timeout := suite.chainA.GetTimeoutHeight()
348+
packet = channeltypes.NewPacket(packetData.GetBytes(), seq, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, timeout, 0)
349+
350+
ctx := suite.chainB.GetContext()
351+
cbs, ok := suite.chainB.App.GetIBCKeeper().PortKeeper.Router.GetRoute(ibctesting.TransferPort)
352+
suite.Require().True(ok)
353+
354+
tc.malleate() // change fields in packet
355+
356+
ack := cbs.OnRecvPacket(ctx, packet, suite.chainB.SenderAccount.GetAddress())
357+
358+
suite.Require().Equal(tc.expAck, ack)
359+
360+
expectedEvents := sdk.Events{
361+
sdk.NewEvent(
362+
types.EventTypePacket,
363+
expectedAttributes...,
364+
),
365+
}.ToABCIEvents()
366+
367+
ibctesting.AssertEvents(suite.T(), expectedEvents, ctx.EventManager().Events().ToABCIEvents())
368+
})
369+
}
370+
}
371+
372+
func (suite *TransferTestSuite) TestOnAcknowledgePacket() {
373+
var (
374+
path *ibctesting.Path
375+
packet channeltypes.Packet
376+
ack []byte
377+
)
378+
379+
testCases := []struct {
380+
name string
381+
malleate func()
382+
expError error
383+
expRefund bool
384+
}{
385+
{
386+
"success",
387+
func() {},
388+
nil,
389+
false,
390+
},
391+
{
392+
"success: refund coins",
393+
func() {
394+
ack = channeltypes.NewErrorAcknowledgement(types.ErrInvalidAmount.Error()).Acknowledgement()
395+
},
396+
nil,
397+
true,
398+
},
399+
{
400+
"cannot refund ack on non-existent channel",
401+
func() {
402+
ack = channeltypes.NewErrorAcknowledgement(types.ErrInvalidAmount.Error()).Acknowledgement()
403+
404+
packet.SourceChannel = "channel-100"
405+
},
406+
errors.New("unable to unescrow tokens"),
407+
false,
408+
},
409+
{
410+
"invalid packet data",
411+
func() {
412+
packet.Data = []byte("invalid data")
413+
},
414+
sdkerrors.ErrUnknownRequest,
415+
false,
416+
},
417+
{
418+
"invalid acknowledgement",
419+
func() {
420+
ack = []byte("invalid ack")
421+
},
422+
sdkerrors.ErrUnknownRequest,
423+
false,
424+
},
425+
{
426+
"cannot refund already acknowledged packet",
427+
func() {
428+
ack = channeltypes.NewErrorAcknowledgement(sdkerrors.ErrInsufficientFunds.Error()).Acknowledgement()
429+
430+
cbs, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.Router.GetRoute(ibctesting.TransferPort)
431+
suite.Require().True(ok)
432+
433+
suite.Require().NoError(cbs.OnAcknowledgementPacket(suite.chainA.GetContext(), packet, ack, suite.chainA.SenderAccount.GetAddress()))
434+
},
435+
errors.New("unable to unescrow tokens"),
436+
false,
437+
},
438+
}
439+
440+
for _, tc := range testCases {
441+
tc := tc
442+
suite.Run(tc.name, func() {
443+
suite.SetupTest() // reset
444+
445+
path = NewTransferPath(suite.chainA, suite.chainB)
446+
suite.coordinator.Setup(path)
447+
448+
timeoutHeight := suite.chainA.GetTimeoutHeight()
449+
msg := types.NewMsgTransfer(
450+
path.EndpointA.ChannelConfig.PortID,
451+
path.EndpointA.ChannelID,
452+
ibctesting.TestCoin,
453+
suite.chainA.SenderAccount.GetAddress().String(),
454+
suite.chainB.SenderAccount.GetAddress().String(),
455+
timeoutHeight,
456+
0,
457+
)
458+
res, err := suite.chainA.SendMsgs(msg)
459+
suite.Require().NoError(err) // message committed
460+
461+
packet, err = ibctesting.ParsePacketFromEvents(res.GetEvents())
462+
suite.Require().NoError(err)
463+
464+
cbs, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.Router.GetRoute(ibctesting.TransferPort)
465+
suite.Require().True(ok)
466+
467+
ack = channeltypes.NewResultAcknowledgement([]byte{byte(1)}).Acknowledgement()
468+
469+
tc.malleate() // change fields in packet
470+
471+
err = cbs.OnAcknowledgementPacket(suite.chainA.GetContext(), packet, ack, suite.chainA.SenderAccount.GetAddress())
472+
473+
if tc.expError == nil {
474+
suite.Require().NoError(err)
475+
476+
if tc.expRefund {
477+
escrowAddress := types.GetEscrowAddress(packet.GetSourcePort(), packet.GetSourceChannel())
478+
escrowBalanceAfter := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), escrowAddress, sdk.DefaultBondDenom)
479+
suite.Require().Equal(sdk.NewInt(0), escrowBalanceAfter.Amount)
480+
}
481+
} else {
482+
suite.Require().Error(err)
483+
suite.Require().Contains(err.Error(), tc.expError.Error())
484+
}
485+
})
486+
}
487+
}
488+
489+
func (suite *TransferTestSuite) TestOnTimeoutPacket() {
490+
var path *ibctesting.Path
491+
var packet channeltypes.Packet
492+
493+
testCases := []struct {
494+
name string
495+
coinsToSendToB sdk.Coin
496+
malleate func()
497+
expError error
498+
}{
499+
{
500+
"success",
501+
ibctesting.TestCoin,
502+
func() {},
503+
nil,
504+
},
505+
{
506+
"non-existent channel",
507+
ibctesting.TestCoin,
508+
func() {
509+
packet.SourceChannel = "channel-100"
510+
},
511+
errors.New("unable to unescrow tokens"),
512+
},
513+
{
514+
"invalid packet data",
515+
ibctesting.TestCoin,
516+
func() {
517+
packet.Data = []byte("invalid data")
518+
},
519+
errors.New("cannot unmarshal ICS-20 transfer packet data"),
520+
},
521+
{
522+
"already timed-out packet",
523+
ibctesting.TestCoin,
524+
func() {
525+
// First timeout the packet
526+
cbs, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.Router.GetRoute(ibctesting.TransferPort)
527+
suite.Require().True(ok)
528+
err := cbs.OnTimeoutPacket(suite.chainA.GetContext(), packet, suite.chainA.SenderAccount.GetAddress())
529+
suite.Require().NoError(err)
530+
},
531+
errors.New("unable to unescrow tokens"),
532+
},
533+
}
534+
535+
for _, tc := range testCases {
536+
tc := tc
537+
suite.Run(tc.name, func() {
538+
suite.SetupTest() // reset
539+
540+
path = NewTransferPath(suite.chainA, suite.chainB)
541+
suite.coordinator.Setup(path)
542+
543+
timeoutHeight := suite.chainA.GetTimeoutHeight()
544+
msg := types.NewMsgTransfer(
545+
path.EndpointA.ChannelConfig.PortID,
546+
path.EndpointA.ChannelID,
547+
tc.coinsToSendToB,
548+
suite.chainA.SenderAccount.GetAddress().String(),
549+
suite.chainB.SenderAccount.GetAddress().String(),
550+
timeoutHeight,
551+
0,
552+
)
553+
res, err := suite.chainA.SendMsgs(msg)
554+
suite.Require().NoError(err) // message committed
555+
packet, err = ibctesting.ParsePacketFromEvents(res.GetEvents())
556+
557+
suite.Require().NoError(err)
558+
559+
cbs, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.Router.GetRoute(ibctesting.TransferPort)
560+
suite.Require().True(ok)
561+
562+
tc.malleate() // change fields in packet
563+
564+
err = cbs.OnTimeoutPacket(suite.chainA.GetContext(), packet, suite.chainA.SenderAccount.GetAddress())
565+
566+
if tc.expError == nil {
567+
suite.Require().NoError(err)
568+
569+
escrowAddress := types.GetEscrowAddress(packet.GetSourcePort(), packet.GetSourceChannel())
570+
escrowBalanceAfter := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), escrowAddress, sdk.DefaultBondDenom)
571+
suite.Require().Equal(sdk.NewInt(0), escrowBalanceAfter.Amount)
572+
} else {
573+
suite.Require().Error(err)
574+
suite.Require().Contains(err.Error(), tc.expError.Error())
575+
}
576+
})
577+
}
578+
}

0 commit comments

Comments
 (0)