Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(e2e): added transfer test #15

Merged
merged 16 commits into from
Aug 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ jobs:
test:
# List your tests here
- TestWithIbcEurekaTestSuite/TestDeploy
- TestWithIbcEurekaTestSuite/TestICS20Transfer
name: ${{ matrix.test }}
runs-on: ubuntu-latest
steps:
Expand Down
20 changes: 10 additions & 10 deletions abi/ICS20Transfer.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@
},
{
"name": "timeoutTimestamp",
"type": "uint32",
"internalType": "uint32"
"type": "uint64",
"internalType": "uint64"
},
{
"name": "sourcePort",
Expand Down Expand Up @@ -103,8 +103,8 @@
},
{
"name": "timeoutTimestamp",
"type": "uint32",
"internalType": "uint32"
"type": "uint64",
"internalType": "uint64"
},
{
"name": "sourcePort",
Expand Down Expand Up @@ -176,8 +176,8 @@
},
{
"name": "timeoutTimestamp",
"type": "uint32",
"internalType": "uint32"
"type": "uint64",
"internalType": "uint64"
},
{
"name": "sourcePort",
Expand Down Expand Up @@ -243,8 +243,8 @@
},
{
"name": "timeoutTimestamp",
"type": "uint32",
"internalType": "uint32"
"type": "uint64",
"internalType": "uint64"
},
{
"name": "sourcePort",
Expand Down Expand Up @@ -345,8 +345,8 @@
},
{
"name": "timeoutTimestamp",
"type": "uint32",
"internalType": "uint32"
"type": "uint64",
"internalType": "uint64"
},
{
"name": "memo",
Expand Down
36 changes: 18 additions & 18 deletions abi/ICS26Router.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@
},
{
"name": "timeoutTimestamp",
"type": "uint32",
"internalType": "uint32"
"type": "uint64",
"internalType": "uint64"
},
{
"name": "sourcePort",
Expand Down Expand Up @@ -218,8 +218,8 @@
},
{
"name": "timeoutTimestamp",
"type": "uint32",
"internalType": "uint32"
"type": "uint64",
"internalType": "uint64"
},
{
"name": "sourcePort",
Expand Down Expand Up @@ -319,8 +319,8 @@
},
{
"name": "timeoutTimestamp",
"type": "uint32",
"internalType": "uint32"
"type": "uint64",
"internalType": "uint64"
},
{
"name": "version",
Expand Down Expand Up @@ -360,8 +360,8 @@
},
{
"name": "timeoutTimestamp",
"type": "uint32",
"internalType": "uint32"
"type": "uint64",
"internalType": "uint64"
},
{
"name": "sourcePort",
Expand Down Expand Up @@ -453,8 +453,8 @@
},
{
"name": "timeoutTimestamp",
"type": "uint32",
"internalType": "uint32"
"type": "uint64",
"internalType": "uint64"
},
{
"name": "sourcePort",
Expand Down Expand Up @@ -552,8 +552,8 @@
},
{
"name": "timeoutTimestamp",
"type": "uint32",
"internalType": "uint32"
"type": "uint64",
"internalType": "uint64"
},
{
"name": "sourcePort",
Expand Down Expand Up @@ -607,8 +607,8 @@
},
{
"name": "timeoutTimestamp",
"type": "uint32",
"internalType": "uint32"
"type": "uint64",
"internalType": "uint64"
},
{
"name": "sourcePort",
Expand Down Expand Up @@ -662,8 +662,8 @@
},
{
"name": "timeoutTimestamp",
"type": "uint32",
"internalType": "uint32"
"type": "uint64",
"internalType": "uint64"
},
{
"name": "sourcePort",
Expand Down Expand Up @@ -717,8 +717,8 @@
},
{
"name": "timeoutTimestamp",
"type": "uint32",
"internalType": "uint32"
"type": "uint64",
"internalType": "uint64"
},
{
"name": "sourcePort",
Expand Down
Binary file modified e2e/artifacts/darwin-aarch64/operator
Binary file not shown.
8 changes: 4 additions & 4 deletions e2e/artifacts/genesis.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"trustedClientState": "000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000012754500000000000000000000000000000000000000000000000000000000001baf800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000673696d642d310000000000000000000000000000000000000000000000000000",
"trustedConsensusState": "0000000000000000000000000000000000000000000000000000000066acb767c22394cd988169e4cff51cf02eee69039b119d7b3959ce598de9adf8de4524014ae23e439252e05b6db14d268bff60e595ec7666772339b013b449e5e7f0e00e",
"updateClientVkey": "0x008d1636cb723e4319abda291c18f7dd68e37c2703f6da3733c3a998bfa039f3",
"membershipVkey": "0x0014aa880aba41e680e859af6ebdefef52df9902ab61975bd1bb340c9b820b2a",
"ucAndMembershipVkey": "0x001d0fed4a58085ccac826775bfe0553ae6e42e52521aa52c3601396854dc4e8"
"trustedConsensusState": "0000000000000000000000000000000000000000000000000000000066b05d264416d86ca61c0fd693df00a5c755d74acdf8f9d5fd3f88dfa98df9dc9a08f906e2d69a8e2501adc2013515c2954fc617365a7d4e1a51bc49ca6bac597971949c",
"updateClientVkey": "0x0068b9d316aced51c5923b2d50692f4a6a9bfefcd89392914b90e77545727fbe",
"membershipVkey": "0x00a4245d249b5c35c9782cc899c8e370a35d5d928187dc9e7acbab7096764b72",
"ucAndMembershipVkey": "0x00cea834e3408d45d29080a3146e4fb1fd0c06503d655bd787219caac86cf59c"
}
Binary file modified e2e/artifacts/linux-x86_64/operator
Binary file not shown.
170 changes: 168 additions & 2 deletions e2e/interchaintestv8/ibc_eureka_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"crypto/ecdsa"
"encoding/hex"
"fmt"
"math/big"
"os"
"strconv"
"strings"
Expand All @@ -14,11 +15,17 @@ import (
"github.com/stretchr/testify/suite"

ethcommon "github.com/ethereum/go-ethereum/common"
ethtypes "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethclient"

banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"

transfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types"
clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types"
channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types"
commitmenttypes "github.com/cosmos/ibc-go/v8/modules/core/23-commitment/types"
ibchost "github.com/cosmos/ibc-go/v8/modules/core/24-host"
ibcexported "github.com/cosmos/ibc-go/v8/modules/core/exported"
mock "github.com/cosmos/ibc-go/v8/modules/light-clients/00-mock"
ibctesting "github.com/cosmos/ibc-go/v8/testing"
Expand All @@ -42,7 +49,9 @@ type IbcEurekaTestSuite struct {
e2esuite.TestSuite

// The private key of a test account
key *ecdsa.PrivateKey
key *ecdsa.PrivateKey
// The private key of the faucet account of interchaintest
faucet *ecdsa.PrivateKey
deployer ibc.Wallet

contractAddresses e2esuite.DeployedContracts
Expand Down Expand Up @@ -79,6 +88,10 @@ func (s *IbcEurekaTestSuite) SetupSuite(ctx context.Context) {
s.Require().NoError(err)
operatorAddress := crypto.PubkeyToAddress(operatorKey.PublicKey).Hex()

// get faucet private key from string
s.faucet, err = crypto.HexToECDSA(testvalues.FaucetPrivateKey)
s.Require().NoError(err)

os.Setenv(testvalues.EnvKeyEthRPC, eth.GetHostRPCAddress())
os.Setenv(testvalues.EnvKeyTendermintRPC, simd.GetHostRPCAddress())
os.Setenv(testvalues.EnvKeySp1Prover, "network")
Expand Down Expand Up @@ -133,9 +146,13 @@ func (s *IbcEurekaTestSuite) SetupSuite(ctx context.Context) {
s.Require().NoError(err)
s.erc20Contract, err = erc20.NewContract(ethcommon.HexToAddress(s.contractAddresses.Erc20), client)
s.Require().NoError(err)
}))

_, err = ethclient.Dial(eth.GetHostRPCAddress())
s.Require().True(s.Run("Fund address with ERC20", func() {
tx, err := s.erc20Contract.Transfer(s.GetTransactOpts(s.faucet), crypto.PubkeyToAddress(s.key.PublicKey), big.NewInt(testvalues.StartingTokenAmount))
s.Require().NoError(err)

_ = s.GetTxReciept(ctx, eth, tx.Hash()) // wait for the tx to be mined
}))

_, simdRelayerUser := s.GetRelayerUsers(ctx)
Expand Down Expand Up @@ -259,5 +276,154 @@ func (s *IbcEurekaTestSuite) TestDeploy() {
s.Require().NoError(err)
s.Require().Equal(s.contractAddresses.Ics20Transfer, strings.ToLower(transferAddress.Hex()))
}))

