From b6599b23601010c12db9a4edfad794ae3f725336 Mon Sep 17 00:00:00 2001 From: John Letey Date: Thu, 17 Oct 2024 12:10:50 +0200 Subject: [PATCH 1/6] feat: ibc e2e tests for fiattokenfactory Co-authored-by: Dan Kanefsky --- e2e/fiat_tf_test.go | 274 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 274 insertions(+) diff --git a/e2e/fiat_tf_test.go b/e2e/fiat_tf_test.go index c7f4cecc..e4120f56 100644 --- a/e2e/fiat_tf_test.go +++ b/e2e/fiat_tf_test.go @@ -10,9 +10,11 @@ import ( fiattokenfactorytypes "github.com/circlefin/noble-fiattokenfactory/x/fiattokenfactory/types" "github.com/cosmos/cosmos-sdk/crypto/keyring" sdk "github.com/cosmos/cosmos-sdk/types" + transfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" "github.com/noble-assets/noble/e2e" "github.com/strangelove-ventures/interchaintest/v8" "github.com/strangelove-ventures/interchaintest/v8/ibc" + "github.com/strangelove-ventures/interchaintest/v8/testutil" "github.com/stretchr/testify/require" ) @@ -1846,3 +1848,275 @@ func TestFiatTFBankSend(t *testing.T) { require.NoError(t, err, "error getting balance") require.Equal(t, amountToSend.Amount, bobBal) } + +func TestFiatTFIBCOut(t *testing.T) { + if testing.Short() { + t.Skip() + } + t.Parallel() + + ctx := context.Background() + + nw, gaia, _, r, ibcPathName, _, eRep, _, _ := e2e.NobleSpinUpIBC(t, ctx, true) + noble := nw.Chain + val := noble.Validators[0] + + w := interchaintest.GetAndFundTestUsers(t, ctx, "default", math.OneInt(), noble, gaia) + nobleWallet := w[0] + gaiaWallet := w[1] + + mintAmount := int64(100) + _, err := val.ExecTx(ctx, nw.FiatTfRoles.Minter.KeyName(), "fiat-tokenfactory", "mint", nobleWallet.FormattedAddress(), fmt.Sprintf("%duusdc", mintAmount)) + require.NoError(t, err, "error minting") + + // noble -> gaia channel info + nobleToGaiaChannelInfo, err := r.GetChannels(ctx, eRep, noble.Config().ChainID) + require.NoError(t, err) + nobleToGaiaChannelID := nobleToGaiaChannelInfo[0].ChannelID + // gaia -> noble channel info + gaiaToNobleChannelInfo, err := r.GetChannels(ctx, eRep, gaia.Config().ChainID) + require.NoError(t, err) + gaiaToNobleChannelID := gaiaToNobleChannelInfo[0].ChannelID + + // uusdc IBC denom on gaia + srcDenomTrace := transfertypes.ParseDenomTrace(transfertypes.GetPrefixedDenom("transfer", gaiaToNobleChannelID, e2e.DenomMetadataUsdc.Base)) + dstIbcDenom := srcDenomTrace.IBCDenom() + + amountToSend := math.NewInt(5) + transfer := ibc.WalletAmount{ + Address: gaiaWallet.FormattedAddress(), + Denom: e2e.DenomMetadataUsdc.Base, + Amount: amountToSend, + } + + // ACTION: IBC send out a TF token while TF is paused + // EXPECTED: Request fails; + + e2e.PauseFiatTF(t, ctx, val, nw.FiatTfRoles.Pauser) + + // ibc transfer noble -> gaia + _, err = noble.SendIBCTransfer(ctx, nobleToGaiaChannelID, nobleWallet.KeyName(), transfer, ibc.TransferOptions{}) + require.ErrorContains(t, err, "the chain is paused") + + // relay MsgRecvPacket & MsgAcknowledgement + require.NoError(t, r.Flush(ctx, eRep, ibcPathName, nobleToGaiaChannelID)) + + gaiaWalletBal, err := gaia.GetBalance(ctx, gaiaWallet.FormattedAddress(), dstIbcDenom) + require.NoError(t, err) + require.True(t, gaiaWalletBal.IsZero()) + + e2e.UnpauseFiatTF(t, ctx, val, nw.FiatTfRoles.Pauser) + + // ACTION: IBC send TF token from a blacklisted user + // EXPECTED: Request fails; + + e2e.BlacklistAccount(t, ctx, val, nw.FiatTfRoles.Blacklister, nobleWallet) + + _, err = noble.SendIBCTransfer(ctx, nobleToGaiaChannelID, nobleWallet.KeyName(), transfer, ibc.TransferOptions{}) + require.ErrorContains(t, err, fmt.Sprintf("an address (%s) is blacklisted and can not send tokens", nobleWallet.FormattedAddress())) + + require.NoError(t, r.Flush(ctx, eRep, ibcPathName, nobleToGaiaChannelID)) + + gaiaWalletBal, err = gaia.GetBalance(ctx, gaiaWallet.FormattedAddress(), dstIbcDenom) + require.NoError(t, err) + require.True(t, gaiaWalletBal.IsZero()) + + e2e.UnblacklistAccount(t, ctx, val, nw.FiatTfRoles.Blacklister, nobleWallet) + + // ACTION: IBC send out a TF token to a blacklisted user + // EXPECTED: Request fails; + + e2e.BlacklistAccount(t, ctx, val, nw.FiatTfRoles.Blacklister, gaiaWallet) + + _, err = noble.SendIBCTransfer(ctx, nobleToGaiaChannelID, nobleWallet.KeyName(), transfer, ibc.TransferOptions{}) + require.ErrorContains(t, err, fmt.Sprintf("an address (%s) is blacklisted and can not receive tokens", gaiaWallet.FormattedAddress())) + + require.NoError(t, r.Flush(ctx, eRep, ibcPathName, nobleToGaiaChannelID)) + + gaiaWalletBal, err = gaia.GetBalance(ctx, gaiaWallet.FormattedAddress(), dstIbcDenom) + require.NoError(t, err) + require.True(t, gaiaWalletBal.IsZero()) + + e2e.UnblacklistAccount(t, ctx, val, nw.FiatTfRoles.Blacklister, gaiaWallet) + + // ACTION: IBC send out a TF token to malformed address + // EXPECTED: Request fails; + + transfer.Address = "malformed-address1234" + + _, err = noble.SendIBCTransfer(ctx, nobleToGaiaChannelID, nobleWallet.KeyName(), transfer, ibc.TransferOptions{}) + require.ErrorContains(t, err, "decoding bech32 failed") + + // ACTION: Successfully IBC send out a TF token to an address on another chain + // EXPECTED: Success; + + transfer.Address = gaiaWallet.FormattedAddress() + + _, err = noble.SendIBCTransfer(ctx, nobleToGaiaChannelID, nobleWallet.KeyName(), transfer, ibc.TransferOptions{}) + require.NoError(t, err) + + require.NoError(t, r.Flush(ctx, eRep, ibcPathName, nobleToGaiaChannelID)) + + gaiaWalletBal, err = gaia.GetBalance(ctx, gaiaWallet.FormattedAddress(), dstIbcDenom) + require.NoError(t, err) + require.Equal(t, transfer.Amount, gaiaWalletBal) +} + +func TestFiatTFIBCIn(t *testing.T) { + if testing.Short() { + t.Skip() + } + t.Parallel() + + ctx := context.Background() + + nw, gaia, _, r, ibcPathName, _, eRep, _, _ := e2e.NobleSpinUpIBC(t, ctx, true) + noble := nw.Chain + val := noble.Validators[0] + + w := interchaintest.GetAndFundTestUsers(t, ctx, "default", math.NewInt(1_000_000), noble, gaia) + nobleWallet := w[0] // 1_000_000ustake + gaiaWallet := w[1] // 1_000_000uatom + + mintAmount := int64(100) + _, err := val.ExecTx(ctx, nw.FiatTfRoles.Minter.KeyName(), "fiat-tokenfactory", "mint", nobleWallet.FormattedAddress(), fmt.Sprintf("%duusdc", mintAmount)) + require.NoError(t, err, "error minting") + + // noble -> gaia channel info + nobleToGaiaChannelInfo, err := r.GetChannels(ctx, eRep, noble.Config().ChainID) + require.NoError(t, err) + nobleToGaiaChannelID := nobleToGaiaChannelInfo[0].ChannelID + // gaia -> noble channel info + gaiaToNobleChannelInfo, err := r.GetChannels(ctx, eRep, gaia.Config().ChainID) + require.NoError(t, err) + gaiaToNobleChannelID := gaiaToNobleChannelInfo[0].ChannelID + + amountToSend := math.NewInt(mintAmount) + transfer := ibc.WalletAmount{ + Address: gaiaWallet.FormattedAddress(), + Denom: e2e.DenomMetadataUsdc.Base, + Amount: amountToSend, + } + + // ibc transfer noble -> gaia + _, err = noble.SendIBCTransfer(ctx, nobleToGaiaChannelID, nobleWallet.KeyName(), transfer, ibc.TransferOptions{}) + require.NoError(t, err) + + // relay MsgRecvPacket & MsgAcknowledgement + require.NoError(t, r.Flush(ctx, eRep, ibcPathName, nobleToGaiaChannelID)) + + // uusdc IBC denom on gaia + srcDenomTrace := transfertypes.ParseDenomTrace(transfertypes.GetPrefixedDenom("transfer", gaiaToNobleChannelID, e2e.DenomMetadataUsdc.Base)) + dstIbcDenom := srcDenomTrace.IBCDenom() + + gaiaWalletBal, err := gaia.GetBalance(ctx, gaiaWallet.FormattedAddress(), dstIbcDenom) + require.NoError(t, err) + require.Equal(t, transfer.Amount, gaiaWalletBal) + + // ACTION: IBC send in a TF token while TF is paused + // EXPECTED: Request fails; + + e2e.PauseFiatTF(t, ctx, val, nw.FiatTfRoles.Pauser) + + amountToSend = math.OneInt() + transfer = ibc.WalletAmount{ + Address: nobleWallet.FormattedAddress(), + Denom: dstIbcDenom, + Amount: amountToSend, + } + + height, err := noble.Height(ctx) + require.NoError(t, err) + + tx, err := gaia.SendIBCTransfer(ctx, gaiaToNobleChannelID, gaiaWallet.KeyName(), transfer, ibc.TransferOptions{}) + require.NoError(t, err, "error broadcasting IBC send") + + require.NoError(t, r.Flush(ctx, eRep, ibcPathName, gaiaToNobleChannelID)) + + heightAfterFlush, err := noble.Height(ctx) + require.NoError(t, err) + + ack, err := testutil.PollForAck(ctx, gaia, height, heightAfterFlush+5, tx.Packet) + require.NoError(t, err, "error polling for ack") + require.Contains(t, string(ack.Acknowledgement), "error handling packet") + + nobleWalletBal, err := noble.GetBalance(ctx, nobleWallet.FormattedAddress(), e2e.DenomMetadataUsdc.Base) + require.NoError(t, err) + require.True(t, nobleWalletBal.IsZero()) + + e2e.UnpauseFiatTF(t, ctx, val, nw.FiatTfRoles.Pauser) + + // ACTION: IBC send in a TF token FROM an address that is blacklisted + // EXPECTED: Request fails; + + e2e.BlacklistAccount(t, ctx, val, nw.FiatTfRoles.Blacklister, gaiaWallet) + + height, err = noble.Height(ctx) + require.NoError(t, err) + + tx, err = gaia.SendIBCTransfer(ctx, gaiaToNobleChannelID, gaiaWallet.KeyName(), transfer, ibc.TransferOptions{}) + require.NoError(t, err, "error broadcasting IBC send") + + require.NoError(t, r.Flush(ctx, eRep, ibcPathName, gaiaToNobleChannelID)) + + heightAfterFlush, err = noble.Height(ctx) + require.NoError(t, err) + + ack, err = testutil.PollForAck(ctx, gaia, height, heightAfterFlush+5, tx.Packet) + require.NoError(t, err, "error polling for ack") + require.Contains(t, string(ack.Acknowledgement), "error handling packet") + + nobleWalletBal, err = noble.GetBalance(ctx, nobleWallet.FormattedAddress(), e2e.DenomMetadataUsdc.Base) + require.NoError(t, err) + require.True(t, nobleWalletBal.IsZero()) + + e2e.UnblacklistAccount(t, ctx, val, nw.FiatTfRoles.Blacklister, gaiaWallet) + + // ACTION: IBC send in a TF token TO an address that is blacklisted + // EXPECTED: Request fails; + + e2e.BlacklistAccount(t, ctx, val, nw.FiatTfRoles.Blacklister, nobleWallet) + + height, err = noble.Height(ctx) + require.NoError(t, err) + + tx, err = gaia.SendIBCTransfer(ctx, gaiaToNobleChannelID, gaiaWallet.KeyName(), transfer, ibc.TransferOptions{}) + require.NoError(t, err, "error broadcasting IBC send") + + require.NoError(t, r.Flush(ctx, eRep, ibcPathName, gaiaToNobleChannelID)) + + heightAfterFlush, err = noble.Height(ctx) + require.NoError(t, err) + + ack, err = testutil.PollForAck(ctx, gaia, height, heightAfterFlush+5, tx.Packet) + require.NoError(t, err, "error polling for ack") + require.Contains(t, string(ack.Acknowledgement), "error handling packet") + + nobleWalletBal, err = noble.GetBalance(ctx, nobleWallet.FormattedAddress(), e2e.DenomMetadataUsdc.Base) + require.NoError(t, err) + require.True(t, nobleWalletBal.IsZero()) + + e2e.UnblacklistAccount(t, ctx, val, nw.FiatTfRoles.Blacklister, nobleWallet) + + // ACTION: Successfully IBC send in a TF token to an address on noble + // EXPECTED: Success; + + height, err = noble.Height(ctx) + require.NoError(t, err) + + tx, err = gaia.SendIBCTransfer(ctx, gaiaToNobleChannelID, gaiaWallet.KeyName(), transfer, ibc.TransferOptions{}) + require.NoError(t, err, "error broadcasting IBC send") + + require.NoError(t, r.Flush(ctx, eRep, ibcPathName, gaiaToNobleChannelID)) + + heightAfterFlush, err = noble.Height(ctx) + require.NoError(t, err) + + ack, err = testutil.PollForAck(ctx, gaia, height, heightAfterFlush+5, tx.Packet) + require.NoError(t, err, "error polling for ack") + require.NotContains(t, string(ack.Acknowledgement), "error handling packet") + + nobleWalletBal, err = noble.GetBalance(ctx, nobleWallet.FormattedAddress(), e2e.DenomMetadataUsdc.Base) + require.NoError(t, err) + require.Equal(t, transfer.Amount, nobleWalletBal) +} From f39d0ede7774277c9ce112d7f0c72e6c931cebe1 Mon Sep 17 00:00:00 2001 From: John Letey Date: Thu, 17 Oct 2024 12:23:28 +0200 Subject: [PATCH 2/6] fix: align with latest error msg --- e2e/fiat_tf_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e/fiat_tf_test.go b/e2e/fiat_tf_test.go index e4120f56..3c12640a 100644 --- a/e2e/fiat_tf_test.go +++ b/e2e/fiat_tf_test.go @@ -1945,7 +1945,7 @@ func TestFiatTFIBCOut(t *testing.T) { transfer.Address = "malformed-address1234" _, err = noble.SendIBCTransfer(ctx, nobleToGaiaChannelID, nobleWallet.KeyName(), transfer, ibc.TransferOptions{}) - require.ErrorContains(t, err, "decoding bech32 failed") + require.ErrorContains(t, err, "error decoding address") // ACTION: Successfully IBC send out a TF token to an address on another chain // EXPECTED: Success; From 2db901c524eaeb9cab4d984dc5d2e8b942a27ef2 Mon Sep 17 00:00:00 2001 From: Dan Kanefsky Date: Sun, 27 Oct 2024 18:04:33 -0500 Subject: [PATCH 3/6] chore: mod tidy --- e2e/go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e/go.mod b/e2e/go.mod index 4eb34d41..9c235685 100644 --- a/e2e/go.mod +++ b/e2e/go.mod @@ -8,6 +8,7 @@ require ( github.com/circlefin/noble-fiattokenfactory v0.0.0-20241015182229-c20bd0c8442f github.com/cosmos/cosmos-sdk v0.50.10 github.com/cosmos/gogoproto v1.7.0 + github.com/cosmos/ibc-go/v8 v8.5.1 github.com/docker/docker v24.0.9+incompatible github.com/ethereum/go-ethereum v1.14.8 github.com/strangelove-ventures/interchaintest/v8 v8.7.1 @@ -76,7 +77,6 @@ require ( github.com/cosmos/gogogateway v1.2.0 // indirect github.com/cosmos/iavl v1.2.0 // indirect github.com/cosmos/ibc-go/modules/capability v1.0.1 // indirect - github.com/cosmos/ibc-go/v8 v8.5.1 // indirect github.com/cosmos/ics23/go v0.11.0 // indirect github.com/cosmos/interchain-security/v5 v5.1.1 // indirect github.com/cosmos/ledger-cosmos-go v0.13.3 // indirect From c18fed9c5efed69ca941ca6b408340e6dc602ea5 Mon Sep 17 00:00:00 2001 From: Dan Kanefsky Date: Sun, 27 Oct 2024 18:25:53 -0500 Subject: [PATCH 4/6] chore: bump go in GH action --- .github/workflows/e2e-tests.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/e2e-tests.yaml b/.github/workflows/e2e-tests.yaml index faea4051..86b0677c 100644 --- a/.github/workflows/e2e-tests.yaml +++ b/.github/workflows/e2e-tests.yaml @@ -47,7 +47,7 @@ jobs: - name: Install Go uses: actions/setup-go@v5 with: - go-version: '1.21' + go-version: '1.22' - name: Generate Matrix id: set-matrix @@ -74,7 +74,7 @@ jobs: - name: Install Go uses: actions/setup-go@v5 with: - go-version: '1.21' + go-version: '1.22' - name: Download Tarball Artifact uses: actions/download-artifact@v4 From ec19bb2271c1c58a59b5bee92636baff1708eecd Mon Sep 17 00:00:00 2001 From: Dan Kanefsky Date: Sun, 27 Oct 2024 19:10:13 -0500 Subject: [PATCH 5/6] empty commit, cleared gh action cache From da845148453ea61e0c34d676de3d64ac2f4219de Mon Sep 17 00:00:00 2001 From: Dan Kanefsky Date: Mon, 28 Oct 2024 07:20:11 -0700 Subject: [PATCH 6/6] fix: height in e2e --- e2e/fiat_tf_test.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/e2e/fiat_tf_test.go b/e2e/fiat_tf_test.go index 3c12640a..9c51a4ce 100644 --- a/e2e/fiat_tf_test.go +++ b/e2e/fiat_tf_test.go @@ -2025,7 +2025,7 @@ func TestFiatTFIBCIn(t *testing.T) { Amount: amountToSend, } - height, err := noble.Height(ctx) + height, err := gaia.Height(ctx) require.NoError(t, err) tx, err := gaia.SendIBCTransfer(ctx, gaiaToNobleChannelID, gaiaWallet.KeyName(), transfer, ibc.TransferOptions{}) @@ -2033,7 +2033,7 @@ func TestFiatTFIBCIn(t *testing.T) { require.NoError(t, r.Flush(ctx, eRep, ibcPathName, gaiaToNobleChannelID)) - heightAfterFlush, err := noble.Height(ctx) + heightAfterFlush, err := gaia.Height(ctx) require.NoError(t, err) ack, err := testutil.PollForAck(ctx, gaia, height, heightAfterFlush+5, tx.Packet) @@ -2051,7 +2051,7 @@ func TestFiatTFIBCIn(t *testing.T) { e2e.BlacklistAccount(t, ctx, val, nw.FiatTfRoles.Blacklister, gaiaWallet) - height, err = noble.Height(ctx) + height, err = gaia.Height(ctx) require.NoError(t, err) tx, err = gaia.SendIBCTransfer(ctx, gaiaToNobleChannelID, gaiaWallet.KeyName(), transfer, ibc.TransferOptions{}) @@ -2059,7 +2059,7 @@ func TestFiatTFIBCIn(t *testing.T) { require.NoError(t, r.Flush(ctx, eRep, ibcPathName, gaiaToNobleChannelID)) - heightAfterFlush, err = noble.Height(ctx) + heightAfterFlush, err = gaia.Height(ctx) require.NoError(t, err) ack, err = testutil.PollForAck(ctx, gaia, height, heightAfterFlush+5, tx.Packet) @@ -2077,7 +2077,7 @@ func TestFiatTFIBCIn(t *testing.T) { e2e.BlacklistAccount(t, ctx, val, nw.FiatTfRoles.Blacklister, nobleWallet) - height, err = noble.Height(ctx) + height, err = gaia.Height(ctx) require.NoError(t, err) tx, err = gaia.SendIBCTransfer(ctx, gaiaToNobleChannelID, gaiaWallet.KeyName(), transfer, ibc.TransferOptions{}) @@ -2085,7 +2085,7 @@ func TestFiatTFIBCIn(t *testing.T) { require.NoError(t, r.Flush(ctx, eRep, ibcPathName, gaiaToNobleChannelID)) - heightAfterFlush, err = noble.Height(ctx) + heightAfterFlush, err = gaia.Height(ctx) require.NoError(t, err) ack, err = testutil.PollForAck(ctx, gaia, height, heightAfterFlush+5, tx.Packet) @@ -2101,7 +2101,7 @@ func TestFiatTFIBCIn(t *testing.T) { // ACTION: Successfully IBC send in a TF token to an address on noble // EXPECTED: Success; - height, err = noble.Height(ctx) + height, err = gaia.Height(ctx) require.NoError(t, err) tx, err = gaia.SendIBCTransfer(ctx, gaiaToNobleChannelID, gaiaWallet.KeyName(), transfer, ibc.TransferOptions{}) @@ -2109,7 +2109,7 @@ func TestFiatTFIBCIn(t *testing.T) { require.NoError(t, r.Flush(ctx, eRep, ibcPathName, gaiaToNobleChannelID)) - heightAfterFlush, err = noble.Height(ctx) + heightAfterFlush, err = gaia.Height(ctx) require.NoError(t, err) ack, err = testutil.PollForAck(ctx, gaia, height, heightAfterFlush+5, tx.Packet)