Skip to content

Commit

Permalink
message and programmable token transfer e2e tests
Browse files Browse the repository at this point in the history
  • Loading branch information
jhweintraub committed Nov 25, 2024
1 parent 89c2558 commit ad9aea9
Showing 1 changed file with 377 additions and 0 deletions.
377 changes: 377 additions & 0 deletions integration-tests/smoke/ccip/ccip_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
})

}

0 comments on commit ad9aea9

Please sign in to comment.