From 2de0bf9a70480351025b9f6d0f48eebd1b8bc2aa Mon Sep 17 00:00:00 2001 From: Josh Date: Thu, 14 Nov 2024 11:26:18 -0500 Subject: [PATCH 01/18] additional e2e integration test first version --- integration-tests/smoke/ccip_test.go | 458 +++++++++++++++++++++++++++ 1 file changed, 458 insertions(+) diff --git a/integration-tests/smoke/ccip_test.go b/integration-tests/smoke/ccip_test.go index 5b0ba285527..a5e7e69d76f 100644 --- a/integration-tests/smoke/ccip_test.go +++ b/integration-tests/smoke/ccip_test.go @@ -1,6 +1,7 @@ package smoke import ( + "fmt" "math/big" "testing" @@ -276,3 +277,460 @@ func TestTokenTransfer(t *testing.T) { require.NoError(t, err) require.Equal(t, twoCoins, balance) } + +func Test_PricingForTokenTransfers(t *testing.T) { + // Deplot the environment + lggr := logger.TestLogger(t) + ctx := ccdeploy.Context(t) + tenv, _, _ := testsetups.NewLocalDevEnvironment(t, lggr) + + // Load the test state + e := tenv.Env + state, err := ccdeploy.LoadOnchainState(e) + require.NoError(t, err) + + feeds := state.Chains[tenv.FeedChainSel].USDFeeds + tokenConfig := ccdeploy.NewTokenConfig() + tokenConfig.UpsertTokenInfo(ccdeploy.LinkSymbol, + pluginconfig.TokenInfo{ + AggregatorAddress: cciptypes.UnknownEncodedAddress(feeds[ccdeploy.LinkSymbol].Address().String()), + Decimals: ccdeploy.LinkDecimals, + DeviationPPB: cciptypes.NewBigIntFromInt64(1e9), + }, + ) + + // Apply migration + output, err := changeset.InitialDeploy(e, ccdeploy.DeployCCIPContractConfig{ + HomeChainSel: tenv.HomeChainSel, + FeedChainSel: tenv.FeedChainSel, + ChainsToDeploy: e.AllChainSelectors(), + TokenConfig: tokenConfig, + MCMSConfig: ccdeploy.NewTestMCMSConfig(t, e), + OCRSecrets: deployment.XXXGenerateTestOCRSecrets(), + }) + require.NoError(t, err) + require.NoError(t, e.ExistingAddresses.Merge(output.AddressBook)) + // Get new state after migration and mock USDC token deployment. + state, err = ccdeploy.LoadOnchainState(e) + require.NoError(t, err) + + // Deploy the token to test transfering + srcToken, _, dstToken, _, err := ccdeploy.DeployTransferableToken( + lggr, + tenv.Env.Chains, + tenv.HomeChainSel, + tenv.FeedChainSel, + state, + e.ExistingAddresses, + "MY_TOKEN", + ) + require.NoError(t, err) + + // Ensure capreg logs are up to date. + ccdeploy.ReplayLogs(t, e.Offchain, tenv.ReplayBlocks) + + // Apply the jobs. + for nodeID, jobs := range output.JobSpecs { + for _, job := range jobs { + // Note these auto-accept + _, err := e.Offchain.ProposeJob(ctx, + &jobv1.ProposeJobRequest{ + NodeId: nodeID, + Spec: job, + }) + require.NoError(t, err) + } + } + + // Add all lanes + require.NoError(t, ccdeploy.AddLanesForAll(e, state)) + // Need to keep track of the block number for each chain so that event subscription can be done from that block. + startBlocks := make(map[uint64]*uint64) + // Send a message from each chain to every other chain. + expectedSeqNum := make(map[uint64]uint64) + + // Mint 2 tokens to be transfered + twoCoins := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(2)) + tx, err := srcToken.Mint( + e.Chains[tenv.HomeChainSel].DeployerKey, + e.Chains[tenv.HomeChainSel].DeployerKey.From, + new(big.Int).Mul(twoCoins, big.NewInt(10)), + ) + + if err != nil { + fmt.Printf("Error minting token: %v\n", err) + } + + // Confirm that mint tx + require.NoError(t, err) + _, err = e.Chains[tenv.HomeChainSel].Confirm(tx) + require.NoError(t, err) + + // Mint a destination token + tx, err = dstToken.Mint( + e.Chains[tenv.FeedChainSel].DeployerKey, + e.Chains[tenv.FeedChainSel].DeployerKey.From, + new(big.Int).Mul(twoCoins, big.NewInt(10)), + ) + + // Confirm the mint tx + require.NoError(t, err) + _, err = e.Chains[tenv.FeedChainSel].Confirm(tx) + require.NoError(t, err) + + linkToken := state.Chains[tenv.HomeChainSel].LinkToken + + // Grant mint and burn roles to the deployer key for the newly deployed linkToken + // Since those roles are not granted automatically + tx, err = linkToken.GrantMintAndBurnRoles(e.Chains[tenv.HomeChainSel].DeployerKey, e.Chains[tenv.HomeChainSel].DeployerKey.From) + require.NoError(t, err) + _, err = e.Chains[tenv.HomeChainSel].Confirm(tx) + require.NoError(t, err) + + // Mint link token and confirm the tx + tx, err = linkToken.Mint( + e.Chains[tenv.HomeChainSel].DeployerKey, + e.Chains[tenv.HomeChainSel].DeployerKey.From, + new(big.Int).Mul(twoCoins, big.NewInt(10)), + ) + require.NoError(t, err) + + _, err = e.Chains[tenv.HomeChainSel].Confirm(tx) + require.NoError(t, err) + + t.Run("Send Token Pay with Link token home chain -> remote", func(t *testing.T) { + // Approve the router to spend the tokens and confirm the tx's + tx, err = srcToken.Approve(e.Chains[tenv.HomeChainSel].DeployerKey, state.Chains[tenv.HomeChainSel].Router.Address(), twoCoins) + require.NoError(t, err) + _, err = e.Chains[tenv.HomeChainSel].Confirm(tx) + require.NoError(t, err) + tx, err = dstToken.Approve(e.Chains[tenv.FeedChainSel].DeployerKey, state.Chains[tenv.FeedChainSel].Router.Address(), twoCoins) + require.NoError(t, err) + _, err = e.Chains[tenv.FeedChainSel].Confirm(tx) + require.NoError(t, err) + // Approve to spend link token + tx, err = linkToken.Approve(e.Chains[tenv.HomeChainSel].DeployerKey, state.Chains[tenv.HomeChainSel].Router.Address(), twoCoins) + require.NoError(t, err) + _, err = e.Chains[tenv.HomeChainSel].Confirm(tx) + require.NoError(t, err) + + // Create two ClientEVMTokenAmount structs to be passed to the router + tokens := map[uint64][]router.ClientEVMTokenAmount{ + tenv.HomeChainSel: {{ + Token: srcToken.Address(), + Amount: twoCoins, + }}, + tenv.FeedChainSel: {{ + Token: dstToken.Address(), + Amount: twoCoins, + }}, + } + + // Assign Src to the Home Chain Selector and destChain to the Feed Chain Selector + src := tenv.HomeChainSel + dest, destChain := tenv.FeedChainSel, e.Chains[tenv.FeedChainSel] + + // get the header for the destination chain and the relevant block number + latesthdr, err := destChain.Client.HeaderByNumber(testcontext.Get(t), nil) + require.NoError(t, err) + block := latesthdr.Number.Uint64() + startBlocks[dest] = &block + + // Send to the receiver on the destination chain paying with LINK token + var ( + receiver = common.LeftPadBytes(state.Chains[dest].Receiver.Address().Bytes(), 32) + data = []byte("hello world") + feeToken = linkToken.Address() + ) + + ccipMessage := router.ClientEVM2AnyMessage{ + Receiver: receiver, + Data: data, + TokenAmounts: tokens[src], + FeeToken: feeToken, + ExtraArgs: nil, + } + + // Get the fee Token Balance Before + feeTokenBalanceBefore, _ := linkToken.BalanceOf(nil, e.Chains[tenv.HomeChainSel].DeployerKey.From) + + // Check the fee Amount + srcFee, err := state.Chains[src].Router.GetFee(nil, dest, ccipMessage) + require.NoError(t, err) + + seqNum := ccdeploy.TestSendRequest(t, e, state, src, dest, false, ccipMessage) + expectedSeqNum[dest] = seqNum + + // Check the fee token balance after the request and ensure fee tokens were spent + feeTokenBalanceAfter, _ := linkToken.BalanceOf(nil, e.Chains[tenv.HomeChainSel].DeployerKey.From) + require.Equal(t, feeTokenBalanceAfter, new(big.Int).Sub(feeTokenBalanceBefore, srcFee)) + + // Wait for all commit reports to land. + ccdeploy.ConfirmCommitForAllWithExpectedSeqNums(t, e, state, expectedSeqNum, startBlocks) + + // After commit is reported on all chains, token prices should be updated in FeeQuoter. + linkAddress := state.Chains[dest].LinkToken.Address() + feeQuoter := state.Chains[dest].FeeQuoter + timestampedPrice, err := feeQuoter.GetTokenPrice(nil, linkAddress) + require.NoError(t, err) + require.Equal(t, ccdeploy.MockLinkPrice, timestampedPrice.Value) + + // Wait for all exec reports to land + ccdeploy.ConfirmExecWithSeqNrForAll(t, e, state, expectedSeqNum, startBlocks) + + balance, err := dstToken.BalanceOf(nil, state.Chains[tenv.FeedChainSel].Receiver.Address()) + require.NoError(t, err) + require.Equal(t, twoCoins, balance) + + // Delete from the expcted seq num the chain that was just tested so that we don't pass it to the + // commit report in the next test + delete(expectedSeqNum, dest) + }) + + t.Run("Send Token Pay with native remote chain -> home", func(t *testing.T) { + // Approve the router to spend the tokens and confirm the tx's + tx, err = srcToken.Approve(e.Chains[tenv.HomeChainSel].DeployerKey, state.Chains[tenv.HomeChainSel].Router.Address(), twoCoins) + require.NoError(t, err) + _, err = e.Chains[tenv.HomeChainSel].Confirm(tx) + require.NoError(t, err) + + tx, err = dstToken.Approve(e.Chains[tenv.FeedChainSel].DeployerKey, state.Chains[tenv.FeedChainSel].Router.Address(), twoCoins) + require.NoError(t, err) + _, err = e.Chains[tenv.FeedChainSel].Confirm(tx) + require.NoError(t, err) + + // Create two ClientEVMTokenAmount structs to be passed to the router + tokens := map[uint64][]router.ClientEVMTokenAmount{ + tenv.HomeChainSel: {{ + Token: dstToken.Address(), + Amount: twoCoins, + }}, + tenv.FeedChainSel: {{ + Token: srcToken.Address(), + Amount: twoCoins, + }}, + } + + // Assign Src to the Home Chain Selector and destChain to the Feed Chain Selector + src := tenv.FeedChainSel + dest, destChain := tenv.HomeChainSel, e.Chains[tenv.HomeChainSel] + + // get the header for the destination chain and the relevant block number + latesthdr, err := destChain.Client.HeaderByNumber(testcontext.Get(t), nil) + require.NoError(t, err) + block := latesthdr.Number.Uint64() + startBlocks[dest] = &block + + // Send to the receiver on the destination chain paying with native token + var ( + receiver = common.LeftPadBytes(state.Chains[dest].Receiver.Address().Bytes(), 32) + data = []byte("hello world") + feeToken = common.HexToAddress("0x0") + ) + + ccipMessage := router.ClientEVM2AnyMessage{ + Receiver: receiver, + Data: data, + TokenAmounts: tokens[dest], + FeeToken: feeToken, + ExtraArgs: nil, + } + + seqNum := ccdeploy.TestSendRequest(t, e, state, src, dest, false, ccipMessage) + expectedSeqNum[dest] = seqNum + + // Wait for all commit reports to land. + ccdeploy.ConfirmCommitForAllWithExpectedSeqNums(t, e, state, expectedSeqNum, startBlocks) + + // After commit is reported on all chains, token prices should be updated in FeeQuoter. + linkAddress := state.Chains[dest].LinkToken.Address() + feeQuoter := state.Chains[dest].FeeQuoter + timestampedPrice, err := feeQuoter.GetTokenPrice(nil, linkAddress) + require.NoError(t, err) + require.Equal(t, ccdeploy.MockLinkPrice, timestampedPrice.Value) + + // Wait for all exec reports to land + ccdeploy.ConfirmExecWithSeqNrForAll(t, e, state, expectedSeqNum, startBlocks) + + balance, err := srcToken.BalanceOf(nil, state.Chains[tenv.HomeChainSel].Receiver.Address()) + require.NoError(t, err) + require.Equal(t, twoCoins, balance) + + delete(expectedSeqNum, dest) + }) + + t.Run("Send Token pay with wrapped native home chain -> remote", func(t *testing.T) { + WETH := state.Chains[tenv.HomeChainSel].Weth9 + + // We need to acquire some WETH to send with the tx so we deposit some ETH into the WETH contract + // but deployerKey is a reference so we need to dereference it and then reassign it + depositOps := *e.Chains[tenv.HomeChainSel].DeployerKey + depositOps.Value = twoCoins + tx, err = WETH.Deposit(&depositOps) + require.NoError(t, err) + _, err = e.Chains[tenv.HomeChainSel].Confirm(tx) + require.NoError(t, err) + + // Approve the router to spend the tokens and confirm the tx's + tx, err = srcToken.Approve(e.Chains[tenv.HomeChainSel].DeployerKey, state.Chains[tenv.HomeChainSel].Router.Address(), twoCoins) + require.NoError(t, err) + _, err = e.Chains[tenv.HomeChainSel].Confirm(tx) + require.NoError(t, err) + + print("APPROVED SRC TO ROUTER") + + tx, err = dstToken.Approve(e.Chains[tenv.FeedChainSel].DeployerKey, state.Chains[tenv.FeedChainSel].Router.Address(), twoCoins) + require.NoError(t, err) + _, err = e.Chains[tenv.FeedChainSel].Confirm(tx) + require.NoError(t, err) + // Approve to spend WETH token as fee + tx, err = WETH.Approve(e.Chains[tenv.HomeChainSel].DeployerKey, state.Chains[tenv.HomeChainSel].Router.Address(), twoCoins) + require.NoError(t, err) + _, err = e.Chains[tenv.HomeChainSel].Confirm(tx) + require.NoError(t, err) + + // Create two ClientEVMTokenAmount structs to be passed to the router + tokens := map[uint64][]router.ClientEVMTokenAmount{ + tenv.HomeChainSel: {{ + Token: srcToken.Address(), + Amount: twoCoins, + }}, + tenv.FeedChainSel: {{ + Token: dstToken.Address(), + Amount: twoCoins, + }}, + } + + // Assign Src to the Home Chain Selector and destChain to the Feed Chain Selector + src := tenv.HomeChainSel + dest, destChain := tenv.FeedChainSel, e.Chains[tenv.FeedChainSel] + + // get the header for the destination chain and the relevant block number + latesthdr, err := destChain.Client.HeaderByNumber(testcontext.Get(t), nil) + require.NoError(t, err) + block := latesthdr.Number.Uint64() + startBlocks[dest] = &block + + // Send to the receiver on the destination chain paying with LINK token + var ( + receiver = common.LeftPadBytes(state.Chains[dest].Receiver.Address().Bytes(), 32) + data = []byte("") + feeToken = state.Chains[src].Weth9.Address() + ) + + ccipMessage := router.ClientEVM2AnyMessage{ + Receiver: receiver, + Data: data, + TokenAmounts: tokens[src], + FeeToken: feeToken, + ExtraArgs: nil, + } + + // Get the fee Token Balance Before + feeTokenBalanceBefore, err := WETH.BalanceOf(nil, e.Chains[src].DeployerKey.From) + require.NoError(t, err) + + // Check the fee Amount + srcFee, err := state.Chains[src].Router.GetFee(nil, dest, ccipMessage) + require.NoError(t, err) + + seqNum := ccdeploy.TestSendRequest(t, e, state, src, dest, false, ccipMessage) + expectedSeqNum[dest] = seqNum + + // Check the fee token balance after the request and ensure fee tokens were spent + feeTokenBalanceAfter, err := WETH.BalanceOf(nil, e.Chains[tenv.HomeChainSel].DeployerKey.From) + require.NoError(t, err) + require.Equal(t, feeTokenBalanceAfter, new(big.Int).Sub(feeTokenBalanceBefore, srcFee)) + + // Wait for all commit reports to land. + ccdeploy.ConfirmCommitForAllWithExpectedSeqNums(t, e, state, expectedSeqNum, startBlocks) + + // After commit is reported on all chains, token prices should be updated in FeeQuoter. + linkAddress := state.Chains[dest].LinkToken.Address() + feeQuoter := state.Chains[dest].FeeQuoter + timestampedPrice, err := feeQuoter.GetTokenPrice(nil, linkAddress) + require.NoError(t, err) + require.Equal(t, ccdeploy.MockLinkPrice, timestampedPrice.Value) + + // Wait for all exec reports to land + ccdeploy.ConfirmExecWithSeqNrForAll(t, e, state, expectedSeqNum, startBlocks) + + balance, err := dstToken.BalanceOf(nil, state.Chains[dest].Receiver.Address()) + require.NoError(t, err) + + // The balance should be 4 since we've already sent 2 tokens over this lane direction in the + // first part of the test, so balance should already be two + require.Equal(t, new(big.Int).Mul(twoCoins, big.NewInt(2)), balance) + }) + + t.Run("Send Token but revert not enough tokens", func(t *testing.T) { + // Approve the router to spend the tokens and confirm the tx's + tx, err = srcToken.Approve(e.Chains[tenv.HomeChainSel].DeployerKey, state.Chains[tenv.HomeChainSel].Router.Address(), twoCoins) + require.NoError(t, err) + _, err = e.Chains[tenv.HomeChainSel].Confirm(tx) + require.NoError(t, err) + + tx, err = dstToken.Approve(e.Chains[tenv.FeedChainSel].DeployerKey, state.Chains[tenv.FeedChainSel].Router.Address(), twoCoins) + require.NoError(t, err) + _, err = e.Chains[tenv.FeedChainSel].Confirm(tx) + require.NoError(t, err) + + existingBalanceSrc, err := dstToken.BalanceOf(nil, e.Chains[tenv.HomeChainSel].DeployerKey.From) + require.NoError(t, err) + + existingBalanceDst, err := dstToken.BalanceOf(nil, e.Chains[tenv.FeedChainSel].DeployerKey.From) + require.NoError(t, err) + + // Assign Src to the Home Chain Selector and destChain to the Feed Chain Selector + src := tenv.FeedChainSel + dest, destChain := tenv.HomeChainSel, e.Chains[tenv.HomeChainSel] + + // Create two ClientEVMTokenAmount structs to be passed to the router + tokens := map[uint64][]router.ClientEVMTokenAmount{ + tenv.HomeChainSel: {{ + Token: dstToken.Address(), + // Send twice as many tokens as available on purpose + Amount: new(big.Int).Mul(existingBalanceSrc, big.NewInt(2)), + }}, + tenv.FeedChainSel: {{ + Token: srcToken.Address(), + Amount: new(big.Int).Mul(existingBalanceDst, big.NewInt(10)), + }}, + } + + // get the header for the destination chain and the relevant block number + latesthdr, err := destChain.Client.HeaderByNumber(testcontext.Get(t), nil) + require.NoError(t, err) + block := latesthdr.Number.Uint64() + startBlocks[dest] = &block + + // Send to the receiver on the destination chain paying with native token + var ( + receiver = common.LeftPadBytes(state.Chains[dest].Receiver.Address().Bytes(), 32) + data = []byte("") + feeToken = common.HexToAddress("0x0") + ) + + ccipMessage := router.ClientEVM2AnyMessage{ + Receiver: receiver, + Data: data, + TokenAmounts: tokens[dest], + FeeToken: feeToken, + ExtraArgs: nil, + } + + // Send the CCP Request + tx, _, err := ccdeploy.CCIPSendRequest( + e, + state, + src, dest, + false, + ccipMessage, + ) + + // Check if the transaction reverted + require.Error(t, err) + require.Nil(t, tx) + }) + +} From 2669b8c34b22c95a59cbe93e069d40e8b7241c8c Mon Sep 17 00:00:00 2001 From: Josh Date: Thu, 14 Nov 2024 11:51:14 -0500 Subject: [PATCH 02/18] attempt fix linter --- integration-tests/smoke/ccip_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/integration-tests/smoke/ccip_test.go b/integration-tests/smoke/ccip_test.go index a5e7e69d76f..51616ff9e62 100644 --- a/integration-tests/smoke/ccip_test.go +++ b/integration-tests/smoke/ccip_test.go @@ -314,7 +314,7 @@ func Test_PricingForTokenTransfers(t *testing.T) { state, err = ccdeploy.LoadOnchainState(e) require.NoError(t, err) - // Deploy the token to test transfering + // Deploy the token to test transferring srcToken, _, dstToken, _, err := ccdeploy.DeployTransferableToken( lggr, tenv.Env.Chains, @@ -349,7 +349,7 @@ func Test_PricingForTokenTransfers(t *testing.T) { // Send a message from each chain to every other chain. expectedSeqNum := make(map[uint64]uint64) - // Mint 2 tokens to be transfered + // Mint 2 tokens to be transferred twoCoins := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(2)) tx, err := srcToken.Mint( e.Chains[tenv.HomeChainSel].DeployerKey, From aa6d84c154e70a965398e295bea3e31731ed3454 Mon Sep 17 00:00:00 2001 From: Josh Date: Thu, 14 Nov 2024 14:39:44 -0500 Subject: [PATCH 03/18] test cleanup and linting --- integration-tests/smoke/ccip_test.go | 191 +++++++++++++-------------- 1 file changed, 95 insertions(+), 96 deletions(-) diff --git a/integration-tests/smoke/ccip_test.go b/integration-tests/smoke/ccip_test.go index 51616ff9e62..d8bb15e933e 100644 --- a/integration-tests/smoke/ccip_test.go +++ b/integration-tests/smoke/ccip_test.go @@ -1,11 +1,11 @@ package smoke import ( - "fmt" "math/big" "testing" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/math" "github.com/stretchr/testify/require" cciptypes "github.com/smartcontractkit/chainlink-ccip/pkg/types/ccipocr3" @@ -15,9 +15,11 @@ import ( "github.com/smartcontractkit/chainlink/deployment" ccdeploy "github.com/smartcontractkit/chainlink/deployment/ccip" + ccipdeployment "github.com/smartcontractkit/chainlink/deployment/ccip" "github.com/smartcontractkit/chainlink/deployment/ccip/changeset" "github.com/smartcontractkit/chainlink/integration-tests/ccip-tests/testsetups" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/shared/generated/burn_mint_erc677" "github.com/smartcontractkit/chainlink/v2/core/logger" ) @@ -278,8 +280,89 @@ func TestTokenTransfer(t *testing.T) { require.Equal(t, twoCoins, balance) } +func setupTokens(t *testing.T, tenv ccipdeployment.DeployedEnv) (srcToken *burn_mint_erc677.BurnMintERC677, dstToken *burn_mint_erc677.BurnMintERC677) { + lggr := logger.TestLogger(t) + + e := tenv.Env + state, err := ccdeploy.LoadOnchainState(e) + require.NoError(t, err) + + twoCoins := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(2)) + + // Deploy the token to test transferring + srcToken, _, dstToken, _, err = ccdeploy.DeployTransferableToken( + lggr, + tenv.Env.Chains, + tenv.HomeChainSel, + tenv.FeedChainSel, + state, + e.ExistingAddresses, + "MY_TOKEN", + ) + + linkToken := state.Chains[tenv.HomeChainSel].LinkToken + + require.NoError(t, err) + + tx, err := srcToken.Mint( + e.Chains[tenv.HomeChainSel].DeployerKey, + e.Chains[tenv.HomeChainSel].DeployerKey.From, + new(big.Int).Mul(twoCoins, big.NewInt(10)), + ) + require.NoError(t, err) + + _, err = e.Chains[tenv.HomeChainSel].Confirm(tx) + require.NoError(t, err) + + // Mint a destination token + tx, err = dstToken.Mint( + e.Chains[tenv.FeedChainSel].DeployerKey, + e.Chains[tenv.FeedChainSel].DeployerKey.From, + new(big.Int).Mul(twoCoins, big.NewInt(10)), + ) + + // Confirm the mint tx + require.NoError(t, err) + _, err = e.Chains[tenv.FeedChainSel].Confirm(tx) + require.NoError(t, err) + + maxUint256 := math.MaxBig256 + + // Approve the router to spend the tokens and confirm the tx's + // To prevent having to approve the router for every transfer, we approve a sufficiently large amount + tx, err = srcToken.Approve(e.Chains[tenv.HomeChainSel].DeployerKey, state.Chains[tenv.HomeChainSel].Router.Address(), maxUint256) + require.NoError(t, err) + _, err = e.Chains[tenv.HomeChainSel].Confirm(tx) + require.NoError(t, err) + + tx, err = dstToken.Approve(e.Chains[tenv.FeedChainSel].DeployerKey, state.Chains[tenv.FeedChainSel].Router.Address(), maxUint256) + require.NoError(t, err) + _, err = e.Chains[tenv.FeedChainSel].Confirm(tx) + require.NoError(t, err) + + // Grant mint and burn roles to the deployer key for the newly deployed linkToken + // Since those roles are not granted automatically + tx, err = linkToken.GrantMintAndBurnRoles(e.Chains[tenv.HomeChainSel].DeployerKey, e.Chains[tenv.HomeChainSel].DeployerKey.From) + require.NoError(t, err) + _, err = e.Chains[tenv.HomeChainSel].Confirm(tx) + require.NoError(t, err) + + // Mint link token and confirm the tx + tx, err = linkToken.Mint( + e.Chains[tenv.HomeChainSel].DeployerKey, + e.Chains[tenv.HomeChainSel].DeployerKey.From, + new(big.Int).Mul(twoCoins, big.NewInt(10)), + ) + require.NoError(t, err) + + _, err = e.Chains[tenv.HomeChainSel].Confirm(tx) + require.NoError(t, err) + + return srcToken, dstToken +} + func Test_PricingForTokenTransfers(t *testing.T) { - // Deplot the environment + // Deploy the environment lggr := logger.TestLogger(t) ctx := ccdeploy.Context(t) tenv, _, _ := testsetups.NewLocalDevEnvironment(t, lggr) @@ -314,17 +397,7 @@ func Test_PricingForTokenTransfers(t *testing.T) { state, err = ccdeploy.LoadOnchainState(e) require.NoError(t, err) - // Deploy the token to test transferring - srcToken, _, dstToken, _, err := ccdeploy.DeployTransferableToken( - lggr, - tenv.Env.Chains, - tenv.HomeChainSel, - tenv.FeedChainSel, - state, - e.ExistingAddresses, - "MY_TOKEN", - ) - require.NoError(t, err) + srcToken, dstToken := setupTokens(t, tenv) // Ensure capreg logs are up to date. ccdeploy.ReplayLogs(t, e.Offchain, tenv.ReplayBlocks) @@ -351,65 +424,12 @@ func Test_PricingForTokenTransfers(t *testing.T) { // Mint 2 tokens to be transferred twoCoins := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(2)) - tx, err := srcToken.Mint( - e.Chains[tenv.HomeChainSel].DeployerKey, - e.Chains[tenv.HomeChainSel].DeployerKey.From, - new(big.Int).Mul(twoCoins, big.NewInt(10)), - ) - - if err != nil { - fmt.Printf("Error minting token: %v\n", err) - } - - // Confirm that mint tx - require.NoError(t, err) - _, err = e.Chains[tenv.HomeChainSel].Confirm(tx) - require.NoError(t, err) - - // Mint a destination token - tx, err = dstToken.Mint( - e.Chains[tenv.FeedChainSel].DeployerKey, - e.Chains[tenv.FeedChainSel].DeployerKey.From, - new(big.Int).Mul(twoCoins, big.NewInt(10)), - ) - - // Confirm the mint tx - require.NoError(t, err) - _, err = e.Chains[tenv.FeedChainSel].Confirm(tx) - require.NoError(t, err) linkToken := state.Chains[tenv.HomeChainSel].LinkToken - // Grant mint and burn roles to the deployer key for the newly deployed linkToken - // Since those roles are not granted automatically - tx, err = linkToken.GrantMintAndBurnRoles(e.Chains[tenv.HomeChainSel].DeployerKey, e.Chains[tenv.HomeChainSel].DeployerKey.From) - require.NoError(t, err) - _, err = e.Chains[tenv.HomeChainSel].Confirm(tx) - require.NoError(t, err) - - // Mint link token and confirm the tx - tx, err = linkToken.Mint( - e.Chains[tenv.HomeChainSel].DeployerKey, - e.Chains[tenv.HomeChainSel].DeployerKey.From, - new(big.Int).Mul(twoCoins, big.NewInt(10)), - ) - require.NoError(t, err) - - _, err = e.Chains[tenv.HomeChainSel].Confirm(tx) - require.NoError(t, err) - t.Run("Send Token Pay with Link token home chain -> remote", func(t *testing.T) { - // Approve the router to spend the tokens and confirm the tx's - tx, err = srcToken.Approve(e.Chains[tenv.HomeChainSel].DeployerKey, state.Chains[tenv.HomeChainSel].Router.Address(), twoCoins) - require.NoError(t, err) - _, err = e.Chains[tenv.HomeChainSel].Confirm(tx) - require.NoError(t, err) - tx, err = dstToken.Approve(e.Chains[tenv.FeedChainSel].DeployerKey, state.Chains[tenv.FeedChainSel].Router.Address(), twoCoins) - require.NoError(t, err) - _, err = e.Chains[tenv.FeedChainSel].Confirm(tx) - require.NoError(t, err) // Approve to spend link token - tx, err = linkToken.Approve(e.Chains[tenv.HomeChainSel].DeployerKey, state.Chains[tenv.HomeChainSel].Router.Address(), twoCoins) + tx, err := linkToken.Approve(e.Chains[tenv.HomeChainSel].DeployerKey, state.Chains[tenv.HomeChainSel].Router.Address(), twoCoins) require.NoError(t, err) _, err = e.Chains[tenv.HomeChainSel].Confirm(tx) require.NoError(t, err) @@ -452,7 +472,8 @@ func Test_PricingForTokenTransfers(t *testing.T) { } // Get the fee Token Balance Before - feeTokenBalanceBefore, _ := linkToken.BalanceOf(nil, e.Chains[tenv.HomeChainSel].DeployerKey.From) + feeTokenBalanceBefore, err := linkToken.BalanceOf(nil, e.Chains[tenv.HomeChainSel].DeployerKey.From) + require.NoError(t, err) // Check the fee Amount srcFee, err := state.Chains[src].Router.GetFee(nil, dest, ccipMessage) @@ -462,7 +483,8 @@ func Test_PricingForTokenTransfers(t *testing.T) { expectedSeqNum[dest] = seqNum // Check the fee token balance after the request and ensure fee tokens were spent - feeTokenBalanceAfter, _ := linkToken.BalanceOf(nil, e.Chains[tenv.HomeChainSel].DeployerKey.From) + feeTokenBalanceAfter, err := linkToken.BalanceOf(nil, e.Chains[tenv.HomeChainSel].DeployerKey.From) + require.NoError(t, err) require.Equal(t, feeTokenBalanceAfter, new(big.Int).Sub(feeTokenBalanceBefore, srcFee)) // Wait for all commit reports to land. @@ -488,17 +510,6 @@ func Test_PricingForTokenTransfers(t *testing.T) { }) t.Run("Send Token Pay with native remote chain -> home", func(t *testing.T) { - // Approve the router to spend the tokens and confirm the tx's - tx, err = srcToken.Approve(e.Chains[tenv.HomeChainSel].DeployerKey, state.Chains[tenv.HomeChainSel].Router.Address(), twoCoins) - require.NoError(t, err) - _, err = e.Chains[tenv.HomeChainSel].Confirm(tx) - require.NoError(t, err) - - tx, err = dstToken.Approve(e.Chains[tenv.FeedChainSel].DeployerKey, state.Chains[tenv.FeedChainSel].Router.Address(), twoCoins) - require.NoError(t, err) - _, err = e.Chains[tenv.FeedChainSel].Confirm(tx) - require.NoError(t, err) - // Create two ClientEVMTokenAmount structs to be passed to the router tokens := map[uint64][]router.ClientEVMTokenAmount{ tenv.HomeChainSel: {{ @@ -566,24 +577,12 @@ func Test_PricingForTokenTransfers(t *testing.T) { // but deployerKey is a reference so we need to dereference it and then reassign it depositOps := *e.Chains[tenv.HomeChainSel].DeployerKey depositOps.Value = twoCoins - tx, err = WETH.Deposit(&depositOps) + tx, err := WETH.Deposit(&depositOps) require.NoError(t, err) _, err = e.Chains[tenv.HomeChainSel].Confirm(tx) require.NoError(t, err) - // Approve the router to spend the tokens and confirm the tx's - tx, err = srcToken.Approve(e.Chains[tenv.HomeChainSel].DeployerKey, state.Chains[tenv.HomeChainSel].Router.Address(), twoCoins) - require.NoError(t, err) - _, err = e.Chains[tenv.HomeChainSel].Confirm(tx) - require.NoError(t, err) - - print("APPROVED SRC TO ROUTER") - - tx, err = dstToken.Approve(e.Chains[tenv.FeedChainSel].DeployerKey, state.Chains[tenv.FeedChainSel].Router.Address(), twoCoins) - require.NoError(t, err) - _, err = e.Chains[tenv.FeedChainSel].Confirm(tx) - require.NoError(t, err) - // Approve to spend WETH token as fee + // Approve to spend WETH token as feeToken tx, err = WETH.Approve(e.Chains[tenv.HomeChainSel].DeployerKey, state.Chains[tenv.HomeChainSel].Router.Address(), twoCoins) require.NoError(t, err) _, err = e.Chains[tenv.HomeChainSel].Confirm(tx) @@ -665,7 +664,7 @@ func Test_PricingForTokenTransfers(t *testing.T) { t.Run("Send Token but revert not enough tokens", func(t *testing.T) { // Approve the router to spend the tokens and confirm the tx's - tx, err = srcToken.Approve(e.Chains[tenv.HomeChainSel].DeployerKey, state.Chains[tenv.HomeChainSel].Router.Address(), twoCoins) + tx, err := srcToken.Approve(e.Chains[tenv.HomeChainSel].DeployerKey, state.Chains[tenv.HomeChainSel].Router.Address(), twoCoins) require.NoError(t, err) _, err = e.Chains[tenv.HomeChainSel].Confirm(tx) require.NoError(t, err) @@ -720,7 +719,7 @@ func Test_PricingForTokenTransfers(t *testing.T) { } // Send the CCP Request - tx, _, err := ccdeploy.CCIPSendRequest( + tx, _, err = ccdeploy.CCIPSendRequest( e, state, src, dest, From 2817ca3c487313ebf4e6c16c2fc2559f151f3d97 Mon Sep 17 00:00:00 2001 From: Josh Date: Fri, 15 Nov 2024 10:07:57 -0500 Subject: [PATCH 04/18] remove duplicate import --- integration-tests/smoke/ccip_test.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/integration-tests/smoke/ccip_test.go b/integration-tests/smoke/ccip_test.go index d8bb15e933e..b03dc6e1d1b 100644 --- a/integration-tests/smoke/ccip_test.go +++ b/integration-tests/smoke/ccip_test.go @@ -15,7 +15,6 @@ import ( "github.com/smartcontractkit/chainlink/deployment" ccdeploy "github.com/smartcontractkit/chainlink/deployment/ccip" - ccipdeployment "github.com/smartcontractkit/chainlink/deployment/ccip" "github.com/smartcontractkit/chainlink/deployment/ccip/changeset" "github.com/smartcontractkit/chainlink/integration-tests/ccip-tests/testsetups" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router" @@ -280,7 +279,7 @@ func TestTokenTransfer(t *testing.T) { require.Equal(t, twoCoins, balance) } -func setupTokens(t *testing.T, tenv ccipdeployment.DeployedEnv) (srcToken *burn_mint_erc677.BurnMintERC677, dstToken *burn_mint_erc677.BurnMintERC677) { +func setupTokens(t *testing.T, tenv ccdeploy.DeployedEnv) (srcToken *burn_mint_erc677.BurnMintERC677, dstToken *burn_mint_erc677.BurnMintERC677) { lggr := logger.TestLogger(t) e := tenv.Env From 75fba5faac4421861698aff736c1343472711bc9 Mon Sep 17 00:00:00 2001 From: Josh Date: Fri, 15 Nov 2024 10:12:19 -0500 Subject: [PATCH 05/18] remove additional message data from ccipSendRequest --- integration-tests/smoke/ccip_test.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/integration-tests/smoke/ccip_test.go b/integration-tests/smoke/ccip_test.go index b03dc6e1d1b..bc9592fb265 100644 --- a/integration-tests/smoke/ccip_test.go +++ b/integration-tests/smoke/ccip_test.go @@ -534,7 +534,7 @@ func Test_PricingForTokenTransfers(t *testing.T) { // Send to the receiver on the destination chain paying with native token var ( receiver = common.LeftPadBytes(state.Chains[dest].Receiver.Address().Bytes(), 32) - data = []byte("hello world") + data = []byte("") feeToken = common.HexToAddress("0x0") ) @@ -732,3 +732,5 @@ func Test_PricingForTokenTransfers(t *testing.T) { }) } + + From 73bcc17529feaeba08dcae3b3d7dceecfab919a8 Mon Sep 17 00:00:00 2001 From: Josh Date: Fri, 15 Nov 2024 10:51:59 -0500 Subject: [PATCH 06/18] attempt lint fix and comment --- integration-tests/smoke/ccip_test.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/integration-tests/smoke/ccip_test.go b/integration-tests/smoke/ccip_test.go index bc9592fb265..ec99efe06ce 100644 --- a/integration-tests/smoke/ccip_test.go +++ b/integration-tests/smoke/ccip_test.go @@ -279,6 +279,8 @@ func TestTokenTransfer(t *testing.T) { require.Equal(t, twoCoins, balance) } +// setupTokens deploys transferable tokens on the source and dest, mints tokens for the source and dest, and +// approves the router to spend the tokens func setupTokens(t *testing.T, tenv ccdeploy.DeployedEnv) (srcToken *burn_mint_erc677.BurnMintERC677, dstToken *burn_mint_erc677.BurnMintERC677) { lggr := logger.TestLogger(t) @@ -730,7 +732,4 @@ func Test_PricingForTokenTransfers(t *testing.T) { require.Error(t, err) require.Nil(t, tx) }) - } - - From 1da4e3efe6d283fd6f5b3d79626f7c6f9f68d7e9 Mon Sep 17 00:00:00 2001 From: Josh Date: Tue, 19 Nov 2024 10:24:12 -0500 Subject: [PATCH 07/18] add new e2e messaging tests --- integration-tests/smoke/ccip_test.go | 262 ++++++++++++++++++++++++++- 1 file changed, 258 insertions(+), 4 deletions(-) diff --git a/integration-tests/smoke/ccip_test.go b/integration-tests/smoke/ccip_test.go index ad588f497c6..b7f0fd20d33 100644 --- a/integration-tests/smoke/ccip_test.go +++ b/integration-tests/smoke/ccip_test.go @@ -8,6 +8,8 @@ import ( "github.com/ethereum/go-ethereum/common/math" "github.com/stretchr/testify/require" + cciptypes "github.com/smartcontractkit/chainlink-ccip/pkg/types/ccipocr3" + "github.com/smartcontractkit/chainlink-ccip/pluginconfig" jobv1 "github.com/smartcontractkit/chainlink-protos/job-distributor/v1/job" "github.com/smartcontractkit/chainlink-testing-framework/lib/utils/testcontext" @@ -360,7 +362,7 @@ func Test_PricingForTokenTransfers(t *testing.T) { // Deploy the environment lggr := logger.TestLogger(t) ctx := ccdeploy.Context(t) - tenv, _, _ := testsetups.NewLocalDevEnvironment(t, lggr) + tenv, _, _ := testsetups.NewLocalDevEnvironmentWithDefaultPrice(t, lggr) // Load the test state e := tenv.Env @@ -474,7 +476,7 @@ func Test_PricingForTokenTransfers(t *testing.T) { srcFee, err := state.Chains[src].Router.GetFee(nil, dest, ccipMessage) require.NoError(t, err) - seqNum := ccdeploy.TestSendRequest(t, e, state, src, dest, false, ccipMessage) + seqNum := ccdeploy.TestSendRequest(t, e, state, src, dest, false, ccipMessage).SequenceNumber expectedSeqNum[dest] = seqNum // Check the fee token balance after the request and ensure fee tokens were spent @@ -542,7 +544,7 @@ func Test_PricingForTokenTransfers(t *testing.T) { ExtraArgs: nil, } - seqNum := ccdeploy.TestSendRequest(t, e, state, src, dest, false, ccipMessage) + seqNum := ccdeploy.TestSendRequest(t, e, state, src, dest, false, ccipMessage).SequenceNumber expectedSeqNum[dest] = seqNum // Wait for all commit reports to land. @@ -628,7 +630,7 @@ func Test_PricingForTokenTransfers(t *testing.T) { srcFee, err := state.Chains[src].Router.GetFee(nil, dest, ccipMessage) require.NoError(t, err) - seqNum := ccdeploy.TestSendRequest(t, e, state, src, dest, false, ccipMessage) + seqNum := ccdeploy.TestSendRequest(t, e, state, src, dest, false, ccipMessage).SequenceNumber expectedSeqNum[dest] = seqNum // Check the fee token balance after the request and ensure fee tokens were spent @@ -727,3 +729,255 @@ func Test_PricingForTokenTransfers(t *testing.T) { require.Nil(t, tx) }) } + +func Test_PricingForMessages(t *testing.T) { + // Deploy the environment + lggr := logger.TestLogger(t) + ctx := ccdeploy.Context(t) + tenv, _, _ := testsetups.NewLocalDevEnvironmentWithDefaultPrice(t, lggr) + + // Load the test state + e := tenv.Env + state, err := ccdeploy.LoadOnchainState(e) + require.NoError(t, err) + + feeds := state.Chains[tenv.FeedChainSel].USDFeeds + tokenConfig := ccdeploy.NewTokenConfig() + tokenConfig.UpsertTokenInfo(ccdeploy.LinkSymbol, + pluginconfig.TokenInfo{ + AggregatorAddress: cciptypes.UnknownEncodedAddress(feeds[ccdeploy.LinkSymbol].Address().String()), + Decimals: ccdeploy.LinkDecimals, + DeviationPPB: cciptypes.NewBigIntFromInt64(1e9), + }, + ) + + // Apply migration + output, err := changeset.InitialDeploy(e, ccdeploy.DeployCCIPContractConfig{ + HomeChainSel: tenv.HomeChainSel, + FeedChainSel: tenv.FeedChainSel, + ChainsToDeploy: e.AllChainSelectors(), + TokenConfig: tokenConfig, + MCMSConfig: ccdeploy.NewTestMCMSConfig(t, e), + OCRSecrets: deployment.XXXGenerateTestOCRSecrets(), + }) + require.NoError(t, err) + require.NoError(t, e.ExistingAddresses.Merge(output.AddressBook)) + // Get new state after migration and mock USDC token deployment. + state, err = ccdeploy.LoadOnchainState(e) + require.NoError(t, err) + + // Ensure capreg logs are up to date. + ccdeploy.ReplayLogs(t, e.Offchain, tenv.ReplayBlocks) + + // Create an empty tokenAmounts map since we are sending a message without a token + tokens := []router.ClientEVMTokenAmount{} + + // Apply the jobs. + for nodeID, jobs := range output.JobSpecs { + for _, job := range jobs { + // Note these auto-accept + _, err := e.Offchain.ProposeJob(ctx, + &jobv1.ProposeJobRequest{ + NodeId: nodeID, + Spec: job, + }) + require.NoError(t, err) + } + } + + // Add all lanes + require.NoError(t, ccdeploy.AddLanesForAll(e, state)) + // Need to keep track of the block number for each chain so that event subscription can be done from that block. + startBlocks := make(map[uint64]*uint64) + // Send a message from each chain to every other chain. + expectedSeqNum := make(map[uint64]uint64) + + // Mint 2 tokens to be transferred + twoCoins := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(2)) + + linkToken := state.Chains[tenv.HomeChainSel].LinkToken + + t.Run("Send Token Pay with Link token home chain -> remote", func(t *testing.T) { + // Approve to spend link token + tx, err := linkToken.Approve(e.Chains[tenv.HomeChainSel].DeployerKey, state.Chains[tenv.HomeChainSel].Router.Address(), twoCoins) + require.NoError(t, err) + _, err = e.Chains[tenv.HomeChainSel].Confirm(tx) + require.NoError(t, err) + + // Assign Src to the Home Chain Selector and destChain to the Feed Chain Selector + src := tenv.HomeChainSel + dest, destChain := tenv.FeedChainSel, e.Chains[tenv.FeedChainSel] + + // get the header for the destination chain and the relevant block number + latesthdr, err := destChain.Client.HeaderByNumber(testcontext.Get(t), nil) + require.NoError(t, err) + block := latesthdr.Number.Uint64() + startBlocks[dest] = &block + + // Send to the receiver on the destination chain paying with LINK token + var ( + receiver = common.LeftPadBytes(state.Chains[dest].Receiver.Address().Bytes(), 32) + data = []byte("hello world") + feeToken = linkToken.Address() + ) + + ccipMessage := router.ClientEVM2AnyMessage{ + Receiver: receiver, + Data: data, + TokenAmounts: tokens, + FeeToken: feeToken, + ExtraArgs: nil, + } + + // Get the fee Token Balance Before + feeTokenBalanceBefore, err := linkToken.BalanceOf(nil, e.Chains[tenv.HomeChainSel].DeployerKey.From) + require.NoError(t, err) + + // Check the fee Amount + srcFee, err := state.Chains[src].Router.GetFee(nil, dest, ccipMessage) + require.NoError(t, err) + + seqNum := ccdeploy.TestSendRequest(t, e, state, src, dest, false, ccipMessage).SequenceNumber + expectedSeqNum[dest] = seqNum + + // Check the fee token balance after the request and ensure fee tokens were spent + feeTokenBalanceAfter, err := linkToken.BalanceOf(nil, e.Chains[tenv.HomeChainSel].DeployerKey.From) + require.NoError(t, err) + require.Equal(t, feeTokenBalanceAfter, new(big.Int).Sub(feeTokenBalanceBefore, srcFee)) + + // Wait for all commit reports to land. + ccdeploy.ConfirmCommitForAllWithExpectedSeqNums(t, e, state, expectedSeqNum, startBlocks) + + // After commit is reported on all chains, token prices should be updated in FeeQuoter. + linkAddress := state.Chains[dest].LinkToken.Address() + feeQuoter := state.Chains[dest].FeeQuoter + timestampedPrice, err := feeQuoter.GetTokenPrice(nil, linkAddress) + require.NoError(t, err) + require.Equal(t, ccdeploy.MockLinkPrice, timestampedPrice.Value) + + // Wait for all exec reports to land + ccdeploy.ConfirmExecWithSeqNrForAll(t, e, state, expectedSeqNum, startBlocks) + + // Delete from the expcted seq num the chain that was just tested so that we don't pass it to the + // commit report in the next test + delete(expectedSeqNum, dest) + }) + + t.Run("Send Token Pay with native remote chain -> home", func(t *testing.T) { + // Assign Src to the Home Chain Selector and destChain to the Feed Chain Selector + src := tenv.FeedChainSel + dest, destChain := tenv.HomeChainSel, e.Chains[tenv.HomeChainSel] + + // get the header for the destination chain and the relevant block number + latesthdr, err := destChain.Client.HeaderByNumber(testcontext.Get(t), nil) + require.NoError(t, err) + block := latesthdr.Number.Uint64() + startBlocks[dest] = &block + + // Send to the receiver on the destination chain paying with native token + var ( + receiver = common.LeftPadBytes(state.Chains[dest].Receiver.Address().Bytes(), 32) + data = []byte("") + feeToken = common.HexToAddress("0x0") + ) + + ccipMessage := router.ClientEVM2AnyMessage{ + Receiver: receiver, + Data: data, + TokenAmounts: tokens, + FeeToken: feeToken, + ExtraArgs: nil, + } + + seqNum := ccdeploy.TestSendRequest(t, e, state, src, dest, false, ccipMessage).SequenceNumber + expectedSeqNum[dest] = seqNum + + // Wait for all commit reports to land. + ccdeploy.ConfirmCommitForAllWithExpectedSeqNums(t, e, state, expectedSeqNum, startBlocks) + + // After commit is reported on all chains, token prices should be updated in FeeQuoter. + linkAddress := state.Chains[dest].LinkToken.Address() + feeQuoter := state.Chains[dest].FeeQuoter + timestampedPrice, err := feeQuoter.GetTokenPrice(nil, linkAddress) + require.NoError(t, err) + require.Equal(t, ccdeploy.MockLinkPrice, timestampedPrice.Value) + + // Wait for all exec reports to land + ccdeploy.ConfirmExecWithSeqNrForAll(t, e, state, expectedSeqNum, startBlocks) + + delete(expectedSeqNum, dest) + }) + + t.Run("Send Token pay with wrapped native home chain -> remote", func(t *testing.T) { + WETH := state.Chains[tenv.HomeChainSel].Weth9 + + // We need to acquire some WETH to send with the tx so we deposit some ETH into the WETH contract + // but deployerKey is a reference so we need to dereference it and then reassign it + depositOps := *e.Chains[tenv.HomeChainSel].DeployerKey + depositOps.Value = twoCoins + tx, err := WETH.Deposit(&depositOps) + require.NoError(t, err) + _, err = e.Chains[tenv.HomeChainSel].Confirm(tx) + require.NoError(t, err) + + // Approve to spend WETH token as feeToken + tx, err = WETH.Approve(e.Chains[tenv.HomeChainSel].DeployerKey, state.Chains[tenv.HomeChainSel].Router.Address(), twoCoins) + require.NoError(t, err) + _, err = e.Chains[tenv.HomeChainSel].Confirm(tx) + require.NoError(t, err) + + // Assign Src to the Home Chain Selector and destChain to the Feed Chain Selector + src := tenv.HomeChainSel + dest, destChain := tenv.FeedChainSel, e.Chains[tenv.FeedChainSel] + + // get the header for the destination chain and the relevant block number + latesthdr, err := destChain.Client.HeaderByNumber(testcontext.Get(t), nil) + require.NoError(t, err) + block := latesthdr.Number.Uint64() + startBlocks[dest] = &block + + // Send to the receiver on the destination chain paying with LINK token + var ( + receiver = common.LeftPadBytes(state.Chains[dest].Receiver.Address().Bytes(), 32) + data = []byte("hello world") + feeToken = state.Chains[src].Weth9.Address() + ) + + ccipMessage := router.ClientEVM2AnyMessage{ + Receiver: receiver, + Data: data, + TokenAmounts: tokens, + FeeToken: feeToken, + ExtraArgs: nil, + } + + // Get the fee Token Balance Before + feeTokenBalanceBefore, err := WETH.BalanceOf(nil, e.Chains[src].DeployerKey.From) + require.NoError(t, err) + + // Check the fee Amount + srcFee, err := state.Chains[src].Router.GetFee(nil, dest, ccipMessage) + require.NoError(t, err) + + seqNum := ccdeploy.TestSendRequest(t, e, state, src, dest, false, ccipMessage).SequenceNumber + expectedSeqNum[dest] = seqNum + + // Check the fee token balance after the request and ensure fee tokens were spent + feeTokenBalanceAfter, err := WETH.BalanceOf(nil, e.Chains[tenv.HomeChainSel].DeployerKey.From) + require.NoError(t, err) + require.Equal(t, feeTokenBalanceAfter, new(big.Int).Sub(feeTokenBalanceBefore, srcFee)) + + // Wait for all commit reports to land. + ccdeploy.ConfirmCommitForAllWithExpectedSeqNums(t, e, state, expectedSeqNum, startBlocks) + + // After commit is reported on all chains, token prices should be updated in FeeQuoter. + linkAddress := state.Chains[dest].LinkToken.Address() + feeQuoter := state.Chains[dest].FeeQuoter + timestampedPrice, err := feeQuoter.GetTokenPrice(nil, linkAddress) + require.NoError(t, err) + require.Equal(t, ccdeploy.MockLinkPrice, timestampedPrice.Value) + + // Wait for all exec reports to land + ccdeploy.ConfirmExecWithSeqNrForAll(t, e, state, expectedSeqNum, startBlocks) + }) +} From c62c8d7537b2384ac22fd4bef65a9b69e04f592f Mon Sep 17 00:00:00 2001 From: Josh Date: Wed, 20 Nov 2024 11:23:02 -0500 Subject: [PATCH 08/18] checkpoint work --- integration-tests/smoke/ccip_test.go | 86 +++++++++++++++++----------- 1 file changed, 53 insertions(+), 33 deletions(-) diff --git a/integration-tests/smoke/ccip_test.go b/integration-tests/smoke/ccip_test.go index b7f0fd20d33..226b7edecb7 100644 --- a/integration-tests/smoke/ccip_test.go +++ b/integration-tests/smoke/ccip_test.go @@ -1,6 +1,7 @@ package smoke import ( + "fmt" "math/big" "testing" @@ -284,7 +285,7 @@ func setupTokens(t *testing.T, tenv ccdeploy.DeployedEnv) (srcToken *burn_mint_e state, err := ccdeploy.LoadOnchainState(e) require.NoError(t, err) - twoCoins := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(2)) + tenCoins := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(10)) // Deploy the token to test transferring srcToken, _, dstToken, _, err = ccdeploy.DeployTransferableToken( @@ -304,7 +305,7 @@ func setupTokens(t *testing.T, tenv ccdeploy.DeployedEnv) (srcToken *burn_mint_e tx, err := srcToken.Mint( e.Chains[tenv.HomeChainSel].DeployerKey, e.Chains[tenv.HomeChainSel].DeployerKey.From, - new(big.Int).Mul(twoCoins, big.NewInt(10)), + new(big.Int).Mul(tenCoins, big.NewInt(10)), ) require.NoError(t, err) @@ -315,7 +316,7 @@ func setupTokens(t *testing.T, tenv ccdeploy.DeployedEnv) (srcToken *burn_mint_e tx, err = dstToken.Mint( e.Chains[tenv.FeedChainSel].DeployerKey, e.Chains[tenv.FeedChainSel].DeployerKey.From, - new(big.Int).Mul(twoCoins, big.NewInt(10)), + new(big.Int).Mul(tenCoins, big.NewInt(10)), ) // Confirm the mint tx @@ -348,7 +349,7 @@ func setupTokens(t *testing.T, tenv ccdeploy.DeployedEnv) (srcToken *burn_mint_e tx, err = linkToken.Mint( e.Chains[tenv.HomeChainSel].DeployerKey, e.Chains[tenv.HomeChainSel].DeployerKey.From, - new(big.Int).Mul(twoCoins, big.NewInt(10)), + new(big.Int).Mul(tenCoins, big.NewInt(10)), ) require.NoError(t, err) @@ -359,38 +360,34 @@ func setupTokens(t *testing.T, tenv ccdeploy.DeployedEnv) (srcToken *burn_mint_e } func Test_PricingForTokenTransfers(t *testing.T) { - // Deploy the environment + t.Parallel() lggr := logger.TestLogger(t) ctx := ccdeploy.Context(t) tenv, _, _ := testsetups.NewLocalDevEnvironmentWithDefaultPrice(t, lggr) - - // Load the test state e := tenv.Env - state, err := ccdeploy.LoadOnchainState(e) + + state, err := ccdeploy.LoadOnchainState(tenv.Env) require.NoError(t, err) feeds := state.Chains[tenv.FeedChainSel].USDFeeds - tokenConfig := ccdeploy.NewTokenConfig() - tokenConfig.UpsertTokenInfo(ccdeploy.LinkSymbol, - pluginconfig.TokenInfo{ - AggregatorAddress: cciptypes.UnknownEncodedAddress(feeds[ccdeploy.LinkSymbol].Address().String()), - Decimals: ccdeploy.LinkDecimals, - DeviationPPB: cciptypes.NewBigIntFromInt64(1e9), - }, - ) + output, err := changeset.DeployPrerequisites(tenv.Env, changeset.DeployPrerequisiteConfig{ + ChainSelectors: tenv.Env.AllChainSelectors(), + }) + require.NoError(t, err) + require.NoError(t, tenv.Env.ExistingAddresses.Merge(output.AddressBook)) // Apply migration - output, err := changeset.InitialDeploy(e, ccdeploy.DeployCCIPContractConfig{ + output, err = changeset.InitialDeploy(tenv.Env, ccdeploy.DeployCCIPContractConfig{ HomeChainSel: tenv.HomeChainSel, FeedChainSel: tenv.FeedChainSel, - ChainsToDeploy: e.AllChainSelectors(), - TokenConfig: tokenConfig, + ChainsToDeploy: tenv.Env.AllChainSelectors(), + TokenConfig: ccdeploy.NewTestTokenConfig(feeds), MCMSConfig: ccdeploy.NewTestMCMSConfig(t, e), OCRSecrets: deployment.XXXGenerateTestOCRSecrets(), }) require.NoError(t, err) - require.NoError(t, e.ExistingAddresses.Merge(output.AddressBook)) - // Get new state after migration and mock USDC token deployment. + require.NoError(t, tenv.Env.ExistingAddresses.Merge(output.AddressBook)) + // Get new state after migration. state, err = ccdeploy.LoadOnchainState(e) require.NoError(t, err) @@ -423,14 +420,23 @@ func Test_PricingForTokenTransfers(t *testing.T) { twoCoins := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(2)) linkToken := state.Chains[tenv.HomeChainSel].LinkToken + maxUint256 := math.MaxBig256 t.Run("Send Token Pay with Link token home chain -> remote", func(t *testing.T) { + src := tenv.HomeChainSel + dest, destChain := tenv.FeedChainSel, e.Chains[tenv.FeedChainSel] + // Approve to spend link token - tx, err := linkToken.Approve(e.Chains[tenv.HomeChainSel].DeployerKey, state.Chains[tenv.HomeChainSel].Router.Address(), twoCoins) + tx, err := linkToken.Approve(e.Chains[src].DeployerKey, state.Chains[src].Router.Address(), maxUint256) require.NoError(t, err) - _, err = e.Chains[tenv.HomeChainSel].Confirm(tx) + _, err = e.Chains[src].Confirm(tx) require.NoError(t, err) + // Get the fee Token Balance Before + srctokenBalance, err := srcToken.BalanceOf(nil, e.Chains[src].DeployerKey.From) + require.NoError(t, err) + require.GreaterOrEqual(t, srctokenBalance.Int64(), twoCoins.Int64()) + // Create two ClientEVMTokenAmount structs to be passed to the router tokens := map[uint64][]router.ClientEVMTokenAmount{ tenv.HomeChainSel: {{ @@ -444,8 +450,6 @@ func Test_PricingForTokenTransfers(t *testing.T) { } // Assign Src to the Home Chain Selector and destChain to the Feed Chain Selector - src := tenv.HomeChainSel - dest, destChain := tenv.FeedChainSel, e.Chains[tenv.FeedChainSel] // get the header for the destination chain and the relevant block number latesthdr, err := destChain.Client.HeaderByNumber(testcontext.Get(t), nil) @@ -469,7 +473,7 @@ func Test_PricingForTokenTransfers(t *testing.T) { } // Get the fee Token Balance Before - feeTokenBalanceBefore, err := linkToken.BalanceOf(nil, e.Chains[tenv.HomeChainSel].DeployerKey.From) + feeTokenBalanceBefore, err := linkToken.BalanceOf(nil, e.Chains[src].DeployerKey.From) require.NoError(t, err) // Check the fee Amount @@ -568,22 +572,33 @@ func Test_PricingForTokenTransfers(t *testing.T) { }) t.Run("Send Token pay with wrapped native home chain -> remote", func(t *testing.T) { - WETH := state.Chains[tenv.HomeChainSel].Weth9 + // Assign Src to the Home Chain Selector and destChain to the Feed Chain Selector + src := tenv.HomeChainSel + dest, destChain := tenv.FeedChainSel, e.Chains[tenv.FeedChainSel] + + WETH := state.Chains[src].Weth9 // We need to acquire some WETH to send with the tx so we deposit some ETH into the WETH contract // but deployerKey is a reference so we need to dereference it and then reassign it depositOps := *e.Chains[tenv.HomeChainSel].DeployerKey - depositOps.Value = twoCoins + depositOps.Value = new(big.Int).Mul(twoCoins, big.NewInt(2)) tx, err := WETH.Deposit(&depositOps) require.NoError(t, err) _, err = e.Chains[tenv.HomeChainSel].Confirm(tx) require.NoError(t, err) // Approve to spend WETH token as feeToken + fmt.Printf("--- APPROVING ROUTER TO SPEND---") tx, err = WETH.Approve(e.Chains[tenv.HomeChainSel].DeployerKey, state.Chains[tenv.HomeChainSel].Router.Address(), twoCoins) require.NoError(t, err) + fmt.Printf("tx: %v\n", tx) _, err = e.Chains[tenv.HomeChainSel].Confirm(tx) require.NoError(t, err) + fmt.Printf("--- APPROVED ---") + + allowance, err := WETH.Allowance(nil, e.Chains[src].DeployerKey.From, state.Chains[src].Router.Address()) + require.NoError(t, err) + require.GreaterOrEqual(t, allowance.Int64(), twoCoins.Int64()) // Create two ClientEVMTokenAmount structs to be passed to the router tokens := map[uint64][]router.ClientEVMTokenAmount{ @@ -597,9 +612,9 @@ func Test_PricingForTokenTransfers(t *testing.T) { }}, } - // Assign Src to the Home Chain Selector and destChain to the Feed Chain Selector - src := tenv.HomeChainSel - dest, destChain := tenv.FeedChainSel, e.Chains[tenv.FeedChainSel] + srcTokenBal, err := srcToken.BalanceOf(nil, e.Chains[src].DeployerKey.From) + require.NoError(t, err) + require.GreaterOrEqual(t, srcTokenBal.Int64(), twoCoins.Int64()) // get the header for the destination chain and the relevant block number latesthdr, err := destChain.Client.HeaderByNumber(testcontext.Get(t), nil) @@ -630,6 +645,11 @@ func Test_PricingForTokenTransfers(t *testing.T) { srcFee, err := state.Chains[src].Router.GetFee(nil, dest, ccipMessage) require.NoError(t, err) + // Check that we have enough WETH to pay the fee + require.GreaterOrEqual(t, feeTokenBalanceBefore.Int64(), srcFee.Int64()) + fmt.Printf("srcFee: %v\n", srcFee) + fmt.Printf("feeTokenBalanceBefore: %v\n", feeTokenBalanceBefore) + seqNum := ccdeploy.TestSendRequest(t, e, state, src, dest, false, ccipMessage).SequenceNumber expectedSeqNum[dest] = seqNum @@ -914,14 +934,14 @@ func Test_PricingForMessages(t *testing.T) { // We need to acquire some WETH to send with the tx so we deposit some ETH into the WETH contract // but deployerKey is a reference so we need to dereference it and then reassign it depositOps := *e.Chains[tenv.HomeChainSel].DeployerKey - depositOps.Value = twoCoins + depositOps.Value = new(big.Int).Mul(twoCoins, big.NewInt(2)) tx, err := WETH.Deposit(&depositOps) require.NoError(t, err) _, err = e.Chains[tenv.HomeChainSel].Confirm(tx) require.NoError(t, err) // Approve to spend WETH token as feeToken - tx, err = WETH.Approve(e.Chains[tenv.HomeChainSel].DeployerKey, state.Chains[tenv.HomeChainSel].Router.Address(), twoCoins) + tx, err = WETH.Approve(e.Chains[tenv.HomeChainSel].DeployerKey, state.Chains[tenv.HomeChainSel].Router.Address(), new(big.Int).Mul(twoCoins, big.NewInt(2))) require.NoError(t, err) _, err = e.Chains[tenv.HomeChainSel].Confirm(tx) require.NoError(t, err) From fa67e21f2e9963366e98ed00ca1e757c2aa808f8 Mon Sep 17 00:00:00 2001 From: Josh Date: Thu, 21 Nov 2024 12:03:54 -0500 Subject: [PATCH 09/18] checkpointing --- integration-tests/smoke/ccip_test.go | 167 +++++++++++++++------------ 1 file changed, 91 insertions(+), 76 deletions(-) diff --git a/integration-tests/smoke/ccip_test.go b/integration-tests/smoke/ccip_test.go index f668b545fe1..305804c0c6f 100644 --- a/integration-tests/smoke/ccip_test.go +++ b/integration-tests/smoke/ccip_test.go @@ -9,8 +9,6 @@ import ( "github.com/ethereum/go-ethereum/common/math" "github.com/stretchr/testify/require" - cciptypes "github.com/smartcontractkit/chainlink-ccip/pkg/types/ccipocr3" - "github.com/smartcontractkit/chainlink-ccip/pluginconfig" "github.com/smartcontractkit/chainlink-testing-framework/lib/utils/testcontext" "github.com/smartcontractkit/chainlink/deployment/ccip/changeset" "github.com/smartcontractkit/chainlink/integration-tests/ccip-tests/testsetups" @@ -204,17 +202,17 @@ func TestTokenTransfer(t *testing.T) { // setupTokens deploys transferable tokens on the source and dest, mints tokens for the source and dest, and // approves the router to spend the tokens -func setupTokens(t *testing.T, tenv ccdeploy.DeployedEnv) (srcToken *burn_mint_erc677.BurnMintERC677, dstToken *burn_mint_erc677.BurnMintERC677) { +func setupTokens(t *testing.T, tenv changeset.DeployedEnv) (srcToken *burn_mint_erc677.BurnMintERC677, dstToken *burn_mint_erc677.BurnMintERC677) { lggr := logger.TestLogger(t) e := tenv.Env - state, err := ccdeploy.LoadOnchainState(e) + state, err := changeset.LoadOnchainState(e) require.NoError(t, err) tenCoins := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(10)) // Deploy the token to test transferring - srcToken, _, dstToken, _, err = ccdeploy.DeployTransferableToken( + srcToken, _, dstToken, _, err = changeset.DeployTransferableToken( lggr, tenv.Env.Chains, tenv.HomeChainSel, @@ -288,59 +286,60 @@ func setupTokens(t *testing.T, tenv ccdeploy.DeployedEnv) (srcToken *burn_mint_e func Test_PricingForTokenTransfers(t *testing.T) { t.Parallel() lggr := logger.TestLogger(t) - ctx := ccdeploy.Context(t) + // ctx := changeset.Context(t) tenv, _, _ := testsetups.NewLocalDevEnvironmentWithDefaultPrice(t, lggr) e := tenv.Env - state, err := ccdeploy.LoadOnchainState(tenv.Env) + state, err := changeset.LoadOnchainState(tenv.Env) require.NoError(t, err) - feeds := state.Chains[tenv.FeedChainSel].USDFeeds + // feeds := state.Chains[tenv.FeedChainSel].USDFeeds output, err := changeset.DeployPrerequisites(tenv.Env, changeset.DeployPrerequisiteConfig{ ChainSelectors: tenv.Env.AllChainSelectors(), }) require.NoError(t, err) require.NoError(t, tenv.Env.ExistingAddresses.Merge(output.AddressBook)) - // Apply migration - output, err = changeset.InitialDeploy(tenv.Env, ccdeploy.DeployCCIPContractConfig{ - HomeChainSel: tenv.HomeChainSel, - FeedChainSel: tenv.FeedChainSel, - ChainsToDeploy: tenv.Env.AllChainSelectors(), - TokenConfig: ccdeploy.NewTestTokenConfig(feeds), - MCMSConfig: ccdeploy.NewTestMCMSConfig(t, e), - OCRSecrets: deployment.XXXGenerateTestOCRSecrets(), - }) + expectedSeqNum := make(map[changeset.SourceDestPair]uint64) + + // // Apply migration + // output, err = changeset.InitialDeploy(tenv.Env, changeset.DeployCCIPContractConfig{ + // HomeChainSel: tenv.HomeChainSel, + // FeedChainSel: tenv.FeedChainSel, + // ChainsToDeploy: tenv.Env.AllChainSelectors(), + // TokenConfig: changeset.NewTestTokenConfig(feeds), + // MCMSConfig: changeset.NewTestMCMSConfig(t, e), + // OCRSecrets: deployment.XXXGenerateTestOCRSecrets(), + // }) require.NoError(t, err) require.NoError(t, tenv.Env.ExistingAddresses.Merge(output.AddressBook)) // Get new state after migration. - state, err = ccdeploy.LoadOnchainState(e) + state, err = changeset.LoadOnchainState(e) require.NoError(t, err) srcToken, dstToken := setupTokens(t, tenv) // Ensure capreg logs are up to date. - ccdeploy.ReplayLogs(t, e.Offchain, tenv.ReplayBlocks) - - // Apply the jobs. - for nodeID, jobs := range output.JobSpecs { - for _, job := range jobs { - // Note these auto-accept - _, err := e.Offchain.ProposeJob(ctx, - &jobv1.ProposeJobRequest{ - NodeId: nodeID, - Spec: job, - }) - require.NoError(t, err) - } - } + changeset.ReplayLogs(t, e.Offchain, tenv.ReplayBlocks) + + // // Apply the jobs. + // for nodeID, jobs := range output.JobSpecs { + // for _, job := range jobs { + // // Note these auto-accept + // _, err := e.Offchain.ProposeJob(ctx, + // &jobv1.ProposeJobRequest{ + // NodeId: nodeID, + // Spec: job, + // }) + // require.NoError(t, err) + // } + // } // Add all lanes - require.NoError(t, ccdeploy.AddLanesForAll(e, state)) + require.NoError(t, changeset.AddLanesForAll(e, state)) // Need to keep track of the block number for each chain so that event subscription can be done from that block. startBlocks := make(map[uint64]*uint64) // Send a message from each chain to every other chain. - expectedSeqNum := make(map[uint64]uint64) // Mint 2 tokens to be transferred twoCoins := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(2)) @@ -352,6 +351,11 @@ func Test_PricingForTokenTransfers(t *testing.T) { src := tenv.HomeChainSel dest, destChain := tenv.FeedChainSel, e.Chains[tenv.FeedChainSel] + sourceDestPair := changeset.SourceDestPair{ + SourceChainSelector: src, + DestChainSelector: dest, + } + // Approve to spend link token tx, err := linkToken.Approve(e.Chains[src].DeployerKey, state.Chains[src].Router.Address(), maxUint256) require.NoError(t, err) @@ -406,8 +410,8 @@ func Test_PricingForTokenTransfers(t *testing.T) { srcFee, err := state.Chains[src].Router.GetFee(nil, dest, ccipMessage) require.NoError(t, err) - seqNum := ccdeploy.TestSendRequest(t, e, state, src, dest, false, ccipMessage).SequenceNumber - expectedSeqNum[dest] = seqNum + seqNum := changeset.TestSendRequest(t, e, state, src, dest, false, ccipMessage).SequenceNumber + expectedSeqNum[sourceDestPair] = seqNum // Check the fee token balance after the request and ensure fee tokens were spent feeTokenBalanceAfter, err := linkToken.BalanceOf(nil, e.Chains[tenv.HomeChainSel].DeployerKey.From) @@ -415,17 +419,17 @@ func Test_PricingForTokenTransfers(t *testing.T) { require.Equal(t, feeTokenBalanceAfter, new(big.Int).Sub(feeTokenBalanceBefore, srcFee)) // Wait for all commit reports to land. - ccdeploy.ConfirmCommitForAllWithExpectedSeqNums(t, e, state, expectedSeqNum, startBlocks) + changeset.ConfirmCommitForAllWithExpectedSeqNums(t, e, state, expectedSeqNum, startBlocks) // After commit is reported on all chains, token prices should be updated in FeeQuoter. linkAddress := state.Chains[dest].LinkToken.Address() feeQuoter := state.Chains[dest].FeeQuoter timestampedPrice, err := feeQuoter.GetTokenPrice(nil, linkAddress) require.NoError(t, err) - require.Equal(t, ccdeploy.MockLinkPrice, timestampedPrice.Value) + require.Equal(t, changeset.MockLinkPrice, timestampedPrice.Value) // Wait for all exec reports to land - ccdeploy.ConfirmExecWithSeqNrForAll(t, e, state, expectedSeqNum, startBlocks) + changeset.ConfirmExecWithSeqNrForAll(t, e, state, expectedSeqNum, startBlocks) balance, err := dstToken.BalanceOf(nil, state.Chains[tenv.FeedChainSel].Receiver.Address()) require.NoError(t, err) @@ -433,7 +437,7 @@ func Test_PricingForTokenTransfers(t *testing.T) { // Delete from the expcted seq num the chain that was just tested so that we don't pass it to the // commit report in the next test - delete(expectedSeqNum, dest) + delete(expectedSeqNum, sourceDestPair) }) t.Run("Send Token Pay with native remote chain -> home", func(t *testing.T) { @@ -453,6 +457,11 @@ func Test_PricingForTokenTransfers(t *testing.T) { src := tenv.FeedChainSel dest, destChain := tenv.HomeChainSel, e.Chains[tenv.HomeChainSel] + sourceDestPair := changeset.SourceDestPair{ + SourceChainSelector: src, + DestChainSelector: dest, + } + // get the header for the destination chain and the relevant block number latesthdr, err := destChain.Client.HeaderByNumber(testcontext.Get(t), nil) require.NoError(t, err) @@ -474,27 +483,27 @@ func Test_PricingForTokenTransfers(t *testing.T) { ExtraArgs: nil, } - seqNum := ccdeploy.TestSendRequest(t, e, state, src, dest, false, ccipMessage).SequenceNumber - expectedSeqNum[dest] = seqNum + seqNum := changeset.TestSendRequest(t, e, state, src, dest, false, ccipMessage).SequenceNumber + expectedSeqNum[sourceDestPair] = seqNum // Wait for all commit reports to land. - ccdeploy.ConfirmCommitForAllWithExpectedSeqNums(t, e, state, expectedSeqNum, startBlocks) + changeset.ConfirmCommitForAllWithExpectedSeqNums(t, e, state, expectedSeqNum, startBlocks) // After commit is reported on all chains, token prices should be updated in FeeQuoter. linkAddress := state.Chains[dest].LinkToken.Address() feeQuoter := state.Chains[dest].FeeQuoter timestampedPrice, err := feeQuoter.GetTokenPrice(nil, linkAddress) require.NoError(t, err) - require.Equal(t, ccdeploy.MockLinkPrice, timestampedPrice.Value) + require.Equal(t, changeset.MockLinkPrice, timestampedPrice.Value) // Wait for all exec reports to land - ccdeploy.ConfirmExecWithSeqNrForAll(t, e, state, expectedSeqNum, startBlocks) + changeset.ConfirmExecWithSeqNrForAll(t, e, state, expectedSeqNum, startBlocks) balance, err := srcToken.BalanceOf(nil, state.Chains[tenv.HomeChainSel].Receiver.Address()) require.NoError(t, err) require.Equal(t, twoCoins, balance) - delete(expectedSeqNum, dest) + delete(expectedSeqNum, sourceDestPair) }) t.Run("Send Token pay with wrapped native home chain -> remote", func(t *testing.T) { @@ -502,6 +511,11 @@ func Test_PricingForTokenTransfers(t *testing.T) { src := tenv.HomeChainSel dest, destChain := tenv.FeedChainSel, e.Chains[tenv.FeedChainSel] + sourceDestPair := changeset.SourceDestPair{ + SourceChainSelector: src, + DestChainSelector: dest, + } + WETH := state.Chains[src].Weth9 // We need to acquire some WETH to send with the tx so we deposit some ETH into the WETH contract @@ -576,8 +590,8 @@ func Test_PricingForTokenTransfers(t *testing.T) { fmt.Printf("srcFee: %v\n", srcFee) fmt.Printf("feeTokenBalanceBefore: %v\n", feeTokenBalanceBefore) - seqNum := ccdeploy.TestSendRequest(t, e, state, src, dest, false, ccipMessage).SequenceNumber - expectedSeqNum[dest] = seqNum + seqNum := changeset.TestSendRequest(t, e, state, src, dest, false, ccipMessage).SequenceNumber + expectedSeqNum[sourceDestPair] = seqNum // Check the fee token balance after the request and ensure fee tokens were spent feeTokenBalanceAfter, err := WETH.BalanceOf(nil, e.Chains[tenv.HomeChainSel].DeployerKey.From) @@ -585,17 +599,17 @@ func Test_PricingForTokenTransfers(t *testing.T) { require.Equal(t, feeTokenBalanceAfter, new(big.Int).Sub(feeTokenBalanceBefore, srcFee)) // Wait for all commit reports to land. - ccdeploy.ConfirmCommitForAllWithExpectedSeqNums(t, e, state, expectedSeqNum, startBlocks) + changeset.ConfirmCommitForAllWithExpectedSeqNums(t, e, state, expectedSeqNum, startBlocks) // After commit is reported on all chains, token prices should be updated in FeeQuoter. linkAddress := state.Chains[dest].LinkToken.Address() feeQuoter := state.Chains[dest].FeeQuoter timestampedPrice, err := feeQuoter.GetTokenPrice(nil, linkAddress) require.NoError(t, err) - require.Equal(t, ccdeploy.MockLinkPrice, timestampedPrice.Value) + require.Equal(t, changeset.MockLinkPrice, timestampedPrice.Value) // Wait for all exec reports to land - ccdeploy.ConfirmExecWithSeqNrForAll(t, e, state, expectedSeqNum, startBlocks) + changeset.ConfirmExecWithSeqNrForAll(t, e, state, expectedSeqNum, startBlocks) balance, err := dstToken.BalanceOf(nil, state.Chains[dest].Receiver.Address()) require.NoError(t, err) @@ -662,7 +676,7 @@ func Test_PricingForTokenTransfers(t *testing.T) { } // Send the CCP Request - tx, _, err = ccdeploy.CCIPSendRequest( + tx, _, err = changeset.CCIPSendRequest( e, state, src, dest, @@ -676,44 +690,45 @@ func Test_PricingForTokenTransfers(t *testing.T) { }) } +/* func Test_PricingForMessages(t *testing.T) { // Deploy the environment lggr := logger.TestLogger(t) - ctx := ccdeploy.Context(t) + ctx := changeset.Context(t) tenv, _, _ := testsetups.NewLocalDevEnvironmentWithDefaultPrice(t, lggr) // Load the test state e := tenv.Env - state, err := ccdeploy.LoadOnchainState(e) + state, err := changeset.LoadOnchainState(e) require.NoError(t, err) feeds := state.Chains[tenv.FeedChainSel].USDFeeds - tokenConfig := ccdeploy.NewTokenConfig() - tokenConfig.UpsertTokenInfo(ccdeploy.LinkSymbol, + tokenConfig := changeset.NewTokenConfig() + tokenConfig.UpsertTokenInfo(changeset.LinkSymbol, pluginconfig.TokenInfo{ - AggregatorAddress: cciptypes.UnknownEncodedAddress(feeds[ccdeploy.LinkSymbol].Address().String()), - Decimals: ccdeploy.LinkDecimals, + AggregatorAddress: cciptypes.UnknownEncodedAddress(feeds[changeset.LinkSymbol].Address().String()), + Decimals: changeset.LinkDecimals, DeviationPPB: cciptypes.NewBigIntFromInt64(1e9), }, ) // Apply migration - output, err := changeset.InitialDeploy(e, ccdeploy.DeployCCIPContractConfig{ + output, err := changeset.InitialDeploy(e, changeset.DeployCCIPContractConfig{ HomeChainSel: tenv.HomeChainSel, FeedChainSel: tenv.FeedChainSel, ChainsToDeploy: e.AllChainSelectors(), TokenConfig: tokenConfig, - MCMSConfig: ccdeploy.NewTestMCMSConfig(t, e), + MCMSConfig: changeset.NewTestMCMSConfig(t, e), OCRSecrets: deployment.XXXGenerateTestOCRSecrets(), }) require.NoError(t, err) require.NoError(t, e.ExistingAddresses.Merge(output.AddressBook)) // Get new state after migration and mock USDC token deployment. - state, err = ccdeploy.LoadOnchainState(e) + state, err = changeset.LoadOnchainState(e) require.NoError(t, err) // Ensure capreg logs are up to date. - ccdeploy.ReplayLogs(t, e.Offchain, tenv.ReplayBlocks) + changeset.ReplayLogs(t, e.Offchain, tenv.ReplayBlocks) // Create an empty tokenAmounts map since we are sending a message without a token tokens := []router.ClientEVMTokenAmount{} @@ -732,7 +747,7 @@ func Test_PricingForMessages(t *testing.T) { } // Add all lanes - require.NoError(t, ccdeploy.AddLanesForAll(e, state)) + require.NoError(t, changeset.AddLanesForAll(e, state)) // Need to keep track of the block number for each chain so that event subscription can be done from that block. startBlocks := make(map[uint64]*uint64) // Send a message from each chain to every other chain. @@ -783,7 +798,7 @@ func Test_PricingForMessages(t *testing.T) { srcFee, err := state.Chains[src].Router.GetFee(nil, dest, ccipMessage) require.NoError(t, err) - seqNum := ccdeploy.TestSendRequest(t, e, state, src, dest, false, ccipMessage).SequenceNumber + seqNum := changeset.TestSendRequest(t, e, state, src, dest, false, ccipMessage).SequenceNumber expectedSeqNum[dest] = seqNum // Check the fee token balance after the request and ensure fee tokens were spent @@ -792,17 +807,17 @@ func Test_PricingForMessages(t *testing.T) { require.Equal(t, feeTokenBalanceAfter, new(big.Int).Sub(feeTokenBalanceBefore, srcFee)) // Wait for all commit reports to land. - ccdeploy.ConfirmCommitForAllWithExpectedSeqNums(t, e, state, expectedSeqNum, startBlocks) + changeset.ConfirmCommitForAllWithExpectedSeqNums(t, e, state, expectedSeqNum, startBlocks) // After commit is reported on all chains, token prices should be updated in FeeQuoter. linkAddress := state.Chains[dest].LinkToken.Address() feeQuoter := state.Chains[dest].FeeQuoter timestampedPrice, err := feeQuoter.GetTokenPrice(nil, linkAddress) require.NoError(t, err) - require.Equal(t, ccdeploy.MockLinkPrice, timestampedPrice.Value) + require.Equal(t, changeset.MockLinkPrice, timestampedPrice.Value) // Wait for all exec reports to land - ccdeploy.ConfirmExecWithSeqNrForAll(t, e, state, expectedSeqNum, startBlocks) + changeset.ConfirmExecWithSeqNrForAll(t, e, state, expectedSeqNum, startBlocks) // Delete from the expcted seq num the chain that was just tested so that we don't pass it to the // commit report in the next test @@ -835,21 +850,21 @@ func Test_PricingForMessages(t *testing.T) { ExtraArgs: nil, } - seqNum := ccdeploy.TestSendRequest(t, e, state, src, dest, false, ccipMessage).SequenceNumber + seqNum := changeset.TestSendRequest(t, e, state, src, dest, false, ccipMessage).SequenceNumber expectedSeqNum[dest] = seqNum // Wait for all commit reports to land. - ccdeploy.ConfirmCommitForAllWithExpectedSeqNums(t, e, state, expectedSeqNum, startBlocks) + changeset.ConfirmCommitForAllWithExpectedSeqNums(t, e, state, expectedSeqNum, startBlocks) // After commit is reported on all chains, token prices should be updated in FeeQuoter. linkAddress := state.Chains[dest].LinkToken.Address() feeQuoter := state.Chains[dest].FeeQuoter timestampedPrice, err := feeQuoter.GetTokenPrice(nil, linkAddress) require.NoError(t, err) - require.Equal(t, ccdeploy.MockLinkPrice, timestampedPrice.Value) + require.Equal(t, changeset.MockLinkPrice, timestampedPrice.Value) // Wait for all exec reports to land - ccdeploy.ConfirmExecWithSeqNrForAll(t, e, state, expectedSeqNum, startBlocks) + changeset.ConfirmExecWithSeqNrForAll(t, e, state, expectedSeqNum, startBlocks) delete(expectedSeqNum, dest) }) @@ -905,7 +920,7 @@ func Test_PricingForMessages(t *testing.T) { srcFee, err := state.Chains[src].Router.GetFee(nil, dest, ccipMessage) require.NoError(t, err) - seqNum := ccdeploy.TestSendRequest(t, e, state, src, dest, false, ccipMessage).SequenceNumber + seqNum := changeset.TestSendRequest(t, e, state, src, dest, false, ccipMessage).SequenceNumber expectedSeqNum[dest] = seqNum // Check the fee token balance after the request and ensure fee tokens were spent @@ -914,16 +929,16 @@ func Test_PricingForMessages(t *testing.T) { require.Equal(t, feeTokenBalanceAfter, new(big.Int).Sub(feeTokenBalanceBefore, srcFee)) // Wait for all commit reports to land. - ccdeploy.ConfirmCommitForAllWithExpectedSeqNums(t, e, state, expectedSeqNum, startBlocks) + changeset.ConfirmCommitForAllWithExpectedSeqNums(t, e, state, expectedSeqNum, startBlocks) // After commit is reported on all chains, token prices should be updated in FeeQuoter. linkAddress := state.Chains[dest].LinkToken.Address() feeQuoter := state.Chains[dest].FeeQuoter timestampedPrice, err := feeQuoter.GetTokenPrice(nil, linkAddress) require.NoError(t, err) - require.Equal(t, ccdeploy.MockLinkPrice, timestampedPrice.Value) + require.Equal(t, changeset.MockLinkPrice, timestampedPrice.Value) // Wait for all exec reports to land - ccdeploy.ConfirmExecWithSeqNrForAll(t, e, state, expectedSeqNum, startBlocks) + changeset.ConfirmExecWithSeqNrForAll(t, e, state, expectedSeqNum, startBlocks) }) -} +}*/ From 5e46a892c2ddeb412e53c66545079972d4476e67 Mon Sep 17 00:00:00 2001 From: Josh Date: Thu, 21 Nov 2024 14:06:54 -0500 Subject: [PATCH 10/18] test passing --- integration-tests/smoke/ccip_test.go | 923 +++++++++++++++++++++++++++ 1 file changed, 923 insertions(+) create mode 100644 integration-tests/smoke/ccip_test.go diff --git a/integration-tests/smoke/ccip_test.go b/integration-tests/smoke/ccip_test.go new file mode 100644 index 00000000000..d6c1b4f05b7 --- /dev/null +++ b/integration-tests/smoke/ccip_test.go @@ -0,0 +1,923 @@ +package smoke + +import ( + "math/big" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/math" + "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/chainlink-testing-framework/lib/utils/testcontext" + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset" + "github.com/smartcontractkit/chainlink/integration-tests/testsetups" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/shared/generated/burn_mint_erc677" + "github.com/smartcontractkit/chainlink/v2/core/logger" +) + +func TestInitialDeployOnLocal(t *testing.T) { + t.Parallel() + lggr := logger.TestLogger(t) + tenv, _, _ := testsetups.NewLocalDevEnvironmentWithDefaultPrice(t, lggr) + e := tenv.Env + state, err := changeset.LoadOnchainState(e) + require.NoError(t, err) + + // Add all lanes + require.NoError(t, changeset.AddLanesForAll(e, state)) + // Need to keep track of the block number for each chain so that event subscription can be done from that block. + startBlocks := make(map[uint64]*uint64) + // Send a message from each chain to every other chain. + expectedSeqNum := make(map[changeset.SourceDestPair]uint64) + for src := range e.Chains { + for dest, destChain := range e.Chains { + if src == dest { + continue + } + latesthdr, err := destChain.Client.HeaderByNumber(testcontext.Get(t), nil) + require.NoError(t, err) + block := latesthdr.Number.Uint64() + startBlocks[dest] = &block + msgSentEvent := changeset.TestSendRequest(t, e, state, src, dest, false, router.ClientEVM2AnyMessage{ + Receiver: common.LeftPadBytes(state.Chains[dest].Receiver.Address().Bytes(), 32), + Data: []byte("hello world"), + TokenAmounts: nil, + FeeToken: common.HexToAddress("0x0"), + ExtraArgs: nil, + }) + expectedSeqNum[changeset.SourceDestPair{ + SourceChainSelector: src, + DestChainSelector: dest, + }] = msgSentEvent.SequenceNumber + } + } + + // Wait for all commit reports to land. + changeset.ConfirmCommitForAllWithExpectedSeqNums(t, e, state, expectedSeqNum, startBlocks) + + // After commit is reported on all chains, token prices should be updated in FeeQuoter. + for dest := range e.Chains { + linkAddress := state.Chains[dest].LinkToken.Address() + feeQuoter := state.Chains[dest].FeeQuoter + timestampedPrice, err := feeQuoter.GetTokenPrice(nil, linkAddress) + require.NoError(t, err) + require.Equal(t, changeset.MockLinkPrice, timestampedPrice.Value) + } + + // Wait for all exec reports to land + changeset.ConfirmExecWithSeqNrForAll(t, e, state, expectedSeqNum, startBlocks) + + // TODO: Apply the proposal. +} + +func TestTokenTransfer(t *testing.T) { + t.Parallel() + lggr := logger.TestLogger(t) + tenv, _, _ := testsetups.NewLocalDevEnvironmentWithDefaultPrice(t, lggr) + e := tenv.Env + state, err := changeset.LoadOnchainState(e) + require.NoError(t, err) + + srcToken, _, dstToken, _, err := changeset.DeployTransferableToken( + lggr, + tenv.Env.Chains, + tenv.HomeChainSel, + tenv.FeedChainSel, + state, + e.ExistingAddresses, + "MY_TOKEN", + ) + require.NoError(t, err) + + // Add all lanes + require.NoError(t, changeset.AddLanesForAll(e, state)) + // Need to keep track of the block number for each chain so that event subscription can be done from that block. + startBlocks := make(map[uint64]*uint64) + // Send a message from each chain to every other chain. + expectedSeqNum := make(map[changeset.SourceDestPair]uint64) + + twoCoins := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(2)) + tx, err := srcToken.Mint( + e.Chains[tenv.HomeChainSel].DeployerKey, + e.Chains[tenv.HomeChainSel].DeployerKey.From, + new(big.Int).Mul(twoCoins, big.NewInt(10)), + ) + require.NoError(t, err) + _, err = e.Chains[tenv.HomeChainSel].Confirm(tx) + require.NoError(t, err) + + tx, err = dstToken.Mint( + e.Chains[tenv.FeedChainSel].DeployerKey, + e.Chains[tenv.FeedChainSel].DeployerKey.From, + new(big.Int).Mul(twoCoins, big.NewInt(10)), + ) + require.NoError(t, err) + _, err = e.Chains[tenv.FeedChainSel].Confirm(tx) + require.NoError(t, err) + + tx, err = srcToken.Approve(e.Chains[tenv.HomeChainSel].DeployerKey, state.Chains[tenv.HomeChainSel].Router.Address(), twoCoins) + require.NoError(t, err) + _, err = e.Chains[tenv.HomeChainSel].Confirm(tx) + require.NoError(t, err) + tx, err = dstToken.Approve(e.Chains[tenv.FeedChainSel].DeployerKey, state.Chains[tenv.FeedChainSel].Router.Address(), twoCoins) + require.NoError(t, err) + _, err = e.Chains[tenv.FeedChainSel].Confirm(tx) + require.NoError(t, err) + + tokens := map[uint64][]router.ClientEVMTokenAmount{ + tenv.HomeChainSel: {{ + Token: srcToken.Address(), + Amount: twoCoins, + }}, + tenv.FeedChainSel: {{ + Token: dstToken.Address(), + Amount: twoCoins, + }}, + } + + for src := range e.Chains { + for dest, destChain := range e.Chains { + if src == dest { + continue + } + latesthdr, err := destChain.Client.HeaderByNumber(testcontext.Get(t), nil) + require.NoError(t, err) + block := latesthdr.Number.Uint64() + startBlocks[dest] = &block + + var ( + receiver = common.LeftPadBytes(state.Chains[dest].Receiver.Address().Bytes(), 32) + data = []byte("hello world") + feeToken = common.HexToAddress("0x0") + ) + if src == tenv.HomeChainSel && dest == tenv.FeedChainSel { + msgSentEvent := changeset.TestSendRequest(t, e, state, src, dest, false, router.ClientEVM2AnyMessage{ + Receiver: receiver, + Data: data, + TokenAmounts: tokens[src], + FeeToken: feeToken, + ExtraArgs: nil, + }) + expectedSeqNum[changeset.SourceDestPair{ + SourceChainSelector: src, + DestChainSelector: dest, + }] = msgSentEvent.SequenceNumber + } else { + msgSentEvent := changeset.TestSendRequest(t, e, state, src, dest, false, router.ClientEVM2AnyMessage{ + Receiver: receiver, + Data: data, + TokenAmounts: nil, + FeeToken: feeToken, + ExtraArgs: nil, + }) + expectedSeqNum[changeset.SourceDestPair{ + SourceChainSelector: src, + DestChainSelector: dest, + }] = msgSentEvent.SequenceNumber + } + } + } + + // Wait for all commit reports to land. + changeset.ConfirmCommitForAllWithExpectedSeqNums(t, e, state, expectedSeqNum, startBlocks) + + // After commit is reported on all chains, token prices should be updated in FeeQuoter. + for dest := range e.Chains { + linkAddress := state.Chains[dest].LinkToken.Address() + feeQuoter := state.Chains[dest].FeeQuoter + timestampedPrice, err := feeQuoter.GetTokenPrice(nil, linkAddress) + require.NoError(t, err) + require.Equal(t, changeset.MockLinkPrice, timestampedPrice.Value) + } + + // Wait for all exec reports to land + changeset.ConfirmExecWithSeqNrForAll(t, e, state, expectedSeqNum, startBlocks) + + balance, err := dstToken.BalanceOf(nil, state.Chains[tenv.FeedChainSel].Receiver.Address()) + require.NoError(t, err) + require.Equal(t, twoCoins, balance) +} + +// setupTokens deploys transferable tokens on the source and dest, mints tokens for the source and dest, and +// approves the router to spend the tokens +func setupTokens(t *testing.T, tenv changeset.DeployedEnv) (srcToken *burn_mint_erc677.BurnMintERC677, dstToken *burn_mint_erc677.BurnMintERC677) { + lggr := logger.TestLogger(t) + + e := tenv.Env + state, err := changeset.LoadOnchainState(e) + require.NoError(t, err) + + tenCoins := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(10)) + + // Deploy the token to test transferring + srcToken, _, dstToken, _, err = changeset.DeployTransferableToken( + lggr, + tenv.Env.Chains, + tenv.HomeChainSel, + tenv.FeedChainSel, + state, + e.ExistingAddresses, + "MY_TOKEN", + ) + + linkToken := state.Chains[tenv.HomeChainSel].LinkToken + + require.NoError(t, err) + + tx, err := srcToken.Mint( + e.Chains[tenv.HomeChainSel].DeployerKey, + e.Chains[tenv.HomeChainSel].DeployerKey.From, + new(big.Int).Mul(tenCoins, big.NewInt(10)), + ) + require.NoError(t, err) + + _, err = e.Chains[tenv.HomeChainSel].Confirm(tx) + require.NoError(t, err) + + // Mint a destination token + tx, err = dstToken.Mint( + e.Chains[tenv.FeedChainSel].DeployerKey, + e.Chains[tenv.FeedChainSel].DeployerKey.From, + new(big.Int).Mul(tenCoins, big.NewInt(10)), + ) + + // Confirm the mint tx + require.NoError(t, err) + _, err = e.Chains[tenv.FeedChainSel].Confirm(tx) + require.NoError(t, err) + + maxUint256 := math.MaxBig256 + + // Approve the router to spend the tokens and confirm the tx's + // To prevent having to approve the router for every transfer, we approve a sufficiently large amount + tx, err = srcToken.Approve(e.Chains[tenv.HomeChainSel].DeployerKey, state.Chains[tenv.HomeChainSel].Router.Address(), maxUint256) + require.NoError(t, err) + _, err = e.Chains[tenv.HomeChainSel].Confirm(tx) + require.NoError(t, err) + + tx, err = dstToken.Approve(e.Chains[tenv.FeedChainSel].DeployerKey, state.Chains[tenv.FeedChainSel].Router.Address(), maxUint256) + require.NoError(t, err) + _, err = e.Chains[tenv.FeedChainSel].Confirm(tx) + require.NoError(t, err) + + // Grant mint and burn roles to the deployer key for the newly deployed linkToken + // Since those roles are not granted automatically + tx, err = linkToken.GrantMintAndBurnRoles(e.Chains[tenv.HomeChainSel].DeployerKey, e.Chains[tenv.HomeChainSel].DeployerKey.From) + require.NoError(t, err) + _, err = e.Chains[tenv.HomeChainSel].Confirm(tx) + require.NoError(t, err) + + // Mint link token and confirm the tx + tx, err = linkToken.Mint( + e.Chains[tenv.HomeChainSel].DeployerKey, + e.Chains[tenv.HomeChainSel].DeployerKey.From, + new(big.Int).Mul(tenCoins, big.NewInt(10)), + ) + require.NoError(t, err) + + _, err = e.Chains[tenv.HomeChainSel].Confirm(tx) + require.NoError(t, err) + + return srcToken, dstToken +} + +func Test_PricingForTokenTransfers(t *testing.T) { + t.Parallel() + lggr := logger.TestLogger(t) + // ctx := changeset.Context(t) + tenv, _, _ := testsetups.NewLocalDevEnvironmentWithDefaultPrice(t, lggr) + e := tenv.Env + + state, err := changeset.LoadOnchainState(tenv.Env) + require.NoError(t, err) + + // feeds := state.Chains[tenv.FeedChainSel].USDFeeds + output, err := changeset.DeployPrerequisites(tenv.Env, changeset.DeployPrerequisiteConfig{ + ChainSelectors: tenv.Env.AllChainSelectors(), + }) + require.NoError(t, err) + require.NoError(t, tenv.Env.ExistingAddresses.Merge(output.AddressBook)) + + expectedSeqNum := make(map[changeset.SourceDestPair]uint64) + + require.NoError(t, err) + require.NoError(t, tenv.Env.ExistingAddresses.Merge(output.AddressBook)) + // Get new state after migration. + state, err = changeset.LoadOnchainState(e) + require.NoError(t, err) + + srcToken, dstToken := setupTokens(t, tenv) + + // Ensure capreg logs are up to date. + changeset.ReplayLogs(t, e.Offchain, tenv.ReplayBlocks) + + // Add all lanes + require.NoError(t, changeset.AddLanesForAll(e, state)) + // Need to keep track of the block number for each chain so that event subscription can be done from that block. + startBlocks := make(map[uint64]*uint64) + // Send a message from each chain to every other chain. + + // Mint 2 tokens to be transferred + twoCoins := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(2)) + + linkToken := state.Chains[tenv.HomeChainSel].LinkToken + maxUint256 := math.MaxBig256 + + t.Run("Send Token Pay with Link token home chain -> remote", func(t *testing.T) { + src := tenv.HomeChainSel + dest, destChain := tenv.FeedChainSel, e.Chains[tenv.FeedChainSel] + + sourceDestPair := changeset.SourceDestPair{ + SourceChainSelector: src, + DestChainSelector: dest, + } + + // Approve to spend link token + tx, err := linkToken.Approve(e.Chains[src].DeployerKey, state.Chains[src].Router.Address(), maxUint256) + require.NoError(t, err) + _, err = e.Chains[src].Confirm(tx) + require.NoError(t, err) + + // Get the fee Token Balance Before + srctokenBalance, err := srcToken.BalanceOf(nil, e.Chains[src].DeployerKey.From) + require.NoError(t, err) + require.GreaterOrEqual(t, srctokenBalance.Int64(), twoCoins.Int64()) + + // Create two ClientEVMTokenAmount structs to be passed to the router + tokens := map[uint64][]router.ClientEVMTokenAmount{ + tenv.HomeChainSel: {{ + Token: srcToken.Address(), + Amount: twoCoins, + }}, + tenv.FeedChainSel: {{ + Token: dstToken.Address(), + Amount: twoCoins, + }}, + } + + // Assign Src to the Home Chain Selector and destChain to the Feed Chain Selector + + // get the header for the destination chain and the relevant block number + latesthdr, err := destChain.Client.HeaderByNumber(testcontext.Get(t), nil) + require.NoError(t, err) + block := latesthdr.Number.Uint64() + startBlocks[dest] = &block + + // Send to the receiver on the destination chain paying with LINK token + var ( + receiver = common.LeftPadBytes(state.Chains[dest].Receiver.Address().Bytes(), 32) + data = []byte("") + feeToken = linkToken.Address() + ) + + ccipMessage := router.ClientEVM2AnyMessage{ + Receiver: receiver, + Data: data, + TokenAmounts: tokens[src], + FeeToken: feeToken, + ExtraArgs: nil, + } + + // Get the fee Token Balance Before + feeTokenBalanceBefore, err := linkToken.BalanceOf(nil, e.Chains[src].DeployerKey.From) + require.NoError(t, err) + + // Check the fee Amount + srcFee, err := state.Chains[src].Router.GetFee(nil, dest, ccipMessage) + require.NoError(t, err) + + seqNum := changeset.TestSendRequest(t, e, state, src, dest, false, ccipMessage).SequenceNumber + expectedSeqNum[sourceDestPair] = seqNum + + // Check the fee token balance after the request and ensure fee tokens were spent + feeTokenBalanceAfter, err := linkToken.BalanceOf(nil, e.Chains[tenv.HomeChainSel].DeployerKey.From) + require.NoError(t, err) + require.Equal(t, feeTokenBalanceAfter, new(big.Int).Sub(feeTokenBalanceBefore, srcFee)) + + // Wait for all commit reports to land. + changeset.ConfirmCommitForAllWithExpectedSeqNums(t, e, state, expectedSeqNum, startBlocks) + + // After commit is reported on all chains, token prices should be updated in FeeQuoter. + linkAddress := state.Chains[dest].LinkToken.Address() + feeQuoter := state.Chains[dest].FeeQuoter + timestampedPrice, err := feeQuoter.GetTokenPrice(nil, linkAddress) + require.NoError(t, err) + require.Equal(t, changeset.MockLinkPrice, timestampedPrice.Value) + + // Wait for all exec reports to land + changeset.ConfirmExecWithSeqNrForAll(t, e, state, expectedSeqNum, startBlocks) + + balance, err := dstToken.BalanceOf(nil, state.Chains[tenv.FeedChainSel].Receiver.Address()) + require.NoError(t, err) + require.Equal(t, twoCoins, balance) + + // Delete from the expcted seq num the chain that was just tested so that we don't pass it to the + // commit report in the next test + delete(expectedSeqNum, sourceDestPair) + }) + + t.Run("Send Token Pay with native remote chain -> home", func(t *testing.T) { + // Create two ClientEVMTokenAmount structs to be passed to the router + tokens := map[uint64][]router.ClientEVMTokenAmount{ + tenv.HomeChainSel: {{ + Token: dstToken.Address(), + Amount: twoCoins, + }}, + tenv.FeedChainSel: {{ + Token: srcToken.Address(), + Amount: twoCoins, + }}, + } + + // Assign Src to the Home Chain Selector and destChain to the Feed Chain Selector + src := tenv.FeedChainSel + dest, destChain := tenv.HomeChainSel, e.Chains[tenv.HomeChainSel] + + sourceDestPair := changeset.SourceDestPair{ + SourceChainSelector: src, + DestChainSelector: dest, + } + + // get the header for the destination chain and the relevant block number + latesthdr, err := destChain.Client.HeaderByNumber(testcontext.Get(t), nil) + require.NoError(t, err) + block := latesthdr.Number.Uint64() + startBlocks[dest] = &block + + // Send to the receiver on the destination chain paying with native token + var ( + receiver = common.LeftPadBytes(state.Chains[dest].Receiver.Address().Bytes(), 32) + data = []byte("") + feeToken = common.HexToAddress("0x0") + ) + + ccipMessage := router.ClientEVM2AnyMessage{ + Receiver: receiver, + Data: data, + TokenAmounts: tokens[dest], + FeeToken: feeToken, + ExtraArgs: nil, + } + + seqNum := changeset.TestSendRequest(t, e, state, src, dest, false, ccipMessage).SequenceNumber + expectedSeqNum[sourceDestPair] = seqNum + + // Wait for all commit reports to land. + changeset.ConfirmCommitForAllWithExpectedSeqNums(t, e, state, expectedSeqNum, startBlocks) + + // After commit is reported on all chains, token prices should be updated in FeeQuoter. + linkAddress := state.Chains[dest].LinkToken.Address() + feeQuoter := state.Chains[dest].FeeQuoter + timestampedPrice, err := feeQuoter.GetTokenPrice(nil, linkAddress) + require.NoError(t, err) + require.Equal(t, changeset.MockLinkPrice, timestampedPrice.Value) + + // Wait for all exec reports to land + changeset.ConfirmExecWithSeqNrForAll(t, e, state, expectedSeqNum, startBlocks) + + balance, err := srcToken.BalanceOf(nil, state.Chains[tenv.HomeChainSel].Receiver.Address()) + require.NoError(t, err) + require.Equal(t, twoCoins, balance) + + delete(expectedSeqNum, sourceDestPair) + }) + + t.Run("Send Token pay with wrapped native home chain -> remote", func(t *testing.T) { + // Assign Src to the Home Chain Selector and destChain to the Feed Chain Selector + src := tenv.HomeChainSel + dest, destChain := tenv.FeedChainSel, e.Chains[tenv.FeedChainSel] + + sourceDestPair := changeset.SourceDestPair{ + SourceChainSelector: src, + DestChainSelector: dest, + } + + WETH := state.Chains[src].Weth9 + + wrappedNative, err := state.Chains[src].Router.GetWrappedNative(nil) + require.NoError(t, err) + require.Equal(t, WETH.Address(), wrappedNative) + + // We need to acquire some WETH to send with the tx so we deposit some ETH into the WETH contract + // but deployerKey is a reference so we need to dereference it and then reassign it + depositOps := *e.Chains[tenv.HomeChainSel].DeployerKey + depositOps.Value = new(big.Int).Mul(twoCoins, big.NewInt(40)) + tx, err := WETH.Deposit(&depositOps) + require.NoError(t, err) + _, err = e.Chains[tenv.HomeChainSel].Confirm(tx) + require.NoError(t, err) + + // Approve to spend 100 WETH token as feeToken + tx, err = WETH.Approve(e.Chains[tenv.HomeChainSel].DeployerKey, state.Chains[src].Router.Address(), new(big.Int).Mul(twoCoins, big.NewInt(50))) + require.NoError(t, err) + _, err = e.Chains[tenv.HomeChainSel].Confirm(tx) + require.NoError(t, err) + + allowance, err := WETH.Allowance(nil, e.Chains[src].DeployerKey.From, state.Chains[src].Router.Address()) + require.NoError(t, err) + require.GreaterOrEqual(t, allowance.Int64(), twoCoins.Int64()) + + // Create two ClientEVMTokenAmount structs to be passed to the router + tokens := map[uint64][]router.ClientEVMTokenAmount{ + tenv.HomeChainSel: {{ + Token: srcToken.Address(), + Amount: twoCoins, + }}, + tenv.FeedChainSel: {{ + Token: dstToken.Address(), + Amount: twoCoins, + }}, + } + + srcTokenBal, err := srcToken.BalanceOf(nil, e.Chains[src].DeployerKey.From) + require.NoError(t, err) + require.GreaterOrEqual(t, srcTokenBal.Int64(), twoCoins.Int64()) + + // get the header for the destination chain and the relevant block number + latesthdr, err := destChain.Client.HeaderByNumber(testcontext.Get(t), nil) + require.NoError(t, err) + block := latesthdr.Number.Uint64() + startBlocks[dest] = &block + + // Send to the receiver on the destination chain paying with LINK token + var ( + receiver = common.LeftPadBytes(state.Chains[dest].Receiver.Address().Bytes(), 32) + data = []byte("") + feeToken = state.Chains[src].Weth9.Address() + ) + + ccipMessage := router.ClientEVM2AnyMessage{ + Receiver: receiver, + Data: data, + TokenAmounts: tokens[src], + FeeToken: feeToken, + ExtraArgs: nil, + } + + // Get the fee Token Balance Before + feeTokenBalanceBefore, err := WETH.BalanceOf(nil, e.Chains[src].DeployerKey.From) + require.NoError(t, err) + + // Check the fee Amount + srcFee, err := state.Chains[src].Router.GetFee(nil, dest, ccipMessage) + require.NoError(t, err) + + // Check that we have enough WETH to pay the fee + require.GreaterOrEqual(t, feeTokenBalanceBefore.Int64(), srcFee.Int64()) + + seqNum := changeset.TestSendRequest(t, e, state, src, dest, false, ccipMessage).SequenceNumber + expectedSeqNum[sourceDestPair] = seqNum + + // Check the fee token balance after the request and ensure fee tokens were spent + feeTokenBalanceAfter, err := WETH.BalanceOf(nil, e.Chains[tenv.HomeChainSel].DeployerKey.From) + require.NoError(t, err) + require.Equal(t, feeTokenBalanceAfter, new(big.Int).Sub(feeTokenBalanceBefore, srcFee)) + + // Wait for all commit reports to land. + changeset.ConfirmCommitForAllWithExpectedSeqNums(t, e, state, expectedSeqNum, startBlocks) + + // After commit is reported on all chains, token prices should be updated in FeeQuoter. + linkAddress := state.Chains[dest].LinkToken.Address() + feeQuoter := state.Chains[dest].FeeQuoter + timestampedPrice, err := feeQuoter.GetTokenPrice(nil, linkAddress) + require.NoError(t, err) + require.Equal(t, changeset.MockLinkPrice, timestampedPrice.Value) + + // Wait for all exec reports to land + changeset.ConfirmExecWithSeqNrForAll(t, e, state, expectedSeqNum, startBlocks) + + balance, err := dstToken.BalanceOf(nil, state.Chains[dest].Receiver.Address()) + require.NoError(t, err) + + // The balance should be 4 since we've already sent 2 tokens over this lane direction in the + // first part of the test, so balance should already be two + require.Equal(t, new(big.Int).Mul(twoCoins, big.NewInt(2)), balance) + }) + + t.Run("Send Token but revert not enough tokens", func(t *testing.T) { + // Approve the router to spend the tokens and confirm the tx's + tx, err := srcToken.Approve(e.Chains[tenv.HomeChainSel].DeployerKey, state.Chains[tenv.HomeChainSel].Router.Address(), twoCoins) + require.NoError(t, err) + _, err = e.Chains[tenv.HomeChainSel].Confirm(tx) + require.NoError(t, err) + + tx, err = dstToken.Approve(e.Chains[tenv.FeedChainSel].DeployerKey, state.Chains[tenv.FeedChainSel].Router.Address(), twoCoins) + require.NoError(t, err) + _, err = e.Chains[tenv.FeedChainSel].Confirm(tx) + require.NoError(t, err) + + existingBalanceSrc, err := dstToken.BalanceOf(nil, e.Chains[tenv.HomeChainSel].DeployerKey.From) + require.NoError(t, err) + + existingBalanceDst, err := dstToken.BalanceOf(nil, e.Chains[tenv.FeedChainSel].DeployerKey.From) + require.NoError(t, err) + + // Assign Src to the Home Chain Selector and destChain to the Feed Chain Selector + src := tenv.FeedChainSel + dest, destChain := tenv.HomeChainSel, e.Chains[tenv.HomeChainSel] + + // Create two ClientEVMTokenAmount structs to be passed to the router + tokens := map[uint64][]router.ClientEVMTokenAmount{ + tenv.HomeChainSel: {{ + Token: dstToken.Address(), + // Send twice as many tokens as available on purpose + Amount: new(big.Int).Mul(existingBalanceSrc, big.NewInt(2)), + }}, + tenv.FeedChainSel: {{ + Token: srcToken.Address(), + Amount: new(big.Int).Mul(existingBalanceDst, big.NewInt(10)), + }}, + } + + // get the header for the destination chain and the relevant block number + latesthdr, err := destChain.Client.HeaderByNumber(testcontext.Get(t), nil) + require.NoError(t, err) + block := latesthdr.Number.Uint64() + startBlocks[dest] = &block + + // Send to the receiver on the destination chain paying with native token + var ( + receiver = common.LeftPadBytes(state.Chains[dest].Receiver.Address().Bytes(), 32) + data = []byte("") + feeToken = common.HexToAddress("0x0") + ) + + ccipMessage := router.ClientEVM2AnyMessage{ + Receiver: receiver, + Data: data, + TokenAmounts: tokens[dest], + FeeToken: feeToken, + ExtraArgs: nil, + } + + // Send the CCP Request + tx, _, err = changeset.CCIPSendRequest( + e, + state, + src, dest, + false, + ccipMessage, + ) + + // Check if the transaction reverted + require.Error(t, err) + require.Nil(t, tx) + }) +} + +func Test_PricingForMessages(t *testing.T) { + t.Parallel() + lggr := logger.TestLogger(t) + // ctx := changeset.Context(t) + tenv, _, _ := testsetups.NewLocalDevEnvironmentWithDefaultPrice(t, lggr) + e := tenv.Env + + state, err := changeset.LoadOnchainState(tenv.Env) + require.NoError(t, err) + + // feeds := state.Chains[tenv.FeedChainSel].USDFeeds + output, err := changeset.DeployPrerequisites(tenv.Env, changeset.DeployPrerequisiteConfig{ + ChainSelectors: tenv.Env.AllChainSelectors(), + }) + require.NoError(t, err) + require.NoError(t, tenv.Env.ExistingAddresses.Merge(output.AddressBook)) + + expectedSeqNum := make(map[changeset.SourceDestPair]uint64) + + require.NoError(t, err) + require.NoError(t, tenv.Env.ExistingAddresses.Merge(output.AddressBook)) + // Get new state after migration. + state, err = changeset.LoadOnchainState(e) + require.NoError(t, err) + + // Ensure capreg logs are up to date. + changeset.ReplayLogs(t, e.Offchain, tenv.ReplayBlocks) + + // Add all lanes + require.NoError(t, changeset.AddLanesForAll(e, state)) + // Need to keep track of the block number for each chain so that event subscription can be done from that block. + startBlocks := make(map[uint64]*uint64) + // Send a message from each chain to every other chain. + + // Mint 2 tokens to be transferred + twoCoins := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(2)) + + linkToken := state.Chains[tenv.HomeChainSel].LinkToken + maxUint256 := math.MaxBig256 + + emptyTokenArray := []router.ClientEVMTokenAmount{} + + t.Run("Send Token Pay with Link token home chain -> remote", func(t *testing.T) { + src := tenv.HomeChainSel + dest, destChain := tenv.FeedChainSel, e.Chains[tenv.FeedChainSel] + + sourceDestPair := changeset.SourceDestPair{ + SourceChainSelector: src, + DestChainSelector: dest, + } + + // Approve to spend link token + tx, err := linkToken.Approve(e.Chains[src].DeployerKey, state.Chains[src].Router.Address(), maxUint256) + require.NoError(t, err) + _, err = e.Chains[src].Confirm(tx) + require.NoError(t, err) + + // get the header for the destination chain and the relevant block number + latesthdr, err := destChain.Client.HeaderByNumber(testcontext.Get(t), nil) + require.NoError(t, err) + block := latesthdr.Number.Uint64() + startBlocks[dest] = &block + + // Send to the receiver on the destination chain paying with LINK token + var ( + receiver = common.LeftPadBytes(state.Chains[dest].Receiver.Address().Bytes(), 32) + data = []byte("hello world") + feeToken = linkToken.Address() + ) + + ccipMessage := router.ClientEVM2AnyMessage{ + Receiver: receiver, + Data: data, + TokenAmounts: emptyTokenArray, + FeeToken: feeToken, + ExtraArgs: nil, + } + + // Get the fee Token Balance Before + feeTokenBalanceBefore, err := linkToken.BalanceOf(nil, e.Chains[src].DeployerKey.From) + require.NoError(t, err) + + // Check the fee Amount + srcFee, err := state.Chains[src].Router.GetFee(nil, dest, ccipMessage) + require.NoError(t, err) + + seqNum := changeset.TestSendRequest(t, e, state, src, dest, false, ccipMessage).SequenceNumber + expectedSeqNum[sourceDestPair] = seqNum + + // Check the fee token balance after the request and ensure fee tokens were spent + feeTokenBalanceAfter, err := linkToken.BalanceOf(nil, e.Chains[tenv.HomeChainSel].DeployerKey.From) + require.NoError(t, err) + require.Equal(t, feeTokenBalanceAfter, new(big.Int).Sub(feeTokenBalanceBefore, srcFee)) + + // Wait for all commit reports to land. + changeset.ConfirmCommitForAllWithExpectedSeqNums(t, e, state, expectedSeqNum, startBlocks) + + // After commit is reported on all chains, token prices should be updated in FeeQuoter. + linkAddress := state.Chains[dest].LinkToken.Address() + feeQuoter := state.Chains[dest].FeeQuoter + timestampedPrice, err := feeQuoter.GetTokenPrice(nil, linkAddress) + require.NoError(t, err) + require.Equal(t, changeset.MockLinkPrice, timestampedPrice.Value) + + // Wait for all exec reports to land + changeset.ConfirmExecWithSeqNrForAll(t, e, state, expectedSeqNum, startBlocks) + + // Delete from the expcted seq num the chain that was just tested so that we don't pass it to the + // commit report in the next test + delete(expectedSeqNum, sourceDestPair) + }) + + t.Run("Send message Pay with native remote chain -> home", func(t *testing.T) { + // Assign Src to the Home Chain Selector and destChain to the Feed Chain Selector + src := tenv.FeedChainSel + dest, destChain := tenv.HomeChainSel, e.Chains[tenv.HomeChainSel] + + sourceDestPair := changeset.SourceDestPair{ + SourceChainSelector: src, + DestChainSelector: dest, + } + + // get the header for the destination chain and the relevant block number + latesthdr, err := destChain.Client.HeaderByNumber(testcontext.Get(t), nil) + require.NoError(t, err) + block := latesthdr.Number.Uint64() + startBlocks[dest] = &block + + // Send to the receiver on the destination chain paying with native token + var ( + receiver = common.LeftPadBytes(state.Chains[dest].Receiver.Address().Bytes(), 32) + data = []byte("hello world") + feeToken = common.HexToAddress("0x0") + ) + + ccipMessage := router.ClientEVM2AnyMessage{ + Receiver: receiver, + Data: data, + TokenAmounts: emptyTokenArray, + FeeToken: feeToken, + ExtraArgs: nil, + } + + seqNum := changeset.TestSendRequest(t, e, state, src, dest, false, ccipMessage).SequenceNumber + expectedSeqNum[sourceDestPair] = seqNum + + // Wait for all commit reports to land. + changeset.ConfirmCommitForAllWithExpectedSeqNums(t, e, state, expectedSeqNum, startBlocks) + + // After commit is reported on all chains, token prices should be updated in FeeQuoter. + linkAddress := state.Chains[dest].LinkToken.Address() + feeQuoter := state.Chains[dest].FeeQuoter + timestampedPrice, err := feeQuoter.GetTokenPrice(nil, linkAddress) + require.NoError(t, err) + require.Equal(t, changeset.MockLinkPrice, timestampedPrice.Value) + + // Wait for all exec reports to land + changeset.ConfirmExecWithSeqNrForAll(t, e, state, expectedSeqNum, startBlocks) + + delete(expectedSeqNum, sourceDestPair) + }) + + t.Run("Send message pay with wrapped native home chain -> remote", func(t *testing.T) { + // Assign Src to the Home Chain Selector and destChain to the Feed Chain Selector + src := tenv.HomeChainSel + dest, destChain := tenv.FeedChainSel, e.Chains[tenv.FeedChainSel] + + sourceDestPair := changeset.SourceDestPair{ + SourceChainSelector: src, + DestChainSelector: dest, + } + + WETH := state.Chains[src].Weth9 + + wrappedNative, err := state.Chains[src].Router.GetWrappedNative(nil) + require.NoError(t, err) + require.Equal(t, WETH.Address(), wrappedNative) + + // We need to acquire some WETH to send with the tx so we deposit some ETH into the WETH contract + // but deployerKey is a reference so we need to dereference it and then reassign it + depositOps := *e.Chains[tenv.HomeChainSel].DeployerKey + depositOps.Value = new(big.Int).Mul(twoCoins, big.NewInt(40)) + tx, err := WETH.Deposit(&depositOps) + require.NoError(t, err) + _, err = e.Chains[tenv.HomeChainSel].Confirm(tx) + require.NoError(t, err) + + // Approve to spend 100 WETH token as feeToken + tx, err = WETH.Approve(e.Chains[tenv.HomeChainSel].DeployerKey, state.Chains[src].Router.Address(), new(big.Int).Mul(twoCoins, big.NewInt(50))) + require.NoError(t, err) + _, err = e.Chains[tenv.HomeChainSel].Confirm(tx) + require.NoError(t, err) + + allowance, err := WETH.Allowance(nil, e.Chains[src].DeployerKey.From, state.Chains[src].Router.Address()) + require.NoError(t, err) + require.GreaterOrEqual(t, allowance.Int64(), twoCoins.Int64()) + + // get the header for the destination chain and the relevant block number + latesthdr, err := destChain.Client.HeaderByNumber(testcontext.Get(t), nil) + require.NoError(t, err) + block := latesthdr.Number.Uint64() + startBlocks[dest] = &block + + // Send to the receiver on the destination chain paying with LINK token + var ( + receiver = common.LeftPadBytes(state.Chains[dest].Receiver.Address().Bytes(), 32) + data = []byte("hello world") + feeToken = state.Chains[src].Weth9.Address() + ) + + ccipMessage := router.ClientEVM2AnyMessage{ + Receiver: receiver, + Data: data, + TokenAmounts: emptyTokenArray, + FeeToken: feeToken, + ExtraArgs: nil, + } + + // Get the fee Token Balance Before + feeTokenBalanceBefore, err := WETH.BalanceOf(nil, e.Chains[src].DeployerKey.From) + require.NoError(t, err) + + // Check the fee Amount + srcFee, err := state.Chains[src].Router.GetFee(nil, dest, ccipMessage) + require.NoError(t, err) + + // Check that we have enough WETH to pay the fee + require.GreaterOrEqual(t, feeTokenBalanceBefore.Int64(), srcFee.Int64()) + + seqNum := changeset.TestSendRequest(t, e, state, src, dest, false, ccipMessage).SequenceNumber + expectedSeqNum[sourceDestPair] = seqNum + + // Check the fee token balance after the request and ensure fee tokens were spent + feeTokenBalanceAfter, err := WETH.BalanceOf(nil, e.Chains[tenv.HomeChainSel].DeployerKey.From) + require.NoError(t, err) + require.Equal(t, feeTokenBalanceAfter, new(big.Int).Sub(feeTokenBalanceBefore, srcFee)) + + // Wait for all commit reports to land. + changeset.ConfirmCommitForAllWithExpectedSeqNums(t, e, state, expectedSeqNum, startBlocks) + + // After commit is reported on all chains, token prices should be updated in FeeQuoter. + linkAddress := state.Chains[dest].LinkToken.Address() + feeQuoter := state.Chains[dest].FeeQuoter + timestampedPrice, err := feeQuoter.GetTokenPrice(nil, linkAddress) + require.NoError(t, err) + require.Equal(t, changeset.MockLinkPrice, timestampedPrice.Value) + + // Wait for all exec reports to land + changeset.ConfirmExecWithSeqNrForAll(t, e, state, expectedSeqNum, startBlocks) + }) + + t.Run("Send programmable token transfer", func(t *testing.T) { + + }) +} From 89c2558452932b92537ec68e89cc241d1efd27d3 Mon Sep 17 00:00:00 2001 From: Josh Date: Fri, 22 Nov 2024 14:08:47 -0500 Subject: [PATCH 11/18] fix smoke tests after they broke in the last merge from develop --- integration-tests/smoke/ccip/ccip_test.go | 469 ++--------- integration-tests/smoke/ccip_test.go | 923 ---------------------- 2 files changed, 71 insertions(+), 1321 deletions(-) delete mode 100644 integration-tests/smoke/ccip_test.go diff --git a/integration-tests/smoke/ccip/ccip_test.go b/integration-tests/smoke/ccip/ccip_test.go index 13f1af6b677..a269fa01755 100644 --- a/integration-tests/smoke/ccip/ccip_test.go +++ b/integration-tests/smoke/ccip/ccip_test.go @@ -1,7 +1,6 @@ package smoke import ( - "fmt" "math/big" "testing" @@ -297,12 +296,9 @@ func Test_PricingForTokenTransfers(t *testing.T) { t.Parallel() lggr := logger.TestLogger(t) // ctx := changeset.Context(t) - tenv, _, _ := testsetups.NewLocalDevEnvironmentWithDefaultPrice(t, lggr) + tenv, _, _ := testsetups.NewLocalDevEnvironmentWithDefaultPrice(t, lggr, nil) e := tenv.Env - state, err := changeset.LoadOnchainState(tenv.Env) - require.NoError(t, err) - // feeds := state.Chains[tenv.FeedChainSel].USDFeeds output, err := changeset.DeployPrerequisites(tenv.Env, changeset.DeployPrerequisiteConfig{ ChainSelectors: tenv.Env.AllChainSelectors(), @@ -311,20 +307,12 @@ func Test_PricingForTokenTransfers(t *testing.T) { require.NoError(t, tenv.Env.ExistingAddresses.Merge(output.AddressBook)) expectedSeqNum := make(map[changeset.SourceDestPair]uint64) + expectedSeqNumExec := make(map[changeset.SourceDestPair][]uint64) - // // Apply migration - // output, err = changeset.InitialDeploy(tenv.Env, changeset.DeployCCIPContractConfig{ - // HomeChainSel: tenv.HomeChainSel, - // FeedChainSel: tenv.FeedChainSel, - // ChainsToDeploy: tenv.Env.AllChainSelectors(), - // TokenConfig: changeset.NewTestTokenConfig(feeds), - // MCMSConfig: changeset.NewTestMCMSConfig(t, e), - // OCRSecrets: deployment.XXXGenerateTestOCRSecrets(), - // }) require.NoError(t, err) require.NoError(t, tenv.Env.ExistingAddresses.Merge(output.AddressBook)) // Get new state after migration. - state, err = changeset.LoadOnchainState(e) + state, err := changeset.LoadOnchainState(e) require.NoError(t, err) srcToken, dstToken := setupTokens(t, tenv) @@ -332,19 +320,6 @@ func Test_PricingForTokenTransfers(t *testing.T) { // Ensure capreg logs are up to date. changeset.ReplayLogs(t, e.Offchain, tenv.ReplayBlocks) - // // Apply the jobs. - // for nodeID, jobs := range output.JobSpecs { - // for _, job := range jobs { - // // Note these auto-accept - // _, err := e.Offchain.ProposeJob(ctx, - // &jobv1.ProposeJobRequest{ - // NodeId: nodeID, - // Spec: job, - // }) - // require.NoError(t, err) - // } - // } - // Add all lanes require.NoError(t, changeset.AddLanesForAll(e, state)) // Need to keep track of the block number for each chain so that event subscription can be done from that block. @@ -357,6 +332,18 @@ func Test_PricingForTokenTransfers(t *testing.T) { linkToken := state.Chains[tenv.HomeChainSel].LinkToken maxUint256 := math.MaxBig256 + // Create two ClientEVMTokenAmount structs to be passed to the router + tokens := map[uint64][]router.ClientEVMTokenAmount{ + tenv.HomeChainSel: {{ + Token: srcToken.Address(), + Amount: twoCoins, + }}, + tenv.FeedChainSel: {{ + Token: dstToken.Address(), + Amount: twoCoins, + }}, + } + t.Run("Send Token Pay with Link token home chain -> remote", func(t *testing.T) { src := tenv.HomeChainSel dest, destChain := tenv.FeedChainSel, e.Chains[tenv.FeedChainSel] @@ -377,18 +364,6 @@ func Test_PricingForTokenTransfers(t *testing.T) { require.NoError(t, err) require.GreaterOrEqual(t, srctokenBalance.Int64(), twoCoins.Int64()) - // Create two ClientEVMTokenAmount structs to be passed to the router - tokens := map[uint64][]router.ClientEVMTokenAmount{ - tenv.HomeChainSel: {{ - Token: srcToken.Address(), - Amount: twoCoins, - }}, - tenv.FeedChainSel: {{ - Token: dstToken.Address(), - Amount: twoCoins, - }}, - } - // Assign Src to the Home Chain Selector and destChain to the Feed Chain Selector // get the header for the destination chain and the relevant block number @@ -420,8 +395,16 @@ func Test_PricingForTokenTransfers(t *testing.T) { srcFee, err := state.Chains[src].Router.GetFee(nil, dest, ccipMessage) require.NoError(t, err) - seqNum := changeset.TestSendRequest(t, e, state, src, dest, false, ccipMessage).SequenceNumber - expectedSeqNum[sourceDestPair] = seqNum + msgSentEvent := changeset.TestSendRequest(t, e, state, src, dest, false, ccipMessage) + + expectedSeqNum[changeset.SourceDestPair{ + SourceChainSelector: src, + DestChainSelector: dest, + }] = msgSentEvent.SequenceNumber + expectedSeqNumExec[changeset.SourceDestPair{ + SourceChainSelector: src, + DestChainSelector: dest, + }] = []uint64{msgSentEvent.SequenceNumber} // Check the fee token balance after the request and ensure fee tokens were spent feeTokenBalanceAfter, err := linkToken.BalanceOf(nil, e.Chains[tenv.HomeChainSel].DeployerKey.From) @@ -439,7 +422,7 @@ func Test_PricingForTokenTransfers(t *testing.T) { require.Equal(t, changeset.MockLinkPrice, timestampedPrice.Value) // Wait for all exec reports to land - changeset.ConfirmExecWithSeqNrForAll(t, e, state, expectedSeqNum, startBlocks) + changeset.ConfirmExecWithSeqNrsForAll(t, e, state, expectedSeqNumExec, startBlocks) balance, err := dstToken.BalanceOf(nil, state.Chains[tenv.FeedChainSel].Receiver.Address()) require.NoError(t, err) @@ -451,18 +434,6 @@ func Test_PricingForTokenTransfers(t *testing.T) { }) t.Run("Send Token Pay with native remote chain -> home", func(t *testing.T) { - // Create two ClientEVMTokenAmount structs to be passed to the router - tokens := map[uint64][]router.ClientEVMTokenAmount{ - tenv.HomeChainSel: {{ - Token: dstToken.Address(), - Amount: twoCoins, - }}, - tenv.FeedChainSel: {{ - Token: srcToken.Address(), - Amount: twoCoins, - }}, - } - // Assign Src to the Home Chain Selector and destChain to the Feed Chain Selector src := tenv.FeedChainSel dest, destChain := tenv.HomeChainSel, e.Chains[tenv.HomeChainSel] @@ -488,13 +459,20 @@ func Test_PricingForTokenTransfers(t *testing.T) { ccipMessage := router.ClientEVM2AnyMessage{ Receiver: receiver, Data: data, - TokenAmounts: tokens[dest], + TokenAmounts: tokens[src], FeeToken: feeToken, ExtraArgs: nil, } - seqNum := changeset.TestSendRequest(t, e, state, src, dest, false, ccipMessage).SequenceNumber - expectedSeqNum[sourceDestPair] = seqNum + msgSentEvent := changeset.TestSendRequest(t, e, state, src, dest, false, ccipMessage) + expectedSeqNum[changeset.SourceDestPair{ + SourceChainSelector: src, + DestChainSelector: dest, + }] = msgSentEvent.SequenceNumber + expectedSeqNumExec[changeset.SourceDestPair{ + SourceChainSelector: src, + DestChainSelector: dest, + }] = []uint64{msgSentEvent.SequenceNumber} // Wait for all commit reports to land. changeset.ConfirmCommitForAllWithExpectedSeqNums(t, e, state, expectedSeqNum, startBlocks) @@ -507,7 +485,7 @@ func Test_PricingForTokenTransfers(t *testing.T) { require.Equal(t, changeset.MockLinkPrice, timestampedPrice.Value) // Wait for all exec reports to land - changeset.ConfirmExecWithSeqNrForAll(t, e, state, expectedSeqNum, startBlocks) + changeset.ConfirmExecWithSeqNrsForAll(t, e, state, expectedSeqNumExec, startBlocks) balance, err := srcToken.BalanceOf(nil, state.Chains[tenv.HomeChainSel].Receiver.Address()) require.NoError(t, err) @@ -521,46 +499,13 @@ func Test_PricingForTokenTransfers(t *testing.T) { src := tenv.HomeChainSel dest, destChain := tenv.FeedChainSel, e.Chains[tenv.FeedChainSel] - sourceDestPair := changeset.SourceDestPair{ - SourceChainSelector: src, - DestChainSelector: dest, - } - WETH := state.Chains[src].Weth9 - // We need to acquire some WETH to send with the tx so we deposit some ETH into the WETH contract - // but deployerKey is a reference so we need to dereference it and then reassign it - depositOps := *e.Chains[tenv.HomeChainSel].DeployerKey - depositOps.Value = new(big.Int).Mul(twoCoins, big.NewInt(2)) - tx, err := WETH.Deposit(&depositOps) - require.NoError(t, err) - _, err = e.Chains[tenv.HomeChainSel].Confirm(tx) - require.NoError(t, err) - // Approve to spend WETH token as feeToken - fmt.Printf("--- APPROVING ROUTER TO SPEND---") - tx, err = WETH.Approve(e.Chains[tenv.HomeChainSel].DeployerKey, state.Chains[tenv.HomeChainSel].Router.Address(), twoCoins) + tx, err := WETH.Approve(e.Chains[tenv.HomeChainSel].DeployerKey, state.Chains[tenv.HomeChainSel].Router.Address(), maxUint256) require.NoError(t, err) - fmt.Printf("tx: %v\n", tx) _, err = e.Chains[tenv.HomeChainSel].Confirm(tx) require.NoError(t, err) - fmt.Printf("--- APPROVED ---") - - allowance, err := WETH.Allowance(nil, e.Chains[src].DeployerKey.From, state.Chains[src].Router.Address()) - require.NoError(t, err) - require.GreaterOrEqual(t, allowance.Int64(), twoCoins.Int64()) - - // Create two ClientEVMTokenAmount structs to be passed to the router - tokens := map[uint64][]router.ClientEVMTokenAmount{ - tenv.HomeChainSel: {{ - Token: srcToken.Address(), - Amount: twoCoins, - }}, - tenv.FeedChainSel: {{ - Token: dstToken.Address(), - Amount: twoCoins, - }}, - } srcTokenBal, err := srcToken.BalanceOf(nil, e.Chains[src].DeployerKey.From) require.NoError(t, err) @@ -587,21 +532,32 @@ func Test_PricingForTokenTransfers(t *testing.T) { ExtraArgs: nil, } - // Get the fee Token Balance Before - feeTokenBalanceBefore, err := WETH.BalanceOf(nil, e.Chains[src].DeployerKey.From) + srcFee, err := state.Chains[src].Router.GetFee(nil, dest, ccipMessage) require.NoError(t, err) - // Check the fee Amount - srcFee, err := state.Chains[src].Router.GetFee(nil, dest, ccipMessage) + // We need to acquire some WETH to send with the tx so we deposit some ETH into the WETH contract + // but deployerKey is a reference so we need to dereference it and then reassign it + // Also the fees have been unusually high so we need to deposit more than usual to ensure the test doesn't fail + depositOps := *e.Chains[tenv.HomeChainSel].DeployerKey + depositOps.Value = srcFee + tx, err = WETH.Deposit(&depositOps) + require.NoError(t, err) + _, err = e.Chains[tenv.HomeChainSel].Confirm(tx) require.NoError(t, err) - // Check that we have enough WETH to pay the fee - require.GreaterOrEqual(t, feeTokenBalanceBefore.Int64(), srcFee.Int64()) - fmt.Printf("srcFee: %v\n", srcFee) - fmt.Printf("feeTokenBalanceBefore: %v\n", feeTokenBalanceBefore) + // Get the fee Token Balance Before + feeTokenBalanceBefore, err := WETH.BalanceOf(nil, e.Chains[src].DeployerKey.From) + require.NoError(t, err) - seqNum := changeset.TestSendRequest(t, e, state, src, dest, false, ccipMessage).SequenceNumber - expectedSeqNum[sourceDestPair] = seqNum + msgSentEvent := changeset.TestSendRequest(t, e, state, src, dest, false, ccipMessage) + expectedSeqNum[changeset.SourceDestPair{ + SourceChainSelector: src, + DestChainSelector: dest, + }] = msgSentEvent.SequenceNumber + expectedSeqNumExec[changeset.SourceDestPair{ + SourceChainSelector: src, + DestChainSelector: dest, + }] = []uint64{msgSentEvent.SequenceNumber} // Check the fee token balance after the request and ensure fee tokens were spent feeTokenBalanceAfter, err := WETH.BalanceOf(nil, e.Chains[tenv.HomeChainSel].DeployerKey.From) @@ -619,7 +575,7 @@ func Test_PricingForTokenTransfers(t *testing.T) { require.Equal(t, changeset.MockLinkPrice, timestampedPrice.Value) // Wait for all exec reports to land - changeset.ConfirmExecWithSeqNrForAll(t, e, state, expectedSeqNum, startBlocks) + changeset.ConfirmExecWithSeqNrsForAll(t, e, state, expectedSeqNumExec, startBlocks) balance, err := dstToken.BalanceOf(nil, state.Chains[dest].Receiver.Address()) require.NoError(t, err) @@ -628,41 +584,10 @@ func Test_PricingForTokenTransfers(t *testing.T) { // first part of the test, so balance should already be two require.Equal(t, new(big.Int).Mul(twoCoins, big.NewInt(2)), balance) }) - t.Run("Send Token but revert not enough tokens", func(t *testing.T) { - // Approve the router to spend the tokens and confirm the tx's - tx, err := srcToken.Approve(e.Chains[tenv.HomeChainSel].DeployerKey, state.Chains[tenv.HomeChainSel].Router.Address(), twoCoins) - require.NoError(t, err) - _, err = e.Chains[tenv.HomeChainSel].Confirm(tx) - require.NoError(t, err) - - tx, err = dstToken.Approve(e.Chains[tenv.FeedChainSel].DeployerKey, state.Chains[tenv.FeedChainSel].Router.Address(), twoCoins) - require.NoError(t, err) - _, err = e.Chains[tenv.FeedChainSel].Confirm(tx) - require.NoError(t, err) - - existingBalanceSrc, err := dstToken.BalanceOf(nil, e.Chains[tenv.HomeChainSel].DeployerKey.From) - require.NoError(t, err) - - existingBalanceDst, err := dstToken.BalanceOf(nil, e.Chains[tenv.FeedChainSel].DeployerKey.From) - require.NoError(t, err) - // Assign Src to the Home Chain Selector and destChain to the Feed Chain Selector - src := tenv.FeedChainSel - dest, destChain := tenv.HomeChainSel, e.Chains[tenv.HomeChainSel] - - // Create two ClientEVMTokenAmount structs to be passed to the router - tokens := map[uint64][]router.ClientEVMTokenAmount{ - tenv.HomeChainSel: {{ - Token: dstToken.Address(), - // Send twice as many tokens as available on purpose - Amount: new(big.Int).Mul(existingBalanceSrc, big.NewInt(2)), - }}, - tenv.FeedChainSel: {{ - Token: srcToken.Address(), - Amount: new(big.Int).Mul(existingBalanceDst, big.NewInt(10)), - }}, - } + src := tenv.HomeChainSel + dest, destChain := tenv.FeedChainSel, e.Chains[tenv.FeedChainSel] // get the header for the destination chain and the relevant block number latesthdr, err := destChain.Client.HeaderByNumber(testcontext.Get(t), nil) @@ -670,285 +595,33 @@ func Test_PricingForTokenTransfers(t *testing.T) { block := latesthdr.Number.Uint64() startBlocks[dest] = &block - // Send to the receiver on the destination chain paying with native token + // Send to the receiver on the destination chain paying with LINK token var ( receiver = common.LeftPadBytes(state.Chains[dest].Receiver.Address().Bytes(), 32) data = []byte("") - feeToken = common.HexToAddress("0x0") + feeToken = linkToken.Address() ) + // Increase the token send amount to more than available to intentionally cause a revert + tokens[src][0].Amount = new(big.Int).Mul(twoCoins, big.NewInt(100)) + ccipMessage := router.ClientEVM2AnyMessage{ Receiver: receiver, Data: data, - TokenAmounts: tokens[dest], + TokenAmounts: tokens[src], FeeToken: feeToken, ExtraArgs: nil, } - // Send the CCP Request - tx, _, err = changeset.CCIPSendRequest( + _, _, err = changeset.CCIPSendRequest( e, state, src, dest, - false, + true, ccipMessage, ) - // Check if the transaction reverted require.Error(t, err) - require.Nil(t, tx) - }) -} -/* -func Test_PricingForMessages(t *testing.T) { - // Deploy the environment - lggr := logger.TestLogger(t) - ctx := changeset.Context(t) - tenv, _, _ := testsetups.NewLocalDevEnvironmentWithDefaultPrice(t, lggr) - - // Load the test state - e := tenv.Env - state, err := changeset.LoadOnchainState(e) - require.NoError(t, err) - - feeds := state.Chains[tenv.FeedChainSel].USDFeeds - tokenConfig := changeset.NewTokenConfig() - tokenConfig.UpsertTokenInfo(changeset.LinkSymbol, - pluginconfig.TokenInfo{ - AggregatorAddress: cciptypes.UnknownEncodedAddress(feeds[changeset.LinkSymbol].Address().String()), - Decimals: changeset.LinkDecimals, - DeviationPPB: cciptypes.NewBigIntFromInt64(1e9), - }, - ) - - // Apply migration - output, err := changeset.InitialDeploy(e, changeset.DeployCCIPContractConfig{ - HomeChainSel: tenv.HomeChainSel, - FeedChainSel: tenv.FeedChainSel, - ChainsToDeploy: e.AllChainSelectors(), - TokenConfig: tokenConfig, - MCMSConfig: changeset.NewTestMCMSConfig(t, e), - OCRSecrets: deployment.XXXGenerateTestOCRSecrets(), }) - require.NoError(t, err) - require.NoError(t, e.ExistingAddresses.Merge(output.AddressBook)) - // Get new state after migration and mock USDC token deployment. - state, err = changeset.LoadOnchainState(e) - require.NoError(t, err) - - // Ensure capreg logs are up to date. - changeset.ReplayLogs(t, e.Offchain, tenv.ReplayBlocks) - - // Create an empty tokenAmounts map since we are sending a message without a token - tokens := []router.ClientEVMTokenAmount{} - - // Apply the jobs. - for nodeID, jobs := range output.JobSpecs { - for _, job := range jobs { - // Note these auto-accept - _, err := e.Offchain.ProposeJob(ctx, - &jobv1.ProposeJobRequest{ - NodeId: nodeID, - Spec: job, - }) - require.NoError(t, err) - } - } - - // Add all lanes - require.NoError(t, changeset.AddLanesForAll(e, state)) - // Need to keep track of the block number for each chain so that event subscription can be done from that block. - startBlocks := make(map[uint64]*uint64) - // Send a message from each chain to every other chain. - expectedSeqNum := make(map[uint64]uint64) - - // Mint 2 tokens to be transferred - twoCoins := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(2)) - - linkToken := state.Chains[tenv.HomeChainSel].LinkToken - - t.Run("Send Token Pay with Link token home chain -> remote", func(t *testing.T) { - // Approve to spend link token - tx, err := linkToken.Approve(e.Chains[tenv.HomeChainSel].DeployerKey, state.Chains[tenv.HomeChainSel].Router.Address(), twoCoins) - require.NoError(t, err) - _, err = e.Chains[tenv.HomeChainSel].Confirm(tx) - require.NoError(t, err) - - // Assign Src to the Home Chain Selector and destChain to the Feed Chain Selector - src := tenv.HomeChainSel - dest, destChain := tenv.FeedChainSel, e.Chains[tenv.FeedChainSel] - - // get the header for the destination chain and the relevant block number - latesthdr, err := destChain.Client.HeaderByNumber(testcontext.Get(t), nil) - require.NoError(t, err) - block := latesthdr.Number.Uint64() - startBlocks[dest] = &block - - // Send to the receiver on the destination chain paying with LINK token - var ( - receiver = common.LeftPadBytes(state.Chains[dest].Receiver.Address().Bytes(), 32) - data = []byte("hello world") - feeToken = linkToken.Address() - ) - - ccipMessage := router.ClientEVM2AnyMessage{ - Receiver: receiver, - Data: data, - TokenAmounts: tokens, - FeeToken: feeToken, - ExtraArgs: nil, - } - - // Get the fee Token Balance Before - feeTokenBalanceBefore, err := linkToken.BalanceOf(nil, e.Chains[tenv.HomeChainSel].DeployerKey.From) - require.NoError(t, err) - - // Check the fee Amount - srcFee, err := state.Chains[src].Router.GetFee(nil, dest, ccipMessage) - require.NoError(t, err) - - seqNum := changeset.TestSendRequest(t, e, state, src, dest, false, ccipMessage).SequenceNumber - expectedSeqNum[dest] = seqNum - - // Check the fee token balance after the request and ensure fee tokens were spent - feeTokenBalanceAfter, err := linkToken.BalanceOf(nil, e.Chains[tenv.HomeChainSel].DeployerKey.From) - require.NoError(t, err) - require.Equal(t, feeTokenBalanceAfter, new(big.Int).Sub(feeTokenBalanceBefore, srcFee)) - - // Wait for all commit reports to land. - changeset.ConfirmCommitForAllWithExpectedSeqNums(t, e, state, expectedSeqNum, startBlocks) - - // After commit is reported on all chains, token prices should be updated in FeeQuoter. - linkAddress := state.Chains[dest].LinkToken.Address() - feeQuoter := state.Chains[dest].FeeQuoter - timestampedPrice, err := feeQuoter.GetTokenPrice(nil, linkAddress) - require.NoError(t, err) - require.Equal(t, changeset.MockLinkPrice, timestampedPrice.Value) - - // Wait for all exec reports to land - changeset.ConfirmExecWithSeqNrForAll(t, e, state, expectedSeqNum, startBlocks) - - // Delete from the expcted seq num the chain that was just tested so that we don't pass it to the - // commit report in the next test - delete(expectedSeqNum, dest) - }) - - t.Run("Send Token Pay with native remote chain -> home", func(t *testing.T) { - // Assign Src to the Home Chain Selector and destChain to the Feed Chain Selector - src := tenv.FeedChainSel - dest, destChain := tenv.HomeChainSel, e.Chains[tenv.HomeChainSel] - - // get the header for the destination chain and the relevant block number - latesthdr, err := destChain.Client.HeaderByNumber(testcontext.Get(t), nil) - require.NoError(t, err) - block := latesthdr.Number.Uint64() - startBlocks[dest] = &block - - // Send to the receiver on the destination chain paying with native token - var ( - receiver = common.LeftPadBytes(state.Chains[dest].Receiver.Address().Bytes(), 32) - data = []byte("") - feeToken = common.HexToAddress("0x0") - ) - - ccipMessage := router.ClientEVM2AnyMessage{ - Receiver: receiver, - Data: data, - TokenAmounts: tokens, - FeeToken: feeToken, - ExtraArgs: nil, - } - - seqNum := changeset.TestSendRequest(t, e, state, src, dest, false, ccipMessage).SequenceNumber - expectedSeqNum[dest] = seqNum - - // Wait for all commit reports to land. - changeset.ConfirmCommitForAllWithExpectedSeqNums(t, e, state, expectedSeqNum, startBlocks) - - // After commit is reported on all chains, token prices should be updated in FeeQuoter. - linkAddress := state.Chains[dest].LinkToken.Address() - feeQuoter := state.Chains[dest].FeeQuoter - timestampedPrice, err := feeQuoter.GetTokenPrice(nil, linkAddress) - require.NoError(t, err) - require.Equal(t, changeset.MockLinkPrice, timestampedPrice.Value) - - // Wait for all exec reports to land - changeset.ConfirmExecWithSeqNrForAll(t, e, state, expectedSeqNum, startBlocks) - - delete(expectedSeqNum, dest) - }) - - t.Run("Send Token pay with wrapped native home chain -> remote", func(t *testing.T) { - WETH := state.Chains[tenv.HomeChainSel].Weth9 - - // We need to acquire some WETH to send with the tx so we deposit some ETH into the WETH contract - // but deployerKey is a reference so we need to dereference it and then reassign it - depositOps := *e.Chains[tenv.HomeChainSel].DeployerKey - depositOps.Value = new(big.Int).Mul(twoCoins, big.NewInt(2)) - tx, err := WETH.Deposit(&depositOps) - require.NoError(t, err) - _, err = e.Chains[tenv.HomeChainSel].Confirm(tx) - require.NoError(t, err) - - // Approve to spend WETH token as feeToken - tx, err = WETH.Approve(e.Chains[tenv.HomeChainSel].DeployerKey, state.Chains[tenv.HomeChainSel].Router.Address(), new(big.Int).Mul(twoCoins, big.NewInt(2))) - require.NoError(t, err) - _, err = e.Chains[tenv.HomeChainSel].Confirm(tx) - require.NoError(t, err) - - // Assign Src to the Home Chain Selector and destChain to the Feed Chain Selector - src := tenv.HomeChainSel - dest, destChain := tenv.FeedChainSel, e.Chains[tenv.FeedChainSel] - - // get the header for the destination chain and the relevant block number - latesthdr, err := destChain.Client.HeaderByNumber(testcontext.Get(t), nil) - require.NoError(t, err) - block := latesthdr.Number.Uint64() - startBlocks[dest] = &block - - // Send to the receiver on the destination chain paying with LINK token - var ( - receiver = common.LeftPadBytes(state.Chains[dest].Receiver.Address().Bytes(), 32) - data = []byte("hello world") - feeToken = state.Chains[src].Weth9.Address() - ) - - ccipMessage := router.ClientEVM2AnyMessage{ - Receiver: receiver, - Data: data, - TokenAmounts: tokens, - FeeToken: feeToken, - ExtraArgs: nil, - } - - // Get the fee Token Balance Before - feeTokenBalanceBefore, err := WETH.BalanceOf(nil, e.Chains[src].DeployerKey.From) - require.NoError(t, err) - - // Check the fee Amount - srcFee, err := state.Chains[src].Router.GetFee(nil, dest, ccipMessage) - require.NoError(t, err) - - seqNum := changeset.TestSendRequest(t, e, state, src, dest, false, ccipMessage).SequenceNumber - expectedSeqNum[dest] = seqNum - - // Check the fee token balance after the request and ensure fee tokens were spent - feeTokenBalanceAfter, err := WETH.BalanceOf(nil, e.Chains[tenv.HomeChainSel].DeployerKey.From) - require.NoError(t, err) - require.Equal(t, feeTokenBalanceAfter, new(big.Int).Sub(feeTokenBalanceBefore, srcFee)) - - // Wait for all commit reports to land. - changeset.ConfirmCommitForAllWithExpectedSeqNums(t, e, state, expectedSeqNum, startBlocks) - - // After commit is reported on all chains, token prices should be updated in FeeQuoter. - linkAddress := state.Chains[dest].LinkToken.Address() - feeQuoter := state.Chains[dest].FeeQuoter - timestampedPrice, err := feeQuoter.GetTokenPrice(nil, linkAddress) - require.NoError(t, err) - require.Equal(t, changeset.MockLinkPrice, timestampedPrice.Value) - - // Wait for all exec reports to land - changeset.ConfirmExecWithSeqNrForAll(t, e, state, expectedSeqNum, startBlocks) - }) -}*/ +} diff --git a/integration-tests/smoke/ccip_test.go b/integration-tests/smoke/ccip_test.go deleted file mode 100644 index d6c1b4f05b7..00000000000 --- a/integration-tests/smoke/ccip_test.go +++ /dev/null @@ -1,923 +0,0 @@ -package smoke - -import ( - "math/big" - "testing" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/math" - "github.com/stretchr/testify/require" - - "github.com/smartcontractkit/chainlink-testing-framework/lib/utils/testcontext" - "github.com/smartcontractkit/chainlink/deployment/ccip/changeset" - "github.com/smartcontractkit/chainlink/integration-tests/testsetups" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/shared/generated/burn_mint_erc677" - "github.com/smartcontractkit/chainlink/v2/core/logger" -) - -func TestInitialDeployOnLocal(t *testing.T) { - t.Parallel() - lggr := logger.TestLogger(t) - tenv, _, _ := testsetups.NewLocalDevEnvironmentWithDefaultPrice(t, lggr) - e := tenv.Env - state, err := changeset.LoadOnchainState(e) - require.NoError(t, err) - - // Add all lanes - require.NoError(t, changeset.AddLanesForAll(e, state)) - // Need to keep track of the block number for each chain so that event subscription can be done from that block. - startBlocks := make(map[uint64]*uint64) - // Send a message from each chain to every other chain. - expectedSeqNum := make(map[changeset.SourceDestPair]uint64) - for src := range e.Chains { - for dest, destChain := range e.Chains { - if src == dest { - continue - } - latesthdr, err := destChain.Client.HeaderByNumber(testcontext.Get(t), nil) - require.NoError(t, err) - block := latesthdr.Number.Uint64() - startBlocks[dest] = &block - msgSentEvent := changeset.TestSendRequest(t, e, state, src, dest, false, router.ClientEVM2AnyMessage{ - Receiver: common.LeftPadBytes(state.Chains[dest].Receiver.Address().Bytes(), 32), - Data: []byte("hello world"), - TokenAmounts: nil, - FeeToken: common.HexToAddress("0x0"), - ExtraArgs: nil, - }) - expectedSeqNum[changeset.SourceDestPair{ - SourceChainSelector: src, - DestChainSelector: dest, - }] = msgSentEvent.SequenceNumber - } - } - - // Wait for all commit reports to land. - changeset.ConfirmCommitForAllWithExpectedSeqNums(t, e, state, expectedSeqNum, startBlocks) - - // After commit is reported on all chains, token prices should be updated in FeeQuoter. - for dest := range e.Chains { - linkAddress := state.Chains[dest].LinkToken.Address() - feeQuoter := state.Chains[dest].FeeQuoter - timestampedPrice, err := feeQuoter.GetTokenPrice(nil, linkAddress) - require.NoError(t, err) - require.Equal(t, changeset.MockLinkPrice, timestampedPrice.Value) - } - - // Wait for all exec reports to land - changeset.ConfirmExecWithSeqNrForAll(t, e, state, expectedSeqNum, startBlocks) - - // TODO: Apply the proposal. -} - -func TestTokenTransfer(t *testing.T) { - t.Parallel() - lggr := logger.TestLogger(t) - tenv, _, _ := testsetups.NewLocalDevEnvironmentWithDefaultPrice(t, lggr) - e := tenv.Env - state, err := changeset.LoadOnchainState(e) - require.NoError(t, err) - - srcToken, _, dstToken, _, err := changeset.DeployTransferableToken( - lggr, - tenv.Env.Chains, - tenv.HomeChainSel, - tenv.FeedChainSel, - state, - e.ExistingAddresses, - "MY_TOKEN", - ) - require.NoError(t, err) - - // Add all lanes - require.NoError(t, changeset.AddLanesForAll(e, state)) - // Need to keep track of the block number for each chain so that event subscription can be done from that block. - startBlocks := make(map[uint64]*uint64) - // Send a message from each chain to every other chain. - expectedSeqNum := make(map[changeset.SourceDestPair]uint64) - - twoCoins := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(2)) - tx, err := srcToken.Mint( - e.Chains[tenv.HomeChainSel].DeployerKey, - e.Chains[tenv.HomeChainSel].DeployerKey.From, - new(big.Int).Mul(twoCoins, big.NewInt(10)), - ) - require.NoError(t, err) - _, err = e.Chains[tenv.HomeChainSel].Confirm(tx) - require.NoError(t, err) - - tx, err = dstToken.Mint( - e.Chains[tenv.FeedChainSel].DeployerKey, - e.Chains[tenv.FeedChainSel].DeployerKey.From, - new(big.Int).Mul(twoCoins, big.NewInt(10)), - ) - require.NoError(t, err) - _, err = e.Chains[tenv.FeedChainSel].Confirm(tx) - require.NoError(t, err) - - tx, err = srcToken.Approve(e.Chains[tenv.HomeChainSel].DeployerKey, state.Chains[tenv.HomeChainSel].Router.Address(), twoCoins) - require.NoError(t, err) - _, err = e.Chains[tenv.HomeChainSel].Confirm(tx) - require.NoError(t, err) - tx, err = dstToken.Approve(e.Chains[tenv.FeedChainSel].DeployerKey, state.Chains[tenv.FeedChainSel].Router.Address(), twoCoins) - require.NoError(t, err) - _, err = e.Chains[tenv.FeedChainSel].Confirm(tx) - require.NoError(t, err) - - tokens := map[uint64][]router.ClientEVMTokenAmount{ - tenv.HomeChainSel: {{ - Token: srcToken.Address(), - Amount: twoCoins, - }}, - tenv.FeedChainSel: {{ - Token: dstToken.Address(), - Amount: twoCoins, - }}, - } - - for src := range e.Chains { - for dest, destChain := range e.Chains { - if src == dest { - continue - } - latesthdr, err := destChain.Client.HeaderByNumber(testcontext.Get(t), nil) - require.NoError(t, err) - block := latesthdr.Number.Uint64() - startBlocks[dest] = &block - - var ( - receiver = common.LeftPadBytes(state.Chains[dest].Receiver.Address().Bytes(), 32) - data = []byte("hello world") - feeToken = common.HexToAddress("0x0") - ) - if src == tenv.HomeChainSel && dest == tenv.FeedChainSel { - msgSentEvent := changeset.TestSendRequest(t, e, state, src, dest, false, router.ClientEVM2AnyMessage{ - Receiver: receiver, - Data: data, - TokenAmounts: tokens[src], - FeeToken: feeToken, - ExtraArgs: nil, - }) - expectedSeqNum[changeset.SourceDestPair{ - SourceChainSelector: src, - DestChainSelector: dest, - }] = msgSentEvent.SequenceNumber - } else { - msgSentEvent := changeset.TestSendRequest(t, e, state, src, dest, false, router.ClientEVM2AnyMessage{ - Receiver: receiver, - Data: data, - TokenAmounts: nil, - FeeToken: feeToken, - ExtraArgs: nil, - }) - expectedSeqNum[changeset.SourceDestPair{ - SourceChainSelector: src, - DestChainSelector: dest, - }] = msgSentEvent.SequenceNumber - } - } - } - - // Wait for all commit reports to land. - changeset.ConfirmCommitForAllWithExpectedSeqNums(t, e, state, expectedSeqNum, startBlocks) - - // After commit is reported on all chains, token prices should be updated in FeeQuoter. - for dest := range e.Chains { - linkAddress := state.Chains[dest].LinkToken.Address() - feeQuoter := state.Chains[dest].FeeQuoter - timestampedPrice, err := feeQuoter.GetTokenPrice(nil, linkAddress) - require.NoError(t, err) - require.Equal(t, changeset.MockLinkPrice, timestampedPrice.Value) - } - - // Wait for all exec reports to land - changeset.ConfirmExecWithSeqNrForAll(t, e, state, expectedSeqNum, startBlocks) - - balance, err := dstToken.BalanceOf(nil, state.Chains[tenv.FeedChainSel].Receiver.Address()) - require.NoError(t, err) - require.Equal(t, twoCoins, balance) -} - -// setupTokens deploys transferable tokens on the source and dest, mints tokens for the source and dest, and -// approves the router to spend the tokens -func setupTokens(t *testing.T, tenv changeset.DeployedEnv) (srcToken *burn_mint_erc677.BurnMintERC677, dstToken *burn_mint_erc677.BurnMintERC677) { - lggr := logger.TestLogger(t) - - e := tenv.Env - state, err := changeset.LoadOnchainState(e) - require.NoError(t, err) - - tenCoins := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(10)) - - // Deploy the token to test transferring - srcToken, _, dstToken, _, err = changeset.DeployTransferableToken( - lggr, - tenv.Env.Chains, - tenv.HomeChainSel, - tenv.FeedChainSel, - state, - e.ExistingAddresses, - "MY_TOKEN", - ) - - linkToken := state.Chains[tenv.HomeChainSel].LinkToken - - require.NoError(t, err) - - tx, err := srcToken.Mint( - e.Chains[tenv.HomeChainSel].DeployerKey, - e.Chains[tenv.HomeChainSel].DeployerKey.From, - new(big.Int).Mul(tenCoins, big.NewInt(10)), - ) - require.NoError(t, err) - - _, err = e.Chains[tenv.HomeChainSel].Confirm(tx) - require.NoError(t, err) - - // Mint a destination token - tx, err = dstToken.Mint( - e.Chains[tenv.FeedChainSel].DeployerKey, - e.Chains[tenv.FeedChainSel].DeployerKey.From, - new(big.Int).Mul(tenCoins, big.NewInt(10)), - ) - - // Confirm the mint tx - require.NoError(t, err) - _, err = e.Chains[tenv.FeedChainSel].Confirm(tx) - require.NoError(t, err) - - maxUint256 := math.MaxBig256 - - // Approve the router to spend the tokens and confirm the tx's - // To prevent having to approve the router for every transfer, we approve a sufficiently large amount - tx, err = srcToken.Approve(e.Chains[tenv.HomeChainSel].DeployerKey, state.Chains[tenv.HomeChainSel].Router.Address(), maxUint256) - require.NoError(t, err) - _, err = e.Chains[tenv.HomeChainSel].Confirm(tx) - require.NoError(t, err) - - tx, err = dstToken.Approve(e.Chains[tenv.FeedChainSel].DeployerKey, state.Chains[tenv.FeedChainSel].Router.Address(), maxUint256) - require.NoError(t, err) - _, err = e.Chains[tenv.FeedChainSel].Confirm(tx) - require.NoError(t, err) - - // Grant mint and burn roles to the deployer key for the newly deployed linkToken - // Since those roles are not granted automatically - tx, err = linkToken.GrantMintAndBurnRoles(e.Chains[tenv.HomeChainSel].DeployerKey, e.Chains[tenv.HomeChainSel].DeployerKey.From) - require.NoError(t, err) - _, err = e.Chains[tenv.HomeChainSel].Confirm(tx) - require.NoError(t, err) - - // Mint link token and confirm the tx - tx, err = linkToken.Mint( - e.Chains[tenv.HomeChainSel].DeployerKey, - e.Chains[tenv.HomeChainSel].DeployerKey.From, - new(big.Int).Mul(tenCoins, big.NewInt(10)), - ) - require.NoError(t, err) - - _, err = e.Chains[tenv.HomeChainSel].Confirm(tx) - require.NoError(t, err) - - return srcToken, dstToken -} - -func Test_PricingForTokenTransfers(t *testing.T) { - t.Parallel() - lggr := logger.TestLogger(t) - // ctx := changeset.Context(t) - tenv, _, _ := testsetups.NewLocalDevEnvironmentWithDefaultPrice(t, lggr) - e := tenv.Env - - state, err := changeset.LoadOnchainState(tenv.Env) - require.NoError(t, err) - - // feeds := state.Chains[tenv.FeedChainSel].USDFeeds - output, err := changeset.DeployPrerequisites(tenv.Env, changeset.DeployPrerequisiteConfig{ - ChainSelectors: tenv.Env.AllChainSelectors(), - }) - require.NoError(t, err) - require.NoError(t, tenv.Env.ExistingAddresses.Merge(output.AddressBook)) - - expectedSeqNum := make(map[changeset.SourceDestPair]uint64) - - require.NoError(t, err) - require.NoError(t, tenv.Env.ExistingAddresses.Merge(output.AddressBook)) - // Get new state after migration. - state, err = changeset.LoadOnchainState(e) - require.NoError(t, err) - - srcToken, dstToken := setupTokens(t, tenv) - - // Ensure capreg logs are up to date. - changeset.ReplayLogs(t, e.Offchain, tenv.ReplayBlocks) - - // Add all lanes - require.NoError(t, changeset.AddLanesForAll(e, state)) - // Need to keep track of the block number for each chain so that event subscription can be done from that block. - startBlocks := make(map[uint64]*uint64) - // Send a message from each chain to every other chain. - - // Mint 2 tokens to be transferred - twoCoins := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(2)) - - linkToken := state.Chains[tenv.HomeChainSel].LinkToken - maxUint256 := math.MaxBig256 - - t.Run("Send Token Pay with Link token home chain -> remote", func(t *testing.T) { - src := tenv.HomeChainSel - dest, destChain := tenv.FeedChainSel, e.Chains[tenv.FeedChainSel] - - sourceDestPair := changeset.SourceDestPair{ - SourceChainSelector: src, - DestChainSelector: dest, - } - - // Approve to spend link token - tx, err := linkToken.Approve(e.Chains[src].DeployerKey, state.Chains[src].Router.Address(), maxUint256) - require.NoError(t, err) - _, err = e.Chains[src].Confirm(tx) - require.NoError(t, err) - - // Get the fee Token Balance Before - srctokenBalance, err := srcToken.BalanceOf(nil, e.Chains[src].DeployerKey.From) - require.NoError(t, err) - require.GreaterOrEqual(t, srctokenBalance.Int64(), twoCoins.Int64()) - - // Create two ClientEVMTokenAmount structs to be passed to the router - tokens := map[uint64][]router.ClientEVMTokenAmount{ - tenv.HomeChainSel: {{ - Token: srcToken.Address(), - Amount: twoCoins, - }}, - tenv.FeedChainSel: {{ - Token: dstToken.Address(), - Amount: twoCoins, - }}, - } - - // Assign Src to the Home Chain Selector and destChain to the Feed Chain Selector - - // get the header for the destination chain and the relevant block number - latesthdr, err := destChain.Client.HeaderByNumber(testcontext.Get(t), nil) - require.NoError(t, err) - block := latesthdr.Number.Uint64() - startBlocks[dest] = &block - - // Send to the receiver on the destination chain paying with LINK token - var ( - receiver = common.LeftPadBytes(state.Chains[dest].Receiver.Address().Bytes(), 32) - data = []byte("") - feeToken = linkToken.Address() - ) - - ccipMessage := router.ClientEVM2AnyMessage{ - Receiver: receiver, - Data: data, - TokenAmounts: tokens[src], - FeeToken: feeToken, - ExtraArgs: nil, - } - - // Get the fee Token Balance Before - feeTokenBalanceBefore, err := linkToken.BalanceOf(nil, e.Chains[src].DeployerKey.From) - require.NoError(t, err) - - // Check the fee Amount - srcFee, err := state.Chains[src].Router.GetFee(nil, dest, ccipMessage) - require.NoError(t, err) - - seqNum := changeset.TestSendRequest(t, e, state, src, dest, false, ccipMessage).SequenceNumber - expectedSeqNum[sourceDestPair] = seqNum - - // Check the fee token balance after the request and ensure fee tokens were spent - feeTokenBalanceAfter, err := linkToken.BalanceOf(nil, e.Chains[tenv.HomeChainSel].DeployerKey.From) - require.NoError(t, err) - require.Equal(t, feeTokenBalanceAfter, new(big.Int).Sub(feeTokenBalanceBefore, srcFee)) - - // Wait for all commit reports to land. - changeset.ConfirmCommitForAllWithExpectedSeqNums(t, e, state, expectedSeqNum, startBlocks) - - // After commit is reported on all chains, token prices should be updated in FeeQuoter. - linkAddress := state.Chains[dest].LinkToken.Address() - feeQuoter := state.Chains[dest].FeeQuoter - timestampedPrice, err := feeQuoter.GetTokenPrice(nil, linkAddress) - require.NoError(t, err) - require.Equal(t, changeset.MockLinkPrice, timestampedPrice.Value) - - // Wait for all exec reports to land - changeset.ConfirmExecWithSeqNrForAll(t, e, state, expectedSeqNum, startBlocks) - - balance, err := dstToken.BalanceOf(nil, state.Chains[tenv.FeedChainSel].Receiver.Address()) - require.NoError(t, err) - require.Equal(t, twoCoins, balance) - - // Delete from the expcted seq num the chain that was just tested so that we don't pass it to the - // commit report in the next test - delete(expectedSeqNum, sourceDestPair) - }) - - t.Run("Send Token Pay with native remote chain -> home", func(t *testing.T) { - // Create two ClientEVMTokenAmount structs to be passed to the router - tokens := map[uint64][]router.ClientEVMTokenAmount{ - tenv.HomeChainSel: {{ - Token: dstToken.Address(), - Amount: twoCoins, - }}, - tenv.FeedChainSel: {{ - Token: srcToken.Address(), - Amount: twoCoins, - }}, - } - - // Assign Src to the Home Chain Selector and destChain to the Feed Chain Selector - src := tenv.FeedChainSel - dest, destChain := tenv.HomeChainSel, e.Chains[tenv.HomeChainSel] - - sourceDestPair := changeset.SourceDestPair{ - SourceChainSelector: src, - DestChainSelector: dest, - } - - // get the header for the destination chain and the relevant block number - latesthdr, err := destChain.Client.HeaderByNumber(testcontext.Get(t), nil) - require.NoError(t, err) - block := latesthdr.Number.Uint64() - startBlocks[dest] = &block - - // Send to the receiver on the destination chain paying with native token - var ( - receiver = common.LeftPadBytes(state.Chains[dest].Receiver.Address().Bytes(), 32) - data = []byte("") - feeToken = common.HexToAddress("0x0") - ) - - ccipMessage := router.ClientEVM2AnyMessage{ - Receiver: receiver, - Data: data, - TokenAmounts: tokens[dest], - FeeToken: feeToken, - ExtraArgs: nil, - } - - seqNum := changeset.TestSendRequest(t, e, state, src, dest, false, ccipMessage).SequenceNumber - expectedSeqNum[sourceDestPair] = seqNum - - // Wait for all commit reports to land. - changeset.ConfirmCommitForAllWithExpectedSeqNums(t, e, state, expectedSeqNum, startBlocks) - - // After commit is reported on all chains, token prices should be updated in FeeQuoter. - linkAddress := state.Chains[dest].LinkToken.Address() - feeQuoter := state.Chains[dest].FeeQuoter - timestampedPrice, err := feeQuoter.GetTokenPrice(nil, linkAddress) - require.NoError(t, err) - require.Equal(t, changeset.MockLinkPrice, timestampedPrice.Value) - - // Wait for all exec reports to land - changeset.ConfirmExecWithSeqNrForAll(t, e, state, expectedSeqNum, startBlocks) - - balance, err := srcToken.BalanceOf(nil, state.Chains[tenv.HomeChainSel].Receiver.Address()) - require.NoError(t, err) - require.Equal(t, twoCoins, balance) - - delete(expectedSeqNum, sourceDestPair) - }) - - t.Run("Send Token pay with wrapped native home chain -> remote", func(t *testing.T) { - // Assign Src to the Home Chain Selector and destChain to the Feed Chain Selector - src := tenv.HomeChainSel - dest, destChain := tenv.FeedChainSel, e.Chains[tenv.FeedChainSel] - - sourceDestPair := changeset.SourceDestPair{ - SourceChainSelector: src, - DestChainSelector: dest, - } - - WETH := state.Chains[src].Weth9 - - wrappedNative, err := state.Chains[src].Router.GetWrappedNative(nil) - require.NoError(t, err) - require.Equal(t, WETH.Address(), wrappedNative) - - // We need to acquire some WETH to send with the tx so we deposit some ETH into the WETH contract - // but deployerKey is a reference so we need to dereference it and then reassign it - depositOps := *e.Chains[tenv.HomeChainSel].DeployerKey - depositOps.Value = new(big.Int).Mul(twoCoins, big.NewInt(40)) - tx, err := WETH.Deposit(&depositOps) - require.NoError(t, err) - _, err = e.Chains[tenv.HomeChainSel].Confirm(tx) - require.NoError(t, err) - - // Approve to spend 100 WETH token as feeToken - tx, err = WETH.Approve(e.Chains[tenv.HomeChainSel].DeployerKey, state.Chains[src].Router.Address(), new(big.Int).Mul(twoCoins, big.NewInt(50))) - require.NoError(t, err) - _, err = e.Chains[tenv.HomeChainSel].Confirm(tx) - require.NoError(t, err) - - allowance, err := WETH.Allowance(nil, e.Chains[src].DeployerKey.From, state.Chains[src].Router.Address()) - require.NoError(t, err) - require.GreaterOrEqual(t, allowance.Int64(), twoCoins.Int64()) - - // Create two ClientEVMTokenAmount structs to be passed to the router - tokens := map[uint64][]router.ClientEVMTokenAmount{ - tenv.HomeChainSel: {{ - Token: srcToken.Address(), - Amount: twoCoins, - }}, - tenv.FeedChainSel: {{ - Token: dstToken.Address(), - Amount: twoCoins, - }}, - } - - srcTokenBal, err := srcToken.BalanceOf(nil, e.Chains[src].DeployerKey.From) - require.NoError(t, err) - require.GreaterOrEqual(t, srcTokenBal.Int64(), twoCoins.Int64()) - - // get the header for the destination chain and the relevant block number - latesthdr, err := destChain.Client.HeaderByNumber(testcontext.Get(t), nil) - require.NoError(t, err) - block := latesthdr.Number.Uint64() - startBlocks[dest] = &block - - // Send to the receiver on the destination chain paying with LINK token - var ( - receiver = common.LeftPadBytes(state.Chains[dest].Receiver.Address().Bytes(), 32) - data = []byte("") - feeToken = state.Chains[src].Weth9.Address() - ) - - ccipMessage := router.ClientEVM2AnyMessage{ - Receiver: receiver, - Data: data, - TokenAmounts: tokens[src], - FeeToken: feeToken, - ExtraArgs: nil, - } - - // Get the fee Token Balance Before - feeTokenBalanceBefore, err := WETH.BalanceOf(nil, e.Chains[src].DeployerKey.From) - require.NoError(t, err) - - // Check the fee Amount - srcFee, err := state.Chains[src].Router.GetFee(nil, dest, ccipMessage) - require.NoError(t, err) - - // Check that we have enough WETH to pay the fee - require.GreaterOrEqual(t, feeTokenBalanceBefore.Int64(), srcFee.Int64()) - - seqNum := changeset.TestSendRequest(t, e, state, src, dest, false, ccipMessage).SequenceNumber - expectedSeqNum[sourceDestPair] = seqNum - - // Check the fee token balance after the request and ensure fee tokens were spent - feeTokenBalanceAfter, err := WETH.BalanceOf(nil, e.Chains[tenv.HomeChainSel].DeployerKey.From) - require.NoError(t, err) - require.Equal(t, feeTokenBalanceAfter, new(big.Int).Sub(feeTokenBalanceBefore, srcFee)) - - // Wait for all commit reports to land. - changeset.ConfirmCommitForAllWithExpectedSeqNums(t, e, state, expectedSeqNum, startBlocks) - - // After commit is reported on all chains, token prices should be updated in FeeQuoter. - linkAddress := state.Chains[dest].LinkToken.Address() - feeQuoter := state.Chains[dest].FeeQuoter - timestampedPrice, err := feeQuoter.GetTokenPrice(nil, linkAddress) - require.NoError(t, err) - require.Equal(t, changeset.MockLinkPrice, timestampedPrice.Value) - - // Wait for all exec reports to land - changeset.ConfirmExecWithSeqNrForAll(t, e, state, expectedSeqNum, startBlocks) - - balance, err := dstToken.BalanceOf(nil, state.Chains[dest].Receiver.Address()) - require.NoError(t, err) - - // The balance should be 4 since we've already sent 2 tokens over this lane direction in the - // first part of the test, so balance should already be two - require.Equal(t, new(big.Int).Mul(twoCoins, big.NewInt(2)), balance) - }) - - t.Run("Send Token but revert not enough tokens", func(t *testing.T) { - // Approve the router to spend the tokens and confirm the tx's - tx, err := srcToken.Approve(e.Chains[tenv.HomeChainSel].DeployerKey, state.Chains[tenv.HomeChainSel].Router.Address(), twoCoins) - require.NoError(t, err) - _, err = e.Chains[tenv.HomeChainSel].Confirm(tx) - require.NoError(t, err) - - tx, err = dstToken.Approve(e.Chains[tenv.FeedChainSel].DeployerKey, state.Chains[tenv.FeedChainSel].Router.Address(), twoCoins) - require.NoError(t, err) - _, err = e.Chains[tenv.FeedChainSel].Confirm(tx) - require.NoError(t, err) - - existingBalanceSrc, err := dstToken.BalanceOf(nil, e.Chains[tenv.HomeChainSel].DeployerKey.From) - require.NoError(t, err) - - existingBalanceDst, err := dstToken.BalanceOf(nil, e.Chains[tenv.FeedChainSel].DeployerKey.From) - require.NoError(t, err) - - // Assign Src to the Home Chain Selector and destChain to the Feed Chain Selector - src := tenv.FeedChainSel - dest, destChain := tenv.HomeChainSel, e.Chains[tenv.HomeChainSel] - - // Create two ClientEVMTokenAmount structs to be passed to the router - tokens := map[uint64][]router.ClientEVMTokenAmount{ - tenv.HomeChainSel: {{ - Token: dstToken.Address(), - // Send twice as many tokens as available on purpose - Amount: new(big.Int).Mul(existingBalanceSrc, big.NewInt(2)), - }}, - tenv.FeedChainSel: {{ - Token: srcToken.Address(), - Amount: new(big.Int).Mul(existingBalanceDst, big.NewInt(10)), - }}, - } - - // get the header for the destination chain and the relevant block number - latesthdr, err := destChain.Client.HeaderByNumber(testcontext.Get(t), nil) - require.NoError(t, err) - block := latesthdr.Number.Uint64() - startBlocks[dest] = &block - - // Send to the receiver on the destination chain paying with native token - var ( - receiver = common.LeftPadBytes(state.Chains[dest].Receiver.Address().Bytes(), 32) - data = []byte("") - feeToken = common.HexToAddress("0x0") - ) - - ccipMessage := router.ClientEVM2AnyMessage{ - Receiver: receiver, - Data: data, - TokenAmounts: tokens[dest], - FeeToken: feeToken, - ExtraArgs: nil, - } - - // Send the CCP Request - tx, _, err = changeset.CCIPSendRequest( - e, - state, - src, dest, - false, - ccipMessage, - ) - - // Check if the transaction reverted - require.Error(t, err) - require.Nil(t, tx) - }) -} - -func Test_PricingForMessages(t *testing.T) { - t.Parallel() - lggr := logger.TestLogger(t) - // ctx := changeset.Context(t) - tenv, _, _ := testsetups.NewLocalDevEnvironmentWithDefaultPrice(t, lggr) - e := tenv.Env - - state, err := changeset.LoadOnchainState(tenv.Env) - require.NoError(t, err) - - // feeds := state.Chains[tenv.FeedChainSel].USDFeeds - output, err := changeset.DeployPrerequisites(tenv.Env, changeset.DeployPrerequisiteConfig{ - ChainSelectors: tenv.Env.AllChainSelectors(), - }) - require.NoError(t, err) - require.NoError(t, tenv.Env.ExistingAddresses.Merge(output.AddressBook)) - - expectedSeqNum := make(map[changeset.SourceDestPair]uint64) - - require.NoError(t, err) - require.NoError(t, tenv.Env.ExistingAddresses.Merge(output.AddressBook)) - // Get new state after migration. - state, err = changeset.LoadOnchainState(e) - require.NoError(t, err) - - // Ensure capreg logs are up to date. - changeset.ReplayLogs(t, e.Offchain, tenv.ReplayBlocks) - - // Add all lanes - require.NoError(t, changeset.AddLanesForAll(e, state)) - // Need to keep track of the block number for each chain so that event subscription can be done from that block. - startBlocks := make(map[uint64]*uint64) - // Send a message from each chain to every other chain. - - // Mint 2 tokens to be transferred - twoCoins := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(2)) - - linkToken := state.Chains[tenv.HomeChainSel].LinkToken - maxUint256 := math.MaxBig256 - - emptyTokenArray := []router.ClientEVMTokenAmount{} - - t.Run("Send Token Pay with Link token home chain -> remote", func(t *testing.T) { - src := tenv.HomeChainSel - dest, destChain := tenv.FeedChainSel, e.Chains[tenv.FeedChainSel] - - sourceDestPair := changeset.SourceDestPair{ - SourceChainSelector: src, - DestChainSelector: dest, - } - - // Approve to spend link token - tx, err := linkToken.Approve(e.Chains[src].DeployerKey, state.Chains[src].Router.Address(), maxUint256) - require.NoError(t, err) - _, err = e.Chains[src].Confirm(tx) - require.NoError(t, err) - - // get the header for the destination chain and the relevant block number - latesthdr, err := destChain.Client.HeaderByNumber(testcontext.Get(t), nil) - require.NoError(t, err) - block := latesthdr.Number.Uint64() - startBlocks[dest] = &block - - // Send to the receiver on the destination chain paying with LINK token - var ( - receiver = common.LeftPadBytes(state.Chains[dest].Receiver.Address().Bytes(), 32) - data = []byte("hello world") - feeToken = linkToken.Address() - ) - - ccipMessage := router.ClientEVM2AnyMessage{ - Receiver: receiver, - Data: data, - TokenAmounts: emptyTokenArray, - FeeToken: feeToken, - ExtraArgs: nil, - } - - // Get the fee Token Balance Before - feeTokenBalanceBefore, err := linkToken.BalanceOf(nil, e.Chains[src].DeployerKey.From) - require.NoError(t, err) - - // Check the fee Amount - srcFee, err := state.Chains[src].Router.GetFee(nil, dest, ccipMessage) - require.NoError(t, err) - - seqNum := changeset.TestSendRequest(t, e, state, src, dest, false, ccipMessage).SequenceNumber - expectedSeqNum[sourceDestPair] = seqNum - - // Check the fee token balance after the request and ensure fee tokens were spent - feeTokenBalanceAfter, err := linkToken.BalanceOf(nil, e.Chains[tenv.HomeChainSel].DeployerKey.From) - require.NoError(t, err) - require.Equal(t, feeTokenBalanceAfter, new(big.Int).Sub(feeTokenBalanceBefore, srcFee)) - - // Wait for all commit reports to land. - changeset.ConfirmCommitForAllWithExpectedSeqNums(t, e, state, expectedSeqNum, startBlocks) - - // After commit is reported on all chains, token prices should be updated in FeeQuoter. - linkAddress := state.Chains[dest].LinkToken.Address() - feeQuoter := state.Chains[dest].FeeQuoter - timestampedPrice, err := feeQuoter.GetTokenPrice(nil, linkAddress) - require.NoError(t, err) - require.Equal(t, changeset.MockLinkPrice, timestampedPrice.Value) - - // Wait for all exec reports to land - changeset.ConfirmExecWithSeqNrForAll(t, e, state, expectedSeqNum, startBlocks) - - // Delete from the expcted seq num the chain that was just tested so that we don't pass it to the - // commit report in the next test - delete(expectedSeqNum, sourceDestPair) - }) - - t.Run("Send message Pay with native remote chain -> home", func(t *testing.T) { - // Assign Src to the Home Chain Selector and destChain to the Feed Chain Selector - src := tenv.FeedChainSel - dest, destChain := tenv.HomeChainSel, e.Chains[tenv.HomeChainSel] - - sourceDestPair := changeset.SourceDestPair{ - SourceChainSelector: src, - DestChainSelector: dest, - } - - // get the header for the destination chain and the relevant block number - latesthdr, err := destChain.Client.HeaderByNumber(testcontext.Get(t), nil) - require.NoError(t, err) - block := latesthdr.Number.Uint64() - startBlocks[dest] = &block - - // Send to the receiver on the destination chain paying with native token - var ( - receiver = common.LeftPadBytes(state.Chains[dest].Receiver.Address().Bytes(), 32) - data = []byte("hello world") - feeToken = common.HexToAddress("0x0") - ) - - ccipMessage := router.ClientEVM2AnyMessage{ - Receiver: receiver, - Data: data, - TokenAmounts: emptyTokenArray, - FeeToken: feeToken, - ExtraArgs: nil, - } - - seqNum := changeset.TestSendRequest(t, e, state, src, dest, false, ccipMessage).SequenceNumber - expectedSeqNum[sourceDestPair] = seqNum - - // Wait for all commit reports to land. - changeset.ConfirmCommitForAllWithExpectedSeqNums(t, e, state, expectedSeqNum, startBlocks) - - // After commit is reported on all chains, token prices should be updated in FeeQuoter. - linkAddress := state.Chains[dest].LinkToken.Address() - feeQuoter := state.Chains[dest].FeeQuoter - timestampedPrice, err := feeQuoter.GetTokenPrice(nil, linkAddress) - require.NoError(t, err) - require.Equal(t, changeset.MockLinkPrice, timestampedPrice.Value) - - // Wait for all exec reports to land - changeset.ConfirmExecWithSeqNrForAll(t, e, state, expectedSeqNum, startBlocks) - - delete(expectedSeqNum, sourceDestPair) - }) - - t.Run("Send message pay with wrapped native home chain -> remote", func(t *testing.T) { - // Assign Src to the Home Chain Selector and destChain to the Feed Chain Selector - src := tenv.HomeChainSel - dest, destChain := tenv.FeedChainSel, e.Chains[tenv.FeedChainSel] - - sourceDestPair := changeset.SourceDestPair{ - SourceChainSelector: src, - DestChainSelector: dest, - } - - WETH := state.Chains[src].Weth9 - - wrappedNative, err := state.Chains[src].Router.GetWrappedNative(nil) - require.NoError(t, err) - require.Equal(t, WETH.Address(), wrappedNative) - - // We need to acquire some WETH to send with the tx so we deposit some ETH into the WETH contract - // but deployerKey is a reference so we need to dereference it and then reassign it - depositOps := *e.Chains[tenv.HomeChainSel].DeployerKey - depositOps.Value = new(big.Int).Mul(twoCoins, big.NewInt(40)) - tx, err := WETH.Deposit(&depositOps) - require.NoError(t, err) - _, err = e.Chains[tenv.HomeChainSel].Confirm(tx) - require.NoError(t, err) - - // Approve to spend 100 WETH token as feeToken - tx, err = WETH.Approve(e.Chains[tenv.HomeChainSel].DeployerKey, state.Chains[src].Router.Address(), new(big.Int).Mul(twoCoins, big.NewInt(50))) - require.NoError(t, err) - _, err = e.Chains[tenv.HomeChainSel].Confirm(tx) - require.NoError(t, err) - - allowance, err := WETH.Allowance(nil, e.Chains[src].DeployerKey.From, state.Chains[src].Router.Address()) - require.NoError(t, err) - require.GreaterOrEqual(t, allowance.Int64(), twoCoins.Int64()) - - // get the header for the destination chain and the relevant block number - latesthdr, err := destChain.Client.HeaderByNumber(testcontext.Get(t), nil) - require.NoError(t, err) - block := latesthdr.Number.Uint64() - startBlocks[dest] = &block - - // Send to the receiver on the destination chain paying with LINK token - var ( - receiver = common.LeftPadBytes(state.Chains[dest].Receiver.Address().Bytes(), 32) - data = []byte("hello world") - feeToken = state.Chains[src].Weth9.Address() - ) - - ccipMessage := router.ClientEVM2AnyMessage{ - Receiver: receiver, - Data: data, - TokenAmounts: emptyTokenArray, - FeeToken: feeToken, - ExtraArgs: nil, - } - - // Get the fee Token Balance Before - feeTokenBalanceBefore, err := WETH.BalanceOf(nil, e.Chains[src].DeployerKey.From) - require.NoError(t, err) - - // Check the fee Amount - srcFee, err := state.Chains[src].Router.GetFee(nil, dest, ccipMessage) - require.NoError(t, err) - - // Check that we have enough WETH to pay the fee - require.GreaterOrEqual(t, feeTokenBalanceBefore.Int64(), srcFee.Int64()) - - seqNum := changeset.TestSendRequest(t, e, state, src, dest, false, ccipMessage).SequenceNumber - expectedSeqNum[sourceDestPair] = seqNum - - // Check the fee token balance after the request and ensure fee tokens were spent - feeTokenBalanceAfter, err := WETH.BalanceOf(nil, e.Chains[tenv.HomeChainSel].DeployerKey.From) - require.NoError(t, err) - require.Equal(t, feeTokenBalanceAfter, new(big.Int).Sub(feeTokenBalanceBefore, srcFee)) - - // Wait for all commit reports to land. - changeset.ConfirmCommitForAllWithExpectedSeqNums(t, e, state, expectedSeqNum, startBlocks) - - // After commit is reported on all chains, token prices should be updated in FeeQuoter. - linkAddress := state.Chains[dest].LinkToken.Address() - feeQuoter := state.Chains[dest].FeeQuoter - timestampedPrice, err := feeQuoter.GetTokenPrice(nil, linkAddress) - require.NoError(t, err) - require.Equal(t, changeset.MockLinkPrice, timestampedPrice.Value) - - // Wait for all exec reports to land - changeset.ConfirmExecWithSeqNrForAll(t, e, state, expectedSeqNum, startBlocks) - }) - - t.Run("Send programmable token transfer", func(t *testing.T) { - - }) -} From ad9aea9049a1711d54d28378eab9b4a254158638 Mon Sep 17 00:00:00 2001 From: Josh Date: Mon, 25 Nov 2024 12:18:48 -0500 Subject: [PATCH 12/18] message and programmable token transfer e2e tests --- integration-tests/smoke/ccip/ccip_test.go | 377 ++++++++++++++++++++++ 1 file changed, 377 insertions(+) diff --git a/integration-tests/smoke/ccip/ccip_test.go b/integration-tests/smoke/ccip/ccip_test.go index a269fa01755..343c9331f9f 100644 --- a/integration-tests/smoke/ccip/ccip_test.go +++ b/integration-tests/smoke/ccip/ccip_test.go @@ -625,3 +625,380 @@ func Test_PricingForTokenTransfers(t *testing.T) { }) } + +func Test_PricingForMessages(t *testing.T) { + t.Parallel() + lggr := logger.TestLogger(t) + // ctx := changeset.Context(t) + tenv, _, _ := testsetups.NewLocalDevEnvironmentWithDefaultPrice(t, lggr, nil) + e := tenv.Env + + // feeds := state.Chains[tenv.FeedChainSel].USDFeeds + output, err := changeset.DeployPrerequisites(tenv.Env, changeset.DeployPrerequisiteConfig{ + ChainSelectors: tenv.Env.AllChainSelectors(), + }) + require.NoError(t, err) + require.NoError(t, tenv.Env.ExistingAddresses.Merge(output.AddressBook)) + + expectedSeqNum := make(map[changeset.SourceDestPair]uint64) + expectedSeqNumExec := make(map[changeset.SourceDestPair][]uint64) + + require.NoError(t, err) + require.NoError(t, tenv.Env.ExistingAddresses.Merge(output.AddressBook)) + // Get new state after migration. + state, err := changeset.LoadOnchainState(e) + require.NoError(t, err) + + srcToken, dstToken := setupTokens(t, tenv) + + // Ensure capreg logs are up to date. + changeset.ReplayLogs(t, e.Offchain, tenv.ReplayBlocks) + + // Add all lanes + require.NoError(t, changeset.AddLanesForAll(e, state)) + // Need to keep track of the block number for each chain so that event subscription can be done from that block. + startBlocks := make(map[uint64]*uint64) + // Send a message from each chain to every other chain. + + // Mint 2 tokens to be transferred + twoCoins := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(2)) + + linkToken := state.Chains[tenv.HomeChainSel].LinkToken + maxUint256 := math.MaxBig256 + + emptyTokenArray := make([]router.ClientEVMTokenAmount, 0) + + // Create two ClientEVMTokenAmount structs to be passed to the router + tokens := map[uint64][]router.ClientEVMTokenAmount{ + tenv.HomeChainSel: {{ + Token: srcToken.Address(), + Amount: twoCoins, + }}, + tenv.FeedChainSel: {{ + Token: dstToken.Address(), + Amount: twoCoins, + }}, + } + + t.Run("Send message Pay with Link token home chain -> remote", func(t *testing.T) { + src := tenv.HomeChainSel + dest, destChain := tenv.FeedChainSel, e.Chains[tenv.FeedChainSel] + + sourceDestPair := changeset.SourceDestPair{ + SourceChainSelector: src, + DestChainSelector: dest, + } + + // Approve to spend link token + tx, err := linkToken.Approve(e.Chains[src].DeployerKey, state.Chains[src].Router.Address(), maxUint256) + require.NoError(t, err) + _, err = e.Chains[src].Confirm(tx) + require.NoError(t, err) + + // Get the fee Token Balance Before + srctokenBalance, err := srcToken.BalanceOf(nil, e.Chains[src].DeployerKey.From) + require.NoError(t, err) + require.GreaterOrEqual(t, srctokenBalance.Int64(), twoCoins.Int64()) + + // Assign Src to the Home Chain Selector and destChain to the Feed Chain Selector + + // get the header for the destination chain and the relevant block number + latesthdr, err := destChain.Client.HeaderByNumber(testcontext.Get(t), nil) + require.NoError(t, err) + block := latesthdr.Number.Uint64() + startBlocks[dest] = &block + + // Send to the receiver on the destination chain paying with LINK token + var ( + receiver = common.LeftPadBytes(state.Chains[dest].Receiver.Address().Bytes(), 32) + data = []byte("hello world") + feeToken = linkToken.Address() + ) + + ccipMessage := router.ClientEVM2AnyMessage{ + Receiver: receiver, + Data: data, + TokenAmounts: tokens[src], + FeeToken: feeToken, + ExtraArgs: nil, + } + + // Get the fee Token Balance Before + feeTokenBalanceBefore, err := linkToken.BalanceOf(nil, e.Chains[src].DeployerKey.From) + require.NoError(t, err) + + // Check the fee Amount + srcFee, err := state.Chains[src].Router.GetFee(nil, dest, ccipMessage) + require.NoError(t, err) + + msgSentEvent := changeset.TestSendRequest(t, e, state, src, dest, false, ccipMessage) + + expectedSeqNum[changeset.SourceDestPair{ + SourceChainSelector: src, + DestChainSelector: dest, + }] = msgSentEvent.SequenceNumber + expectedSeqNumExec[changeset.SourceDestPair{ + SourceChainSelector: src, + DestChainSelector: dest, + }] = []uint64{msgSentEvent.SequenceNumber} + + // Check the fee token balance after the request and ensure fee tokens were spent + feeTokenBalanceAfter, err := linkToken.BalanceOf(nil, e.Chains[tenv.HomeChainSel].DeployerKey.From) + require.NoError(t, err) + require.Equal(t, feeTokenBalanceAfter, new(big.Int).Sub(feeTokenBalanceBefore, srcFee)) + + // Wait for all commit reports to land. + changeset.ConfirmCommitForAllWithExpectedSeqNums(t, e, state, expectedSeqNum, startBlocks) + + // After commit is reported on all chains, token prices should be updated in FeeQuoter. + linkAddress := state.Chains[dest].LinkToken.Address() + feeQuoter := state.Chains[dest].FeeQuoter + timestampedPrice, err := feeQuoter.GetTokenPrice(nil, linkAddress) + require.NoError(t, err) + require.Equal(t, changeset.MockLinkPrice, timestampedPrice.Value) + + // Wait for all exec reports to land + changeset.ConfirmExecWithSeqNrsForAll(t, e, state, expectedSeqNumExec, startBlocks) + + balance, err := dstToken.BalanceOf(nil, state.Chains[tenv.FeedChainSel].Receiver.Address()) + require.NoError(t, err) + require.Equal(t, twoCoins, balance) + + // Delete from the expcted seq num the chain that was just tested so that we don't pass it to the + // commit report in the next test + delete(expectedSeqNum, sourceDestPair) + }) + + t.Run("Send message Pay with native remote chain -> home", func(t *testing.T) { + // Assign Src to the Home Chain Selector and destChain to the Feed Chain Selector + src := tenv.FeedChainSel + dest, destChain := tenv.HomeChainSel, e.Chains[tenv.HomeChainSel] + + sourceDestPair := changeset.SourceDestPair{ + SourceChainSelector: src, + DestChainSelector: dest, + } + + // get the header for the destination chain and the relevant block number + latesthdr, err := destChain.Client.HeaderByNumber(testcontext.Get(t), nil) + require.NoError(t, err) + block := latesthdr.Number.Uint64() + startBlocks[dest] = &block + + // Send to the receiver on the destination chain paying with native token + var ( + receiver = common.LeftPadBytes(state.Chains[dest].Receiver.Address().Bytes(), 32) + data = []byte("hello world") + feeToken = common.HexToAddress("0x0") + ) + + ccipMessage := router.ClientEVM2AnyMessage{ + Receiver: receiver, + Data: data, + TokenAmounts: emptyTokenArray, + FeeToken: feeToken, + ExtraArgs: nil, + } + + msgSentEvent := changeset.TestSendRequest(t, e, state, src, dest, false, ccipMessage) + expectedSeqNum[changeset.SourceDestPair{ + SourceChainSelector: src, + DestChainSelector: dest, + }] = msgSentEvent.SequenceNumber + expectedSeqNumExec[changeset.SourceDestPair{ + SourceChainSelector: src, + DestChainSelector: dest, + }] = []uint64{msgSentEvent.SequenceNumber} + + // Wait for all commit reports to land. + changeset.ConfirmCommitForAllWithExpectedSeqNums(t, e, state, expectedSeqNum, startBlocks) + + // After commit is reported on all chains, token prices should be updated in FeeQuoter. + linkAddress := state.Chains[dest].LinkToken.Address() + feeQuoter := state.Chains[dest].FeeQuoter + timestampedPrice, err := feeQuoter.GetTokenPrice(nil, linkAddress) + require.NoError(t, err) + require.Equal(t, changeset.MockLinkPrice, timestampedPrice.Value) + + // Wait for all exec reports to land + changeset.ConfirmExecWithSeqNrsForAll(t, e, state, expectedSeqNumExec, startBlocks) + + delete(expectedSeqNum, sourceDestPair) + }) + + t.Run("Send message pay with wrapped native home chain -> remote", func(t *testing.T) { + // Assign Src to the Home Chain Selector and destChain to the Feed Chain Selector + src := tenv.HomeChainSel + dest, destChain := tenv.FeedChainSel, e.Chains[tenv.FeedChainSel] + + WETH := state.Chains[src].Weth9 + + // Approve to spend WETH token as feeToken + tx, err := WETH.Approve(e.Chains[tenv.HomeChainSel].DeployerKey, state.Chains[tenv.HomeChainSel].Router.Address(), maxUint256) + require.NoError(t, err) + _, err = e.Chains[tenv.HomeChainSel].Confirm(tx) + require.NoError(t, err) + + srcTokenBal, err := srcToken.BalanceOf(nil, e.Chains[src].DeployerKey.From) + require.NoError(t, err) + require.GreaterOrEqual(t, srcTokenBal.Int64(), twoCoins.Int64()) + + // get the header for the destination chain and the relevant block number + latesthdr, err := destChain.Client.HeaderByNumber(testcontext.Get(t), nil) + require.NoError(t, err) + block := latesthdr.Number.Uint64() + startBlocks[dest] = &block + + // Send to the receiver on the destination chain paying with LINK token + var ( + receiver = common.LeftPadBytes(state.Chains[dest].Receiver.Address().Bytes(), 32) + data = []byte("hello world") + feeToken = state.Chains[src].Weth9.Address() + ) + + ccipMessage := router.ClientEVM2AnyMessage{ + Receiver: receiver, + Data: data, + TokenAmounts: tokens[src], + FeeToken: feeToken, + ExtraArgs: nil, + } + + srcFee, err := state.Chains[src].Router.GetFee(nil, dest, ccipMessage) + require.NoError(t, err) + + // We need to acquire some WETH to send with the tx so we deposit some ETH into the WETH contract + // but deployerKey is a reference so we need to dereference it and then reassign it + // Also the fees have been unusually high so we need to deposit more than usual to ensure the test doesn't fail + depositOps := *e.Chains[tenv.HomeChainSel].DeployerKey + depositOps.Value = srcFee + tx, err = WETH.Deposit(&depositOps) + require.NoError(t, err) + _, err = e.Chains[tenv.HomeChainSel].Confirm(tx) + require.NoError(t, err) + + // Get the fee Token Balance Before + feeTokenBalanceBefore, err := WETH.BalanceOf(nil, e.Chains[src].DeployerKey.From) + require.NoError(t, err) + + msgSentEvent := changeset.TestSendRequest(t, e, state, src, dest, false, ccipMessage) + expectedSeqNum[changeset.SourceDestPair{ + SourceChainSelector: src, + DestChainSelector: dest, + }] = msgSentEvent.SequenceNumber + expectedSeqNumExec[changeset.SourceDestPair{ + SourceChainSelector: src, + DestChainSelector: dest, + }] = []uint64{msgSentEvent.SequenceNumber} + + // Check the fee token balance after the request and ensure fee tokens were spent + feeTokenBalanceAfter, err := WETH.BalanceOf(nil, e.Chains[tenv.HomeChainSel].DeployerKey.From) + require.NoError(t, err) + require.Equal(t, feeTokenBalanceAfter, new(big.Int).Sub(feeTokenBalanceBefore, srcFee)) + + // Wait for all commit reports to land. + changeset.ConfirmCommitForAllWithExpectedSeqNums(t, e, state, expectedSeqNum, startBlocks) + + // After commit is reported on all chains, token prices should be updated in FeeQuoter. + linkAddress := state.Chains[dest].LinkToken.Address() + feeQuoter := state.Chains[dest].FeeQuoter + timestampedPrice, err := feeQuoter.GetTokenPrice(nil, linkAddress) + require.NoError(t, err) + require.Equal(t, changeset.MockLinkPrice, timestampedPrice.Value) + + // Wait for all exec reports to land + changeset.ConfirmExecWithSeqNrsForAll(t, e, state, expectedSeqNumExec, startBlocks) + + balance, err := dstToken.BalanceOf(nil, state.Chains[dest].Receiver.Address()) + require.NoError(t, err) + + // The balance should be 4 since we've already sent 2 tokens over this lane direction in the + // first part of the test, so balance should already be two + require.Equal(t, new(big.Int).Mul(twoCoins, big.NewInt(2)), balance) + }) + t.Run("Send Programmable Token Transfers paying in link", func(t *testing.T) { + src := tenv.HomeChainSel + dest, destChain := tenv.FeedChainSel, e.Chains[tenv.FeedChainSel] + + // Approve to spend link token + tx, err := linkToken.Approve(e.Chains[src].DeployerKey, state.Chains[src].Router.Address(), maxUint256) + require.NoError(t, err) + _, err = e.Chains[src].Confirm(tx) + require.NoError(t, err) + + // Get the fee Token Balance Before + srctokenBalance, err := srcToken.BalanceOf(nil, e.Chains[src].DeployerKey.From) + require.NoError(t, err) + require.GreaterOrEqual(t, srctokenBalance.Int64(), twoCoins.Int64()) + + // Assign Src to the Home Chain Selector and destChain to the Feed Chain Selector + + // get the header for the destination chain and the relevant block number + latesthdr, err := destChain.Client.HeaderByNumber(testcontext.Get(t), nil) + require.NoError(t, err) + block := latesthdr.Number.Uint64() + startBlocks[dest] = &block + + // Send to the receiver on the destination chain paying with LINK token + var ( + receiver = common.LeftPadBytes(state.Chains[dest].Receiver.Address().Bytes(), 32) + data = []byte("hello world") + feeToken = linkToken.Address() + ) + + ccipMessage := router.ClientEVM2AnyMessage{ + Receiver: receiver, + Data: data, + TokenAmounts: tokens[src], + FeeToken: feeToken, + ExtraArgs: nil, + } + + // Get the fee Token Balance Before + feeTokenBalanceBefore, err := linkToken.BalanceOf(nil, e.Chains[src].DeployerKey.From) + require.NoError(t, err) + + // Check the fee Amount + srcFee, err := state.Chains[src].Router.GetFee(nil, dest, ccipMessage) + require.NoError(t, err) + + msgSentEvent := changeset.TestSendRequest(t, e, state, src, dest, false, ccipMessage) + + expectedSeqNum[changeset.SourceDestPair{ + SourceChainSelector: src, + DestChainSelector: dest, + }] = msgSentEvent.SequenceNumber + expectedSeqNumExec[changeset.SourceDestPair{ + SourceChainSelector: src, + DestChainSelector: dest, + }] = []uint64{msgSentEvent.SequenceNumber} + + // Check the fee token balance after the request and ensure fee tokens were spent + feeTokenBalanceAfter, err := linkToken.BalanceOf(nil, e.Chains[tenv.HomeChainSel].DeployerKey.From) + require.NoError(t, err) + require.Equal(t, feeTokenBalanceAfter, new(big.Int).Sub(feeTokenBalanceBefore, srcFee)) + + balanceBefore, err := dstToken.BalanceOf(nil, state.Chains[tenv.FeedChainSel].Receiver.Address()) + require.NoError(t, err) + + // Wait for all commit reports to land. + changeset.ConfirmCommitForAllWithExpectedSeqNums(t, e, state, expectedSeqNum, startBlocks) + + // After commit is reported on all chains, token prices should be updated in FeeQuoter. + linkAddress := state.Chains[dest].LinkToken.Address() + feeQuoter := state.Chains[dest].FeeQuoter + timestampedPrice, err := feeQuoter.GetTokenPrice(nil, linkAddress) + require.NoError(t, err) + require.Equal(t, changeset.MockLinkPrice, timestampedPrice.Value) + + // Wait for all exec reports to land + changeset.ConfirmExecWithSeqNrsForAll(t, e, state, expectedSeqNumExec, startBlocks) + + balanceAfter, err := dstToken.BalanceOf(nil, state.Chains[tenv.FeedChainSel].Receiver.Address()) + require.NoError(t, err) + require.Equal(t, new(big.Int).Add(balanceBefore, twoCoins), balanceAfter) + + // Delete from the expcted seq num the chain that was just tested so that we don't pass it to the + }) + +} From 4c62b51c2d4f6541a293135c4e893d173111b5d2 Mon Sep 17 00:00:00 2001 From: Josh Date: Mon, 25 Nov 2024 14:36:09 -0500 Subject: [PATCH 13/18] bump smoke test timeout parameter --- .github/e2e-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/e2e-tests.yml b/.github/e2e-tests.yml index 79bdae33a89..3679c03a47f 100644 --- a/.github/e2e-tests.yml +++ b/.github/e2e-tests.yml @@ -942,7 +942,7 @@ runner-test-matrix: triggers: - PR E2E Core Tests - Nightly E2E Tests - test_cmd: cd integration-tests/smoke/ccip && go test ccip_test.go -timeout 12m -test.parallel=2 -count=1 -json + test_cmd: cd integration-tests/smoke/ccip && go test ccip_test.go -timeout 17m -test.parallel=2 -count=1 -json pyroscope_env: ci-smoke-ccipv1_6-evm-simulated test_env_vars: E2E_TEST_SELECTED_NETWORK: SIMULATED_1,SIMULATED_2 From 2cd35a785800b2d96ce0f43ec1682e7e9438242d Mon Sep 17 00:00:00 2001 From: Josh Date: Mon, 25 Nov 2024 15:03:28 -0500 Subject: [PATCH 14/18] bump time again --- .github/e2e-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/e2e-tests.yml b/.github/e2e-tests.yml index 3679c03a47f..4666c43623d 100644 --- a/.github/e2e-tests.yml +++ b/.github/e2e-tests.yml @@ -942,7 +942,7 @@ runner-test-matrix: triggers: - PR E2E Core Tests - Nightly E2E Tests - test_cmd: cd integration-tests/smoke/ccip && go test ccip_test.go -timeout 17m -test.parallel=2 -count=1 -json + test_cmd: cd integration-tests/smoke/ccip && go test ccip_test.go -timeout 25m -test.parallel=2 -count=1 -json pyroscope_env: ci-smoke-ccipv1_6-evm-simulated test_env_vars: E2E_TEST_SELECTED_NETWORK: SIMULATED_1,SIMULATED_2 From 73d5dfe0c6304452cb876df9103860b37e76c639 Mon Sep 17 00:00:00 2001 From: Makram Kamaleddine Date: Thu, 28 Nov 2024 16:50:04 +0400 Subject: [PATCH 15/18] fix flakey assertion use the fee token paid from the event rather than the call before the request is made --- integration-tests/smoke/ccip/ccip_test.go | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/integration-tests/smoke/ccip/ccip_test.go b/integration-tests/smoke/ccip/ccip_test.go index 725eca7a604..8ee498da101 100644 --- a/integration-tests/smoke/ccip/ccip_test.go +++ b/integration-tests/smoke/ccip/ccip_test.go @@ -391,10 +391,6 @@ func Test_PricingForTokenTransfers(t *testing.T) { feeTokenBalanceBefore, err := linkToken.BalanceOf(nil, e.Chains[src].DeployerKey.From) require.NoError(t, err) - // Check the fee Amount - srcFee, err := state.Chains[src].Router.GetFee(nil, dest, ccipMessage) - require.NoError(t, err) - msgSentEvent := changeset.TestSendRequest(t, e, state, src, dest, false, ccipMessage) expectedSeqNum[changeset.SourceDestPair{ @@ -409,7 +405,7 @@ func Test_PricingForTokenTransfers(t *testing.T) { // Check the fee token balance after the request and ensure fee tokens were spent feeTokenBalanceAfter, err := linkToken.BalanceOf(nil, e.Chains[tenv.HomeChainSel].DeployerKey.From) require.NoError(t, err) - require.Equal(t, feeTokenBalanceAfter, new(big.Int).Sub(feeTokenBalanceBefore, srcFee)) + require.Equal(t, feeTokenBalanceAfter, new(big.Int).Sub(feeTokenBalanceBefore, msgSentEvent.Message.FeeTokenAmount)) // Wait for all commit reports to land. changeset.ConfirmCommitForAllWithExpectedSeqNums(t, e, state, expectedSeqNum, startBlocks) From b7ac67106b9c89d457e0eea3d320dcdb16a7f06a Mon Sep 17 00:00:00 2001 From: Makram Kamaleddine Date: Thu, 28 Nov 2024 20:33:36 +0400 Subject: [PATCH 16/18] refactor, use sim backend --- deployment/address_book.go | 1 + deployment/ccip/changeset/state.go | 40 +- deployment/ccip/changeset/test_helpers.go | 2 +- integration-tests/smoke/ccip/ccip_test.go | 1005 +++++++-------------- 4 files changed, 365 insertions(+), 683 deletions(-) diff --git a/deployment/address_book.go b/deployment/address_book.go index 3125313a841..7997507554f 100644 --- a/deployment/address_book.go +++ b/deployment/address_book.go @@ -27,6 +27,7 @@ var ( Version1_1_0 = *semver.MustParse("1.1.0") Version1_2_0 = *semver.MustParse("1.2.0") Version1_5_0 = *semver.MustParse("1.5.0") + Version1_5_1 = *semver.MustParse("1.5.1") Version1_6_0_dev = *semver.MustParse("1.6.0-dev") ) diff --git a/deployment/ccip/changeset/state.go b/deployment/ccip/changeset/state.go index 61b58b59af6..add99386a31 100644 --- a/deployment/ccip/changeset/state.go +++ b/deployment/ccip/changeset/state.go @@ -3,6 +3,9 @@ package changeset import ( "fmt" + burn_mint_token_pool "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/burn_mint_token_pool_1_4_0" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/shared/generated/erc20" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/mock_usdc_token_messenger" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/mock_usdc_token_transmitter" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/usdc_token_pool" @@ -75,7 +78,8 @@ type CCIPChainState struct { // and the respective token contract // This is more of an illustration of how we'll have tokens, and it might need some work later to work properly. // Not all tokens will be burn and mint tokens. - BurnMintTokens677 map[TokenSymbol]*burn_mint_erc677.BurnMintERC677 + BurnMintTokens677 map[TokenSymbol]*burn_mint_erc677.BurnMintERC677 + BurnMintTokenPools map[TokenSymbol]*burn_mint_token_pool.BurnMintTokenPool // Map between token Symbol (e.g. LinkSymbol, WethSymbol) // and the respective aggregator USD feed contract USDFeeds map[TokenSymbol]*aggregator_v3_interface.AggregatorV3Interface @@ -438,6 +442,40 @@ func LoadChainState(chain deployment.Chain, addresses map[string]deployment.Type return state, fmt.Errorf("unknown feed description %s", desc) } state.USDFeeds[key] = feed + case deployment.NewTypeAndVersion(BurnMintTokenPool, deployment.Version1_5_1).String(): + pool, err := burn_mint_token_pool.NewBurnMintTokenPool(common.HexToAddress(address), chain.Client) + if err != nil { + return state, err + } + if state.BurnMintTokenPools == nil { + state.BurnMintTokenPools = make(map[TokenSymbol]*burn_mint_token_pool.BurnMintTokenPool) + } + tokAddress, err := pool.GetToken(nil) + if err != nil { + return state, err + } + tok, err := erc20.NewERC20(tokAddress, chain.Client) + if err != nil { + return state, err + } + symbol, err := tok.Symbol(nil) + if err != nil { + return state, err + } + state.BurnMintTokenPools[TokenSymbol(symbol)] = pool + case deployment.NewTypeAndVersion(BurnMintToken, deployment.Version1_0_0).String(): + tok, err := burn_mint_erc677.NewBurnMintERC677(common.HexToAddress(address), chain.Client) + if err != nil { + return state, err + } + if state.BurnMintTokens677 == nil { + state.BurnMintTokens677 = make(map[TokenSymbol]*burn_mint_erc677.BurnMintERC677) + } + symbol, err := tok.Symbol(nil) + if err != nil { + return state, fmt.Errorf("failed to get token symbol of token at %s: %w", address, err) + } + state.BurnMintTokens677[TokenSymbol(symbol)] = tok default: return state, fmt.Errorf("unknown contract %s", tvStr) } diff --git a/deployment/ccip/changeset/test_helpers.go b/deployment/ccip/changeset/test_helpers.go index a0bd3a0f56d..e948386fb89 100644 --- a/deployment/ccip/changeset/test_helpers.go +++ b/deployment/ccip/changeset/test_helpers.go @@ -1003,7 +1003,7 @@ func deployTransferTokenOneEnd( common.HexToAddress(routerAddress), ) return deployment.ContractDeploy[*burn_mint_token_pool.BurnMintTokenPool]{ - tokenPoolAddress, tokenPoolContract, tx, deployment.NewTypeAndVersion(BurnMintTokenPool, deployment.Version1_0_0), err2, + tokenPoolAddress, tokenPoolContract, tx, deployment.NewTypeAndVersion(BurnMintTokenPool, deployment.Version1_5_1), err2, } }) if err != nil { diff --git a/integration-tests/smoke/ccip/ccip_test.go b/integration-tests/smoke/ccip/ccip_test.go index 8ee498da101..ef8d4095b1f 100644 --- a/integration-tests/smoke/ccip/ccip_test.go +++ b/integration-tests/smoke/ccip/ccip_test.go @@ -4,6 +4,13 @@ import ( "math/big" "testing" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + + "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" + "github.com/smartcontractkit/chainlink/deployment" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/weth9_wrapper" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/math" "github.com/stretchr/testify/require" @@ -211,82 +218,74 @@ func TestTokenTransfer(t *testing.T) { // setupTokens deploys transferable tokens on the source and dest, mints tokens for the source and dest, and // approves the router to spend the tokens -func setupTokens(t *testing.T, tenv changeset.DeployedEnv) (srcToken *burn_mint_erc677.BurnMintERC677, dstToken *burn_mint_erc677.BurnMintERC677) { +func setupTokens( + t *testing.T, + state changeset.CCIPOnChainState, + tenv changeset.DeployedEnv, + src, dest uint64, + transferTokenMintAmount, + feeTokenMintAmount *big.Int, +) ( + srcToken *burn_mint_erc677.BurnMintERC677, + dstToken *burn_mint_erc677.BurnMintERC677, +) { lggr := logger.TestLogger(t) - e := tenv.Env - state, err := changeset.LoadOnchainState(e) - require.NoError(t, err) - - tenCoins := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(10)) // Deploy the token to test transferring - srcToken, _, dstToken, _, err = changeset.DeployTransferableToken( + srcToken, _, dstToken, _, err := changeset.DeployTransferableToken( lggr, tenv.Env.Chains, - tenv.HomeChainSel, - tenv.FeedChainSel, + src, + dest, state, - e.ExistingAddresses, + tenv.Env.ExistingAddresses, "MY_TOKEN", ) - - linkToken := state.Chains[tenv.HomeChainSel].LinkToken - require.NoError(t, err) + linkToken := state.Chains[src].LinkToken + tx, err := srcToken.Mint( - e.Chains[tenv.HomeChainSel].DeployerKey, - e.Chains[tenv.HomeChainSel].DeployerKey.From, - new(big.Int).Mul(tenCoins, big.NewInt(10)), + e.Chains[src].DeployerKey, + e.Chains[src].DeployerKey.From, + transferTokenMintAmount, ) - require.NoError(t, err) - - _, err = e.Chains[tenv.HomeChainSel].Confirm(tx) + _, err = deployment.ConfirmIfNoError(e.Chains[src], tx, err) require.NoError(t, err) // Mint a destination token tx, err = dstToken.Mint( - e.Chains[tenv.FeedChainSel].DeployerKey, - e.Chains[tenv.FeedChainSel].DeployerKey.From, - new(big.Int).Mul(tenCoins, big.NewInt(10)), + e.Chains[dest].DeployerKey, + e.Chains[dest].DeployerKey.From, + transferTokenMintAmount, ) - - // Confirm the mint tx + _, err = deployment.ConfirmIfNoError(e.Chains[dest], tx, err) require.NoError(t, err) - _, err = e.Chains[tenv.FeedChainSel].Confirm(tx) - require.NoError(t, err) - - maxUint256 := math.MaxBig256 // Approve the router to spend the tokens and confirm the tx's // To prevent having to approve the router for every transfer, we approve a sufficiently large amount - tx, err = srcToken.Approve(e.Chains[tenv.HomeChainSel].DeployerKey, state.Chains[tenv.HomeChainSel].Router.Address(), maxUint256) - require.NoError(t, err) - _, err = e.Chains[tenv.HomeChainSel].Confirm(tx) + tx, err = srcToken.Approve(e.Chains[src].DeployerKey, state.Chains[src].Router.Address(), math.MaxBig256) + _, err = deployment.ConfirmIfNoError(e.Chains[src], tx, err) require.NoError(t, err) - tx, err = dstToken.Approve(e.Chains[tenv.FeedChainSel].DeployerKey, state.Chains[tenv.FeedChainSel].Router.Address(), maxUint256) - require.NoError(t, err) - _, err = e.Chains[tenv.FeedChainSel].Confirm(tx) + tx, err = dstToken.Approve(e.Chains[dest].DeployerKey, state.Chains[dest].Router.Address(), math.MaxBig256) + _, err = deployment.ConfirmIfNoError(e.Chains[dest], tx, err) require.NoError(t, err) // Grant mint and burn roles to the deployer key for the newly deployed linkToken // Since those roles are not granted automatically - tx, err = linkToken.GrantMintAndBurnRoles(e.Chains[tenv.HomeChainSel].DeployerKey, e.Chains[tenv.HomeChainSel].DeployerKey.From) - require.NoError(t, err) - _, err = e.Chains[tenv.HomeChainSel].Confirm(tx) + tx, err = linkToken.GrantMintAndBurnRoles(e.Chains[src].DeployerKey, e.Chains[src].DeployerKey.From) + _, err = deployment.ConfirmIfNoError(e.Chains[src], tx, err) require.NoError(t, err) // Mint link token and confirm the tx tx, err = linkToken.Mint( - e.Chains[tenv.HomeChainSel].DeployerKey, - e.Chains[tenv.HomeChainSel].DeployerKey.From, - new(big.Int).Mul(tenCoins, big.NewInt(10)), + e.Chains[src].DeployerKey, + e.Chains[src].DeployerKey.From, + feeTokenMintAmount, ) - require.NoError(t, err) - - _, err = e.Chains[tenv.HomeChainSel].Confirm(tx) + _, err = deployment.ConfirmIfNoError(e.Chains[src], tx, err) require.NoError(t, err) return srcToken, dstToken @@ -294,707 +293,351 @@ func setupTokens(t *testing.T, tenv changeset.DeployedEnv) (srcToken *burn_mint_ func Test_PricingForTokenTransfers(t *testing.T) { t.Parallel() - lggr := logger.TestLogger(t) - // ctx := changeset.Context(t) - tenv, _, _ := testsetups.NewLocalDevEnvironmentWithDefaultPrice(t, lggr, nil) + tenv := changeset.NewMemoryEnvironmentWithJobsAndContracts(t, logger.TestLogger(t), 2, 4, nil) e := tenv.Env - // feeds := state.Chains[tenv.FeedChainSel].USDFeeds - output, err := changeset.DeployPrerequisites(tenv.Env, changeset.DeployPrerequisiteConfig{ - ChainSelectors: tenv.Env.AllChainSelectors(), - }) - require.NoError(t, err) - require.NoError(t, tenv.Env.ExistingAddresses.Merge(output.AddressBook)) - - expectedSeqNum := make(map[changeset.SourceDestPair]uint64) - expectedSeqNumExec := make(map[changeset.SourceDestPair][]uint64) + allChains := tenv.Env.AllChainSelectors() + require.Len(t, allChains, 2, "need two chains for this test") + sourceChain := allChains[0] + destChain := allChains[1] - require.NoError(t, err) - require.NoError(t, tenv.Env.ExistingAddresses.Merge(output.AddressBook)) // Get new state after migration. state, err := changeset.LoadOnchainState(e) require.NoError(t, err) - srcToken, dstToken := setupTokens(t, tenv) + srcToken, dstToken := setupTokens( + t, + state, + tenv, + sourceChain, + destChain, + deployment.E18Mult(10_000), + deployment.E18Mult(10_000), + ) // Ensure capreg logs are up to date. changeset.ReplayLogs(t, e.Offchain, tenv.ReplayBlocks) // Add all lanes require.NoError(t, changeset.AddLanesForAll(e, state)) - // Need to keep track of the block number for each chain so that event subscription can be done from that block. - startBlocks := make(map[uint64]*uint64) - // Send a message from each chain to every other chain. - - // Mint 2 tokens to be transferred - twoCoins := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(2)) - - linkToken := state.Chains[tenv.HomeChainSel].LinkToken - maxUint256 := math.MaxBig256 - - // Create two ClientEVMTokenAmount structs to be passed to the router - tokens := map[uint64][]router.ClientEVMTokenAmount{ - tenv.HomeChainSel: {{ - Token: srcToken.Address(), - Amount: twoCoins, - }}, - tenv.FeedChainSel: {{ - Token: dstToken.Address(), - Amount: twoCoins, - }}, - } - - t.Run("Send Token Pay with Link token home chain -> remote", func(t *testing.T) { - src := tenv.HomeChainSel - dest, destChain := tenv.FeedChainSel, e.Chains[tenv.FeedChainSel] - - sourceDestPair := changeset.SourceDestPair{ - SourceChainSelector: src, - DestChainSelector: dest, - } - - // Approve to spend link token - tx, err := linkToken.Approve(e.Chains[src].DeployerKey, state.Chains[src].Router.Address(), maxUint256) - require.NoError(t, err) - _, err = e.Chains[src].Confirm(tx) - require.NoError(t, err) - - // Get the fee Token Balance Before - srctokenBalance, err := srcToken.BalanceOf(nil, e.Chains[src].DeployerKey.From) - require.NoError(t, err) - require.GreaterOrEqual(t, srctokenBalance.Int64(), twoCoins.Int64()) - - // Assign Src to the Home Chain Selector and destChain to the Feed Chain Selector - - // get the header for the destination chain and the relevant block number - latesthdr, err := destChain.Client.HeaderByNumber(testcontext.Get(t), nil) - require.NoError(t, err) - block := latesthdr.Number.Uint64() - startBlocks[dest] = &block - - // Send to the receiver on the destination chain paying with LINK token - var ( - receiver = common.LeftPadBytes(state.Chains[dest].Receiver.Address().Bytes(), 32) - data = []byte("hello world") - feeToken = linkToken.Address() - ) - - ccipMessage := router.ClientEVM2AnyMessage{ - Receiver: receiver, - Data: data, - TokenAmounts: tokens[src], - FeeToken: feeToken, - ExtraArgs: nil, - } - - // Get the fee Token Balance Before - feeTokenBalanceBefore, err := linkToken.BalanceOf(nil, e.Chains[src].DeployerKey.From) - require.NoError(t, err) - - msgSentEvent := changeset.TestSendRequest(t, e, state, src, dest, false, ccipMessage) - expectedSeqNum[changeset.SourceDestPair{ - SourceChainSelector: src, - DestChainSelector: dest, - }] = msgSentEvent.SequenceNumber - expectedSeqNumExec[changeset.SourceDestPair{ - SourceChainSelector: src, - DestChainSelector: dest, - }] = []uint64{msgSentEvent.SequenceNumber} - - // Check the fee token balance after the request and ensure fee tokens were spent - feeTokenBalanceAfter, err := linkToken.BalanceOf(nil, e.Chains[tenv.HomeChainSel].DeployerKey.From) - require.NoError(t, err) - require.Equal(t, feeTokenBalanceAfter, new(big.Int).Sub(feeTokenBalanceBefore, msgSentEvent.Message.FeeTokenAmount)) - - // Wait for all commit reports to land. - changeset.ConfirmCommitForAllWithExpectedSeqNums(t, e, state, expectedSeqNum, startBlocks) - - // After commit is reported on all chains, token prices should be updated in FeeQuoter. - linkAddress := state.Chains[dest].LinkToken.Address() - feeQuoter := state.Chains[dest].FeeQuoter - timestampedPrice, err := feeQuoter.GetTokenPrice(nil, linkAddress) - require.NoError(t, err) - require.Equal(t, changeset.MockLinkPrice, timestampedPrice.Value) - - // Wait for all exec reports to land - changeset.ConfirmExecWithSeqNrsForAll(t, e, state, expectedSeqNumExec, startBlocks) - - balance, err := dstToken.BalanceOf(nil, state.Chains[tenv.FeedChainSel].Receiver.Address()) - require.NoError(t, err) - require.Equal(t, twoCoins, balance) - - // Delete from the expcted seq num the chain that was just tested so that we don't pass it to the - // commit report in the next test - delete(expectedSeqNum, sourceDestPair) + t.Run("Send programmable token transfer pay with Link token", func(t *testing.T) { + runFeeTokenTestCase(feeTokenTestCase{ + t: t, + dst: destChain, + src: sourceChain, + env: tenv, + tokenAmounts: []router.ClientEVMTokenAmount{ + { + Token: srcToken.Address(), + Amount: deployment.E18Mult(2), + }, + }, + feeToken: state.Chains[sourceChain].LinkToken.Address(), + data: []byte("hello ptt world"), + receiver: common.LeftPadBytes(state.Chains[destChain].Receiver.Address().Bytes(), 32), + srcToken: srcToken, + dstToken: dstToken, + assertTokenBalance: true, + }) }) - t.Run("Send Token Pay with native remote chain -> home", func(t *testing.T) { - // Assign Src to the Home Chain Selector and destChain to the Feed Chain Selector - src := tenv.FeedChainSel - dest, destChain := tenv.HomeChainSel, e.Chains[tenv.HomeChainSel] - - sourceDestPair := changeset.SourceDestPair{ - SourceChainSelector: src, - DestChainSelector: dest, - } - - // get the header for the destination chain and the relevant block number - latesthdr, err := destChain.Client.HeaderByNumber(testcontext.Get(t), nil) - require.NoError(t, err) - block := latesthdr.Number.Uint64() - startBlocks[dest] = &block - - // Send to the receiver on the destination chain paying with native token - var ( - receiver = common.LeftPadBytes(state.Chains[dest].Receiver.Address().Bytes(), 32) - data = []byte("") - feeToken = common.HexToAddress("0x0") - ) - - ccipMessage := router.ClientEVM2AnyMessage{ - Receiver: receiver, - Data: data, - TokenAmounts: tokens[src], - FeeToken: feeToken, - ExtraArgs: nil, - } - - msgSentEvent := changeset.TestSendRequest(t, e, state, src, dest, false, ccipMessage) - expectedSeqNum[changeset.SourceDestPair{ - SourceChainSelector: src, - DestChainSelector: dest, - }] = msgSentEvent.SequenceNumber - expectedSeqNumExec[changeset.SourceDestPair{ - SourceChainSelector: src, - DestChainSelector: dest, - }] = []uint64{msgSentEvent.SequenceNumber} - - // Wait for all commit reports to land. - changeset.ConfirmCommitForAllWithExpectedSeqNums(t, e, state, expectedSeqNum, startBlocks) - - // After commit is reported on all chains, token prices should be updated in FeeQuoter. - linkAddress := state.Chains[dest].LinkToken.Address() - feeQuoter := state.Chains[dest].FeeQuoter - timestampedPrice, err := feeQuoter.GetTokenPrice(nil, linkAddress) - require.NoError(t, err) - require.Equal(t, changeset.MockLinkPrice, timestampedPrice.Value) - - // Wait for all exec reports to land - changeset.ConfirmExecWithSeqNrsForAll(t, e, state, expectedSeqNumExec, startBlocks) - - balance, err := srcToken.BalanceOf(nil, state.Chains[tenv.HomeChainSel].Receiver.Address()) - require.NoError(t, err) - require.Equal(t, twoCoins, balance) - - delete(expectedSeqNum, sourceDestPair) + t.Run("Send programmable token transfer pay with native", func(t *testing.T) { + runFeeTokenTestCase(feeTokenTestCase{ + t: t, + + // note the order of src and dest is reversed here + src: destChain, + dst: sourceChain, + + env: tenv, + tokenAmounts: []router.ClientEVMTokenAmount{ + { + Token: dstToken.Address(), + Amount: deployment.E18Mult(2), + }, + }, + feeToken: common.HexToAddress("0x0"), + data: []byte("hello ptt world"), + receiver: common.LeftPadBytes(state.Chains[sourceChain].Receiver.Address().Bytes(), 32), + + // note the order of src and dest is reversed here + srcToken: dstToken, + dstToken: srcToken, + assertTokenBalance: true, + }) }) - t.Run("Send Token pay with wrapped native home chain -> remote", func(t *testing.T) { - // Assign Src to the Home Chain Selector and destChain to the Feed Chain Selector - src := tenv.HomeChainSel - dest, destChain := tenv.FeedChainSel, e.Chains[tenv.FeedChainSel] - - WETH := state.Chains[src].Weth9 - - // Approve to spend WETH token as feeToken - tx, err := WETH.Approve(e.Chains[tenv.HomeChainSel].DeployerKey, state.Chains[tenv.HomeChainSel].Router.Address(), maxUint256) - require.NoError(t, err) - _, err = e.Chains[tenv.HomeChainSel].Confirm(tx) - require.NoError(t, err) - - srcTokenBal, err := srcToken.BalanceOf(nil, e.Chains[src].DeployerKey.From) - require.NoError(t, err) - require.GreaterOrEqual(t, srcTokenBal.Int64(), twoCoins.Int64()) - - // get the header for the destination chain and the relevant block number - latesthdr, err := destChain.Client.HeaderByNumber(testcontext.Get(t), nil) - require.NoError(t, err) - block := latesthdr.Number.Uint64() - startBlocks[dest] = &block - - // Send to the receiver on the destination chain paying with LINK token - var ( - receiver = common.LeftPadBytes(state.Chains[dest].Receiver.Address().Bytes(), 32) - data = []byte("") - feeToken = state.Chains[src].Weth9.Address() - ) - - ccipMessage := router.ClientEVM2AnyMessage{ - Receiver: receiver, - Data: data, - TokenAmounts: tokens[src], - FeeToken: feeToken, - ExtraArgs: nil, - } - - srcFee, err := state.Chains[src].Router.GetFee(nil, dest, ccipMessage) - require.NoError(t, err) - - // We need to acquire some WETH to send with the tx so we deposit some ETH into the WETH contract - // but deployerKey is a reference so we need to dereference it and then reassign it - // Also the fees have been unusually high so we need to deposit more than usual to ensure the test doesn't fail - depositOps := *e.Chains[tenv.HomeChainSel].DeployerKey - depositOps.Value = srcFee - tx, err = WETH.Deposit(&depositOps) - require.NoError(t, err) - _, err = e.Chains[tenv.HomeChainSel].Confirm(tx) - require.NoError(t, err) - - // Get the fee Token Balance Before - feeTokenBalanceBefore, err := WETH.BalanceOf(nil, e.Chains[src].DeployerKey.From) - require.NoError(t, err) - - msgSentEvent := changeset.TestSendRequest(t, e, state, src, dest, false, ccipMessage) - expectedSeqNum[changeset.SourceDestPair{ - SourceChainSelector: src, - DestChainSelector: dest, - }] = msgSentEvent.SequenceNumber - expectedSeqNumExec[changeset.SourceDestPair{ - SourceChainSelector: src, - DestChainSelector: dest, - }] = []uint64{msgSentEvent.SequenceNumber} - - // Check the fee token balance after the request and ensure fee tokens were spent - feeTokenBalanceAfter, err := WETH.BalanceOf(nil, e.Chains[tenv.HomeChainSel].DeployerKey.From) - require.NoError(t, err) - require.Equal(t, feeTokenBalanceAfter, new(big.Int).Sub(feeTokenBalanceBefore, srcFee)) - - // Wait for all commit reports to land. - changeset.ConfirmCommitForAllWithExpectedSeqNums(t, e, state, expectedSeqNum, startBlocks) - - // After commit is reported on all chains, token prices should be updated in FeeQuoter. - linkAddress := state.Chains[dest].LinkToken.Address() - feeQuoter := state.Chains[dest].FeeQuoter - timestampedPrice, err := feeQuoter.GetTokenPrice(nil, linkAddress) - require.NoError(t, err) - require.Equal(t, changeset.MockLinkPrice, timestampedPrice.Value) - - // Wait for all exec reports to land - changeset.ConfirmExecWithSeqNrsForAll(t, e, state, expectedSeqNumExec, startBlocks) - - balance, err := dstToken.BalanceOf(nil, state.Chains[dest].Receiver.Address()) - require.NoError(t, err) - - // The balance should be 4 since we've already sent 2 tokens over this lane direction in the - // first part of the test, so balance should already be two - require.Equal(t, new(big.Int).Mul(twoCoins, big.NewInt(2)), balance) + t.Run("Send programmable token transfer pay with wrapped native", func(t *testing.T) { + runFeeTokenTestCase(feeTokenTestCase{ + t: t, + src: sourceChain, + dst: destChain, + env: tenv, + tokenAmounts: []router.ClientEVMTokenAmount{ + { + Token: srcToken.Address(), + Amount: deployment.E18Mult(2), + }, + }, + feeToken: state.Chains[sourceChain].Weth9.Address(), + data: []byte("hello ptt world"), + receiver: common.LeftPadBytes(state.Chains[destChain].Receiver.Address().Bytes(), 32), + srcToken: srcToken, + dstToken: dstToken, + assertTokenBalance: true, + }) }) - t.Run("Send Token but revert not enough tokens", func(t *testing.T) { - // Assign Src to the Home Chain Selector and destChain to the Feed Chain Selector - src := tenv.HomeChainSel - dest, destChain := tenv.FeedChainSel, e.Chains[tenv.FeedChainSel] - - // get the header for the destination chain and the relevant block number - latesthdr, err := destChain.Client.HeaderByNumber(testcontext.Get(t), nil) - require.NoError(t, err) - block := latesthdr.Number.Uint64() - startBlocks[dest] = &block + t.Run("Send programmable token transfer but revert not enough tokens", func(t *testing.T) { // Send to the receiver on the destination chain paying with LINK token var ( - receiver = common.LeftPadBytes(state.Chains[dest].Receiver.Address().Bytes(), 32) + receiver = common.LeftPadBytes(state.Chains[destChain].Receiver.Address().Bytes(), 32) data = []byte("") - feeToken = linkToken.Address() + feeToken = state.Chains[sourceChain].LinkToken.Address() ) // Increase the token send amount to more than available to intentionally cause a revert - tokens[src][0].Amount = new(big.Int).Mul(twoCoins, big.NewInt(100)) - ccipMessage := router.ClientEVM2AnyMessage{ - Receiver: receiver, - Data: data, - TokenAmounts: tokens[src], - FeeToken: feeToken, - ExtraArgs: nil, + Receiver: receiver, + Data: data, + TokenAmounts: []router.ClientEVMTokenAmount{ + { + Token: srcToken.Address(), + Amount: deployment.E18Mult(100_000_000), + }, + }, + FeeToken: feeToken, + ExtraArgs: nil, } _, _, err = changeset.CCIPSendRequest( e, state, - src, dest, + sourceChain, destChain, true, ccipMessage, ) - require.Error(t, err) - }) -} - -func Test_PricingForMessages(t *testing.T) { - t.Parallel() - lggr := logger.TestLogger(t) - // ctx := changeset.Context(t) - tenv, _, _ := testsetups.NewLocalDevEnvironmentWithDefaultPrice(t, lggr, nil) - e := tenv.Env - // feeds := state.Chains[tenv.FeedChainSel].USDFeeds - output, err := changeset.DeployPrerequisites(tenv.Env, changeset.DeployPrerequisiteConfig{ - ChainSelectors: tenv.Env.AllChainSelectors(), + t.Run("Send data-only message pay with link token", func(t *testing.T) { + runFeeTokenTestCase(feeTokenTestCase{ + t: t, + src: sourceChain, + dst: destChain, + env: tenv, + // no tokens, only data + tokenAmounts: nil, + feeToken: state.Chains[sourceChain].LinkToken.Address(), + data: []byte("hello link world"), + receiver: common.LeftPadBytes(state.Chains[destChain].Receiver.Address().Bytes(), 32), + srcToken: srcToken, + dstToken: dstToken, + assertTokenBalance: false, + }) }) - require.NoError(t, err) - require.NoError(t, tenv.Env.ExistingAddresses.Merge(output.AddressBook)) - expectedSeqNum := make(map[changeset.SourceDestPair]uint64) - expectedSeqNumExec := make(map[changeset.SourceDestPair][]uint64) - - require.NoError(t, err) - require.NoError(t, tenv.Env.ExistingAddresses.Merge(output.AddressBook)) - // Get new state after migration. - state, err := changeset.LoadOnchainState(e) - require.NoError(t, err) + t.Run("Send message pay with native", func(t *testing.T) { + runFeeTokenTestCase(feeTokenTestCase{ + t: t, + src: sourceChain, + dst: destChain, + env: tenv, + // no tokens, only data + tokenAmounts: nil, + feeToken: common.HexToAddress("0x0"), + data: []byte("hello native world"), + receiver: common.LeftPadBytes(state.Chains[destChain].Receiver.Address().Bytes(), 32), + srcToken: srcToken, + dstToken: dstToken, + assertTokenBalance: false, + }) + }) - srcToken, dstToken := setupTokens(t, tenv) + t.Run("Send message pay with wrapped native", func(t *testing.T) { + runFeeTokenTestCase(feeTokenTestCase{ + t: t, + src: sourceChain, + dst: destChain, + env: tenv, + // no tokens, only data + tokenAmounts: nil, + feeToken: state.Chains[sourceChain].Weth9.Address(), + data: []byte("hello wrapped native world"), + receiver: common.LeftPadBytes(state.Chains[destChain].Receiver.Address().Bytes(), 32), + srcToken: srcToken, + dstToken: dstToken, + assertTokenBalance: false, + }) + }) +} - // Ensure capreg logs are up to date. - changeset.ReplayLogs(t, e.Offchain, tenv.ReplayBlocks) +type feeTokenTestCase struct { + t *testing.T + src, dst uint64 + env changeset.DeployedEnv + srcToken, dstToken *burn_mint_erc677.BurnMintERC677 + tokenAmounts []router.ClientEVMTokenAmount + feeToken common.Address + receiver []byte + data []byte + assertTokenBalance bool +} - // Add all lanes - require.NoError(t, changeset.AddLanesForAll(e, state)) +func runFeeTokenTestCase(tc feeTokenTestCase) { + ctx := tests.Context(tc.t) // Need to keep track of the block number for each chain so that event subscription can be done from that block. startBlocks := make(map[uint64]*uint64) - // Send a message from each chain to every other chain. - - // Mint 2 tokens to be transferred - twoCoins := new(big.Int).Mul(big.NewInt(1e18), big.NewInt(2)) + expectedSeqNum := make(map[changeset.SourceDestPair]uint64) + expectedSeqNumExec := make(map[changeset.SourceDestPair][]uint64) - linkToken := state.Chains[tenv.HomeChainSel].LinkToken - maxUint256 := math.MaxBig256 + srcChain := tc.env.Env.Chains[tc.src] + dstChain := tc.env.Env.Chains[tc.dst] - emptyTokenArray := make([]router.ClientEVMTokenAmount, 0) + state, err := changeset.LoadOnchainState(tc.env.Env) + require.NoError(tc.t, err) - // Create two ClientEVMTokenAmount structs to be passed to the router - tokens := map[uint64][]router.ClientEVMTokenAmount{ - tenv.HomeChainSel: {{ - Token: srcToken.Address(), - Amount: twoCoins, - }}, - tenv.FeedChainSel: {{ - Token: dstToken.Address(), - Amount: twoCoins, - }}, + var dstTokBalanceBefore *big.Int + if tc.assertTokenBalance { + var err error + dstTokBalanceBefore, err = tc.dstToken.BalanceOf(nil, state.Chains[tc.dst].Receiver.Address()) + require.NoError(tc.t, err) + tc.t.Logf("destination token balance before of receiver %s: %s", + state.Chains[tc.dst].Receiver.Address(), + dstTokBalanceBefore.String()) } - t.Run("Send message Pay with Link token home chain -> remote", func(t *testing.T) { - src := tenv.HomeChainSel - dest, destChain := tenv.FeedChainSel, e.Chains[tenv.FeedChainSel] - - sourceDestPair := changeset.SourceDestPair{ - SourceChainSelector: src, - DestChainSelector: dest, - } - - // Approve to spend link token - tx, err := linkToken.Approve(e.Chains[src].DeployerKey, state.Chains[src].Router.Address(), maxUint256) - require.NoError(t, err) - _, err = e.Chains[src].Confirm(tx) - require.NoError(t, err) - - // Get the fee Token Balance Before - srctokenBalance, err := srcToken.BalanceOf(nil, e.Chains[src].DeployerKey.From) - require.NoError(t, err) - require.GreaterOrEqual(t, srctokenBalance.Int64(), twoCoins.Int64()) - - // Assign Src to the Home Chain Selector and destChain to the Feed Chain Selector - - // get the header for the destination chain and the relevant block number - latesthdr, err := destChain.Client.HeaderByNumber(testcontext.Get(t), nil) - require.NoError(t, err) - block := latesthdr.Number.Uint64() - startBlocks[dest] = &block - - // Send to the receiver on the destination chain paying with LINK token - var ( - receiver = common.LeftPadBytes(state.Chains[dest].Receiver.Address().Bytes(), 32) - data = []byte("hello world") - feeToken = linkToken.Address() - ) - - ccipMessage := router.ClientEVM2AnyMessage{ - Receiver: receiver, - Data: data, - TokenAmounts: tokens[src], - FeeToken: feeToken, - ExtraArgs: nil, - } - - // Get the fee Token Balance Before - feeTokenBalanceBefore, err := linkToken.BalanceOf(nil, e.Chains[src].DeployerKey.From) - require.NoError(t, err) - - // Check the fee Amount - srcFee, err := state.Chains[src].Router.GetFee(nil, dest, ccipMessage) - require.NoError(t, err) - - msgSentEvent := changeset.TestSendRequest(t, e, state, src, dest, false, ccipMessage) - - expectedSeqNum[changeset.SourceDestPair{ - SourceChainSelector: src, - DestChainSelector: dest, - }] = msgSentEvent.SequenceNumber - expectedSeqNumExec[changeset.SourceDestPair{ - SourceChainSelector: src, - DestChainSelector: dest, - }] = []uint64{msgSentEvent.SequenceNumber} - - // Check the fee token balance after the request and ensure fee tokens were spent - feeTokenBalanceAfter, err := linkToken.BalanceOf(nil, e.Chains[tenv.HomeChainSel].DeployerKey.From) - require.NoError(t, err) - require.Equal(t, feeTokenBalanceAfter, new(big.Int).Sub(feeTokenBalanceBefore, srcFee)) - - // Wait for all commit reports to land. - changeset.ConfirmCommitForAllWithExpectedSeqNums(t, e, state, expectedSeqNum, startBlocks) - - // After commit is reported on all chains, token prices should be updated in FeeQuoter. - linkAddress := state.Chains[dest].LinkToken.Address() - feeQuoter := state.Chains[dest].FeeQuoter - timestampedPrice, err := feeQuoter.GetTokenPrice(nil, linkAddress) - require.NoError(t, err) - require.Equal(t, changeset.MockLinkPrice, timestampedPrice.Value) + // if fee token is not native then approve the router to spend the fee token from the sender. + var feeTokenWrapper *burn_mint_erc677.BurnMintERC677 + if tc.feeToken != common.HexToAddress("0x0") { + if tc.feeToken == state.Chains[tc.src].Weth9.Address() { + // Deposit some ETH into the WETH contract + weth9, err := weth9_wrapper.NewWETH9(state.Chains[tc.src].Weth9.Address(), srcChain.Client) + require.NoError(tc.t, err) - // Wait for all exec reports to land - changeset.ConfirmExecWithSeqNrsForAll(t, e, state, expectedSeqNumExec, startBlocks) + balance, err := srcChain.Client.BalanceAt(ctx, srcChain.DeployerKey.From, nil) + require.NoError(tc.t, err) - balance, err := dstToken.BalanceOf(nil, state.Chains[tenv.FeedChainSel].Receiver.Address()) - require.NoError(t, err) - require.Equal(t, twoCoins, balance) - - // Delete from the expcted seq num the chain that was just tested so that we don't pass it to the - // commit report in the next test - delete(expectedSeqNum, sourceDestPair) - }) + tc.t.Logf("balance before deposit: %s", balance.String()) - t.Run("Send message Pay with native remote chain -> home", func(t *testing.T) { - // Assign Src to the Home Chain Selector and destChain to the Feed Chain Selector - src := tenv.FeedChainSel - dest, destChain := tenv.HomeChainSel, e.Chains[tenv.HomeChainSel] - - sourceDestPair := changeset.SourceDestPair{ - SourceChainSelector: src, - DestChainSelector: dest, + srcChain.DeployerKey.Value = assets.Ether(100).ToInt() + tx, err := weth9.Deposit(srcChain.DeployerKey) + _, err = deployment.ConfirmIfNoError(srcChain, tx, err) + require.NoError(tc.t, err) + srcChain.DeployerKey.Value = big.NewInt(0) } - // get the header for the destination chain and the relevant block number - latesthdr, err := destChain.Client.HeaderByNumber(testcontext.Get(t), nil) - require.NoError(t, err) - block := latesthdr.Number.Uint64() - startBlocks[dest] = &block + var err error + feeTokenWrapper, err = burn_mint_erc677.NewBurnMintERC677(tc.feeToken, srcChain.Client) + require.NoError(tc.t, err) - // Send to the receiver on the destination chain paying with native token - var ( - receiver = common.LeftPadBytes(state.Chains[dest].Receiver.Address().Bytes(), 32) - data = []byte("hello world") - feeToken = common.HexToAddress("0x0") - ) + // Approve the router to spend fee token + tx, err := feeTokenWrapper.Approve(srcChain.DeployerKey, state.Chains[tc.src].Router.Address(), math.MaxBig256) - ccipMessage := router.ClientEVM2AnyMessage{ - Receiver: receiver, - Data: data, - TokenAmounts: emptyTokenArray, - FeeToken: feeToken, - ExtraArgs: nil, - } - - msgSentEvent := changeset.TestSendRequest(t, e, state, src, dest, false, ccipMessage) - expectedSeqNum[changeset.SourceDestPair{ - SourceChainSelector: src, - DestChainSelector: dest, - }] = msgSentEvent.SequenceNumber - expectedSeqNumExec[changeset.SourceDestPair{ - SourceChainSelector: src, - DestChainSelector: dest, - }] = []uint64{msgSentEvent.SequenceNumber} - - // Wait for all commit reports to land. - changeset.ConfirmCommitForAllWithExpectedSeqNums(t, e, state, expectedSeqNum, startBlocks) - - // After commit is reported on all chains, token prices should be updated in FeeQuoter. - linkAddress := state.Chains[dest].LinkToken.Address() - feeQuoter := state.Chains[dest].FeeQuoter - timestampedPrice, err := feeQuoter.GetTokenPrice(nil, linkAddress) - require.NoError(t, err) - require.Equal(t, changeset.MockLinkPrice, timestampedPrice.Value) - - // Wait for all exec reports to land - changeset.ConfirmExecWithSeqNrsForAll(t, e, state, expectedSeqNumExec, startBlocks) - - delete(expectedSeqNum, sourceDestPair) - }) - - t.Run("Send message pay with wrapped native home chain -> remote", func(t *testing.T) { - // Assign Src to the Home Chain Selector and destChain to the Feed Chain Selector - src := tenv.HomeChainSel - dest, destChain := tenv.FeedChainSel, e.Chains[tenv.FeedChainSel] - - WETH := state.Chains[src].Weth9 - - // Approve to spend WETH token as feeToken - tx, err := WETH.Approve(e.Chains[tenv.HomeChainSel].DeployerKey, state.Chains[tenv.HomeChainSel].Router.Address(), maxUint256) - require.NoError(t, err) - _, err = e.Chains[tenv.HomeChainSel].Confirm(tx) - require.NoError(t, err) - - srcTokenBal, err := srcToken.BalanceOf(nil, e.Chains[src].DeployerKey.From) - require.NoError(t, err) - require.GreaterOrEqual(t, srcTokenBal.Int64(), twoCoins.Int64()) - - // get the header for the destination chain and the relevant block number - latesthdr, err := destChain.Client.HeaderByNumber(testcontext.Get(t), nil) - require.NoError(t, err) - block := latesthdr.Number.Uint64() - startBlocks[dest] = &block + _, err = deployment.ConfirmIfNoError(srcChain, tx, err) + require.NoError(tc.t, err) + } - // Send to the receiver on the destination chain paying with LINK token - var ( - receiver = common.LeftPadBytes(state.Chains[dest].Receiver.Address().Bytes(), 32) - data = []byte("hello world") - feeToken = state.Chains[src].Weth9.Address() - ) + // get the header for the destination chain and the relevant block number + latesthdr, err := dstChain.Client.HeaderByNumber(testcontext.Get(tc.t), nil) + require.NoError(tc.t, err) + block := latesthdr.Number.Uint64() + startBlocks[tc.dst] = &block + + // Get the fee Token Balance Before, if not fee token set get native balance. + var feeTokenBalanceBefore *big.Int + if feeTokenWrapper != nil { + feeTokenBalanceBefore, err = feeTokenWrapper.BalanceOf(&bind.CallOpts{ + Context: ctx, + }, srcChain.DeployerKey.From) + require.NoError(tc.t, err) + } else { + feeTokenBalanceBefore, err = srcChain.Client.BalanceAt(ctx, srcChain.DeployerKey.From, nil) + require.NoError(tc.t, err) + } + tc.t.Logf("fee token balance before: %s, fee token enabled: %s", + feeTokenBalanceBefore.String(), tc.feeToken.String()) - ccipMessage := router.ClientEVM2AnyMessage{ - Receiver: receiver, - Data: data, - TokenAmounts: tokens[src], - FeeToken: feeToken, + msgSentEvent := changeset.TestSendRequest( + tc.t, + tc.env.Env, + state, + tc.src, + tc.dst, + false, + router.ClientEVM2AnyMessage{ + Receiver: tc.receiver, + Data: tc.data, + TokenAmounts: tc.tokenAmounts, + FeeToken: tc.feeToken, ExtraArgs: nil, - } - - srcFee, err := state.Chains[src].Router.GetFee(nil, dest, ccipMessage) - require.NoError(t, err) - - // We need to acquire some WETH to send with the tx so we deposit some ETH into the WETH contract - // but deployerKey is a reference so we need to dereference it and then reassign it - // Also the fees have been unusually high so we need to deposit more than usual to ensure the test doesn't fail - depositOps := *e.Chains[tenv.HomeChainSel].DeployerKey - depositOps.Value = srcFee - tx, err = WETH.Deposit(&depositOps) - require.NoError(t, err) - _, err = e.Chains[tenv.HomeChainSel].Confirm(tx) - require.NoError(t, err) - - // Get the fee Token Balance Before - feeTokenBalanceBefore, err := WETH.BalanceOf(nil, e.Chains[src].DeployerKey.From) - require.NoError(t, err) - - msgSentEvent := changeset.TestSendRequest(t, e, state, src, dest, false, ccipMessage) - expectedSeqNum[changeset.SourceDestPair{ - SourceChainSelector: src, - DestChainSelector: dest, - }] = msgSentEvent.SequenceNumber - expectedSeqNumExec[changeset.SourceDestPair{ - SourceChainSelector: src, - DestChainSelector: dest, - }] = []uint64{msgSentEvent.SequenceNumber} - - // Check the fee token balance after the request and ensure fee tokens were spent - feeTokenBalanceAfter, err := WETH.BalanceOf(nil, e.Chains[tenv.HomeChainSel].DeployerKey.From) - require.NoError(t, err) - require.Equal(t, feeTokenBalanceAfter, new(big.Int).Sub(feeTokenBalanceBefore, srcFee)) - - // Wait for all commit reports to land. - changeset.ConfirmCommitForAllWithExpectedSeqNums(t, e, state, expectedSeqNum, startBlocks) - - // After commit is reported on all chains, token prices should be updated in FeeQuoter. - linkAddress := state.Chains[dest].LinkToken.Address() - feeQuoter := state.Chains[dest].FeeQuoter - timestampedPrice, err := feeQuoter.GetTokenPrice(nil, linkAddress) - require.NoError(t, err) - require.Equal(t, changeset.MockLinkPrice, timestampedPrice.Value) - - // Wait for all exec reports to land - changeset.ConfirmExecWithSeqNrsForAll(t, e, state, expectedSeqNumExec, startBlocks) - - balance, err := dstToken.BalanceOf(nil, state.Chains[dest].Receiver.Address()) - require.NoError(t, err) - - // The balance should be 4 since we've already sent 2 tokens over this lane direction in the - // first part of the test, so balance should already be two - require.Equal(t, new(big.Int).Mul(twoCoins, big.NewInt(2)), balance) - }) - t.Run("Send Programmable Token Transfers paying in link", func(t *testing.T) { - src := tenv.HomeChainSel - dest, destChain := tenv.FeedChainSel, e.Chains[tenv.FeedChainSel] - - // Approve to spend link token - tx, err := linkToken.Approve(e.Chains[src].DeployerKey, state.Chains[src].Router.Address(), maxUint256) - require.NoError(t, err) - _, err = e.Chains[src].Confirm(tx) - require.NoError(t, err) + }, + ) - // Get the fee Token Balance Before - srctokenBalance, err := srcToken.BalanceOf(nil, e.Chains[src].DeployerKey.From) - require.NoError(t, err) - require.GreaterOrEqual(t, srctokenBalance.Int64(), twoCoins.Int64()) + expectedSeqNum[changeset.SourceDestPair{ + SourceChainSelector: tc.src, + DestChainSelector: tc.dst, + }] = msgSentEvent.SequenceNumber + expectedSeqNumExec[changeset.SourceDestPair{ + SourceChainSelector: tc.src, + DestChainSelector: tc.dst, + }] = []uint64{msgSentEvent.SequenceNumber} + + // Check the fee token balance after the request and ensure fee tokens were spent + var feeTokenBalanceAfter *big.Int + if feeTokenWrapper != nil { + feeTokenBalanceAfter, err = feeTokenWrapper.BalanceOf(&bind.CallOpts{ + Context: ctx, + }, srcChain.DeployerKey.From) + require.NoError(tc.t, err) + } else { + feeTokenBalanceAfter, err = srcChain.Client.BalanceAt(ctx, srcChain.DeployerKey.From, nil) + require.NoError(tc.t, err) + } + tc.t.Logf("fee token balance after: %s, fee token: %s, fee paid: %s", + feeTokenBalanceAfter.String(), tc.feeToken.String(), msgSentEvent.Message.FeeTokenAmount) + // in the case we have no fee token, native is also used to pay for the tx, + // so we have to subtract that as well + if feeTokenWrapper == nil { + receipt, err := srcChain.Client.TransactionReceipt(ctx, msgSentEvent.Raw.TxHash) + require.NoError(tc.t, err) + txCostWei := new(big.Int).Mul(big.NewInt(int64(receipt.GasUsed)), receipt.EffectiveGasPrice) + feeTokenBalanceBefore.Sub(feeTokenBalanceBefore, txCostWei) + } + require.Equal( + tc.t, + feeTokenBalanceAfter, + new(big.Int).Sub(feeTokenBalanceBefore, msgSentEvent.Message.FeeTokenAmount), + ) - // Assign Src to the Home Chain Selector and destChain to the Feed Chain Selector + // Wait for all commit reports to land. + changeset.ConfirmCommitForAllWithExpectedSeqNums(tc.t, tc.env.Env, state, expectedSeqNum, startBlocks) - // get the header for the destination chain and the relevant block number - latesthdr, err := destChain.Client.HeaderByNumber(testcontext.Get(t), nil) - require.NoError(t, err) - block := latesthdr.Number.Uint64() - startBlocks[dest] = &block + // After commit is reported on all chains, token prices should be updated in FeeQuoter. + linkAddress := state.Chains[tc.dst].LinkToken.Address() + feeQuoter := state.Chains[tc.dst].FeeQuoter + timestampedPrice, err := feeQuoter.GetTokenPrice(&bind.CallOpts{ + Context: ctx, + }, linkAddress) + require.NoError(tc.t, err) + require.Equal(tc.t, changeset.MockLinkPrice, timestampedPrice.Value) - // Send to the receiver on the destination chain paying with LINK token - var ( - receiver = common.LeftPadBytes(state.Chains[dest].Receiver.Address().Bytes(), 32) - data = []byte("hello world") - feeToken = linkToken.Address() + // Wait for all exec reports to land + changeset.ConfirmExecWithSeqNrsForAll(tc.t, tc.env.Env, state, expectedSeqNumExec, startBlocks) + + if tc.assertTokenBalance { + require.Len(tc.t, tc.tokenAmounts, 1) + expectedTransferAmount := tc.tokenAmounts[0].Amount + + balanceAfter, err := tc.dstToken.BalanceOf(&bind.CallOpts{ + Context: ctx, + }, state.Chains[tc.dst].Receiver.Address()) + require.NoError(tc.t, err) + require.Equal( + tc.t, + new(big.Int).Add(dstTokBalanceBefore, expectedTransferAmount), + balanceAfter, ) - - ccipMessage := router.ClientEVM2AnyMessage{ - Receiver: receiver, - Data: data, - TokenAmounts: tokens[src], - FeeToken: feeToken, - ExtraArgs: nil, - } - - // Get the fee Token Balance Before - feeTokenBalanceBefore, err := linkToken.BalanceOf(nil, e.Chains[src].DeployerKey.From) - require.NoError(t, err) - - // Check the fee Amount - srcFee, err := state.Chains[src].Router.GetFee(nil, dest, ccipMessage) - require.NoError(t, err) - - msgSentEvent := changeset.TestSendRequest(t, e, state, src, dest, false, ccipMessage) - - expectedSeqNum[changeset.SourceDestPair{ - SourceChainSelector: src, - DestChainSelector: dest, - }] = msgSentEvent.SequenceNumber - expectedSeqNumExec[changeset.SourceDestPair{ - SourceChainSelector: src, - DestChainSelector: dest, - }] = []uint64{msgSentEvent.SequenceNumber} - - // Check the fee token balance after the request and ensure fee tokens were spent - feeTokenBalanceAfter, err := linkToken.BalanceOf(nil, e.Chains[tenv.HomeChainSel].DeployerKey.From) - require.NoError(t, err) - require.Equal(t, feeTokenBalanceAfter, new(big.Int).Sub(feeTokenBalanceBefore, srcFee)) - - balanceBefore, err := dstToken.BalanceOf(nil, state.Chains[tenv.FeedChainSel].Receiver.Address()) - require.NoError(t, err) - - // Wait for all commit reports to land. - changeset.ConfirmCommitForAllWithExpectedSeqNums(t, e, state, expectedSeqNum, startBlocks) - - // After commit is reported on all chains, token prices should be updated in FeeQuoter. - linkAddress := state.Chains[dest].LinkToken.Address() - feeQuoter := state.Chains[dest].FeeQuoter - timestampedPrice, err := feeQuoter.GetTokenPrice(nil, linkAddress) - require.NoError(t, err) - require.Equal(t, changeset.MockLinkPrice, timestampedPrice.Value) - - // Wait for all exec reports to land - changeset.ConfirmExecWithSeqNrsForAll(t, e, state, expectedSeqNumExec, startBlocks) - - balanceAfter, err := dstToken.BalanceOf(nil, state.Chains[tenv.FeedChainSel].Receiver.Address()) - require.NoError(t, err) - require.Equal(t, new(big.Int).Add(balanceBefore, twoCoins), balanceAfter) - - // Delete from the expcted seq num the chain that was just tested so that we don't pass it to the - }) - + } } From 5775b579502c4f56ae9e1bf3eb295c9b853b207b Mon Sep 17 00:00:00 2001 From: Makram Kamaleddine Date: Thu, 28 Nov 2024 20:45:46 +0400 Subject: [PATCH 17/18] fix workflow --- .github/integration-in-memory-tests.yml | 8 + .../smoke/ccip/ccip_fees_test.go | 447 ++++++++++++++++++ integration-tests/smoke/ccip/ccip_test.go | 435 ----------------- 3 files changed, 455 insertions(+), 435 deletions(-) create mode 100644 integration-tests/smoke/ccip/ccip_fees_test.go diff --git a/.github/integration-in-memory-tests.yml b/.github/integration-in-memory-tests.yml index f97f3332eb7..4865676d727 100644 --- a/.github/integration-in-memory-tests.yml +++ b/.github/integration-in-memory-tests.yml @@ -8,6 +8,14 @@ runner-test-matrix: # START: CCIPv1.6 tests + - id: smoke/ccip/ccip_fees_test.go:* + path: integration-tests/smoke/ccip/ccip_fees_test.go + test_env_type: in-memory + runs_on: ubuntu-latest + triggers: + - PR Integration CCIP Tests + test_cmd: cd integration-tests/smoke/ccip && go test ccip_fees_test.go -timeout 12m -test.parallel=2 -count=1 -json + - id: smoke/ccip/ccip_messaging_test.go:* path: integration-tests/smoke/ccip/ccip_messaging_test.go test_env_type: in-memory diff --git a/integration-tests/smoke/ccip/ccip_fees_test.go b/integration-tests/smoke/ccip/ccip_fees_test.go new file mode 100644 index 00000000000..2b943de93ac --- /dev/null +++ b/integration-tests/smoke/ccip/ccip_fees_test.go @@ -0,0 +1,447 @@ +package smoke + +import ( + "math/big" + "testing" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/math" + "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" + "github.com/smartcontractkit/chainlink-testing-framework/lib/utils/testcontext" + "github.com/smartcontractkit/chainlink/deployment" + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/weth9_wrapper" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/shared/generated/burn_mint_erc677" + "github.com/smartcontractkit/chainlink/v2/core/logger" +) + +// setupTokens deploys transferable tokens on the source and dest, mints tokens for the source and dest, and +// approves the router to spend the tokens +func setupTokens( + t *testing.T, + state changeset.CCIPOnChainState, + tenv changeset.DeployedEnv, + src, dest uint64, + transferTokenMintAmount, + feeTokenMintAmount *big.Int, +) ( + srcToken *burn_mint_erc677.BurnMintERC677, + dstToken *burn_mint_erc677.BurnMintERC677, +) { + lggr := logger.TestLogger(t) + e := tenv.Env + + // Deploy the token to test transferring + srcToken, _, dstToken, _, err := changeset.DeployTransferableToken( + lggr, + tenv.Env.Chains, + src, + dest, + state, + tenv.Env.ExistingAddresses, + "MY_TOKEN", + ) + require.NoError(t, err) + + linkToken := state.Chains[src].LinkToken + + tx, err := srcToken.Mint( + e.Chains[src].DeployerKey, + e.Chains[src].DeployerKey.From, + transferTokenMintAmount, + ) + _, err = deployment.ConfirmIfNoError(e.Chains[src], tx, err) + require.NoError(t, err) + + // Mint a destination token + tx, err = dstToken.Mint( + e.Chains[dest].DeployerKey, + e.Chains[dest].DeployerKey.From, + transferTokenMintAmount, + ) + _, err = deployment.ConfirmIfNoError(e.Chains[dest], tx, err) + require.NoError(t, err) + + // Approve the router to spend the tokens and confirm the tx's + // To prevent having to approve the router for every transfer, we approve a sufficiently large amount + tx, err = srcToken.Approve(e.Chains[src].DeployerKey, state.Chains[src].Router.Address(), math.MaxBig256) + _, err = deployment.ConfirmIfNoError(e.Chains[src], tx, err) + require.NoError(t, err) + + tx, err = dstToken.Approve(e.Chains[dest].DeployerKey, state.Chains[dest].Router.Address(), math.MaxBig256) + _, err = deployment.ConfirmIfNoError(e.Chains[dest], tx, err) + require.NoError(t, err) + + // Grant mint and burn roles to the deployer key for the newly deployed linkToken + // Since those roles are not granted automatically + tx, err = linkToken.GrantMintAndBurnRoles(e.Chains[src].DeployerKey, e.Chains[src].DeployerKey.From) + _, err = deployment.ConfirmIfNoError(e.Chains[src], tx, err) + require.NoError(t, err) + + // Mint link token and confirm the tx + tx, err = linkToken.Mint( + e.Chains[src].DeployerKey, + e.Chains[src].DeployerKey.From, + feeTokenMintAmount, + ) + _, err = deployment.ConfirmIfNoError(e.Chains[src], tx, err) + require.NoError(t, err) + + return srcToken, dstToken +} + +func Test_CCIPFees(t *testing.T) { + t.Parallel() + tenv := changeset.NewMemoryEnvironmentWithJobsAndContracts(t, logger.TestLogger(t), 2, 4, nil) + e := tenv.Env + + allChains := tenv.Env.AllChainSelectors() + require.Len(t, allChains, 2, "need two chains for this test") + sourceChain := allChains[0] + destChain := allChains[1] + + // Get new state after migration. + state, err := changeset.LoadOnchainState(e) + require.NoError(t, err) + + srcToken, dstToken := setupTokens( + t, + state, + tenv, + sourceChain, + destChain, + deployment.E18Mult(10_000), + deployment.E18Mult(10_000), + ) + + // Ensure capreg logs are up to date. + changeset.ReplayLogs(t, e.Offchain, tenv.ReplayBlocks) + + // Add all lanes + require.NoError(t, changeset.AddLanesForAll(e, state)) + + t.Run("Send programmable token transfer pay with Link token", func(t *testing.T) { + runFeeTokenTestCase(feeTokenTestCase{ + t: t, + dst: destChain, + src: sourceChain, + env: tenv, + tokenAmounts: []router.ClientEVMTokenAmount{ + { + Token: srcToken.Address(), + Amount: deployment.E18Mult(2), + }, + }, + feeToken: state.Chains[sourceChain].LinkToken.Address(), + data: []byte("hello ptt world"), + receiver: common.LeftPadBytes(state.Chains[destChain].Receiver.Address().Bytes(), 32), + srcToken: srcToken, + dstToken: dstToken, + assertTokenBalance: true, + }) + }) + + t.Run("Send programmable token transfer pay with native", func(t *testing.T) { + runFeeTokenTestCase(feeTokenTestCase{ + t: t, + + // note the order of src and dest is reversed here + src: destChain, + dst: sourceChain, + + env: tenv, + tokenAmounts: []router.ClientEVMTokenAmount{ + { + Token: dstToken.Address(), + Amount: deployment.E18Mult(2), + }, + }, + feeToken: common.HexToAddress("0x0"), + data: []byte("hello ptt world"), + receiver: common.LeftPadBytes(state.Chains[sourceChain].Receiver.Address().Bytes(), 32), + + // note the order of src and dest is reversed here + srcToken: dstToken, + dstToken: srcToken, + assertTokenBalance: true, + }) + }) + + t.Run("Send programmable token transfer pay with wrapped native", func(t *testing.T) { + runFeeTokenTestCase(feeTokenTestCase{ + t: t, + src: sourceChain, + dst: destChain, + env: tenv, + tokenAmounts: []router.ClientEVMTokenAmount{ + { + Token: srcToken.Address(), + Amount: deployment.E18Mult(2), + }, + }, + feeToken: state.Chains[sourceChain].Weth9.Address(), + data: []byte("hello ptt world"), + receiver: common.LeftPadBytes(state.Chains[destChain].Receiver.Address().Bytes(), 32), + srcToken: srcToken, + dstToken: dstToken, + assertTokenBalance: true, + }) + }) + + t.Run("Send programmable token transfer but revert not enough tokens", func(t *testing.T) { + // Send to the receiver on the destination chain paying with LINK token + var ( + receiver = common.LeftPadBytes(state.Chains[destChain].Receiver.Address().Bytes(), 32) + data = []byte("") + feeToken = state.Chains[sourceChain].LinkToken.Address() + ) + + // Increase the token send amount to more than available to intentionally cause a revert + ccipMessage := router.ClientEVM2AnyMessage{ + Receiver: receiver, + Data: data, + TokenAmounts: []router.ClientEVMTokenAmount{ + { + Token: srcToken.Address(), + Amount: deployment.E18Mult(100_000_000), + }, + }, + FeeToken: feeToken, + ExtraArgs: nil, + } + + _, _, err = changeset.CCIPSendRequest( + e, + state, + sourceChain, destChain, + true, + ccipMessage, + ) + require.Error(t, err) + }) + + t.Run("Send data-only message pay with link token", func(t *testing.T) { + runFeeTokenTestCase(feeTokenTestCase{ + t: t, + src: sourceChain, + dst: destChain, + env: tenv, + // no tokens, only data + tokenAmounts: nil, + feeToken: state.Chains[sourceChain].LinkToken.Address(), + data: []byte("hello link world"), + receiver: common.LeftPadBytes(state.Chains[destChain].Receiver.Address().Bytes(), 32), + srcToken: srcToken, + dstToken: dstToken, + assertTokenBalance: false, + }) + }) + + t.Run("Send message pay with native", func(t *testing.T) { + runFeeTokenTestCase(feeTokenTestCase{ + t: t, + src: sourceChain, + dst: destChain, + env: tenv, + // no tokens, only data + tokenAmounts: nil, + feeToken: common.HexToAddress("0x0"), + data: []byte("hello native world"), + receiver: common.LeftPadBytes(state.Chains[destChain].Receiver.Address().Bytes(), 32), + srcToken: srcToken, + dstToken: dstToken, + assertTokenBalance: false, + }) + }) + + t.Run("Send message pay with wrapped native", func(t *testing.T) { + runFeeTokenTestCase(feeTokenTestCase{ + t: t, + src: sourceChain, + dst: destChain, + env: tenv, + // no tokens, only data + tokenAmounts: nil, + feeToken: state.Chains[sourceChain].Weth9.Address(), + data: []byte("hello wrapped native world"), + receiver: common.LeftPadBytes(state.Chains[destChain].Receiver.Address().Bytes(), 32), + srcToken: srcToken, + dstToken: dstToken, + assertTokenBalance: false, + }) + }) +} + +type feeTokenTestCase struct { + t *testing.T + src, dst uint64 + env changeset.DeployedEnv + srcToken, dstToken *burn_mint_erc677.BurnMintERC677 + tokenAmounts []router.ClientEVMTokenAmount + feeToken common.Address + receiver []byte + data []byte + assertTokenBalance bool +} + +func runFeeTokenTestCase(tc feeTokenTestCase) { + ctx := tests.Context(tc.t) + // Need to keep track of the block number for each chain so that event subscription can be done from that block. + startBlocks := make(map[uint64]*uint64) + expectedSeqNum := make(map[changeset.SourceDestPair]uint64) + expectedSeqNumExec := make(map[changeset.SourceDestPair][]uint64) + + srcChain := tc.env.Env.Chains[tc.src] + dstChain := tc.env.Env.Chains[tc.dst] + + state, err := changeset.LoadOnchainState(tc.env.Env) + require.NoError(tc.t, err) + + var dstTokBalanceBefore *big.Int + if tc.assertTokenBalance { + var err error + dstTokBalanceBefore, err = tc.dstToken.BalanceOf(nil, state.Chains[tc.dst].Receiver.Address()) + require.NoError(tc.t, err) + tc.t.Logf("destination token balance before of receiver %s: %s", + state.Chains[tc.dst].Receiver.Address(), + dstTokBalanceBefore.String()) + } + + // if fee token is not native then approve the router to spend the fee token from the sender. + var feeTokenWrapper *burn_mint_erc677.BurnMintERC677 + if tc.feeToken != common.HexToAddress("0x0") { + if tc.feeToken == state.Chains[tc.src].Weth9.Address() { + // Deposit some ETH into the WETH contract + weth9, err := weth9_wrapper.NewWETH9(state.Chains[tc.src].Weth9.Address(), srcChain.Client) + require.NoError(tc.t, err) + + balance, err := srcChain.Client.BalanceAt(ctx, srcChain.DeployerKey.From, nil) + require.NoError(tc.t, err) + + tc.t.Logf("balance before deposit: %s", balance.String()) + + srcChain.DeployerKey.Value = assets.Ether(100).ToInt() + tx, err := weth9.Deposit(srcChain.DeployerKey) + _, err = deployment.ConfirmIfNoError(srcChain, tx, err) + require.NoError(tc.t, err) + srcChain.DeployerKey.Value = big.NewInt(0) + } + + var err error + feeTokenWrapper, err = burn_mint_erc677.NewBurnMintERC677(tc.feeToken, srcChain.Client) + require.NoError(tc.t, err) + + // Approve the router to spend fee token + tx, err := feeTokenWrapper.Approve(srcChain.DeployerKey, state.Chains[tc.src].Router.Address(), math.MaxBig256) + + _, err = deployment.ConfirmIfNoError(srcChain, tx, err) + require.NoError(tc.t, err) + } + + // get the header for the destination chain and the relevant block number + latesthdr, err := dstChain.Client.HeaderByNumber(testcontext.Get(tc.t), nil) + require.NoError(tc.t, err) + block := latesthdr.Number.Uint64() + startBlocks[tc.dst] = &block + + // Get the fee Token Balance Before, if not fee token set get native balance. + var feeTokenBalanceBefore *big.Int + if feeTokenWrapper != nil { + feeTokenBalanceBefore, err = feeTokenWrapper.BalanceOf(&bind.CallOpts{ + Context: ctx, + }, srcChain.DeployerKey.From) + require.NoError(tc.t, err) + } else { + feeTokenBalanceBefore, err = srcChain.Client.BalanceAt(ctx, srcChain.DeployerKey.From, nil) + require.NoError(tc.t, err) + } + tc.t.Logf("fee token balance before: %s, fee token enabled: %s", + feeTokenBalanceBefore.String(), tc.feeToken.String()) + + msgSentEvent := changeset.TestSendRequest( + tc.t, + tc.env.Env, + state, + tc.src, + tc.dst, + false, + router.ClientEVM2AnyMessage{ + Receiver: tc.receiver, + Data: tc.data, + TokenAmounts: tc.tokenAmounts, + FeeToken: tc.feeToken, + ExtraArgs: nil, + }, + ) + + expectedSeqNum[changeset.SourceDestPair{ + SourceChainSelector: tc.src, + DestChainSelector: tc.dst, + }] = msgSentEvent.SequenceNumber + expectedSeqNumExec[changeset.SourceDestPair{ + SourceChainSelector: tc.src, + DestChainSelector: tc.dst, + }] = []uint64{msgSentEvent.SequenceNumber} + + // Check the fee token balance after the request and ensure fee tokens were spent + var feeTokenBalanceAfter *big.Int + if feeTokenWrapper != nil { + feeTokenBalanceAfter, err = feeTokenWrapper.BalanceOf(&bind.CallOpts{ + Context: ctx, + }, srcChain.DeployerKey.From) + require.NoError(tc.t, err) + } else { + feeTokenBalanceAfter, err = srcChain.Client.BalanceAt(ctx, srcChain.DeployerKey.From, nil) + require.NoError(tc.t, err) + } + tc.t.Logf("fee token balance after: %s, fee token: %s, fee paid: %s", + feeTokenBalanceAfter.String(), tc.feeToken.String(), msgSentEvent.Message.FeeTokenAmount) + // in the case we have no fee token, native is also used to pay for the tx, + // so we have to subtract that as well + if feeTokenWrapper == nil { + receipt, err := srcChain.Client.TransactionReceipt(ctx, msgSentEvent.Raw.TxHash) + require.NoError(tc.t, err) + txCostWei := new(big.Int).Mul(big.NewInt(int64(receipt.GasUsed)), receipt.EffectiveGasPrice) + feeTokenBalanceBefore.Sub(feeTokenBalanceBefore, txCostWei) + } + require.Equal( + tc.t, + feeTokenBalanceAfter, + new(big.Int).Sub(feeTokenBalanceBefore, msgSentEvent.Message.FeeTokenAmount), + ) + + // Wait for all commit reports to land. + changeset.ConfirmCommitForAllWithExpectedSeqNums(tc.t, tc.env.Env, state, expectedSeqNum, startBlocks) + + // After commit is reported on all chains, token prices should be updated in FeeQuoter. + linkAddress := state.Chains[tc.dst].LinkToken.Address() + feeQuoter := state.Chains[tc.dst].FeeQuoter + timestampedPrice, err := feeQuoter.GetTokenPrice(&bind.CallOpts{ + Context: ctx, + }, linkAddress) + require.NoError(tc.t, err) + require.Equal(tc.t, changeset.MockLinkPrice, timestampedPrice.Value) + + // Wait for all exec reports to land + changeset.ConfirmExecWithSeqNrsForAll(tc.t, tc.env.Env, state, expectedSeqNumExec, startBlocks) + + if tc.assertTokenBalance { + require.Len(tc.t, tc.tokenAmounts, 1) + expectedTransferAmount := tc.tokenAmounts[0].Amount + + balanceAfter, err := tc.dstToken.BalanceOf(&bind.CallOpts{ + Context: ctx, + }, state.Chains[tc.dst].Receiver.Address()) + require.NoError(tc.t, err) + require.Equal( + tc.t, + new(big.Int).Add(dstTokBalanceBefore, expectedTransferAmount), + balanceAfter, + ) + } +} diff --git a/integration-tests/smoke/ccip/ccip_test.go b/integration-tests/smoke/ccip/ccip_test.go index ef8d4095b1f..d2adbaaa484 100644 --- a/integration-tests/smoke/ccip/ccip_test.go +++ b/integration-tests/smoke/ccip/ccip_test.go @@ -4,15 +4,7 @@ import ( "math/big" "testing" - "github.com/ethereum/go-ethereum/accounts/abi/bind" - - "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" - "github.com/smartcontractkit/chainlink/deployment" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/weth9_wrapper" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/math" "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-testing-framework/lib/utils/testcontext" @@ -21,7 +13,6 @@ import ( testsetups "github.com/smartcontractkit/chainlink/integration-tests/testsetups/ccip" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/onramp" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/shared/generated/burn_mint_erc677" "github.com/smartcontractkit/chainlink/v2/core/logger" ) @@ -215,429 +206,3 @@ func TestTokenTransfer(t *testing.T) { require.NoError(t, err) require.Equal(t, twoCoins, balance) } - -// setupTokens deploys transferable tokens on the source and dest, mints tokens for the source and dest, and -// approves the router to spend the tokens -func setupTokens( - t *testing.T, - state changeset.CCIPOnChainState, - tenv changeset.DeployedEnv, - src, dest uint64, - transferTokenMintAmount, - feeTokenMintAmount *big.Int, -) ( - srcToken *burn_mint_erc677.BurnMintERC677, - dstToken *burn_mint_erc677.BurnMintERC677, -) { - lggr := logger.TestLogger(t) - e := tenv.Env - - // Deploy the token to test transferring - srcToken, _, dstToken, _, err := changeset.DeployTransferableToken( - lggr, - tenv.Env.Chains, - src, - dest, - state, - tenv.Env.ExistingAddresses, - "MY_TOKEN", - ) - require.NoError(t, err) - - linkToken := state.Chains[src].LinkToken - - tx, err := srcToken.Mint( - e.Chains[src].DeployerKey, - e.Chains[src].DeployerKey.From, - transferTokenMintAmount, - ) - _, err = deployment.ConfirmIfNoError(e.Chains[src], tx, err) - require.NoError(t, err) - - // Mint a destination token - tx, err = dstToken.Mint( - e.Chains[dest].DeployerKey, - e.Chains[dest].DeployerKey.From, - transferTokenMintAmount, - ) - _, err = deployment.ConfirmIfNoError(e.Chains[dest], tx, err) - require.NoError(t, err) - - // Approve the router to spend the tokens and confirm the tx's - // To prevent having to approve the router for every transfer, we approve a sufficiently large amount - tx, err = srcToken.Approve(e.Chains[src].DeployerKey, state.Chains[src].Router.Address(), math.MaxBig256) - _, err = deployment.ConfirmIfNoError(e.Chains[src], tx, err) - require.NoError(t, err) - - tx, err = dstToken.Approve(e.Chains[dest].DeployerKey, state.Chains[dest].Router.Address(), math.MaxBig256) - _, err = deployment.ConfirmIfNoError(e.Chains[dest], tx, err) - require.NoError(t, err) - - // Grant mint and burn roles to the deployer key for the newly deployed linkToken - // Since those roles are not granted automatically - tx, err = linkToken.GrantMintAndBurnRoles(e.Chains[src].DeployerKey, e.Chains[src].DeployerKey.From) - _, err = deployment.ConfirmIfNoError(e.Chains[src], tx, err) - require.NoError(t, err) - - // Mint link token and confirm the tx - tx, err = linkToken.Mint( - e.Chains[src].DeployerKey, - e.Chains[src].DeployerKey.From, - feeTokenMintAmount, - ) - _, err = deployment.ConfirmIfNoError(e.Chains[src], tx, err) - require.NoError(t, err) - - return srcToken, dstToken -} - -func Test_PricingForTokenTransfers(t *testing.T) { - t.Parallel() - tenv := changeset.NewMemoryEnvironmentWithJobsAndContracts(t, logger.TestLogger(t), 2, 4, nil) - e := tenv.Env - - allChains := tenv.Env.AllChainSelectors() - require.Len(t, allChains, 2, "need two chains for this test") - sourceChain := allChains[0] - destChain := allChains[1] - - // Get new state after migration. - state, err := changeset.LoadOnchainState(e) - require.NoError(t, err) - - srcToken, dstToken := setupTokens( - t, - state, - tenv, - sourceChain, - destChain, - deployment.E18Mult(10_000), - deployment.E18Mult(10_000), - ) - - // Ensure capreg logs are up to date. - changeset.ReplayLogs(t, e.Offchain, tenv.ReplayBlocks) - - // Add all lanes - require.NoError(t, changeset.AddLanesForAll(e, state)) - - t.Run("Send programmable token transfer pay with Link token", func(t *testing.T) { - runFeeTokenTestCase(feeTokenTestCase{ - t: t, - dst: destChain, - src: sourceChain, - env: tenv, - tokenAmounts: []router.ClientEVMTokenAmount{ - { - Token: srcToken.Address(), - Amount: deployment.E18Mult(2), - }, - }, - feeToken: state.Chains[sourceChain].LinkToken.Address(), - data: []byte("hello ptt world"), - receiver: common.LeftPadBytes(state.Chains[destChain].Receiver.Address().Bytes(), 32), - srcToken: srcToken, - dstToken: dstToken, - assertTokenBalance: true, - }) - }) - - t.Run("Send programmable token transfer pay with native", func(t *testing.T) { - runFeeTokenTestCase(feeTokenTestCase{ - t: t, - - // note the order of src and dest is reversed here - src: destChain, - dst: sourceChain, - - env: tenv, - tokenAmounts: []router.ClientEVMTokenAmount{ - { - Token: dstToken.Address(), - Amount: deployment.E18Mult(2), - }, - }, - feeToken: common.HexToAddress("0x0"), - data: []byte("hello ptt world"), - receiver: common.LeftPadBytes(state.Chains[sourceChain].Receiver.Address().Bytes(), 32), - - // note the order of src and dest is reversed here - srcToken: dstToken, - dstToken: srcToken, - assertTokenBalance: true, - }) - }) - - t.Run("Send programmable token transfer pay with wrapped native", func(t *testing.T) { - runFeeTokenTestCase(feeTokenTestCase{ - t: t, - src: sourceChain, - dst: destChain, - env: tenv, - tokenAmounts: []router.ClientEVMTokenAmount{ - { - Token: srcToken.Address(), - Amount: deployment.E18Mult(2), - }, - }, - feeToken: state.Chains[sourceChain].Weth9.Address(), - data: []byte("hello ptt world"), - receiver: common.LeftPadBytes(state.Chains[destChain].Receiver.Address().Bytes(), 32), - srcToken: srcToken, - dstToken: dstToken, - assertTokenBalance: true, - }) - }) - - t.Run("Send programmable token transfer but revert not enough tokens", func(t *testing.T) { - // Send to the receiver on the destination chain paying with LINK token - var ( - receiver = common.LeftPadBytes(state.Chains[destChain].Receiver.Address().Bytes(), 32) - data = []byte("") - feeToken = state.Chains[sourceChain].LinkToken.Address() - ) - - // Increase the token send amount to more than available to intentionally cause a revert - ccipMessage := router.ClientEVM2AnyMessage{ - Receiver: receiver, - Data: data, - TokenAmounts: []router.ClientEVMTokenAmount{ - { - Token: srcToken.Address(), - Amount: deployment.E18Mult(100_000_000), - }, - }, - FeeToken: feeToken, - ExtraArgs: nil, - } - - _, _, err = changeset.CCIPSendRequest( - e, - state, - sourceChain, destChain, - true, - ccipMessage, - ) - require.Error(t, err) - }) - - t.Run("Send data-only message pay with link token", func(t *testing.T) { - runFeeTokenTestCase(feeTokenTestCase{ - t: t, - src: sourceChain, - dst: destChain, - env: tenv, - // no tokens, only data - tokenAmounts: nil, - feeToken: state.Chains[sourceChain].LinkToken.Address(), - data: []byte("hello link world"), - receiver: common.LeftPadBytes(state.Chains[destChain].Receiver.Address().Bytes(), 32), - srcToken: srcToken, - dstToken: dstToken, - assertTokenBalance: false, - }) - }) - - t.Run("Send message pay with native", func(t *testing.T) { - runFeeTokenTestCase(feeTokenTestCase{ - t: t, - src: sourceChain, - dst: destChain, - env: tenv, - // no tokens, only data - tokenAmounts: nil, - feeToken: common.HexToAddress("0x0"), - data: []byte("hello native world"), - receiver: common.LeftPadBytes(state.Chains[destChain].Receiver.Address().Bytes(), 32), - srcToken: srcToken, - dstToken: dstToken, - assertTokenBalance: false, - }) - }) - - t.Run("Send message pay with wrapped native", func(t *testing.T) { - runFeeTokenTestCase(feeTokenTestCase{ - t: t, - src: sourceChain, - dst: destChain, - env: tenv, - // no tokens, only data - tokenAmounts: nil, - feeToken: state.Chains[sourceChain].Weth9.Address(), - data: []byte("hello wrapped native world"), - receiver: common.LeftPadBytes(state.Chains[destChain].Receiver.Address().Bytes(), 32), - srcToken: srcToken, - dstToken: dstToken, - assertTokenBalance: false, - }) - }) -} - -type feeTokenTestCase struct { - t *testing.T - src, dst uint64 - env changeset.DeployedEnv - srcToken, dstToken *burn_mint_erc677.BurnMintERC677 - tokenAmounts []router.ClientEVMTokenAmount - feeToken common.Address - receiver []byte - data []byte - assertTokenBalance bool -} - -func runFeeTokenTestCase(tc feeTokenTestCase) { - ctx := tests.Context(tc.t) - // Need to keep track of the block number for each chain so that event subscription can be done from that block. - startBlocks := make(map[uint64]*uint64) - expectedSeqNum := make(map[changeset.SourceDestPair]uint64) - expectedSeqNumExec := make(map[changeset.SourceDestPair][]uint64) - - srcChain := tc.env.Env.Chains[tc.src] - dstChain := tc.env.Env.Chains[tc.dst] - - state, err := changeset.LoadOnchainState(tc.env.Env) - require.NoError(tc.t, err) - - var dstTokBalanceBefore *big.Int - if tc.assertTokenBalance { - var err error - dstTokBalanceBefore, err = tc.dstToken.BalanceOf(nil, state.Chains[tc.dst].Receiver.Address()) - require.NoError(tc.t, err) - tc.t.Logf("destination token balance before of receiver %s: %s", - state.Chains[tc.dst].Receiver.Address(), - dstTokBalanceBefore.String()) - } - - // if fee token is not native then approve the router to spend the fee token from the sender. - var feeTokenWrapper *burn_mint_erc677.BurnMintERC677 - if tc.feeToken != common.HexToAddress("0x0") { - if tc.feeToken == state.Chains[tc.src].Weth9.Address() { - // Deposit some ETH into the WETH contract - weth9, err := weth9_wrapper.NewWETH9(state.Chains[tc.src].Weth9.Address(), srcChain.Client) - require.NoError(tc.t, err) - - balance, err := srcChain.Client.BalanceAt(ctx, srcChain.DeployerKey.From, nil) - require.NoError(tc.t, err) - - tc.t.Logf("balance before deposit: %s", balance.String()) - - srcChain.DeployerKey.Value = assets.Ether(100).ToInt() - tx, err := weth9.Deposit(srcChain.DeployerKey) - _, err = deployment.ConfirmIfNoError(srcChain, tx, err) - require.NoError(tc.t, err) - srcChain.DeployerKey.Value = big.NewInt(0) - } - - var err error - feeTokenWrapper, err = burn_mint_erc677.NewBurnMintERC677(tc.feeToken, srcChain.Client) - require.NoError(tc.t, err) - - // Approve the router to spend fee token - tx, err := feeTokenWrapper.Approve(srcChain.DeployerKey, state.Chains[tc.src].Router.Address(), math.MaxBig256) - - _, err = deployment.ConfirmIfNoError(srcChain, tx, err) - require.NoError(tc.t, err) - } - - // get the header for the destination chain and the relevant block number - latesthdr, err := dstChain.Client.HeaderByNumber(testcontext.Get(tc.t), nil) - require.NoError(tc.t, err) - block := latesthdr.Number.Uint64() - startBlocks[tc.dst] = &block - - // Get the fee Token Balance Before, if not fee token set get native balance. - var feeTokenBalanceBefore *big.Int - if feeTokenWrapper != nil { - feeTokenBalanceBefore, err = feeTokenWrapper.BalanceOf(&bind.CallOpts{ - Context: ctx, - }, srcChain.DeployerKey.From) - require.NoError(tc.t, err) - } else { - feeTokenBalanceBefore, err = srcChain.Client.BalanceAt(ctx, srcChain.DeployerKey.From, nil) - require.NoError(tc.t, err) - } - tc.t.Logf("fee token balance before: %s, fee token enabled: %s", - feeTokenBalanceBefore.String(), tc.feeToken.String()) - - msgSentEvent := changeset.TestSendRequest( - tc.t, - tc.env.Env, - state, - tc.src, - tc.dst, - false, - router.ClientEVM2AnyMessage{ - Receiver: tc.receiver, - Data: tc.data, - TokenAmounts: tc.tokenAmounts, - FeeToken: tc.feeToken, - ExtraArgs: nil, - }, - ) - - expectedSeqNum[changeset.SourceDestPair{ - SourceChainSelector: tc.src, - DestChainSelector: tc.dst, - }] = msgSentEvent.SequenceNumber - expectedSeqNumExec[changeset.SourceDestPair{ - SourceChainSelector: tc.src, - DestChainSelector: tc.dst, - }] = []uint64{msgSentEvent.SequenceNumber} - - // Check the fee token balance after the request and ensure fee tokens were spent - var feeTokenBalanceAfter *big.Int - if feeTokenWrapper != nil { - feeTokenBalanceAfter, err = feeTokenWrapper.BalanceOf(&bind.CallOpts{ - Context: ctx, - }, srcChain.DeployerKey.From) - require.NoError(tc.t, err) - } else { - feeTokenBalanceAfter, err = srcChain.Client.BalanceAt(ctx, srcChain.DeployerKey.From, nil) - require.NoError(tc.t, err) - } - tc.t.Logf("fee token balance after: %s, fee token: %s, fee paid: %s", - feeTokenBalanceAfter.String(), tc.feeToken.String(), msgSentEvent.Message.FeeTokenAmount) - // in the case we have no fee token, native is also used to pay for the tx, - // so we have to subtract that as well - if feeTokenWrapper == nil { - receipt, err := srcChain.Client.TransactionReceipt(ctx, msgSentEvent.Raw.TxHash) - require.NoError(tc.t, err) - txCostWei := new(big.Int).Mul(big.NewInt(int64(receipt.GasUsed)), receipt.EffectiveGasPrice) - feeTokenBalanceBefore.Sub(feeTokenBalanceBefore, txCostWei) - } - require.Equal( - tc.t, - feeTokenBalanceAfter, - new(big.Int).Sub(feeTokenBalanceBefore, msgSentEvent.Message.FeeTokenAmount), - ) - - // Wait for all commit reports to land. - changeset.ConfirmCommitForAllWithExpectedSeqNums(tc.t, tc.env.Env, state, expectedSeqNum, startBlocks) - - // After commit is reported on all chains, token prices should be updated in FeeQuoter. - linkAddress := state.Chains[tc.dst].LinkToken.Address() - feeQuoter := state.Chains[tc.dst].FeeQuoter - timestampedPrice, err := feeQuoter.GetTokenPrice(&bind.CallOpts{ - Context: ctx, - }, linkAddress) - require.NoError(tc.t, err) - require.Equal(tc.t, changeset.MockLinkPrice, timestampedPrice.Value) - - // Wait for all exec reports to land - changeset.ConfirmExecWithSeqNrsForAll(tc.t, tc.env.Env, state, expectedSeqNumExec, startBlocks) - - if tc.assertTokenBalance { - require.Len(tc.t, tc.tokenAmounts, 1) - expectedTransferAmount := tc.tokenAmounts[0].Amount - - balanceAfter, err := tc.dstToken.BalanceOf(&bind.CallOpts{ - Context: ctx, - }, state.Chains[tc.dst].Receiver.Address()) - require.NoError(tc.t, err) - require.Equal( - tc.t, - new(big.Int).Add(dstTokBalanceBefore, expectedTransferAmount), - balanceAfter, - ) - } -} From 85531a19faab09c7b6b20c49de6651b5c173e944 Mon Sep 17 00:00:00 2001 From: Makram Kamaleddine Date: Thu, 28 Nov 2024 21:22:34 +0400 Subject: [PATCH 18/18] fix lint --- integration-tests/smoke/ccip/ccip_fees_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration-tests/smoke/ccip/ccip_fees_test.go b/integration-tests/smoke/ccip/ccip_fees_test.go index 2b943de93ac..89b8b973036 100644 --- a/integration-tests/smoke/ccip/ccip_fees_test.go +++ b/integration-tests/smoke/ccip/ccip_fees_test.go @@ -406,7 +406,7 @@ func runFeeTokenTestCase(tc feeTokenTestCase) { if feeTokenWrapper == nil { receipt, err := srcChain.Client.TransactionReceipt(ctx, msgSentEvent.Raw.TxHash) require.NoError(tc.t, err) - txCostWei := new(big.Int).Mul(big.NewInt(int64(receipt.GasUsed)), receipt.EffectiveGasPrice) + txCostWei := new(big.Int).Mul(new(big.Int).SetUint64(receipt.GasUsed), receipt.EffectiveGasPrice) feeTokenBalanceBefore.Sub(feeTokenBalanceBefore, txCostWei) } require.Equal(