diff --git a/integration-tests/actions/seth/actions.go b/integration-tests/actions/seth/actions.go index 79ef6edb357..59554d21cfc 100644 --- a/integration-tests/actions/seth/actions.go +++ b/integration-tests/actions/seth/actions.go @@ -177,10 +177,10 @@ func SendFunds(logger zerolog.Logger, client *seth.Client, payload FundsToSendPa func DeployForwarderContracts( t *testing.T, seth *seth.Client, - linkTokenData seth.DeploymentData, + linkTokenAddress common.Address, numberOfOperatorForwarderPairs int, ) (operators []common.Address, authorizedForwarders []common.Address, operatorFactoryInstance contracts.OperatorFactory) { - instance, err := contracts.DeployEthereumOperatorFactory(seth, linkTokenData.Address) + instance, err := contracts.DeployEthereumOperatorFactory(seth, linkTokenAddress) require.NoError(t, err, "failed to create new instance of operator factory") operatorFactoryInstance = &instance diff --git a/integration-tests/actions/vrf/vrfv1/actions.go b/integration-tests/actions/vrf/vrfv1/actions.go index f8d7190709f..67110c543e5 100644 --- a/integration-tests/actions/vrf/vrfv1/actions.go +++ b/integration-tests/actions/vrf/vrfv1/actions.go @@ -3,7 +3,8 @@ package vrfv1 import ( "fmt" - "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + "github.com/smartcontractkit/seth" + "github.com/smartcontractkit/chainlink/integration-tests/contracts" ) @@ -19,21 +20,18 @@ type Contracts struct { Consumer contracts.VRFConsumer } -func DeployVRFContracts(cd contracts.ContractDeployer, bc blockchain.EVMClient, lt contracts.LinkToken) (*Contracts, error) { - bhs, err := cd.DeployBlockhashStore() +func DeployVRFContracts(client *seth.Client, linkTokenAddress string) (*Contracts, error) { + bhs, err := contracts.DeployBlockhashStore(client) if err != nil { return nil, fmt.Errorf("%s, err %w", ErrDeployBHSV1, err) } - coordinator, err := cd.DeployVRFCoordinator(lt.Address(), bhs.Address()) + coordinator, err := contracts.DeployVRFCoordinator(client, linkTokenAddress, bhs.Address()) if err != nil { return nil, fmt.Errorf("%s, err %w", ErrDeployVRFCootrinatorV1, err) } - consumer, err := cd.DeployVRFConsumer(lt.Address(), coordinator.Address()) + consumer, err := contracts.DeployVRFConsumer(client, linkTokenAddress, coordinator.Address()) if err != nil { return nil, fmt.Errorf("%s, err %w", ErrDeployVRFConsumerV1, err) } - if err := bc.WaitForEvents(); err != nil { - return nil, err - } return &Contracts{bhs, coordinator, consumer}, nil } diff --git a/integration-tests/chaos/ocr_chaos_test.go b/integration-tests/chaos/ocr_chaos_test.go index c99318d51dd..6e397694cc9 100644 --- a/integration-tests/chaos/ocr_chaos_test.go +++ b/integration-tests/chaos/ocr_chaos_test.go @@ -5,6 +5,7 @@ import ( "math/big" "testing" + "github.com/ethereum/go-ethereum/common" "github.com/onsi/gomega" "github.com/smartcontractkit/seth" "github.com/stretchr/testify/require" @@ -187,13 +188,13 @@ func TestOCRChaos(t *testing.T) { ms, err := ctfClient.ConnectMockServer(testEnvironment) require.NoError(t, err, "Creating mockserver clients shouldn't fail") - linkDeploymentData, err := contracts.DeployLinkTokenContract(seth) + linkContract, err := contracts.DeployLinkTokenContract(l, seth) require.NoError(t, err, "Error deploying link token contract") err = actions_seth.FundChainlinkNodesFromRootAddress(l, seth, contracts.ChainlinkK8sClientToChainlinkNodeWithKeysAndAddress(chainlinkNodes), big.NewFloat(10)) require.NoError(t, err) - ocrInstances, err := actions_seth.DeployOCRv1Contracts(l, seth, 1, linkDeploymentData.Address, contracts.ChainlinkK8sClientToChainlinkNodeWithKeysAndAddress(workerNodes)) + ocrInstances, err := actions_seth.DeployOCRv1Contracts(l, seth, 1, common.HexToAddress(linkContract.Address()), contracts.ChainlinkK8sClientToChainlinkNodeWithKeysAndAddress(workerNodes)) require.NoError(t, err) err = actions.CreateOCRJobs(ocrInstances, bootstrapNode, workerNodes, 5, ms, fmt.Sprint(seth.ChainID)) require.NoError(t, err) diff --git a/integration-tests/contracts/contract_deployer.go b/integration-tests/contracts/contract_deployer.go index c7407b79e54..675afa58fda 100644 --- a/integration-tests/contracts/contract_deployer.go +++ b/integration-tests/contracts/contract_deployer.go @@ -539,7 +539,7 @@ func (e *EthereumContractDeployer) DeployLinkTokenContract() (LinkToken, error) return nil, err } - return &EthereumLinkToken{ + return &LegacyEthereumLinkToken{ client: e.client, instance: instance.(*link_token_interface.LinkToken), address: *linkTokenAddress, @@ -558,7 +558,7 @@ func (e *EthereumContractDeployer) LoadLinkToken(address common.Address) (LinkTo if err != nil { return nil, err } - return &EthereumLinkToken{ + return &LegacyEthereumLinkToken{ address: address, client: e.client, instance: instance.(*link_token_interface.LinkToken), diff --git a/integration-tests/contracts/contract_loader.go b/integration-tests/contracts/contract_loader.go index 9c26a671194..38b09687c20 100644 --- a/integration-tests/contracts/contract_loader.go +++ b/integration-tests/contracts/contract_loader.go @@ -181,7 +181,7 @@ func (e *EthereumContractLoader) LoadLINKToken(addr string) (LinkToken, error) { if err != nil { return nil, err } - return &EthereumLinkToken{ + return &LegacyEthereumLinkToken{ client: e.client, instance: instance.(*link_token_interface.LinkToken), address: common.HexToAddress(addr), diff --git a/integration-tests/contracts/ethereum_contracts.go b/integration-tests/contracts/ethereum_contracts.go index 1035a073f51..f7fa3803204 100644 --- a/integration-tests/contracts/ethereum_contracts.go +++ b/integration-tests/contracts/ethereum_contracts.go @@ -1192,8 +1192,8 @@ func (f *FluxAggregatorRoundConfirmer) Complete() bool { return f.complete } -// EthereumLinkToken represents a LinkToken address -type EthereumLinkToken struct { +// LegacyEthereumLinkToken represents a LinkToken address +type LegacyEthereumLinkToken struct { client blockchain.EVMClient instance *link_token_interface.LinkToken address common.Address @@ -1201,7 +1201,7 @@ type EthereumLinkToken struct { } // Fund the LINK Token contract with ETH to distribute the token -func (l *EthereumLinkToken) Fund(ethAmount *big.Float) error { +func (l *LegacyEthereumLinkToken) Fund(ethAmount *big.Float) error { gasEstimates, err := l.client.EstimateGas(ethereum.CallMsg{ To: &l.address, }) @@ -1211,7 +1211,7 @@ func (l *EthereumLinkToken) Fund(ethAmount *big.Float) error { return l.client.Fund(l.address.Hex(), ethAmount, gasEstimates) } -func (l *EthereumLinkToken) BalanceOf(ctx context.Context, addr string) (*big.Int, error) { +func (l *LegacyEthereumLinkToken) BalanceOf(ctx context.Context, addr string) (*big.Int, error) { opts := &bind.CallOpts{ From: common.HexToAddress(l.client.GetDefaultWallet().Address()), Context: ctx, @@ -1224,7 +1224,7 @@ func (l *EthereumLinkToken) BalanceOf(ctx context.Context, addr string) (*big.In } // Name returns the name of the link token -func (l *EthereumLinkToken) Name(ctxt context.Context) (string, error) { +func (l *LegacyEthereumLinkToken) Name(ctxt context.Context) (string, error) { opts := &bind.CallOpts{ From: common.HexToAddress(l.client.GetDefaultWallet().Address()), Context: ctxt, @@ -1232,11 +1232,11 @@ func (l *EthereumLinkToken) Name(ctxt context.Context) (string, error) { return l.instance.Name(opts) } -func (l *EthereumLinkToken) Address() string { +func (l *LegacyEthereumLinkToken) Address() string { return l.address.Hex() } -func (l *EthereumLinkToken) Approve(to string, amount *big.Int) error { +func (l *LegacyEthereumLinkToken) Approve(to string, amount *big.Int) error { opts, err := l.client.TransactionOpts(l.client.GetDefaultWallet()) if err != nil { return err @@ -1254,7 +1254,7 @@ func (l *EthereumLinkToken) Approve(to string, amount *big.Int) error { return l.client.ProcessTransaction(tx) } -func (l *EthereumLinkToken) Transfer(to string, amount *big.Int) error { +func (l *LegacyEthereumLinkToken) Transfer(to string, amount *big.Int) error { opts, err := l.client.TransactionOpts(l.client.GetDefaultWallet()) if err != nil { return err @@ -1272,7 +1272,7 @@ func (l *EthereumLinkToken) Transfer(to string, amount *big.Int) error { return l.client.ProcessTransaction(tx) } -func (l *EthereumLinkToken) TransferAndCall(to string, amount *big.Int, data []byte) (*types.Transaction, error) { +func (l *LegacyEthereumLinkToken) TransferAndCall(to string, amount *big.Int, data []byte) (*types.Transaction, error) { opts, err := l.client.TransactionOpts(l.client.GetDefaultWallet()) if err != nil { return nil, err diff --git a/integration-tests/contracts/ethereum_contracts_seth.go b/integration-tests/contracts/ethereum_contracts_seth.go index a2703a0e019..5101a20ba48 100644 --- a/integration-tests/contracts/ethereum_contracts_seth.go +++ b/integration-tests/contracts/ethereum_contracts_seth.go @@ -20,9 +20,9 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/wrappers" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/authorized_forwarder" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/link_token_interface" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/operator_factory" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/operator_wrapper" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/shared/generated/link_token" ) // EthereumOffchainAggregator represents the offchain aggregation contract @@ -568,15 +568,91 @@ func (e *EthereumOffchainAggregatorV2) ParseEventAnswerUpdated(log types.Log) (* return e.contract.ParseAnswerUpdated(log) } -func DeployLinkTokenContract(client *seth.Client) (seth.DeploymentData, error) { - linkTokenAbi, err := link_token.LinkTokenMetaData.GetAbi() +// EthereumLinkToken represents a LinkToken address +type EthereumLinkToken struct { + client *seth.Client + instance *link_token_interface.LinkToken + address common.Address + l zerolog.Logger +} + +func DeployLinkTokenContract(l zerolog.Logger, client *seth.Client) (*EthereumLinkToken, error) { + linkTokenAbi, err := link_token_interface.LinkTokenMetaData.GetAbi() if err != nil { - return seth.DeploymentData{}, fmt.Errorf("failed to get LinkToken ABI: %w", err) + return &EthereumLinkToken{}, fmt.Errorf("failed to get LinkToken ABI: %w", err) } - linkDeploymentData, err := client.DeployContract(client.NewTXOpts(), "LinkToken", *linkTokenAbi, common.FromHex(link_token.LinkTokenMetaData.Bin)) + linkDeploymentData, err := client.DeployContract(client.NewTXOpts(), "LinkToken", *linkTokenAbi, common.FromHex(link_token_interface.LinkTokenMetaData.Bin)) if err != nil { - return seth.DeploymentData{}, fmt.Errorf("LinkToken instance deployment have failed: %w", err) + return &EthereumLinkToken{}, fmt.Errorf("LinkToken instance deployment have failed: %w", err) } - return linkDeploymentData, nil + linkToken, err := link_token_interface.NewLinkToken(linkDeploymentData.Address, wrappers.MustNewWrappedContractBackend(nil, client)) + if err != nil { + return &EthereumLinkToken{}, fmt.Errorf("failed to instantiate LinkToken instance: %w", err) + } + + return &EthereumLinkToken{ + client: client, + instance: linkToken, + address: linkDeploymentData.Address, + l: l, + }, nil +} + +// Fund the LINK Token contract with ETH to distribute the token +func (l *EthereumLinkToken) Fund(_ *big.Float) error { + panic("do not use this function, use actions_seth.SendFunds instead") +} + +func (l *EthereumLinkToken) BalanceOf(ctx context.Context, addr string) (*big.Int, error) { + return l.instance.BalanceOf(&bind.CallOpts{ + From: l.client.Addresses[0], + Context: ctx, + }, common.HexToAddress(addr)) + +} + +// Name returns the name of the link token +func (l *EthereumLinkToken) Name(ctx context.Context) (string, error) { + return l.instance.Name(&bind.CallOpts{ + From: l.client.Addresses[0], + Context: ctx, + }) +} + +func (l *EthereumLinkToken) Address() string { + return l.address.Hex() +} + +func (l *EthereumLinkToken) Approve(to string, amount *big.Int) error { + l.l.Info(). + Str("From", l.client.Addresses[0].Hex()). + Str("To", to). + Str("Amount", amount.String()). + Msg("Approving LINK Transfer") + _, err := l.client.Decode(l.instance.Approve(l.client.NewTXOpts(), common.HexToAddress(to), amount)) + return err +} + +func (l *EthereumLinkToken) Transfer(to string, amount *big.Int) error { + l.l.Info(). + Str("From", l.client.Addresses[0].Hex()). + Str("To", to). + Str("Amount", amount.String()). + Msg("Transferring LINK") + _, err := l.client.Decode(l.instance.Transfer(l.client.NewTXOpts(), common.HexToAddress(to), amount)) + return err +} + +func (l *EthereumLinkToken) TransferAndCall(to string, amount *big.Int, data []byte) (*types.Transaction, error) { + l.l.Info(). + Str("From", l.client.Addresses[0].Hex()). + Str("To", to). + Str("Amount", amount.String()). + Msg("Transferring and Calling LINK") + decodedTx, err := l.client.Decode(l.instance.TransferAndCall(l.client.NewTXOpts(), common.HexToAddress(to), amount, data)) + if err != nil { + return nil, err + } + return decodedTx.Transaction, nil } diff --git a/integration-tests/contracts/ethereum_ocr2vrf_contracts.go b/integration-tests/contracts/ethereum_ocr2vrf_contracts.go index cb52d1941a8..473b308dc42 100644 --- a/integration-tests/contracts/ethereum_ocr2vrf_contracts.go +++ b/integration-tests/contracts/ethereum_ocr2vrf_contracts.go @@ -49,8 +49,8 @@ type EthereumVRFBeaconConsumer struct { vrfBeaconConsumer *vrf_beacon_consumer.BeaconVRFConsumer } -// EthereumVRFCoordinator represents VRF coordinator contract -type EthereumVRFCoordinator struct { +// LegacyEthereumVRFCoordinator represents VRF coordinator contract +type LegacyEthereumVRFCoordinator struct { address *common.Address client blockchain.EVMClient coordinator *solidity_vrf_coordinator_interface.VRFCoordinator @@ -125,7 +125,7 @@ func (e *EthereumContractDeployer) DeployBatchBlockhashStore(blockhashStoreAddr if err != nil { return nil, err } - return &EthereumBatchBlockhashStore{ + return &LegacyEthereumBatchBlockhashStore{ client: e.client, batchBlockhashStore: instance.(*batch_blockhash_store.BatchBlockhashStore), address: address, diff --git a/integration-tests/contracts/ethereum_vrf_contracts.go b/integration-tests/contracts/ethereum_vrf_contracts.go index a67d30bd201..c2f12e29446 100644 --- a/integration-tests/contracts/ethereum_vrf_contracts.go +++ b/integration-tests/contracts/ethereum_vrf_contracts.go @@ -21,22 +21,22 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/solidity_vrf_wrapper" ) -// EthereumBatchBlockhashStore represents BatchBlockhashStore contract -type EthereumBatchBlockhashStore struct { +// LegacyEthereumBatchBlockhashStore represents BatchBlockhashStore contract +type LegacyEthereumBatchBlockhashStore struct { address *common.Address client blockchain.EVMClient batchBlockhashStore *batch_blockhash_store.BatchBlockhashStore } -// EthereumBlockhashStore represents a blockhash store for VRF contract -type EthereumBlockhashStore struct { +// LegacyEthereumBlockhashStore represents a blockhash store for VRF contract +type LegacyEthereumBlockhashStore struct { address *common.Address client blockchain.EVMClient blockHashStore *blockhash_store.BlockhashStore } -// EthereumVRFConsumer represents VRF consumer contract -type EthereumVRFConsumer struct { +// LegacyEthereumVRFConsumer represents VRF consumer contract +type LegacyEthereumVRFConsumer struct { address *common.Address client blockchain.EVMClient consumer *solidity_vrf_consumer_interface.VRFConsumer @@ -52,8 +52,8 @@ type VRFConsumerRoundConfirmer struct { done bool } -// EthereumVRF represents a VRF contract -type EthereumVRF struct { +// LegacyEthereumVRF represents a VRF contract +type LegacyEthereumVRF struct { client blockchain.EVMClient vrf *solidity_vrf_wrapper.VRF address *common.Address @@ -70,7 +70,7 @@ func (e *EthereumContractDeployer) DeployVRFContract() (VRF, error) { if err != nil { return nil, err } - return &EthereumVRF{ + return &LegacyEthereumVRF{ client: e.client, vrf: instance.(*solidity_vrf_wrapper.VRF), address: address, @@ -88,7 +88,7 @@ func (e *EthereumContractDeployer) DeployBlockhashStore() (BlockHashStore, error if err != nil { return nil, err } - return &EthereumBlockhashStore{ + return &LegacyEthereumBlockhashStore{ client: e.client, blockHashStore: instance.(*blockhash_store.BlockhashStore), address: address, @@ -106,7 +106,7 @@ func (e *EthereumContractDeployer) DeployVRFCoordinator(linkAddr string, bhsAddr if err != nil { return nil, err } - return &EthereumVRFCoordinator{ + return &LegacyEthereumVRFCoordinator{ client: e.client, coordinator: instance.(*solidity_vrf_coordinator_interface.VRFCoordinator), address: address, @@ -124,18 +124,18 @@ func (e *EthereumContractDeployer) DeployVRFConsumer(linkAddr string, coordinato if err != nil { return nil, err } - return &EthereumVRFConsumer{ + return &LegacyEthereumVRFConsumer{ client: e.client, consumer: instance.(*solidity_vrf_consumer_interface.VRFConsumer), address: address, }, err } -func (v *EthereumBlockhashStore) Address() string { +func (v *LegacyEthereumBlockhashStore) Address() string { return v.address.Hex() } -func (v *EthereumBlockhashStore) GetBlockHash(ctx context.Context, blockNumber *big.Int) ([32]byte, error) { +func (v *LegacyEthereumBlockhashStore) GetBlockHash(ctx context.Context, blockNumber *big.Int) ([32]byte, error) { opts := &bind.CallOpts{ From: common.HexToAddress(v.client.GetDefaultWallet().Address()), Context: ctx, @@ -147,12 +147,12 @@ func (v *EthereumBlockhashStore) GetBlockHash(ctx context.Context, blockNumber * return blockHash, nil } -func (v *EthereumVRFCoordinator) Address() string { +func (v *LegacyEthereumVRFCoordinator) Address() string { return v.address.Hex() } // HashOfKey get a hash of proving key to use it as a request ID part for VRF -func (v *EthereumVRFCoordinator) HashOfKey(ctx context.Context, pubKey [2]*big.Int) ([32]byte, error) { +func (v *LegacyEthereumVRFCoordinator) HashOfKey(ctx context.Context, pubKey [2]*big.Int) ([32]byte, error) { opts := &bind.CallOpts{ From: common.HexToAddress(v.client.GetDefaultWallet().Address()), Context: ctx, @@ -165,7 +165,7 @@ func (v *EthereumVRFCoordinator) HashOfKey(ctx context.Context, pubKey [2]*big.I } // RegisterProvingKey register VRF proving key -func (v *EthereumVRFCoordinator) RegisterProvingKey( +func (v *LegacyEthereumVRFCoordinator) RegisterProvingKey( fee *big.Int, oracleAddr string, publicProvingKey [2]*big.Int, @@ -182,11 +182,11 @@ func (v *EthereumVRFCoordinator) RegisterProvingKey( return v.client.ProcessTransaction(tx) } -func (v *EthereumVRFConsumer) Address() string { +func (v *LegacyEthereumVRFConsumer) Address() string { return v.address.Hex() } -func (v *EthereumVRFConsumer) Fund(ethAmount *big.Float) error { +func (v *LegacyEthereumVRFConsumer) Fund(ethAmount *big.Float) error { gasEstimates, err := v.client.EstimateGas(ethereum.CallMsg{ To: v.address, }) @@ -197,7 +197,7 @@ func (v *EthereumVRFConsumer) Fund(ethAmount *big.Float) error { } // RequestRandomness requests VRF randomness -func (v *EthereumVRFConsumer) RequestRandomness(hash [32]byte, fee *big.Int) error { +func (v *LegacyEthereumVRFConsumer) RequestRandomness(hash [32]byte, fee *big.Int) error { opts, err := v.client.TransactionOpts(v.client.GetDefaultWallet()) if err != nil { return err @@ -210,7 +210,7 @@ func (v *EthereumVRFConsumer) RequestRandomness(hash [32]byte, fee *big.Int) err } // CurrentRoundID helper roundID counter in consumer to check when all randomness requests are finished -func (v *EthereumVRFConsumer) CurrentRoundID(ctx context.Context) (*big.Int, error) { +func (v *LegacyEthereumVRFConsumer) CurrentRoundID(ctx context.Context) (*big.Int, error) { opts := &bind.CallOpts{ From: common.HexToAddress(v.client.GetDefaultWallet().Address()), Context: ctx, @@ -219,7 +219,7 @@ func (v *EthereumVRFConsumer) CurrentRoundID(ctx context.Context) (*big.Int, err } // RandomnessOutput get VRF randomness output -func (v *EthereumVRFConsumer) RandomnessOutput(ctx context.Context) (*big.Int, error) { +func (v *LegacyEthereumVRFConsumer) RandomnessOutput(ctx context.Context) (*big.Int, error) { opts := &bind.CallOpts{ From: common.HexToAddress(v.client.GetDefaultWallet().Address()), Context: ctx, @@ -290,7 +290,7 @@ func (f *VRFConsumerRoundConfirmer) Wait() error { } // Fund sends specified currencies to the contract -func (v *EthereumVRF) Fund(ethAmount *big.Float) error { +func (v *LegacyEthereumVRF) Fund(ethAmount *big.Float) error { gasEstimates, err := v.client.EstimateGas(ethereum.CallMsg{ To: v.address, }) @@ -301,7 +301,7 @@ func (v *EthereumVRF) Fund(ethAmount *big.Float) error { } // ProofLength returns the PROOFLENGTH call from the VRF contract -func (v *EthereumVRF) ProofLength(ctxt context.Context) (*big.Int, error) { +func (v *LegacyEthereumVRF) ProofLength(ctxt context.Context) (*big.Int, error) { opts := &bind.CallOpts{ From: common.HexToAddress(v.client.GetDefaultWallet().Address()), Context: ctxt, @@ -309,6 +309,6 @@ func (v *EthereumVRF) ProofLength(ctxt context.Context) (*big.Int, error) { return v.vrf.PROOFLENGTH(opts) } -func (v *EthereumBatchBlockhashStore) Address() string { +func (v *LegacyEthereumBatchBlockhashStore) Address() string { return v.address.Hex() } diff --git a/integration-tests/contracts/ethereum_vrf_contracts_seth.go b/integration-tests/contracts/ethereum_vrf_contracts_seth.go new file mode 100644 index 00000000000..f352e901a0c --- /dev/null +++ b/integration-tests/contracts/ethereum_vrf_contracts_seth.go @@ -0,0 +1,247 @@ +package contracts + +import ( + "context" + "fmt" + "math/big" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/smartcontractkit/seth" + + "github.com/smartcontractkit/chainlink/integration-tests/wrappers" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/blockhash_store" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/solidity_vrf_consumer_interface" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/solidity_vrf_coordinator_interface" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/solidity_vrf_wrapper" +) + +// EthereumBlockhashStore represents a blockhash store for VRF contract +type EthereumBlockhashStore struct { + address *common.Address + client *seth.Client + blockHashStore *blockhash_store.BlockhashStore +} + +// EthereumVRFCoordinator represents VRF coordinator contract +type EthereumVRFCoordinator struct { + address *common.Address + client *seth.Client + coordinator *solidity_vrf_coordinator_interface.VRFCoordinator +} + +// EthereumVRFConsumer represents VRF consumer contract +type EthereumVRFConsumer struct { + address *common.Address + client *seth.Client + consumer *solidity_vrf_consumer_interface.VRFConsumer +} + +// EthereumVRF represents a VRF contract +type EthereumVRF struct { + client *seth.Client + vrf *solidity_vrf_wrapper.VRF + address *common.Address +} + +// DeployVRFContract deploy VRFv1 contract +func DeployVRFv1Contract(seth *seth.Client) (VRF, error) { + abi, err := solidity_vrf_wrapper.VRFMetaData.GetAbi() + if err != nil { + return &EthereumVRF{}, fmt.Errorf("failed to get VRF ABI: %w", err) + } + + vrfDeploymentData, err := seth.DeployContract( + seth.NewTXOpts(), + "VRF", + *abi, + common.FromHex(solidity_vrf_wrapper.VRFMetaData.Bin)) + if err != nil { + return &EthereumVRF{}, fmt.Errorf("VRF instance deployment have failed: %w", err) + } + + vrf, err := solidity_vrf_wrapper.NewVRF(vrfDeploymentData.Address, wrappers.MustNewWrappedContractBackend(nil, seth)) + if err != nil { + return &EthereumVRF{}, fmt.Errorf("failed to instantiate VRF instance: %w", err) + } + + return &EthereumVRF{ + client: seth, + vrf: vrf, + address: &vrfDeploymentData.Address, + }, err +} + +// DeployBlockhashStore deploys blockhash store used with VRF contract +func DeployBlockhashStore(seth *seth.Client) (BlockHashStore, error) { + abi, err := blockhash_store.BlockhashStoreMetaData.GetAbi() + if err != nil { + return &EthereumBlockhashStore{}, fmt.Errorf("failed to get BlockhashStore ABI: %w", err) + } + + storeDeploymentData, err := seth.DeployContract( + seth.NewTXOpts(), + "BlockhashStore", + *abi, + common.FromHex(blockhash_store.BlockhashStoreMetaData.Bin)) + if err != nil { + return &EthereumBlockhashStore{}, fmt.Errorf("BlockhashStore instance deployment have failed: %w", err) + } + + store, err := blockhash_store.NewBlockhashStore(storeDeploymentData.Address, wrappers.MustNewWrappedContractBackend(nil, seth)) + if err != nil { + return &EthereumBlockhashStore{}, fmt.Errorf("failed to instantiate BlockhashStore instance: %w", err) + } + + return &EthereumBlockhashStore{ + client: seth, + blockHashStore: store, + address: &storeDeploymentData.Address, + }, err +} + +// DeployVRFCoordinator deploys VRF coordinator contract +func DeployVRFCoordinator(seth *seth.Client, linkAddr, bhsAddr string) (VRFCoordinator, error) { + abi, err := solidity_vrf_coordinator_interface.VRFCoordinatorMetaData.GetAbi() + if err != nil { + return &EthereumVRFCoordinator{}, fmt.Errorf("failed to get VRFCoordinator ABI: %w", err) + } + + coordinatorDeploymentData, err := seth.DeployContract( + seth.NewTXOpts(), + "VRFCoordinator", + *abi, + common.FromHex(solidity_vrf_coordinator_interface.VRFCoordinatorMetaData.Bin), + common.HexToAddress(linkAddr), + common.HexToAddress(bhsAddr)) + if err != nil { + return &EthereumVRFCoordinator{}, fmt.Errorf("VRFCoordinator instance deployment have failed: %w", err) + } + + coordinator, err := solidity_vrf_coordinator_interface.NewVRFCoordinator(coordinatorDeploymentData.Address, wrappers.MustNewWrappedContractBackend(nil, seth)) + if err != nil { + return &EthereumVRFCoordinator{}, fmt.Errorf("failed to instantiate VRFCoordinator instance: %w", err) + } + + return &EthereumVRFCoordinator{ + client: seth, + coordinator: coordinator, + address: &coordinatorDeploymentData.Address, + }, err +} + +// DeployVRFConsumer deploys VRF consumer contract +func DeployVRFConsumer(seth *seth.Client, linkAddr, coordinatorAddr string) (VRFConsumer, error) { + abi, err := solidity_vrf_consumer_interface.VRFConsumerMetaData.GetAbi() + if err != nil { + return &EthereumVRFConsumer{}, fmt.Errorf("failed to get VRFConsumer ABI: %w", err) + } + + consumerDeploymentData, err := seth.DeployContract( + seth.NewTXOpts(), + "VRFConsumer", + *abi, + common.FromHex(solidity_vrf_consumer_interface.VRFConsumerMetaData.Bin), + common.HexToAddress(coordinatorAddr), + common.HexToAddress(linkAddr), + ) + if err != nil { + return &EthereumVRFConsumer{}, fmt.Errorf("VRFConsumer instance deployment have failed: %w", err) + } + + consumer, err := solidity_vrf_consumer_interface.NewVRFConsumer(consumerDeploymentData.Address, wrappers.MustNewWrappedContractBackend(nil, seth)) + if err != nil { + return &EthereumVRFConsumer{}, fmt.Errorf("failed to instantiate VRFConsumer instance: %w", err) + } + + return &EthereumVRFConsumer{ + client: seth, + consumer: consumer, + address: &consumerDeploymentData.Address, + }, err +} + +func (v *EthereumBlockhashStore) Address() string { + return v.address.Hex() +} + +func (v *EthereumBlockhashStore) GetBlockHash(ctx context.Context, blockNumber *big.Int) ([32]byte, error) { + blockHash, err := v.blockHashStore.GetBlockhash(&bind.CallOpts{ + From: v.client.Addresses[0], + Context: ctx, + }, blockNumber) + if err != nil { + return [32]byte{}, err + } + return blockHash, nil +} + +func (v *EthereumVRFCoordinator) Address() string { + return v.address.Hex() +} + +// HashOfKey get a hash of proving key to use it as a request ID part for VRF +func (v *EthereumVRFCoordinator) HashOfKey(ctx context.Context, pubKey [2]*big.Int) ([32]byte, error) { + hash, err := v.coordinator.HashOfKey(&bind.CallOpts{ + From: v.client.Addresses[0], + Context: ctx, + }, pubKey) + if err != nil { + return [32]byte{}, err + } + return hash, nil +} + +// RegisterProvingKey register VRF proving key +func (v *EthereumVRFCoordinator) RegisterProvingKey( + fee *big.Int, + oracleAddr string, + publicProvingKey [2]*big.Int, + jobID [32]byte, +) error { + _, err := v.client.Decode(v.coordinator.RegisterProvingKey(v.client.NewTXOpts(), fee, common.HexToAddress(oracleAddr), publicProvingKey, jobID)) + return err +} + +func (v *EthereumVRFConsumer) Address() string { + return v.address.Hex() +} + +func (v *EthereumVRFConsumer) Fund(_ *big.Float) error { + panic("do not use this function, use actions_seth.SendFunds() instead, otherwise we will have to deal with circular dependencies") +} + +// RequestRandomness requests VRF randomness +func (v *EthereumVRFConsumer) RequestRandomness(hash [32]byte, fee *big.Int) error { + _, err := v.client.Decode(v.consumer.TestRequestRandomness(v.client.NewTXOpts(), hash, fee)) + return err +} + +// CurrentRoundID helper roundID counter in consumer to check when all randomness requests are finished +func (v *EthereumVRFConsumer) CurrentRoundID(ctx context.Context) (*big.Int, error) { + return v.consumer.CurrentRoundID(&bind.CallOpts{ + From: v.client.Addresses[0], + Context: ctx, + }) +} + +// RandomnessOutput get VRF randomness output +func (v *EthereumVRFConsumer) RandomnessOutput(ctx context.Context) (*big.Int, error) { + return v.consumer.RandomnessOutput(&bind.CallOpts{ + From: v.client.Addresses[0], + Context: ctx, + }) +} + +// Fund sends specified currencies to the contract +func (v *EthereumVRF) Fund(_ *big.Float) error { + panic("do not use this function, use actions_seth.SendFunds() instead, otherwise we will have to deal with circular dependencies") +} + +// ProofLength returns the PROOFLENGTH call from the VRF contract +func (v *EthereumVRF) ProofLength(ctx context.Context) (*big.Int, error) { + return v.vrf.PROOFLENGTH(&bind.CallOpts{ + From: v.client.Addresses[0], + Context: ctx, + }) +} diff --git a/integration-tests/docker/test_env/test_env.go b/integration-tests/docker/test_env/test_env.go index d2f13387d36..13e92c50a1f 100644 --- a/integration-tests/docker/test_env/test_env.go +++ b/integration-tests/docker/test_env/test_env.go @@ -39,7 +39,7 @@ type CLClusterTestEnv struct { ClCluster *ClCluster MockAdapter *test_env.Killgrave evmClients map[int64]blockchain.EVMClient - SethClient *seth.Client + sethClients map[int64]*seth.Client ContractDeployer contracts.ContractDeployer ContractLoader contracts.ContractLoader PrivateEthereumConfigs []*test_env.EthereumNetwork // new approach to private chains, supporting eth1 and eth2 @@ -198,7 +198,7 @@ func (te *CLClusterTestEnv) Cleanup() error { te.logWhetherAllContainersAreRunning() - if len(te.evmClients) == 0 && te.SethClient == nil { + if len(te.evmClients) == 0 && len(te.sethClients) == 0 { return fmt.Errorf("both EVMClients and SethClient are nil, unable to return funds from chainlink nodes during cleanup") } else if te.isSimulatedNetwork { te.l.Info(). @@ -215,8 +215,8 @@ func (te *CLClusterTestEnv) Cleanup() error { return err } - if te.SethClient != nil { - te.SethClient.Client.Close() + for _, sethClient := range te.sethClients { + sethClient.Client.Close() } return nil @@ -244,7 +244,7 @@ func (te *CLClusterTestEnv) logWhetherAllContainersAreRunning() { func (te *CLClusterTestEnv) returnFunds() error { te.l.Info().Msg("Attempting to return Chainlink node funds to default network wallets") - if len(te.evmClients) == 0 && te.SethClient == nil { + if len(te.evmClients) == 0 && len(te.sethClients) == 0 { return fmt.Errorf("both EVMClients and SethClient are nil, unable to return funds from chainlink nodes") } @@ -278,8 +278,8 @@ func (te *CLClusterTestEnv) returnFunds() error { } } - if te.SethClient != nil { - if err := actions_seth.ReturnFunds(te.l, te.SethClient, contracts.ChainlinkClientToChainlinkNodeWithKeysAndAddress(te.ClCluster.NodeAPIs())); err != nil { + for _, sethClient := range te.sethClients { + if err := actions_seth.ReturnFunds(te.l, sethClient, contracts.ChainlinkClientToChainlinkNodeWithKeysAndAddress(te.ClCluster.NodeAPIs())); err != nil { te.l.Error().Err(err).Msg("Error returning funds from node") } } @@ -296,6 +296,14 @@ func (te *CLClusterTestEnv) GetEVMClient(chainId int64) (blockchain.EVMClient, e return nil, fmt.Errorf("no EVMClient available for chain ID %d", chainId) } +func (te *CLClusterTestEnv) GetSethClient(chainId int64) (*seth.Client, error) { + if sethClient, ok := te.sethClients[chainId]; ok { + return sethClient, nil + } + + return nil, fmt.Errorf("no Seth client available for chain ID %d", chainId) +} + func (te *CLClusterTestEnv) GetRpcProvider(chainId int64) (*test_env.RpcProvider, error) { if rpc, ok := te.rpcProviders[chainId]; ok { return rpc, nil diff --git a/integration-tests/docker/test_env/test_env_builder.go b/integration-tests/docker/test_env/test_env_builder.go index 0c237a81156..07d14f1885c 100644 --- a/integration-tests/docker/test_env/test_env_builder.go +++ b/integration-tests/docker/test_env/test_env_builder.go @@ -301,14 +301,31 @@ func (b *CLTestEnvBuilder) Build() (*CLClusterTestEnv, error) { //TODO remove after fixing in CTF networkConfig.ChainID = int64(en.EthereumChainConfig.ChainID) - evmClient, err := blockchain.NewEVMClientFromNetwork(networkConfig, b.l) - if err != nil { - return nil, err + if b.hasEVMClient { + evmClient, err := blockchain.NewEVMClientFromNetwork(networkConfig, b.l) + if err != nil { + return nil, err + } + b.te.evmClients[networkConfig.ChainID] = evmClient + } + + if b.hasSeth { + readSethCfg := b.testConfig.GetSethConfig() + sethCfg := utils.MergeSethAndEvmNetworkConfigs(b.l, networkConfig, *readSethCfg) + err = utils.ValidateSethNetworkConfig(sethCfg.Network) + if err != nil { + return nil, err + } + seth, err := seth.NewClientWithConfig(&sethCfg) + if err != nil { + return nil, err + } + + b.te.sethClients[networkConfig.ChainID] = seth } b.te.rpcProviders[networkConfig.ChainID] = &rpcProvider b.te.EVMNetworks = append(b.te.EVMNetworks, &networkConfig) - b.te.evmClients[networkConfig.ChainID] = evmClient } err = b.te.StartClCluster(b.clNodeConfig, b.clNodesCount, b.secretsConfig, b.testConfig, b.clNodesOpts...) @@ -377,6 +394,7 @@ func (b *CLTestEnvBuilder) Build() (*CLClusterTestEnv, error) { } if b.hasSeth { + b.te.sethClients = make(map[int64]*seth.Client) readSethCfg := b.testConfig.GetSethConfig() sethCfg := utils.MergeSethAndEvmNetworkConfigs(b.l, networkConfig, *readSethCfg) err = utils.ValidateSethNetworkConfig(sethCfg.Network) @@ -388,7 +406,7 @@ func (b *CLTestEnvBuilder) Build() (*CLClusterTestEnv, error) { return nil, err } - b.te.SethClient = seth + b.te.sethClients[networkConfig.ChainID] = seth } } @@ -453,8 +471,10 @@ func (b *CLTestEnvBuilder) Build() (*CLClusterTestEnv, error) { } } if b.hasSeth { - if err := actions_seth.FundChainlinkNodesFromRootAddress(b.l, b.te.SethClient, contracts.ChainlinkClientToChainlinkNodeWithKeysAndAddress(b.te.ClCluster.NodeAPIs()), b.ETHFunds); err != nil { - return nil, err + for _, sethClient := range b.te.sethClients { + if err := actions_seth.FundChainlinkNodesFromRootAddress(b.l, sethClient, contracts.ChainlinkClientToChainlinkNodeWithKeysAndAddress(b.te.ClCluster.NodeAPIs()), b.ETHFunds); err != nil { + return nil, err + } } } } diff --git a/integration-tests/load/ocr/helper.go b/integration-tests/load/ocr/helper.go index c80cedb64fc..ad07ccd4fd4 100644 --- a/integration-tests/load/ocr/helper.go +++ b/integration-tests/load/ocr/helper.go @@ -27,11 +27,11 @@ func SetupCluster( if err != nil { return common.Address{}, err } - linkDeploymentData, err := contracts.DeployLinkTokenContract(seth) + linkContract, err := contracts.DeployLinkTokenContract(l, seth) if err != nil { return common.Address{}, err } - return linkDeploymentData.Address, nil + return common.HexToAddress(linkContract.Address()), nil } func SetupFeed( diff --git a/integration-tests/smoke/ocr2_test.go b/integration-tests/smoke/ocr2_test.go index b70796c4ab8..70945d242c1 100644 --- a/integration-tests/smoke/ocr2_test.go +++ b/integration-tests/smoke/ocr2_test.go @@ -7,10 +7,13 @@ import ( "testing" "time" + "github.com/ethereum/go-ethereum/common" "github.com/rs/zerolog" + "github.com/smartcontractkit/seth" "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-testing-framework/logging" + "github.com/smartcontractkit/chainlink-testing-framework/networks" "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" "github.com/smartcontractkit/chainlink/v2/core/config/env" @@ -43,11 +46,11 @@ func TestOCRv2Basic(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - env, aggregatorContracts := prepareORCv2SmokeTestEnv(t, l, 5) + env, aggregatorContracts, sethClient := prepareORCv2SmokeTestEnv(t, l, 5) err := env.MockAdapter.SetAdapterBasedIntValuePath("ocr2", []string{http.MethodGet, http.MethodPost}, 10) require.NoError(t, err) - err = actions_seth.WatchNewRound(l, env.SethClient, 2, contracts.V2OffChainAgrregatorToOffChainAggregatorWithRounds(aggregatorContracts), time.Minute*5) + err = actions_seth.WatchNewRound(l, sethClient, 2, contracts.V2OffChainAgrregatorToOffChainAggregatorWithRounds(aggregatorContracts), time.Minute*5) require.NoError(t, err) roundData, err := aggregatorContracts[0].GetRound(testcontext.Get(t), big.NewInt(2)) @@ -65,13 +68,13 @@ func TestOCRv2Request(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - env, aggregatorContracts := prepareORCv2SmokeTestEnv(t, l, 5) + _, aggregatorContracts, sethClient := prepareORCv2SmokeTestEnv(t, l, 5) // Keep the mockserver value the same and continually request new rounds for round := 2; round <= 4; round++ { err := actions_seth.StartNewRound(contracts.V2OffChainAgrregatorToOffChainAggregatorWithRounds(aggregatorContracts)) require.NoError(t, err, "Error starting new OCR2 round") - err = actions_seth.WatchNewRound(l, env.SethClient, int64(round), contracts.V2OffChainAgrregatorToOffChainAggregatorWithRounds(aggregatorContracts), time.Minute*5) + err = actions_seth.WatchNewRound(l, sethClient, int64(round), contracts.V2OffChainAgrregatorToOffChainAggregatorWithRounds(aggregatorContracts), time.Minute*5) require.NoError(t, err, "Error watching for new OCR2 round") roundData, err := aggregatorContracts[0].GetRound(testcontext.Get(t), big.NewInt(int64(round))) require.NoError(t, err, "Getting latest answer from OCR contract shouldn't fail") @@ -87,13 +90,13 @@ func TestOCRv2JobReplacement(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - env, aggregatorContracts := prepareORCv2SmokeTestEnv(t, l, 5) + env, aggregatorContracts, sethClient := prepareORCv2SmokeTestEnv(t, l, 5) nodeClients := env.ClCluster.NodeAPIs() bootstrapNode, workerNodes := nodeClients[0], nodeClients[1:] err := env.MockAdapter.SetAdapterBasedIntValuePath("ocr2", []string{http.MethodGet, http.MethodPost}, 10) require.NoError(t, err) - err = actions_seth.WatchNewRound(l, env.SethClient, 2, contracts.V2OffChainAgrregatorToOffChainAggregatorWithRounds(aggregatorContracts), time.Minute*5) + err = actions_seth.WatchNewRound(l, sethClient, 2, contracts.V2OffChainAgrregatorToOffChainAggregatorWithRounds(aggregatorContracts), time.Minute*5) require.NoError(t, err, "Error watching for new OCR2 round") roundData, err := aggregatorContracts[0].GetRound(testcontext.Get(t), big.NewInt(2)) @@ -109,10 +112,10 @@ func TestOCRv2JobReplacement(t *testing.T) { err = actions.DeleteBridges(nodeClients) require.NoError(t, err) - err = actions.CreateOCRv2JobsLocal(aggregatorContracts, bootstrapNode, workerNodes, env.MockAdapter, "ocr2", 15, uint64(env.SethClient.ChainID), false, false) + err = actions.CreateOCRv2JobsLocal(aggregatorContracts, bootstrapNode, workerNodes, env.MockAdapter, "ocr2", 15, uint64(sethClient.ChainID), false, false) require.NoError(t, err, "Error creating OCRv2 jobs") - err = actions_seth.WatchNewRound(l, env.SethClient, 3, contracts.V2OffChainAgrregatorToOffChainAggregatorWithRounds(aggregatorContracts), time.Minute*3) + err = actions_seth.WatchNewRound(l, sethClient, 3, contracts.V2OffChainAgrregatorToOffChainAggregatorWithRounds(aggregatorContracts), time.Minute*3) require.NoError(t, err, "Error watching for new OCR2 round") roundData, err = aggregatorContracts[0].GetRound(testcontext.Get(t), big.NewInt(3)) @@ -123,7 +126,7 @@ func TestOCRv2JobReplacement(t *testing.T) { ) } -func prepareORCv2SmokeTestEnv(t *testing.T, l zerolog.Logger, firstRoundResult int) (*test_env.CLClusterTestEnv, []contracts.OffchainAggregatorV2) { +func prepareORCv2SmokeTestEnv(t *testing.T, l zerolog.Logger, firstRoundResult int) (*test_env.CLClusterTestEnv, []contracts.OffchainAggregatorV2, *seth.Client) { config, err := tc.GetConfig("Smoke", tc.OCR2) if err != nil { t.Fatal(err) @@ -149,13 +152,17 @@ func prepareORCv2SmokeTestEnv(t *testing.T, l zerolog.Logger, firstRoundResult i Build() require.NoError(t, err) + selectedNetwork := networks.MustGetSelectedNetworkConfig(config.Network)[0] + sethClient, err := env.GetSethClient(selectedNetwork.ChainID) + require.NoError(t, err, "Error getting seth client") + nodeClients := env.ClCluster.NodeAPIs() bootstrapNode, workerNodes := nodeClients[0], nodeClients[1:] - linkDeploymentData, err := contracts.DeployLinkTokenContract(env.SethClient) + linkContract, err := contracts.DeployLinkTokenContract(l, sethClient) require.NoError(t, err, "Error deploying link token contract") - err = actions_seth.FundChainlinkNodesFromRootAddress(l, env.SethClient, contracts.ChainlinkClientToChainlinkNodeWithKeysAndAddress(workerNodes), big.NewFloat(.05)) + err = actions_seth.FundChainlinkNodesFromRootAddress(l, sethClient, contracts.ChainlinkClientToChainlinkNodeWithKeysAndAddress(workerNodes), big.NewFloat(.05)) require.NoError(t, err, "Error funding Chainlink nodes") // Gather transmitters @@ -169,10 +176,10 @@ func prepareORCv2SmokeTestEnv(t *testing.T, l zerolog.Logger, firstRoundResult i } ocrOffchainOptions := contracts.DefaultOffChainAggregatorOptions() - aggregatorContracts, err := actions_seth.DeployOCRv2Contracts(l, env.SethClient, 1, linkDeploymentData.Address, transmitters, ocrOffchainOptions) + aggregatorContracts, err := actions_seth.DeployOCRv2Contracts(l, sethClient, 1, common.HexToAddress(linkContract.Address()), transmitters, ocrOffchainOptions) require.NoError(t, err, "Error deploying OCRv2 aggregator contracts") - err = actions.CreateOCRv2JobsLocal(aggregatorContracts, bootstrapNode, workerNodes, env.MockAdapter, "ocr2", 5, uint64(env.SethClient.ChainID), false, false) + err = actions.CreateOCRv2JobsLocal(aggregatorContracts, bootstrapNode, workerNodes, env.MockAdapter, "ocr2", 5, uint64(sethClient.ChainID), false, false) require.NoError(t, err, "Error creating OCRv2 jobs") ocrv2Config, err := actions.BuildMedianOCR2ConfigLocal(workerNodes, ocrOffchainOptions) @@ -181,7 +188,7 @@ func prepareORCv2SmokeTestEnv(t *testing.T, l zerolog.Logger, firstRoundResult i err = actions_seth.ConfigureOCRv2AggregatorContracts(ocrv2Config, aggregatorContracts) require.NoError(t, err, "Error configuring OCRv2 aggregator contracts") - err = actions_seth.WatchNewRound(l, env.SethClient, 1, contracts.V2OffChainAgrregatorToOffChainAggregatorWithRounds(aggregatorContracts), time.Minute*5) + err = actions_seth.WatchNewRound(l, sethClient, 1, contracts.V2OffChainAgrregatorToOffChainAggregatorWithRounds(aggregatorContracts), time.Minute*5) require.NoError(t, err, "Error watching for new OCR2 round") roundData, err := aggregatorContracts[0].GetRound(testcontext.Get(t), big.NewInt(1)) require.NoError(t, err, "Getting latest answer from OCR contract shouldn't fail") @@ -190,5 +197,5 @@ func prepareORCv2SmokeTestEnv(t *testing.T, l zerolog.Logger, firstRoundResult i roundData.Answer.Int64(), ) - return env, aggregatorContracts + return env, aggregatorContracts, sethClient } diff --git a/integration-tests/smoke/ocr_test.go b/integration-tests/smoke/ocr_test.go index 8047a19a50c..5a6001cd1e7 100644 --- a/integration-tests/smoke/ocr_test.go +++ b/integration-tests/smoke/ocr_test.go @@ -5,17 +5,19 @@ import ( "testing" "time" + "github.com/ethereum/go-ethereum/common" "github.com/rs/zerolog" + "github.com/smartcontractkit/seth" "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-testing-framework/logging" + "github.com/smartcontractkit/chainlink-testing-framework/networks" "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" "github.com/smartcontractkit/chainlink/integration-tests/actions" + actions_seth "github.com/smartcontractkit/chainlink/integration-tests/actions/seth" "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" - - actions_seth "github.com/smartcontractkit/chainlink/integration-tests/actions/seth" tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" ) @@ -27,13 +29,14 @@ func TestOCRBasic(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - env, ocrInstances := prepareORCv1SmokeTestEnv(t, l, 5) + env, ocrInstances, sethClient := prepareORCv1SmokeTestEnv(t, l, 5) nodeClients := env.ClCluster.NodeAPIs() workerNodes := nodeClients[1:] err := actions.SetAllAdapterResponsesToTheSameValueLocal(10, ocrInstances, workerNodes, env.MockAdapter) require.NoError(t, err, "Error setting all adapter responses to the same value") - err = actions_seth.WatchNewRound(l, env.SethClient, 2, contracts.V1OffChainAgrregatorToOffChainAggregatorWithRounds(ocrInstances), time.Duration(3*time.Minute)) + + err = actions_seth.WatchNewRound(l, sethClient, 2, contracts.V1OffChainAgrregatorToOffChainAggregatorWithRounds(ocrInstances), time.Duration(3*time.Minute)) require.NoError(t, err, ErrWatchingNewOCRRound) answer, err := ocrInstances[0].GetLatestAnswer(testcontext.Get(t)) @@ -45,13 +48,13 @@ func TestOCRJobReplacement(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - env, ocrInstances := prepareORCv1SmokeTestEnv(t, l, 5) + env, ocrInstances, sethClient := prepareORCv1SmokeTestEnv(t, l, 5) nodeClients := env.ClCluster.NodeAPIs() bootstrapNode, workerNodes := nodeClients[0], nodeClients[1:] err := actions.SetAllAdapterResponsesToTheSameValueLocal(10, ocrInstances, workerNodes, env.MockAdapter) require.NoError(t, err, "Error setting all adapter responses to the same value") - err = actions_seth.WatchNewRound(l, env.SethClient, 2, contracts.V1OffChainAgrregatorToOffChainAggregatorWithRounds(ocrInstances), time.Duration(3*time.Minute)) + err = actions_seth.WatchNewRound(l, sethClient, 2, contracts.V1OffChainAgrregatorToOffChainAggregatorWithRounds(ocrInstances), time.Duration(3*time.Minute)) require.NoError(t, err, ErrWatchingNewOCRRound) answer, err := ocrInstances[0].GetLatestAnswer(testcontext.Get(t)) @@ -65,10 +68,10 @@ func TestOCRJobReplacement(t *testing.T) { require.NoError(t, err, "Error deleting OCR bridges") //Recreate job - err = actions.CreateOCRJobsLocal(ocrInstances, bootstrapNode, workerNodes, 5, env.MockAdapter, big.NewInt(env.SethClient.ChainID)) + err = actions.CreateOCRJobsLocal(ocrInstances, bootstrapNode, workerNodes, 5, env.MockAdapter, big.NewInt(sethClient.ChainID)) require.NoError(t, err, "Error creating OCR jobs") - err = actions_seth.WatchNewRound(l, env.SethClient, 1, contracts.V1OffChainAgrregatorToOffChainAggregatorWithRounds(ocrInstances), time.Duration(3*time.Minute)) + err = actions_seth.WatchNewRound(l, sethClient, 1, contracts.V1OffChainAgrregatorToOffChainAggregatorWithRounds(ocrInstances), time.Duration(3*time.Minute)) require.NoError(t, err, ErrWatchingNewOCRRound) answer, err = ocrInstances[0].GetLatestAnswer(testcontext.Get(t)) @@ -76,7 +79,7 @@ func TestOCRJobReplacement(t *testing.T) { require.Equal(t, int64(10), answer.Int64(), "Expected latest answer from OCR contract to be 10 but got %d", answer.Int64()) } -func prepareORCv1SmokeTestEnv(t *testing.T, l zerolog.Logger, firstRoundResult int64) (*test_env.CLClusterTestEnv, []contracts.OffchainAggregator) { +func prepareORCv1SmokeTestEnv(t *testing.T, l zerolog.Logger, firstRoundResult int64) (*test_env.CLClusterTestEnv, []contracts.OffchainAggregator, *seth.Client) { config, err := tc.GetConfig("Smoke", tc.OCR) if err != nil { t.Fatal(err) @@ -97,24 +100,28 @@ func prepareORCv1SmokeTestEnv(t *testing.T, l zerolog.Logger, firstRoundResult i Build() require.NoError(t, err) + selectedNetwork := networks.MustGetSelectedNetworkConfig(config.Network)[0] + sethClient, err := env.GetSethClient(selectedNetwork.ChainID) + require.NoError(t, err, "Error getting seth client") + nodeClients := env.ClCluster.NodeAPIs() bootstrapNode, workerNodes := nodeClients[0], nodeClients[1:] - linkDeploymentData, err := contracts.DeployLinkTokenContract(env.SethClient) + linkContract, err := contracts.DeployLinkTokenContract(l, sethClient) require.NoError(t, err, "Error deploying link token contract") - ocrInstances, err := actions_seth.DeployOCRv1Contracts(l, env.SethClient, 1, linkDeploymentData.Address, contracts.ChainlinkClientToChainlinkNodeWithKeysAndAddress(workerNodes)) + ocrInstances, err := actions_seth.DeployOCRv1Contracts(l, sethClient, 1, common.HexToAddress(linkContract.Address()), contracts.ChainlinkClientToChainlinkNodeWithKeysAndAddress(workerNodes)) require.NoError(t, err, "Error deploying OCR contracts") - err = actions.CreateOCRJobsLocal(ocrInstances, bootstrapNode, workerNodes, 5, env.MockAdapter, big.NewInt(env.SethClient.ChainID)) + err = actions.CreateOCRJobsLocal(ocrInstances, bootstrapNode, workerNodes, 5, env.MockAdapter, big.NewInt(sethClient.ChainID)) require.NoError(t, err, "Error creating OCR jobs") - err = actions_seth.WatchNewRound(l, env.SethClient, 1, contracts.V1OffChainAgrregatorToOffChainAggregatorWithRounds(ocrInstances), time.Duration(3*time.Minute)) + err = actions_seth.WatchNewRound(l, sethClient, 1, contracts.V1OffChainAgrregatorToOffChainAggregatorWithRounds(ocrInstances), time.Duration(3*time.Minute)) require.NoError(t, err, "Error watching for new OCR round") answer, err := ocrInstances[0].GetLatestAnswer(testcontext.Get(t)) require.NoError(t, err, "Getting latest answer from OCR contract shouldn't fail") require.Equal(t, firstRoundResult, answer.Int64(), "Expected latest answer from OCR contract to be 5 but got %d", answer.Int64()) - return env, ocrInstances + return env, ocrInstances, sethClient } diff --git a/integration-tests/smoke/vrf_test.go b/integration-tests/smoke/vrf_test.go index b49c785477d..3a28c14be00 100644 --- a/integration-tests/smoke/vrf_test.go +++ b/integration-tests/smoke/vrf_test.go @@ -8,16 +8,18 @@ import ( "github.com/google/uuid" "github.com/onsi/gomega" + "github.com/rs/zerolog" + "github.com/smartcontractkit/seth" "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-testing-framework/logging" "github.com/smartcontractkit/chainlink-testing-framework/networks" "github.com/smartcontractkit/chainlink-testing-framework/utils/testcontext" - "github.com/smartcontractkit/chainlink/integration-tests/actions/vrf/vrfv1" - "github.com/smartcontractkit/chainlink/integration-tests/actions" + "github.com/smartcontractkit/chainlink/integration-tests/actions/vrf/vrfv1" "github.com/smartcontractkit/chainlink/integration-tests/client" + ethcontracts "github.com/smartcontractkit/chainlink/integration-tests/contracts" "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" ) @@ -25,41 +27,7 @@ import ( func TestVRFBasic(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - - config, err := tc.GetConfig("Smoke", tc.VRF) - if err != nil { - t.Fatal(err) - } - - privateNetwork, err := actions.EthereumNetworkConfigFromConfig(l, &config) - require.NoError(t, err, "Error building ethereum network config") - - env, err := test_env.NewCLTestEnvBuilder(). - WithTestInstance(t). - WithTestConfig(&config). - WithPrivateEthereumNetwork(privateNetwork). - WithCLNodes(1). - WithFunding(big.NewFloat(.1)). - WithStandardCleanup(). - Build() - require.NoError(t, err) - env.ParallelTransactions(true) - - network := networks.MustGetSelectedNetworkConfig(config.GetNetworkConfig())[0] - evmClient, err := env.GetEVMClient(network.ChainID) - require.NoError(t, err, "Getting EVM client shouldn't fail") - - lt, err := actions.DeployLINKToken(env.ContractDeployer) - require.NoError(t, err, "Deploying Link Token Contract shouldn't fail") - contracts, err := vrfv1.DeployVRFContracts(env.ContractDeployer, evmClient, lt) - require.NoError(t, err, "Deploying VRF Contracts shouldn't fail") - - err = lt.Transfer(contracts.Consumer.Address(), big.NewInt(2e18)) - require.NoError(t, err, "Funding consumer contract shouldn't fail") - _, err = env.ContractDeployer.DeployVRFContract() - require.NoError(t, err, "Deploying VRF contract shouldn't fail") - err = evmClient.WaitForEvents() - require.NoError(t, err, "Waiting for event subscriptions in nodes shouldn't fail") + env, contracts, sethClient := prepareVRFtestEnv(t, l) for _, n := range env.ClCluster.Nodes { nodeKey, err := n.API.MustCreateVRFKey() @@ -78,7 +46,7 @@ func TestVRFBasic(t *testing.T) { MinIncomingConfirmations: 1, PublicKey: pubKeyCompressed, ExternalJobID: jobUUID.String(), - EVMChainID: evmClient.GetChainID().String(), + EVMChainID: fmt.Sprint(sethClient.ChainID), ObservationSource: ost, }) require.NoError(t, err, "Creating VRF Job shouldn't fail") @@ -127,40 +95,7 @@ func TestVRFBasic(t *testing.T) { func TestVRFJobReplacement(t *testing.T) { t.Parallel() l := logging.GetTestLogger(t) - config, err := tc.GetConfig("Smoke", tc.VRF) - if err != nil { - t.Fatal(err) - } - - privateNetwork, err := actions.EthereumNetworkConfigFromConfig(l, &config) - require.NoError(t, err, "Error building ethereum network config") - - env, err := test_env.NewCLTestEnvBuilder(). - WithTestInstance(t). - WithTestConfig(&config). - WithPrivateEthereumNetwork(privateNetwork). - WithCLNodes(1). - WithFunding(big.NewFloat(.1)). - WithStandardCleanup(). - Build() - require.NoError(t, err) - env.ParallelTransactions(true) - - network := networks.MustGetSelectedNetworkConfig(config.GetNetworkConfig())[0] - evmClient, err := env.GetEVMClient(network.ChainID) - require.NoError(t, err, "Getting EVM client shouldn't fail") - - lt, err := actions.DeployLINKToken(env.ContractDeployer) - require.NoError(t, err, "Deploying Link Token Contract shouldn't fail") - contracts, err := vrfv1.DeployVRFContracts(env.ContractDeployer, evmClient, lt) - require.NoError(t, err, "Deploying VRF Contracts shouldn't fail") - - err = lt.Transfer(contracts.Consumer.Address(), big.NewInt(2e18)) - require.NoError(t, err, "Funding consumer contract shouldn't fail") - _, err = env.ContractDeployer.DeployVRFContract() - require.NoError(t, err, "Deploying VRF contract shouldn't fail") - err = evmClient.WaitForEvents() - require.NoError(t, err, "Waiting for event subscriptions in nodes shouldn't fail") + env, contracts, sethClient := prepareVRFtestEnv(t, l) for _, n := range env.ClCluster.Nodes { nodeKey, err := n.API.MustCreateVRFKey() @@ -179,7 +114,7 @@ func TestVRFJobReplacement(t *testing.T) { MinIncomingConfirmations: 1, PublicKey: pubKeyCompressed, ExternalJobID: jobUUID.String(), - EVMChainID: evmClient.GetChainID().String(), + EVMChainID: fmt.Sprint(sethClient.ChainID), ObservationSource: ost, }) require.NoError(t, err, "Creating VRF Job shouldn't fail") @@ -228,7 +163,7 @@ func TestVRFJobReplacement(t *testing.T) { MinIncomingConfirmations: 1, PublicKey: pubKeyCompressed, ExternalJobID: jobUUID.String(), - EVMChainID: evmClient.GetChainID().String(), + EVMChainID: fmt.Sprint(sethClient.ChainID), ObservationSource: ost, }) require.NoError(t, err, "Recreating VRF Job shouldn't fail") @@ -246,3 +181,38 @@ func TestVRFJobReplacement(t *testing.T) { }, timeout, "1s").Should(gomega.Succeed()) } } + +func prepareVRFtestEnv(t *testing.T, l zerolog.Logger) (*test_env.CLClusterTestEnv, *vrfv1.Contracts, *seth.Client) { + config, err := tc.GetConfig("Smoke", tc.VRF) + require.NoError(t, err, "Error getting config") + + privateNetwork, err := actions.EthereumNetworkConfigFromConfig(l, &config) + require.NoError(t, err, "Error building ethereum network config") + + env, err := test_env.NewCLTestEnvBuilder(). + WithTestInstance(t). + WithTestConfig(&config). + WithPrivateEthereumNetwork(privateNetwork). + WithCLNodes(1). + WithFunding(big.NewFloat(.1)). + WithStandardCleanup(). + WithSeth(). + Build() + require.NoError(t, err) + + network := networks.MustGetSelectedNetworkConfig(config.GetNetworkConfig())[0] + sethClient, err := env.GetSethClient(network.ChainID) + require.NoError(t, err, "Getting Seth client shouldn't fail") + + lt, err := ethcontracts.DeployLinkTokenContract(l, sethClient) + require.NoError(t, err, "Deploying Link Token Contract shouldn't fail") + contracts, err := vrfv1.DeployVRFContracts(sethClient, lt.Address()) + require.NoError(t, err, "Deploying VRF Contracts shouldn't fail") + + err = lt.Transfer(contracts.Consumer.Address(), big.NewInt(2e18)) + require.NoError(t, err, "Funding consumer contract shouldn't fail") + _, err = ethcontracts.DeployVRFv1Contract(sethClient) + require.NoError(t, err, "Deploying VRF contract shouldn't fail") + + return env, contracts, sethClient +} diff --git a/integration-tests/testsetups/ocr.go b/integration-tests/testsetups/ocr.go index 14e337a43b2..d30797ac507 100644 --- a/integration-tests/testsetups/ocr.go +++ b/integration-tests/testsetups/ocr.go @@ -185,8 +185,7 @@ func (o *OCRSoakTest) Setup(ocrTestConfig tt.OcrTestConfig) { o.mockServer, err = ctfClient.ConnectMockServer(o.testEnvironment) require.NoError(o.t, err, "Creating mockserver clients shouldn't fail") - // Deploy LINK - linkDeploymentData, err := contracts.DeployLinkTokenContract(seth) + linkContract, err := contracts.DeployLinkTokenContract(o.log, seth) require.NoError(o.t, err, "Error deploying LINK contract") // Fund Chainlink nodes, excluding the bootstrap node @@ -199,7 +198,7 @@ func (o *OCRSoakTest) Setup(ocrTestConfig tt.OcrTestConfig) { if o.OperatorForwarderFlow { var operators []common.Address operators, forwarders, _ = actions_seth.DeployForwarderContracts( - o.t, o.seth, linkDeploymentData, len(o.workerNodes), + o.t, o.seth, common.HexToAddress(linkContract.Address()), len(o.workerNodes), ) require.Equal(o.t, len(o.workerNodes), len(operators), "Number of operators should match number of nodes") require.Equal(o.t, len(o.workerNodes), len(forwarders), "Number of authorized forwarders should match number of nodes") @@ -218,7 +217,7 @@ func (o *OCRSoakTest) Setup(ocrTestConfig tt.OcrTestConfig) { o.log, o.seth, *o.Config.OCR.Soak.NumberOfContracts, - linkDeploymentData.Address, + common.HexToAddress(linkContract.Address()), contracts.ChainlinkK8sClientToChainlinkNodeWithKeysAndAddress(o.workerNodes), forwarders, ) @@ -228,7 +227,7 @@ func (o *OCRSoakTest) Setup(ocrTestConfig tt.OcrTestConfig) { o.log, seth, *o.Config.OCR.Soak.NumberOfContracts, - linkDeploymentData.Address, + common.HexToAddress(linkContract.Address()), contracts.ChainlinkK8sClientToChainlinkNodeWithKeysAndAddress(o.workerNodes), ) require.NoError(o.t, err) @@ -253,7 +252,7 @@ func (o *OCRSoakTest) Setup(ocrTestConfig tt.OcrTestConfig) { o.log, o.seth, *ocrTestConfig.GetOCRConfig().Soak.NumberOfContracts, - linkDeploymentData.Address, + common.HexToAddress(linkContract.Address()), transmitters, ocrOffchainOptions, )