-
Notifications
You must be signed in to change notification settings - Fork 1.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[CCIP-5117] integration-tests/smoke/ccip: factor out fee test helpers #16496
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,228 @@ | ||
package feestest | ||
|
||
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-integrations/evm/assets" | ||
"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/deployment/ccip/changeset/testhelpers" | ||
"github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/v1_2_0/router" | ||
"github.com/smartcontractkit/chainlink/v2/core/gethwrappers/shared/generated/burn_mint_erc677" | ||
"github.com/smartcontractkit/chainlink/v2/core/gethwrappers/shared/generated/weth9" | ||
) | ||
|
||
// NewFeeTokenTestCase creates a new FeeTokenTestCase to test fee token usage scenarios. | ||
func NewFeeTokenTestCase( | ||
t *testing.T, | ||
env deployment.Environment, | ||
src, dst uint64, | ||
feeToken common.Address, | ||
tokenAmounts []router.ClientEVMTokenAmount, | ||
srcToken, dstToken *burn_mint_erc677.BurnMintERC677, | ||
receiver []byte, | ||
data []byte, | ||
assertTokenBalance, assertExecution bool, | ||
) FeeTokenTestCase { | ||
return FeeTokenTestCase{ | ||
t: t, | ||
src: src, | ||
dst: dst, | ||
env: env, | ||
srcToken: srcToken, | ||
dstToken: dstToken, | ||
tokenAmounts: tokenAmounts, | ||
feeToken: feeToken, | ||
receiver: receiver, | ||
data: data, | ||
assertTokenBalance: assertTokenBalance, | ||
assertExecution: assertExecution, | ||
} | ||
} | ||
|
||
type FeeTokenTestCase struct { | ||
t *testing.T | ||
src, dst uint64 | ||
env deployment.Environment | ||
srcToken, dstToken *burn_mint_erc677.BurnMintERC677 | ||
tokenAmounts []router.ClientEVMTokenAmount | ||
feeToken common.Address | ||
receiver []byte | ||
data []byte | ||
assertTokenBalance bool | ||
assertExecution bool | ||
} | ||
|
||
func RunFeeTokenTestCase(tc FeeTokenTestCase) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Code is basically copy/paste of what was in ccip_fees_test.go, just made public and moved to |
||
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[testhelpers.SourceDestPair]uint64) | ||
expectedSeqNumExec := make(map[testhelpers.SourceDestPair][]uint64) | ||
|
||
srcChain := tc.env.Chains[tc.src] | ||
dstChain := tc.env.Chains[tc.dst] | ||
|
||
state, err := changeset.LoadOnchainState(tc.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.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) | ||
|
||
bal, err := feeTokenWrapper.BalanceOf(&bind.CallOpts{ | ||
Context: ctx, | ||
}, srcChain.DeployerKey.From) | ||
require.NoError(tc.t, err) | ||
|
||
tc.t.Logf("fee token balance before approval: %s", bal.String()) | ||
|
||
// 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 := testhelpers.TestSendRequest( | ||
tc.t, | ||
tc.env, | ||
state, | ||
tc.src, | ||
tc.dst, | ||
false, | ||
router.ClientEVM2AnyMessage{ | ||
Receiver: tc.receiver, | ||
Data: tc.data, | ||
TokenAmounts: tc.tokenAmounts, | ||
FeeToken: tc.feeToken, | ||
ExtraArgs: nil, | ||
}, | ||
) | ||
|
||
expectedSeqNum[testhelpers.SourceDestPair{ | ||
SourceChainSelector: tc.src, | ||
DestChainSelector: tc.dst, | ||
}] = msgSentEvent.SequenceNumber | ||
expectedSeqNumExec[testhelpers.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(new(big.Int).SetUint64(receipt.GasUsed), receipt.EffectiveGasPrice) | ||
feeTokenBalanceBefore.Sub(feeTokenBalanceBefore, txCostWei) | ||
} | ||
require.Equal( | ||
tc.t, | ||
feeTokenBalanceAfter, | ||
new(big.Int).Sub(feeTokenBalanceBefore, msgSentEvent.Message.FeeTokenAmount), | ||
) | ||
|
||
if tc.assertExecution { | ||
// Wait for all commit reports to land. | ||
testhelpers.ConfirmCommitForAllWithExpectedSeqNums(tc.t, tc.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 | ||
testhelpers.ConfirmExecWithSeqNrsForAll(tc.t, tc.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, | ||
) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -221,10 +221,7 @@ func CCIPSendRequest( | |
} | ||
|
||
tx, err := r.CcipSend(cfg.Sender, cfg.DestChain, msg) | ||
if err != nil { | ||
return nil, 0, errors.Wrap(err, "failed to send CCIP message") | ||
} | ||
blockNum, err := e.Chains[cfg.SourceChain].Confirm(tx) | ||
blockNum, err := deployment.ConfirmIfNoErrorWithABI(e.Chains[cfg.SourceChain], tx, router.RouterABI, err) | ||
Comment on lines
-227
to
+224
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Prints out revert reason, useful |
||
if err != nil { | ||
return tx, 0, errors.Wrap(err, "failed to confirm CCIP message") | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was taking really long on my PC but I think there's an issue w/ my PC. Anyway, doesn't hurt to bump, will revisit this once we drop round times significantly and make the tests faster.