s.Require().True(s.Run("Verify ERC20 Genesis", func() {
userBalance, err := s.erc20Contract.BalanceOf(nil, crypto.PubkeyToAddress(s.key.PublicKey))
s.Require().NoError(err)
s.Require().Equal(testvalues.StartingTokenAmount, userBalance.Int64())
}))
}))
}

func (s *IbcEurekaTestSuite) TestICS20Transfer() {
ctx := context.Background()

s.SetupSuite(ctx)

eth, simd := s.ChainA, s.ChainB

transferAmount := big.NewInt(testvalues.TransferAmount)
userAddress := crypto.PubkeyToAddress(s.key.PublicKey)
receiver := s.UserB
var packet ics26router.IICS26RouterMsgsPacket
var recvAck []byte

s.Require().True(s.Run("Approve the ICS20Transfer contract to spend the erc20 tokens", func() {
ics20Address := ethcommon.HexToAddress(s.contractAddresses.Ics20Transfer)
tx, err := s.erc20Contract.Approve(s.GetTransactOpts(s.key), ics20Address, transferAmount)
s.Require().NoError(err)
receipt := s.GetTxReciept(ctx, eth, tx.Hash())
s.Require().Equal(ethtypes.ReceiptStatusSuccessful, receipt.Status)

allowance, err := s.erc20Contract.Allowance(nil, userAddress, ics20Address)
s.Require().NoError(err)
s.Require().Equal(transferAmount, allowance)
}))

s.Require().True(s.Run("sendTransfer on Ethereum side", func() {
timeout := uint64(time.Now().Add(30 * time.Minute).UnixNano())
msgSendTransfer := ics20transfer.IICS20TransferMsgsSendTransferMsg{
Denom: s.contractAddresses.Erc20,
Amount: transferAmount,
Receiver: receiver.FormattedAddress(),
SourceChannel: s.ethClientID,
DestPort: "transfer",
TimeoutTimestamp: timeout,
Memo: "testmemo",
}

tx, err := s.ics20Contract.SendTransfer(s.GetTransactOpts(s.key), msgSendTransfer)
s.Require().NoError(err)
receipt := s.GetTxReciept(ctx, eth, tx.Hash())
s.Require().Equal(ethtypes.ReceiptStatusSuccessful, receipt.Status)

transferEvent, err := e2esuite.GetEvmEvent(receipt, s.ics20Contract.ParseICS20Transfer)
s.Require().NoError(err)
s.Require().Equal(s.contractAddresses.Erc20, strings.ToLower(transferEvent.PacketData.Erc20ContractAddress.Hex()))
s.Require().Equal(transferAmount, transferEvent.PacketData.Amount)
s.Require().Equal(userAddress, transferEvent.PacketData.Sender)
s.Require().Equal(receiver.FormattedAddress(), transferEvent.PacketData.Receiver)
s.Require().Equal("testmemo", transferEvent.PacketData.Memo)

sendPacketEvent, err := e2esuite.GetEvmEvent(receipt, s.ics26Contract.ParseSendPacket)
s.Require().NoError(err)
packet = sendPacketEvent.Packet
s.Require().Equal(uint32(1), packet.Sequence)
s.Require().Equal(timeout, packet.TimeoutTimestamp)
s.Require().Equal("transfer", packet.SourcePort)
s.Require().Equal(s.ethClientID, packet.SourceChannel)
s.Require().Equal("transfer", packet.DestPort)
s.Require().Equal(s.simdClientID, packet.DestChannel)
s.Require().Equal(transfertypes.Version, packet.Version)
}))

// TODO: When using a non-mock light client on the cosmos side, the client there needs to be updated at this point

s.Require().True(s.Run("recvPacket on Cosmos side", func() {
resp, err := e2esuite.GRPCQuery[clienttypes.QueryClientStateResponse](ctx, simd, &clienttypes.QueryClientStateRequest{
ClientId: s.simdClientID,
})
s.Require().NoError(err)
var clientState mock.ClientState
err = simd.Config().EncodingConfig.Codec.Unmarshal(resp.ClientState.Value, &clientState)
s.Require().NoError(err)

txResp, err := s.BroadcastMessages(ctx, simd, s.UserB, 200_000, &channeltypes.MsgRecvPacket{
Packet: channeltypes.Packet{
Sequence: uint64(packet.Sequence),
SourcePort: packet.SourcePort,
SourceChannel: packet.SourceChannel,
DestinationPort: packet.DestPort,
DestinationChannel: packet.DestChannel,
Data: packet.Data,
TimeoutHeight: clienttypes.Height{},
TimeoutTimestamp: packet.TimeoutTimestamp,
},
ProofCommitment: []byte("doesn't matter"),
ProofHeight: clientState.LatestHeight,
Signer: s.UserB.FormattedAddress(),
})
s.Require().NoError(err)

recvAck, err = ibctesting.ParseAckFromEvents(txResp.Events)
s.Require().NoError(err)
s.Require().NotNil(recvAck)

s.Require().True(s.Run("Verify balances", func() {
ibcDenom := transfertypes.ParseDenomTrace(
fmt.Sprintf("%s/%s/%s", transfertypes.PortID, "00-mock-0", s.contractAddresses.Erc20),
).IBCDenom()

// Check the balance of UserB
resp, err := e2esuite.GRPCQuery[banktypes.QueryBalanceResponse](ctx, simd, &banktypes.QueryBalanceRequest{
Address: s.UserB.FormattedAddress(),
Denom: ibcDenom,
})
s.Require().NoError(err)
s.Require().NotNil(resp.Balance)
s.Require().Equal(testvalues.TransferAmount, resp.Balance.Amount.Int64())
s.Require().Equal(ibcDenom, resp.Balance.Denom)
}))
}))

s.True(s.Run("acknowledgePacket on Ethereum side", func() {
clientState, err := s.sp1Ics07Contract.GetClientState(nil)
s.Require().NoError(err)

trustedHeight := clientState.LatestHeight.RevisionHeight
latestHeight, err := simd.Height(ctx)
s.Require().NoError(err)

// This will be a non-membership proof since no packets have been sent
packetAckPath := ibchost.PacketAcknowledgementPath(packet.DestPort, packet.DestChannel, uint64(packet.Sequence))
proofHeight, ucAndMemProof, err := operator.UpdateClientAndMembershipProof(
uint64(trustedHeight), uint64(latestHeight), packetAckPath,
"--trust-level", testvalues.DefaultTrustLevel.String(),
"--trusting-period", strconv.Itoa(testvalues.DefaultTrustPeriod),
)
s.Require().NoError(err)

msg := ics26router.IICS26RouterMsgsMsgAckPacket{
Packet: packet,
Acknowledgement: recvAck,
ProofAcked: ucAndMemProof,
ProofHeight: *proofHeight,
}

tx, err := s.ics26Contract.AckPacket(s.GetTransactOpts(s.key), msg)
s.Require().NoError(err)

receipt := s.GetTxReciept(ctx, eth, tx.Hash())
s.Require().Equal(ethtypes.ReceiptStatusSuccessful, receipt.Status)
}))
}
Loading
Loading