diff --git a/.github/e2e-tests.yml b/.github/e2e-tests.yml index aee250420e0..87e7b07af5b 100644 --- a/.github/e2e-tests.yml +++ b/.github/e2e-tests.yml @@ -943,7 +943,7 @@ runner-test-matrix: - PR E2E Core Tests - Merge Queue E2E Core Tests - Nightly E2E Tests - test_cmd: cd integration-tests/ && go test smoke/ccip_test.go -timeout 12m -test.parallel=1 -count=1 -json + test_cmd: cd integration-tests/ && go test smoke/ccip_test.go -timeout 12m -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 diff --git a/deployment/ccip/add_lane_test.go b/deployment/ccip/add_lane_test.go index 02fea79c911..eb0d805a926 100644 --- a/deployment/ccip/add_lane_test.go +++ b/deployment/ccip/add_lane_test.go @@ -32,9 +32,13 @@ func TestAddLane(t *testing.T) { feeds := state.Chains[e.FeedChainSel].USDFeeds tokenConfig := NewTestTokenConfig(feeds) + newAddresses := deployment.NewMemoryAddressBook() + err = DeployPrerequisiteChainContracts(e.Env, newAddresses, e.Env.AllChainSelectors()) + require.NoError(t, err) + require.NoError(t, e.Env.ExistingAddresses.Merge(newAddresses)) // Set up CCIP contracts and a DON per chain. - newAddresses := deployment.NewMemoryAddressBook() + newAddresses = deployment.NewMemoryAddressBook() err = DeployCCIPContracts(e.Env, newAddresses, DeployCCIPContractConfig{ HomeChainSel: e.HomeChainSel, FeedChainSel: e.FeedChainSel, diff --git a/deployment/ccip/changeset/add_chain_test.go b/deployment/ccip/changeset/add_chain_test.go index 6a87bdd0a0a..8bbbdf3d340 100644 --- a/deployment/ccip/changeset/add_chain_test.go +++ b/deployment/ccip/changeset/add_chain_test.go @@ -36,9 +36,13 @@ func TestAddChainInbound(t *testing.T) { newChain := e.Env.AllChainSelectorsExcluding([]uint64{e.HomeChainSel})[0] // We deploy to the rest. initialDeploy := e.Env.AllChainSelectorsExcluding([]uint64{newChain}) + newAddresses := deployment.NewMemoryAddressBook() + err = ccipdeployment.DeployPrerequisiteChainContracts(e.Env, newAddresses, initialDeploy) + require.NoError(t, err) + require.NoError(t, e.Env.ExistingAddresses.Merge(newAddresses)) tokenConfig := ccipdeployment.NewTestTokenConfig(state.Chains[e.FeedChainSel].USDFeeds) - newAddresses := deployment.NewMemoryAddressBook() + newAddresses = deployment.NewMemoryAddressBook() err = ccipdeployment.DeployCCIPContracts(e.Env, newAddresses, ccipdeployment.DeployCCIPContractConfig{ HomeChainSel: e.HomeChainSel, FeedChainSel: e.FeedChainSel, @@ -68,15 +72,16 @@ func TestAddChainInbound(t *testing.T) { require.NoError(t, err) // Deploy contracts to new chain - newChainAddresses := deployment.NewMemoryAddressBook() + newAddresses = deployment.NewMemoryAddressBook() + err = ccipdeployment.DeployPrerequisiteChainContracts(e.Env, newAddresses, []uint64{newChain}) + require.NoError(t, err) + require.NoError(t, e.Env.ExistingAddresses.Merge(newAddresses)) + newAddresses = deployment.NewMemoryAddressBook() err = ccipdeployment.DeployChainContracts(e.Env, - e.Env.Chains[newChain], newChainAddresses, - ccipdeployment.FeeTokenContracts{ - LinkToken: state.Chains[newChain].LinkToken, - Weth9: state.Chains[newChain].Weth9, - }, ccipdeployment.NewTestMCMSConfig(t, e.Env), rmnHome) + e.Env.Chains[newChain], newAddresses, + ccipdeployment.NewTestMCMSConfig(t, e.Env), rmnHome) require.NoError(t, err) - require.NoError(t, e.Env.ExistingAddresses.Merge(newChainAddresses)) + require.NoError(t, e.Env.ExistingAddresses.Merge(newAddresses)) state, err = ccipdeployment.LoadOnchainState(e.Env) require.NoError(t, err) diff --git a/deployment/ccip/changeset/home_chain.go b/deployment/ccip/changeset/home_chain.go index 7d7f64a8bb8..0fabd2efb18 100644 --- a/deployment/ccip/changeset/home_chain.go +++ b/deployment/ccip/changeset/home_chain.go @@ -17,7 +17,6 @@ var _ deployment.ChangeSet[DeployHomeChainConfig] = DeployHomeChain // DeployHomeChain is a separate changeset because it is a standalone deployment performed once in home chain for the entire CCIP deployment. func DeployHomeChain(env deployment.Environment, cfg DeployHomeChainConfig) (deployment.ChangesetOutput, error) { - err := cfg.Validate() if err != nil { return deployment.ChangesetOutput{}, errors.Wrapf(deployment.ErrInvalidConfig, "%v", err) diff --git a/deployment/ccip/changeset/initial_deploy_test.go b/deployment/ccip/changeset/initial_deploy_test.go index b7dbdfcc972..e62092608ae 100644 --- a/deployment/ccip/changeset/initial_deploy_test.go +++ b/deployment/ccip/changeset/initial_deploy_test.go @@ -4,12 +4,12 @@ import ( "testing" "github.com/ethereum/go-ethereum/common" - "github.com/smartcontractkit/chainlink/deployment" - - ccdeploy "github.com/smartcontractkit/chainlink/deployment/ccip" jobv1 "github.com/smartcontractkit/chainlink-protos/job-distributor/v1/job" + "github.com/smartcontractkit/chainlink/deployment" + ccdeploy "github.com/smartcontractkit/chainlink/deployment/ccip" + "github.com/smartcontractkit/chainlink-testing-framework/lib/utils/testcontext" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router" @@ -26,9 +26,13 @@ func TestInitialDeploy(t *testing.T) { state, err := ccdeploy.LoadOnchainState(tenv.Env) require.NoError(t, err) - require.NotNil(t, state.Chains[tenv.HomeChainSel].LinkToken) + output, err := DeployPrerequisites(e, DeployPrerequisiteConfig{ + ChainSelectors: tenv.Env.AllChainSelectors(), + }) + require.NoError(t, err) + require.NoError(t, tenv.Env.ExistingAddresses.Merge(output.AddressBook)) - output, err := InitialDeploy(tenv.Env, ccdeploy.DeployCCIPContractConfig{ + output, err = InitialDeploy(tenv.Env, ccdeploy.DeployCCIPContractConfig{ HomeChainSel: tenv.HomeChainSel, FeedChainSel: tenv.FeedChainSel, ChainsToDeploy: tenv.Env.AllChainSelectors(), @@ -41,7 +45,7 @@ func TestInitialDeploy(t *testing.T) { require.NoError(t, tenv.Env.ExistingAddresses.Merge(output.AddressBook)) state, err = ccdeploy.LoadOnchainState(e) require.NoError(t, err) - + require.NotNil(t, state.Chains[tenv.HomeChainSel].LinkToken) // Ensure capreg logs are up to date. ccdeploy.ReplayLogs(t, e.Offchain, tenv.ReplayBlocks) diff --git a/deployment/ccip/changeset/prerequisites.go b/deployment/ccip/changeset/prerequisites.go new file mode 100644 index 00000000000..7bead1cc05c --- /dev/null +++ b/deployment/ccip/changeset/prerequisites.go @@ -0,0 +1,58 @@ +package changeset + +import ( + "fmt" + + "github.com/ethereum/go-ethereum/common" + "github.com/pkg/errors" + "github.com/smartcontractkit/ccip-owner-contracts/pkg/proposal/timelock" + chain_selectors "github.com/smartcontractkit/chain-selectors" + + "github.com/smartcontractkit/chainlink/deployment" + ccipdeployment "github.com/smartcontractkit/chainlink/deployment/ccip" +) + +var ( + _ deployment.ChangeSet[DeployPrerequisiteConfig] = DeployPrerequisites +) + +// DeployPrerequisites deploys the pre-requisite contracts for CCIP +// pre-requisite contracts are the contracts which can be reused from previous versions of CCIP +func DeployPrerequisites(env deployment.Environment, cfg DeployPrerequisiteConfig) (deployment.ChangesetOutput, error) { + err := cfg.Validate() + if err != nil { + return deployment.ChangesetOutput{}, errors.Wrapf(deployment.ErrInvalidConfig, "%v", err) + } + ab := deployment.NewMemoryAddressBook() + err = ccipdeployment.DeployPrerequisiteChainContracts(env, ab, cfg.ChainSelectors) + if err != nil { + env.Logger.Errorw("Failed to deploy prerequisite contracts", "err", err, "addressBook", ab) + return deployment.ChangesetOutput{}, fmt.Errorf("failed to deploy prerequisite contracts: %w", err) + } + return deployment.ChangesetOutput{ + Proposals: []timelock.MCMSWithTimelockProposal{}, + AddressBook: ab, + JobSpecs: nil, + }, nil +} + +type DeployPrerequisiteConfig struct { + ChainSelectors []uint64 + // TODO handle tokens and feeds in prerequisite config + Tokens map[ccipdeployment.TokenSymbol]common.Address + Feeds map[ccipdeployment.TokenSymbol]common.Address +} + +func (c DeployPrerequisiteConfig) Validate() error { + for _, cs := range c.ChainSelectors { + if cs == 0 { + return fmt.Errorf("chain selector must be set") + } + _, err := chain_selectors.ChainIdFromSelector(cs) + if err != nil { + return fmt.Errorf("invalid chain selector: %d - %w", cs, err) + } + + } + return nil +} diff --git a/deployment/ccip/changeset/prerequisites_test.go b/deployment/ccip/changeset/prerequisites_test.go new file mode 100644 index 00000000000..94d5c8d0581 --- /dev/null +++ b/deployment/ccip/changeset/prerequisites_test.go @@ -0,0 +1,37 @@ +package changeset + +import ( + "testing" + + "github.com/stretchr/testify/require" + "go.uber.org/zap/zapcore" + + ccipdeployment "github.com/smartcontractkit/chainlink/deployment/ccip" + "github.com/smartcontractkit/chainlink/deployment/environment/memory" + "github.com/smartcontractkit/chainlink/v2/core/logger" +) + +func TestDeployPrerequisites(t *testing.T) { + t.Parallel() + lggr := logger.TestLogger(t) + e := memory.NewMemoryEnvironment(t, lggr, zapcore.InfoLevel, memory.MemoryEnvironmentConfig{ + Bootstraps: 1, + Chains: 2, + Nodes: 4, + }) + newChain := e.AllChainSelectors()[0] + cfg := DeployPrerequisiteConfig{ + ChainSelectors: []uint64{newChain}, + } + output, err := DeployPrerequisites(e, cfg) + require.NoError(t, err) + err = e.ExistingAddresses.Merge(output.AddressBook) + require.NoError(t, err) + state, err := ccipdeployment.LoadOnchainState(e) + require.NoError(t, err) + require.NotNil(t, state.Chains[newChain].LinkToken) + require.NotNil(t, state.Chains[newChain].Weth9) + require.NotNil(t, state.Chains[newChain].TokenAdminRegistry) + require.NotNil(t, state.Chains[newChain].RegistryModule) + require.NotNil(t, state.Chains[newChain].Router) +} diff --git a/deployment/ccip/changeset/save_existing.go b/deployment/ccip/changeset/save_existing.go new file mode 100644 index 00000000000..8995fdf7f4c --- /dev/null +++ b/deployment/ccip/changeset/save_existing.go @@ -0,0 +1,68 @@ +package changeset + +import ( + "fmt" + + "github.com/ethereum/go-ethereum/common" + "github.com/pkg/errors" + "github.com/smartcontractkit/ccip-owner-contracts/pkg/proposal/timelock" + chain_selectors "github.com/smartcontractkit/chain-selectors" + + "github.com/smartcontractkit/chainlink/deployment" +) + +var ( + _ deployment.ChangeSet[ExistingContractsConfig] = SaveExistingContracts +) + +type Contract struct { + Address common.Address + TypeAndVersion deployment.TypeAndVersion + ChainSelector uint64 +} + +type ExistingContractsConfig struct { + ExistingContracts []Contract +} + +func (cfg ExistingContractsConfig) Validate() error { + for _, ec := range cfg.ExistingContracts { + if ec.ChainSelector == 0 { + return fmt.Errorf("chain selectors must be set") + } + _, err := chain_selectors.ChainIdFromSelector(ec.ChainSelector) + if err != nil { + return fmt.Errorf("invalid chain selector: %d - %w", ec.ChainSelector, err) + } + if ec.Address == (common.Address{}) { + return fmt.Errorf("address must be set") + } + if ec.TypeAndVersion.Type == "" { + return fmt.Errorf("type must be set") + } + if val, err := ec.TypeAndVersion.Version.Value(); err != nil || val == "" { + return fmt.Errorf("version must be set") + } + } + return nil +} + +func SaveExistingContracts(env deployment.Environment, cfg ExistingContractsConfig) (deployment.ChangesetOutput, error) { + err := cfg.Validate() + if err != nil { + return deployment.ChangesetOutput{}, errors.Wrapf(deployment.ErrInvalidConfig, "%v", err) + } + ab := deployment.NewMemoryAddressBook() + for _, ec := range cfg.ExistingContracts { + err = ab.Save(ec.ChainSelector, ec.Address.String(), ec.TypeAndVersion) + if err != nil { + env.Logger.Errorw("Failed to save existing contract", "err", err, "addressBook", ab) + return deployment.ChangesetOutput{}, fmt.Errorf("failed to save existing contract: %w", err) + } + } + return deployment.ChangesetOutput{ + Proposals: []timelock.MCMSWithTimelockProposal{}, + AddressBook: ab, + JobSpecs: nil, + }, nil +} diff --git a/deployment/ccip/changeset/save_existing_test.go b/deployment/ccip/changeset/save_existing_test.go new file mode 100644 index 00000000000..5f09c13b272 --- /dev/null +++ b/deployment/ccip/changeset/save_existing_test.go @@ -0,0 +1,69 @@ +package changeset + +import ( + "math/big" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/require" + "go.uber.org/zap/zapcore" + + "github.com/smartcontractkit/chainlink/deployment" + ccipdeployment "github.com/smartcontractkit/chainlink/deployment/ccip" + "github.com/smartcontractkit/chainlink/deployment/environment/memory" + "github.com/smartcontractkit/chainlink/v2/core/logger" +) + +func TestSaveExisting(t *testing.T) { + t.Parallel() + lggr := logger.TestLogger(t) + e := memory.NewMemoryEnvironment(t, lggr, zapcore.InfoLevel, memory.MemoryEnvironmentConfig{ + Bootstraps: 1, + Chains: 2, + Nodes: 4, + }) + chains := e.AllChainSelectors() + chain1 := chains[0] + chain2 := chains[1] + cfg := ExistingContractsConfig{ + ExistingContracts: []Contract{ + { + Address: common.BigToAddress(big.NewInt(1)), + TypeAndVersion: deployment.NewTypeAndVersion(ccipdeployment.LinkToken, deployment.Version1_0_0), + ChainSelector: chain1, + }, + { + Address: common.BigToAddress(big.NewInt(2)), + TypeAndVersion: deployment.NewTypeAndVersion(ccipdeployment.WETH9, deployment.Version1_0_0), + ChainSelector: chain1, + }, + { + Address: common.BigToAddress(big.NewInt(3)), + TypeAndVersion: deployment.NewTypeAndVersion(ccipdeployment.TokenAdminRegistry, deployment.Version1_5_0), + ChainSelector: chain1, + }, + { + Address: common.BigToAddress(big.NewInt(4)), + TypeAndVersion: deployment.NewTypeAndVersion(ccipdeployment.RegistryModule, deployment.Version1_5_0), + ChainSelector: chain2, + }, + { + Address: common.BigToAddress(big.NewInt(5)), + TypeAndVersion: deployment.NewTypeAndVersion(ccipdeployment.Router, deployment.Version1_2_0), + ChainSelector: chain2, + }, + }, + } + + output, err := SaveExistingContracts(e, cfg) + require.NoError(t, err) + err = e.ExistingAddresses.Merge(output.AddressBook) + require.NoError(t, err) + state, err := ccipdeployment.LoadOnchainState(e) + require.NoError(t, err) + require.Equal(t, state.Chains[chain1].LinkToken.Address(), common.BigToAddress(big.NewInt(1))) + require.Equal(t, state.Chains[chain1].Weth9.Address(), common.BigToAddress(big.NewInt(2))) + require.Equal(t, state.Chains[chain1].TokenAdminRegistry.Address(), common.BigToAddress(big.NewInt(3))) + require.Equal(t, state.Chains[chain2].RegistryModule.Address(), common.BigToAddress(big.NewInt(4))) + require.Equal(t, state.Chains[chain2].Router.Address(), common.BigToAddress(big.NewInt(5))) +} diff --git a/deployment/ccip/deploy.go b/deployment/ccip/deploy.go index 8a33cf0d26d..5a4ad1bb394 100644 --- a/deployment/ccip/deploy.go +++ b/deployment/ccip/deploy.go @@ -7,21 +7,22 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/pkg/errors" "github.com/smartcontractkit/ccip-owner-contracts/pkg/config" owner_helpers "github.com/smartcontractkit/ccip-owner-contracts/pkg/gethwrappers" "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink/deployment" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/fee_quoter" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/registry_module_owner_custom" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/rmn_home" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/ccip_home" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/fee_quoter" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/maybe_revert_message_receiver" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/mock_rmn_contract" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/nonce_manager" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/offramp" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/onramp" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/registry_module_owner_custom" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/rmn_home" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/rmn_proxy_contract" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/rmn_remote" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router" @@ -31,6 +32,7 @@ import ( ) var ( + MockRMN deployment.ContractType = "MockRMN" RMNRemote deployment.ContractType = "RMNRemote" LinkToken deployment.ContractType = "LinkToken" ARMProxy deployment.ContractType = "ARMProxy" @@ -60,6 +62,207 @@ var ( BurnMintTokenPool deployment.ContractType = "BurnMintTokenPool" ) +func DeployPrerequisiteChainContracts(e deployment.Environment, ab deployment.AddressBook, selectors []uint64) error { + state, err := LoadOnchainState(e) + if err != nil { + e.Logger.Errorw("Failed to load existing onchain state", "err") + return err + } + for _, sel := range selectors { + chain := e.Chains[sel] + err = DeployPrerequisiteContracts(e, ab, state, chain) + if err != nil { + return errors.Wrapf(err, "failed to deploy prerequisite contracts for chain %d", sel) + } + } + return nil +} + +// DeployPrerequisiteContracts deploys the contracts that can be ported from previous CCIP version to the new one. +// This is only required for staging and test environments where the contracts are not already deployed. +func DeployPrerequisiteContracts(e deployment.Environment, ab deployment.AddressBook, state CCIPOnChainState, chain deployment.Chain) error { + lggr := e.Logger + chainState, chainExists := state.Chains[chain.Selector] + var weth9Contract *weth9.WETH9 + var linkTokenContract *burn_mint_erc677.BurnMintERC677 + var tokenAdminReg *token_admin_registry.TokenAdminRegistry + var registryModule *registry_module_owner_custom.RegistryModuleOwnerCustom + var rmnProxy *rmn_proxy_contract.RMNProxyContract + var r *router.Router + if chainExists { + weth9Contract = chainState.Weth9 + linkTokenContract = chainState.LinkToken + tokenAdminReg = chainState.TokenAdminRegistry + registryModule = chainState.RegistryModule + rmnProxy = chainState.RMNProxyExisting + r = chainState.Router + } + if rmnProxy == nil { + // we want to replicate the mainnet scenario where RMNProxy is already deployed with some existing RMN + // This will need us to use two different RMNProxy contracts + // 1. RMNProxyNew with RMNRemote - ( deployed later in chain contracts) + // 2. RMNProxyExisting with mockRMN - ( deployed here, replicating the behavior of existing RMNProxy with already set RMN) + rmn, err := deployment.DeployContract(lggr, chain, ab, + func(chain deployment.Chain) deployment.ContractDeploy[*mock_rmn_contract.MockRMNContract] { + rmnAddr, tx2, rmn, err2 := mock_rmn_contract.DeployMockRMNContract( + chain.DeployerKey, + chain.Client, + ) + return deployment.ContractDeploy[*mock_rmn_contract.MockRMNContract]{ + rmnAddr, rmn, tx2, deployment.NewTypeAndVersion(MockRMN, deployment.Version1_0_0), err2, + } + }) + if err != nil { + lggr.Errorw("Failed to deploy mock RMN", "err", err) + return err + } + lggr.Infow("deployed mock RMN", "addr", rmn.Address) + rmnProxyContract, err := deployment.DeployContract(lggr, chain, ab, + func(chain deployment.Chain) deployment.ContractDeploy[*rmn_proxy_contract.RMNProxyContract] { + rmnProxyAddr, tx2, rmnProxy, err2 := rmn_proxy_contract.DeployRMNProxyContract( + chain.DeployerKey, + chain.Client, + rmn.Address, + ) + return deployment.ContractDeploy[*rmn_proxy_contract.RMNProxyContract]{ + rmnProxyAddr, rmnProxy, tx2, deployment.NewTypeAndVersion(ARMProxy, deployment.Version1_0_0), err2, + } + }) + if err != nil { + lggr.Errorw("Failed to deploy RMNProxyNew", "err", err) + return err + } + lggr.Infow("deployed RMNProxyNew", "addr", rmnProxyContract.Address) + rmnProxy = rmnProxyContract.Contract + } + if tokenAdminReg == nil { + tokenAdminRegistry, err := deployment.DeployContract(e.Logger, chain, ab, + func(chain deployment.Chain) deployment.ContractDeploy[*token_admin_registry.TokenAdminRegistry] { + tokenAdminRegistryAddr, tx2, tokenAdminRegistry, err2 := token_admin_registry.DeployTokenAdminRegistry( + chain.DeployerKey, + chain.Client) + return deployment.ContractDeploy[*token_admin_registry.TokenAdminRegistry]{ + tokenAdminRegistryAddr, tokenAdminRegistry, tx2, deployment.NewTypeAndVersion(TokenAdminRegistry, deployment.Version1_5_0), err2, + } + }) + if err != nil { + e.Logger.Errorw("Failed to deploy token admin registry", "err", err) + return err + } + e.Logger.Infow("deployed tokenAdminRegistry", "addr", tokenAdminRegistry) + tokenAdminReg = tokenAdminRegistry.Contract + } else { + e.Logger.Infow("tokenAdminRegistry already deployed", "addr", tokenAdminReg.Address) + } + if registryModule == nil { + customRegistryModule, err := deployment.DeployContract(e.Logger, chain, ab, + func(chain deployment.Chain) deployment.ContractDeploy[*registry_module_owner_custom.RegistryModuleOwnerCustom] { + regModAddr, tx2, regMod, err2 := registry_module_owner_custom.DeployRegistryModuleOwnerCustom( + chain.DeployerKey, + chain.Client, + tokenAdminReg.Address()) + return deployment.ContractDeploy[*registry_module_owner_custom.RegistryModuleOwnerCustom]{ + regModAddr, regMod, tx2, deployment.NewTypeAndVersion(RegistryModule, deployment.Version1_5_0), err2, + } + }) + if err != nil { + e.Logger.Errorw("Failed to deploy custom registry module", "err", err) + return err + } + e.Logger.Infow("deployed custom registry module", "addr", customRegistryModule) + registryModule = customRegistryModule.Contract + } else { + e.Logger.Infow("custom registry module already deployed", "addr", registryModule.Address) + } + isRegistryAdded, err := tokenAdminReg.IsRegistryModule(nil, registryModule.Address()) + if err != nil { + e.Logger.Errorw("Failed to check if registry module is added on token admin registry", "err", err) + return fmt.Errorf("failed to check if registry module is added on token admin registry: %w", err) + } + if !isRegistryAdded { + tx, err := tokenAdminReg.AddRegistryModule(chain.DeployerKey, registryModule.Address()) + if err != nil { + e.Logger.Errorw("Failed to assign registry module on token admin registry", "err", err) + return fmt.Errorf("failed to assign registry module on token admin registry: %w", err) + } + + _, err = chain.Confirm(tx) + if err != nil { + e.Logger.Errorw("Failed to confirm assign registry module on token admin registry", "err", err) + return fmt.Errorf("failed to confirm assign registry module on token admin registry: %w", err) + } + e.Logger.Infow("assigned registry module on token admin registry") + } + if weth9Contract == nil { + weth, err := deployment.DeployContract(lggr, chain, ab, + func(chain deployment.Chain) deployment.ContractDeploy[*weth9.WETH9] { + weth9Addr, tx2, weth9c, err2 := weth9.DeployWETH9( + chain.DeployerKey, + chain.Client, + ) + return deployment.ContractDeploy[*weth9.WETH9]{ + weth9Addr, weth9c, tx2, deployment.NewTypeAndVersion(WETH9, deployment.Version1_0_0), err2, + } + }) + if err != nil { + lggr.Errorw("Failed to deploy weth9", "err", err) + return err + } + lggr.Infow("deployed weth9", "addr", weth.Address) + weth9Contract = weth.Contract + } else { + lggr.Infow("weth9 already deployed", "addr", weth9Contract.Address) + } + if linkTokenContract == nil { + linkToken, err := deployment.DeployContract(lggr, chain, ab, + func(chain deployment.Chain) deployment.ContractDeploy[*burn_mint_erc677.BurnMintERC677] { + linkTokenAddr, tx2, linkToken, err2 := burn_mint_erc677.DeployBurnMintERC677( + chain.DeployerKey, + chain.Client, + "Link Token", + "LINK", + uint8(18), + big.NewInt(0).Mul(big.NewInt(1e9), big.NewInt(1e18)), + ) + return deployment.ContractDeploy[*burn_mint_erc677.BurnMintERC677]{ + linkTokenAddr, linkToken, tx2, deployment.NewTypeAndVersion(LinkToken, deployment.Version1_0_0), err2, + } + }) + if err != nil { + lggr.Errorw("Failed to deploy linkToken", "err", err) + return err + } + lggr.Infow("deployed linkToken", "addr", linkToken.Address) + linkTokenContract = linkToken.Contract + } else { + lggr.Infow("linkToken already deployed", "addr", linkTokenContract.Address) + } + // if router is not already deployed, we deploy it + if r == nil { + routerContract, err := deployment.DeployContract(e.Logger, chain, ab, + func(chain deployment.Chain) deployment.ContractDeploy[*router.Router] { + routerAddr, tx2, routerC, err2 := router.DeployRouter( + chain.DeployerKey, + chain.Client, + weth9Contract.Address(), + rmnProxy.Address(), + ) + return deployment.ContractDeploy[*router.Router]{ + routerAddr, routerC, tx2, deployment.NewTypeAndVersion(Router, deployment.Version1_2_0), err2, + } + }) + if err != nil { + e.Logger.Errorw("Failed to deploy router", "err", err) + return err + } + e.Logger.Infow("deployed router", "addr", routerContract.Address) + r = routerContract.Contract + } else { + e.Logger.Infow("router already deployed", "addr", chainState.Router.Address) + } + return nil +} + type DeployCCIPContractConfig struct { HomeChainSel uint64 FeedChainSel uint64 @@ -137,10 +340,7 @@ func DeployCCIPContracts(e deployment.Environment, ab deployment.AddressBook, c if existingState.Chains[chainSel].LinkToken == nil || existingState.Chains[chainSel].Weth9 == nil { return fmt.Errorf("fee tokens not found for chain %d", chainSel) } - err = DeployChainContracts(e, chain, ab, FeeTokenContracts{ - LinkToken: existingState.Chains[chainSel].LinkToken, - Weth9: existingState.Chains[chainSel].Weth9, - }, c.MCMSConfig, rmnHome) + err = DeployChainContracts(e, chain, ab, c.MCMSConfig, rmnHome) if err != nil { return err } @@ -296,70 +496,10 @@ func DeployMCMSContracts( }, nil } -func DeployFeeTokensToChains(lggr logger.Logger, ab deployment.AddressBook, chains map[uint64]deployment.Chain) error { - for _, chain := range chains { - _, err := DeployFeeTokens(lggr, chain, ab) - if err != nil { - return err - } - } - return nil -} - -// DeployFeeTokens deploys link and weth9. This is _usually_ for test environments only, -// real environments they tend to already exist, but sometimes we still have to deploy them to real chains. -func DeployFeeTokens(lggr logger.Logger, chain deployment.Chain, ab deployment.AddressBook) (FeeTokenContracts, error) { - weth9, err := deployment.DeployContract(lggr, chain, ab, - func(chain deployment.Chain) deployment.ContractDeploy[*weth9.WETH9] { - weth9Addr, tx2, weth9c, err2 := weth9.DeployWETH9( - chain.DeployerKey, - chain.Client, - ) - return deployment.ContractDeploy[*weth9.WETH9]{ - weth9Addr, weth9c, tx2, deployment.NewTypeAndVersion(WETH9, deployment.Version1_0_0), err2, - } - }) - if err != nil { - lggr.Errorw("Failed to deploy weth9", "err", err) - return FeeTokenContracts{}, err - } - lggr.Infow("deployed weth9", "addr", weth9.Address) - - linkToken, err := deployment.DeployContract(lggr, chain, ab, - func(chain deployment.Chain) deployment.ContractDeploy[*burn_mint_erc677.BurnMintERC677] { - linkTokenAddr, tx2, linkToken, err2 := burn_mint_erc677.DeployBurnMintERC677( - chain.DeployerKey, - chain.Client, - "Link Token", - "LINK", - uint8(18), - big.NewInt(0).Mul(big.NewInt(1e9), big.NewInt(1e18)), - ) - return deployment.ContractDeploy[*burn_mint_erc677.BurnMintERC677]{ - linkTokenAddr, linkToken, tx2, deployment.NewTypeAndVersion(LinkToken, deployment.Version1_0_0), err2, - } - }) - if err != nil { - lggr.Errorw("Failed to deploy linkToken", "err", err) - return FeeTokenContracts{}, err - } - lggr.Infow("deployed linkToken", "addr", linkToken.Address) - return FeeTokenContracts{ - LinkToken: linkToken.Contract, - Weth9: weth9.Contract, - }, nil -} - -type FeeTokenContracts struct { - LinkToken *burn_mint_erc677.BurnMintERC677 - Weth9 *weth9.WETH9 -} - func DeployChainContracts( e deployment.Environment, chain deployment.Chain, ab deployment.AddressBook, - contractConfig FeeTokenContracts, mcmsConfig MCMSConfig, rmnHome *rmn_home.RMNHome, ) error { @@ -367,41 +507,77 @@ func DeployChainContracts( if err != nil { return err } - ccipReceiver, err := deployment.DeployContract(e.Logger, chain, ab, - func(chain deployment.Chain) deployment.ContractDeploy[*maybe_revert_message_receiver.MaybeRevertMessageReceiver] { - receiverAddr, tx, receiver, err2 := maybe_revert_message_receiver.DeployMaybeRevertMessageReceiver( - chain.DeployerKey, - chain.Client, - false, - ) - return deployment.ContractDeploy[*maybe_revert_message_receiver.MaybeRevertMessageReceiver]{ - receiverAddr, receiver, tx, deployment.NewTypeAndVersion(CCIPReceiver, deployment.Version1_0_0), err2, - } - }) + // check for existing contracts + state, err := LoadOnchainState(e) if err != nil { - e.Logger.Errorw("Failed to deploy receiver", "err", err) + e.Logger.Errorw("Failed to load existing onchain state", "err") return err } - e.Logger.Infow("deployed receiver", "addr", ccipReceiver.Address) - - // TODO: Correctly configure RMN remote. - rmnRemote, err := deployment.DeployContract(e.Logger, chain, ab, - func(chain deployment.Chain) deployment.ContractDeploy[*rmn_remote.RMNRemote] { - rmnRemoteAddr, tx, rmnRemote, err2 := rmn_remote.DeployRMNRemote( - chain.DeployerKey, - chain.Client, - chain.Selector, - ) - return deployment.ContractDeploy[*rmn_remote.RMNRemote]{ - rmnRemoteAddr, rmnRemote, tx, deployment.NewTypeAndVersion(RMNRemote, deployment.Version1_6_0_dev), err2, - } - }) - if err != nil { - e.Logger.Errorw("Failed to deploy RMNRemote", "err", err) - return err + chainState, chainExists := state.Chains[chain.Selector] + if !chainExists { + return fmt.Errorf("chain %d not found in existing state, deploy the prerequisites first", chain.Selector) + } + if chainState.Weth9 == nil { + return fmt.Errorf("weth9 not found for chain %d, deploy the prerequisites first", chain.Selector) + } + weth9Contract := chainState.Weth9 + if chainState.LinkToken == nil { + return fmt.Errorf("link token not found for chain %d, deploy the prerequisites first", chain.Selector) + } + linkTokenContract := chainState.LinkToken + if chainState.TokenAdminRegistry == nil { + return fmt.Errorf("token admin registry not found for chain %d, deploy the prerequisites first", chain.Selector) + } + tokenAdminReg := chainState.TokenAdminRegistry + if chainState.RegistryModule == nil { + return fmt.Errorf("registry module not found for chain %d, deploy the prerequisites first", chain.Selector) + } + if chainState.Router == nil { + return fmt.Errorf("router not found for chain %d, deploy the prerequisites first", chain.Selector) + } + if chainState.Receiver == nil { + ccipReceiver, err := deployment.DeployContract(e.Logger, chain, ab, + func(chain deployment.Chain) deployment.ContractDeploy[*maybe_revert_message_receiver.MaybeRevertMessageReceiver] { + receiverAddr, tx, receiver, err2 := maybe_revert_message_receiver.DeployMaybeRevertMessageReceiver( + chain.DeployerKey, + chain.Client, + false, + ) + return deployment.ContractDeploy[*maybe_revert_message_receiver.MaybeRevertMessageReceiver]{ + receiverAddr, receiver, tx, deployment.NewTypeAndVersion(CCIPReceiver, deployment.Version1_0_0), err2, + } + }) + if err != nil { + e.Logger.Errorw("Failed to deploy receiver", "err", err) + return err + } + e.Logger.Infow("deployed receiver", "addr", ccipReceiver.Address) + } else { + e.Logger.Infow("receiver already deployed", "addr", chainState.Receiver.Address) + } + rmnRemoteContract := chainState.RMNRemote + if chainState.RMNRemote == nil { + // TODO: Correctly configure RMN remote. + rmnRemote, err := deployment.DeployContract(e.Logger, chain, ab, + func(chain deployment.Chain) deployment.ContractDeploy[*rmn_remote.RMNRemote] { + rmnRemoteAddr, tx, rmnRemote, err2 := rmn_remote.DeployRMNRemote( + chain.DeployerKey, + chain.Client, + chain.Selector, + ) + return deployment.ContractDeploy[*rmn_remote.RMNRemote]{ + rmnRemoteAddr, rmnRemote, tx, deployment.NewTypeAndVersion(RMNRemote, deployment.Version1_6_0_dev), err2, + } + }) + if err != nil { + e.Logger.Errorw("Failed to deploy RMNRemote", "err", err) + return err + } + e.Logger.Infow("deployed RMNRemote", "addr", rmnRemote.Address) + rmnRemoteContract = rmnRemote.Contract + } else { + e.Logger.Infow("rmn remote already deployed", "addr", chainState.RMNRemote.Address) } - e.Logger.Infow("deployed RMNRemote", "addr", rmnRemote.Address) - activeDigest, err := rmnHome.GetActiveDigest(&bind.CallOpts{}) if err != nil { e.Logger.Errorw("Failed to get active digest", "err", err) @@ -409,7 +585,7 @@ func DeployChainContracts( } e.Logger.Infow("setting active home digest to rmn remote", "digest", activeDigest) - tx, err := rmnRemote.Contract.SetConfig(chain.DeployerKey, rmn_remote.RMNRemoteConfig{ + tx, err := rmnRemoteContract.SetConfig(chain.DeployerKey, rmn_remote.RMNRemoteConfig{ RmnHomeContractConfigDigest: activeDigest, Signers: []rmn_remote.RMNRemoteSigner{ {NodeIndex: 0, OnchainPublicKey: common.Address{1}}, @@ -421,225 +597,194 @@ func DeployChainContracts( return err } - rmnProxy, err := deployment.DeployContract(e.Logger, chain, ab, - func(chain deployment.Chain) deployment.ContractDeploy[*rmn_proxy_contract.RMNProxyContract] { - rmnProxyAddr, tx2, rmnProxy, err2 := rmn_proxy_contract.DeployRMNProxyContract( - chain.DeployerKey, - chain.Client, - rmnRemote.Address, - ) - return deployment.ContractDeploy[*rmn_proxy_contract.RMNProxyContract]{ - rmnProxyAddr, rmnProxy, tx2, deployment.NewTypeAndVersion(ARMProxy, deployment.Version1_0_0), err2, - } - }) - if err != nil { - e.Logger.Errorw("Failed to deploy rmnProxy", "err", err) - return err - } - e.Logger.Infow("deployed rmnProxy", "addr", rmnProxy.Address) - - routerContract, err := deployment.DeployContract(e.Logger, chain, ab, - func(chain deployment.Chain) deployment.ContractDeploy[*router.Router] { - routerAddr, tx2, routerC, err2 := router.DeployRouter( - chain.DeployerKey, - chain.Client, - contractConfig.Weth9.Address(), - rmnProxy.Address, - ) - return deployment.ContractDeploy[*router.Router]{ - routerAddr, routerC, tx2, deployment.NewTypeAndVersion(Router, deployment.Version1_2_0), err2, - } - }) - if err != nil { - e.Logger.Errorw("Failed to deploy router", "err", err) - return err - } - e.Logger.Infow("deployed router", "addr", routerContract.Address) - - testRouterContract, err := deployment.DeployContract(e.Logger, chain, ab, - func(chain deployment.Chain) deployment.ContractDeploy[*router.Router] { - routerAddr, tx2, routerC, err2 := router.DeployRouter( - chain.DeployerKey, - chain.Client, - contractConfig.Weth9.Address(), - rmnProxy.Address, - ) - return deployment.ContractDeploy[*router.Router]{ - routerAddr, routerC, tx2, deployment.NewTypeAndVersion(TestRouter, deployment.Version1_2_0), err2, - } - }) - if err != nil { - e.Logger.Errorw("Failed to deploy test router", "err", err) - return err - } - e.Logger.Infow("deployed test router", "addr", testRouterContract.Address) - - tokenAdminRegistry, err := deployment.DeployContract(e.Logger, chain, ab, - func(chain deployment.Chain) deployment.ContractDeploy[*token_admin_registry.TokenAdminRegistry] { - tokenAdminRegistryAddr, tx2, tokenAdminRegistry, err2 := token_admin_registry.DeployTokenAdminRegistry( - chain.DeployerKey, - chain.Client) - return deployment.ContractDeploy[*token_admin_registry.TokenAdminRegistry]{ - tokenAdminRegistryAddr, tokenAdminRegistry, tx2, deployment.NewTypeAndVersion(TokenAdminRegistry, deployment.Version1_5_0), err2, - } - }) - if err != nil { - e.Logger.Errorw("Failed to deploy token admin registry", "err", err) - return err - } - e.Logger.Infow("deployed tokenAdminRegistry", "addr", tokenAdminRegistry) - - customRegistryModule, err := deployment.DeployContract(e.Logger, chain, ab, - func(chain deployment.Chain) deployment.ContractDeploy[*registry_module_owner_custom.RegistryModuleOwnerCustom] { - regModAddr, tx2, regMod, err2 := registry_module_owner_custom.DeployRegistryModuleOwnerCustom( - chain.DeployerKey, - chain.Client, - tokenAdminRegistry.Address) - return deployment.ContractDeploy[*registry_module_owner_custom.RegistryModuleOwnerCustom]{ - regModAddr, regMod, tx2, deployment.NewTypeAndVersion(RegistryModule, deployment.Version1_5_0), err2, - } - }) - if err != nil { - e.Logger.Errorw("Failed to deploy custom registry module", "err", err) - return err - } - e.Logger.Infow("deployed custom registry module", "addr", tokenAdminRegistry) - - tx, err = tokenAdminRegistry.Contract.AddRegistryModule(chain.DeployerKey, customRegistryModule.Address) - if err != nil { - e.Logger.Errorw("Failed to assign registry module on token admin registry", "err", err) - return fmt.Errorf("failed to assign registry module on token admin registry: %w", err) - } - - _, err = chain.Confirm(tx) - if err != nil { - e.Logger.Errorw("Failed to confirm assign registry module on token admin registry", "err", err) - return fmt.Errorf("failed to confirm assign registry module on token admin registry: %w", err) - } - - e.Logger.Infow("assigned registry module on token admin registry") - - nonceManager, err := deployment.DeployContract(e.Logger, chain, ab, - func(chain deployment.Chain) deployment.ContractDeploy[*nonce_manager.NonceManager] { - nonceManagerAddr, tx2, nonceManager, err2 := nonce_manager.DeployNonceManager( - chain.DeployerKey, - chain.Client, - []common.Address{}, // Need to add onRamp after - ) - return deployment.ContractDeploy[*nonce_manager.NonceManager]{ - nonceManagerAddr, nonceManager, tx2, deployment.NewTypeAndVersion(NonceManager, deployment.Version1_6_0_dev), err2, - } - }) - if err != nil { - e.Logger.Errorw("Failed to deploy nonce manager", "err", err) - return err - } - e.Logger.Infow("Deployed nonce manager", "addr", nonceManager.Address) - - feeQuoter, err := deployment.DeployContract(e.Logger, chain, ab, - func(chain deployment.Chain) deployment.ContractDeploy[*fee_quoter.FeeQuoter] { - prAddr, tx2, pr, err2 := fee_quoter.DeployFeeQuoter( - chain.DeployerKey, - chain.Client, - fee_quoter.FeeQuoterStaticConfig{ - MaxFeeJuelsPerMsg: big.NewInt(0).Mul(big.NewInt(2e2), big.NewInt(1e18)), - LinkToken: contractConfig.LinkToken.Address(), - TokenPriceStalenessThreshold: uint32(24 * 60 * 60), - }, - []common.Address{mcmsContracts.Timelock.Address}, // timelock should be able to update, ramps added after - []common.Address{contractConfig.Weth9.Address(), contractConfig.LinkToken.Address()}, // fee tokens - []fee_quoter.FeeQuoterTokenPriceFeedUpdate{}, - []fee_quoter.FeeQuoterTokenTransferFeeConfigArgs{}, // TODO: tokens - []fee_quoter.FeeQuoterPremiumMultiplierWeiPerEthArgs{ - { - PremiumMultiplierWeiPerEth: 9e17, // 0.9 ETH - Token: contractConfig.LinkToken.Address(), + // we deploy a new RMNProxy so that RMNRemote can be tested first before pointing it to the main Existing RMNProxy + // To differentiate between the two RMNProxies, we will deploy new one with Version1_6_0_dev + rmnProxyContract := chainState.RMNProxyNew + if chainState.RMNProxyNew == nil { + // we deploy a new rmnproxy contract to test RMNRemote + rmnProxy, err := deployment.DeployContract(e.Logger, chain, ab, + func(chain deployment.Chain) deployment.ContractDeploy[*rmn_proxy_contract.RMNProxyContract] { + rmnProxyAddr, tx, rmnProxy, err2 := rmn_proxy_contract.DeployRMNProxyContract( + chain.DeployerKey, + chain.Client, + rmnRemoteContract.Address(), + ) + return deployment.ContractDeploy[*rmn_proxy_contract.RMNProxyContract]{ + rmnProxyAddr, rmnProxy, tx, deployment.NewTypeAndVersion(ARMProxy, deployment.Version1_6_0_dev), err2, + } + }) + if err != nil { + e.Logger.Errorw("Failed to deploy RMNProxyNew", "err", err) + return err + } + e.Logger.Infow("deployed new RMNProxyNew", "addr", rmnProxy.Address) + rmnProxyContract = rmnProxy.Contract + } else { + e.Logger.Infow("rmn proxy already deployed", "addr", chainState.RMNProxyNew.Address) + } + if chainState.TestRouter == nil { + testRouterContract, err := deployment.DeployContract(e.Logger, chain, ab, + func(chain deployment.Chain) deployment.ContractDeploy[*router.Router] { + routerAddr, tx2, routerC, err2 := router.DeployRouter( + chain.DeployerKey, + chain.Client, + weth9Contract.Address(), + rmnProxyContract.Address(), + ) + return deployment.ContractDeploy[*router.Router]{ + routerAddr, routerC, tx2, deployment.NewTypeAndVersion(TestRouter, deployment.Version1_2_0), err2, + } + }) + if err != nil { + e.Logger.Errorw("Failed to deploy test router", "err", err) + return err + } + e.Logger.Infow("deployed test router", "addr", testRouterContract.Address) + } else { + e.Logger.Infow("test router already deployed", "addr", chainState.TestRouter.Address) + } + + nmContract := chainState.NonceManager + if chainState.NonceManager == nil { + nonceManager, err := deployment.DeployContract(e.Logger, chain, ab, + func(chain deployment.Chain) deployment.ContractDeploy[*nonce_manager.NonceManager] { + nonceManagerAddr, tx2, nonceManager, err2 := nonce_manager.DeployNonceManager( + chain.DeployerKey, + chain.Client, + []common.Address{}, // Need to add onRamp after + ) + return deployment.ContractDeploy[*nonce_manager.NonceManager]{ + nonceManagerAddr, nonceManager, tx2, deployment.NewTypeAndVersion(NonceManager, deployment.Version1_6_0_dev), err2, + } + }) + if err != nil { + e.Logger.Errorw("Failed to deploy nonce manager", "err", err) + return err + } + e.Logger.Infow("Deployed nonce manager", "addr", nonceManager.Address) + nmContract = nonceManager.Contract + } else { + e.Logger.Infow("nonce manager already deployed", "addr", chainState.NonceManager.Address) + } + feeQuoterContract := chainState.FeeQuoter + if chainState.FeeQuoter == nil { + feeQuoter, err := deployment.DeployContract(e.Logger, chain, ab, + func(chain deployment.Chain) deployment.ContractDeploy[*fee_quoter.FeeQuoter] { + prAddr, tx2, pr, err2 := fee_quoter.DeployFeeQuoter( + chain.DeployerKey, + chain.Client, + fee_quoter.FeeQuoterStaticConfig{ + MaxFeeJuelsPerMsg: big.NewInt(0).Mul(big.NewInt(2e2), big.NewInt(1e18)), + LinkToken: linkTokenContract.Address(), + TokenPriceStalenessThreshold: uint32(24 * 60 * 60), }, - { - PremiumMultiplierWeiPerEth: 1e18, - Token: contractConfig.Weth9.Address(), + []common.Address{mcmsContracts.Timelock.Address}, // timelock should be able to update, ramps added after + []common.Address{weth9Contract.Address(), linkTokenContract.Address()}, // fee tokens + []fee_quoter.FeeQuoterTokenPriceFeedUpdate{}, + []fee_quoter.FeeQuoterTokenTransferFeeConfigArgs{}, // TODO: tokens + []fee_quoter.FeeQuoterPremiumMultiplierWeiPerEthArgs{ + { + PremiumMultiplierWeiPerEth: 9e17, // 0.9 ETH + Token: linkTokenContract.Address(), + }, + { + PremiumMultiplierWeiPerEth: 1e18, + Token: weth9Contract.Address(), + }, }, - }, - []fee_quoter.FeeQuoterDestChainConfigArgs{}, - ) - return deployment.ContractDeploy[*fee_quoter.FeeQuoter]{ - prAddr, pr, tx2, deployment.NewTypeAndVersion(FeeQuoter, deployment.Version1_6_0_dev), err2, - } - }) - if err != nil { - e.Logger.Errorw("Failed to deploy fee quoter", "err", err) - return err - } - e.Logger.Infow("Deployed fee quoter", "addr", feeQuoter.Address) - - onRamp, err := deployment.DeployContract(e.Logger, chain, ab, - func(chain deployment.Chain) deployment.ContractDeploy[*onramp.OnRamp] { - onRampAddr, tx2, onRamp, err2 := onramp.DeployOnRamp( - chain.DeployerKey, - chain.Client, - onramp.OnRampStaticConfig{ - ChainSelector: chain.Selector, - RmnRemote: rmnProxy.Address, - NonceManager: nonceManager.Address, - TokenAdminRegistry: tokenAdminRegistry.Address, - }, - onramp.OnRampDynamicConfig{ - FeeQuoter: feeQuoter.Address, - FeeAggregator: common.HexToAddress("0x1"), // TODO real fee aggregator - }, - []onramp.OnRampDestChainConfigArgs{}, - ) - return deployment.ContractDeploy[*onramp.OnRamp]{ - onRampAddr, onRamp, tx2, deployment.NewTypeAndVersion(OnRamp, deployment.Version1_6_0_dev), err2, - } - }) - if err != nil { - e.Logger.Errorw("Failed to deploy onramp", "err", err) - return err - } - e.Logger.Infow("Deployed onramp", "addr", onRamp.Address) - - offRamp, err := deployment.DeployContract(e.Logger, chain, ab, - func(chain deployment.Chain) deployment.ContractDeploy[*offramp.OffRamp] { - offRampAddr, tx2, offRamp, err2 := offramp.DeployOffRamp( - chain.DeployerKey, - chain.Client, - offramp.OffRampStaticConfig{ - ChainSelector: chain.Selector, - RmnRemote: rmnProxy.Address, - NonceManager: nonceManager.Address, - TokenAdminRegistry: tokenAdminRegistry.Address, - }, - offramp.OffRampDynamicConfig{ - FeeQuoter: feeQuoter.Address, - PermissionLessExecutionThresholdSeconds: uint32(86400), - IsRMNVerificationDisabled: true, - }, - []offramp.OffRampSourceChainConfigArgs{}, - ) - return deployment.ContractDeploy[*offramp.OffRamp]{ - offRampAddr, offRamp, tx2, deployment.NewTypeAndVersion(OffRamp, deployment.Version1_6_0_dev), err2, - } - }) - if err != nil { - e.Logger.Errorw("Failed to deploy offramp", "err", err) - return err + []fee_quoter.FeeQuoterDestChainConfigArgs{}, + ) + return deployment.ContractDeploy[*fee_quoter.FeeQuoter]{ + prAddr, pr, tx2, deployment.NewTypeAndVersion(FeeQuoter, deployment.Version1_6_0_dev), err2, + } + }) + if err != nil { + e.Logger.Errorw("Failed to deploy fee quoter", "err", err) + return err + } + e.Logger.Infow("Deployed fee quoter", "addr", feeQuoter.Address) + feeQuoterContract = feeQuoter.Contract + } else { + e.Logger.Infow("fee quoter already deployed", "addr", chainState.FeeQuoter.Address) + } + onRampContract := chainState.OnRamp + if onRampContract == nil { + onRamp, err := deployment.DeployContract(e.Logger, chain, ab, + func(chain deployment.Chain) deployment.ContractDeploy[*onramp.OnRamp] { + onRampAddr, tx2, onRamp, err2 := onramp.DeployOnRamp( + chain.DeployerKey, + chain.Client, + onramp.OnRampStaticConfig{ + ChainSelector: chain.Selector, + RmnRemote: rmnProxyContract.Address(), + NonceManager: nmContract.Address(), + TokenAdminRegistry: tokenAdminReg.Address(), + }, + onramp.OnRampDynamicConfig{ + FeeQuoter: feeQuoterContract.Address(), + FeeAggregator: common.HexToAddress("0x1"), // TODO real fee aggregator + }, + []onramp.OnRampDestChainConfigArgs{}, + ) + return deployment.ContractDeploy[*onramp.OnRamp]{ + onRampAddr, onRamp, tx2, deployment.NewTypeAndVersion(OnRamp, deployment.Version1_6_0_dev), err2, + } + }) + if err != nil { + e.Logger.Errorw("Failed to deploy onramp", "err", err) + return err + } + e.Logger.Infow("Deployed onramp", "addr", onRamp.Address) + onRampContract = onRamp.Contract + } else { + e.Logger.Infow("onramp already deployed", "addr", chainState.OnRamp.Address) + } + offRampContract := chainState.OffRamp + if offRampContract == nil { + offRamp, err := deployment.DeployContract(e.Logger, chain, ab, + func(chain deployment.Chain) deployment.ContractDeploy[*offramp.OffRamp] { + offRampAddr, tx2, offRamp, err2 := offramp.DeployOffRamp( + chain.DeployerKey, + chain.Client, + offramp.OffRampStaticConfig{ + ChainSelector: chain.Selector, + RmnRemote: rmnProxyContract.Address(), + NonceManager: nmContract.Address(), + TokenAdminRegistry: tokenAdminReg.Address(), + }, + offramp.OffRampDynamicConfig{ + FeeQuoter: feeQuoterContract.Address(), + PermissionLessExecutionThresholdSeconds: uint32(86400), + IsRMNVerificationDisabled: true, + }, + []offramp.OffRampSourceChainConfigArgs{}, + ) + return deployment.ContractDeploy[*offramp.OffRamp]{ + Address: offRampAddr, Contract: offRamp, Tx: tx2, Tv: deployment.NewTypeAndVersion(OffRamp, deployment.Version1_6_0_dev), Err: err2, + } + }) + if err != nil { + e.Logger.Errorw("Failed to deploy offramp", "err", err) + return err + } + e.Logger.Infow("Deployed offramp", "addr", offRamp.Address) + offRampContract = offRamp.Contract + } else { + e.Logger.Infow("offramp already deployed", "addr", chainState.OffRamp.Address) } - e.Logger.Infow("Deployed offramp", "addr", offRamp.Address) - // Basic wiring is always needed. - tx, err = feeQuoter.Contract.ApplyAuthorizedCallerUpdates(chain.DeployerKey, fee_quoter.AuthorizedCallersAuthorizedCallerArgs{ + tx, err = feeQuoterContract.ApplyAuthorizedCallerUpdates(chain.DeployerKey, fee_quoter.AuthorizedCallersAuthorizedCallerArgs{ // TODO: We enable the deployer initially to set prices // Should be removed after. - AddedCallers: []common.Address{offRamp.Contract.Address(), chain.DeployerKey.From}, + AddedCallers: []common.Address{offRampContract.Address(), chain.DeployerKey.From}, }) if _, err := deployment.ConfirmIfNoError(chain, tx, err); err != nil { e.Logger.Errorw("Failed to confirm fee quoter authorized caller update", "err", err) return err } - tx, err = nonceManager.Contract.ApplyAuthorizedCallerUpdates(chain.DeployerKey, nonce_manager.AuthorizedCallersAuthorizedCallerArgs{ - AddedCallers: []common.Address{offRamp.Contract.Address(), onRamp.Contract.Address()}, + tx, err = nmContract.ApplyAuthorizedCallerUpdates(chain.DeployerKey, nonce_manager.AuthorizedCallersAuthorizedCallerArgs{ + AddedCallers: []common.Address{offRampContract.Address(), onRampContract.Address()}, }) if _, err := deployment.ConfirmIfNoError(chain, tx, err); err != nil { e.Logger.Errorw("Failed to update nonce manager with ramps", "err", err) diff --git a/deployment/ccip/deploy_test.go b/deployment/ccip/deploy_test.go index 63aeacb4bdf..f32dd63f806 100644 --- a/deployment/ccip/deploy_test.go +++ b/deployment/ccip/deploy_test.go @@ -10,7 +10,6 @@ import ( "github.com/smartcontractkit/chainlink/deployment" "github.com/smartcontractkit/chainlink/deployment/environment/memory" - "github.com/smartcontractkit/chainlink/v2/core/logger" ) @@ -45,6 +44,11 @@ func TestDeployCCIPContracts(t *testing.T) { require.NotNil(t, s.Chains[feedChainSel].USDFeeds) newAddresses := deployment.NewMemoryAddressBook() + err = DeployPrerequisiteChainContracts(e, newAddresses, e.AllChainSelectors()) + require.NoError(t, err) + require.NoError(t, e.ExistingAddresses.Merge(newAddresses)) + + newAddresses = deployment.NewMemoryAddressBook() err = DeployCCIPContracts(e, newAddresses, DeployCCIPContractConfig{ HomeChainSel: homeChainSel, FeedChainSel: feedChainSel, diff --git a/deployment/ccip/state.go b/deployment/ccip/state.go index 650f46d2b3a..cbcdcc1e116 100644 --- a/deployment/ccip/state.go +++ b/deployment/ccip/state.go @@ -17,6 +17,7 @@ import ( common_v1_0 "github.com/smartcontractkit/chainlink/deployment/common/view/v1_0" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/ccip_config" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/commit_store" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/mock_rmn_contract" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/registry_module_owner_custom" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/rmn_home" @@ -45,7 +46,8 @@ type CCIPChainState struct { OnRamp *onramp.OnRamp OffRamp *offramp.OffRamp FeeQuoter *fee_quoter.FeeQuoter - RMNProxy *rmn_proxy_contract.RMNProxyContract + RMNProxyNew *rmn_proxy_contract.RMNProxyContract + RMNProxyExisting *rmn_proxy_contract.RMNProxyContract NonceManager *nonce_manager.NonceManager TokenAdminRegistry *token_admin_registry.TokenAdminRegistry RegistryModule *registry_module_owner_custom.RegistryModuleOwnerCustom @@ -53,6 +55,7 @@ type CCIPChainState struct { CommitStore *commit_store.CommitStore Weth9 *weth9.WETH9 RMNRemote *rmn_remote.RMNRemote + MockRMN *mock_rmn_contract.MockRMNContract // TODO: May need to support older link too LinkToken *burn_mint_erc677.BurnMintERC677 // Map between token Descriptor (e.g. LinkSymbol, WethSymbol) @@ -150,12 +153,12 @@ func (c CCIPChainState) GenerateView() (view.ChainView, error) { chainView.CommitStore[c.CommitStore.Address().Hex()] = commitStoreView } - if c.RMNProxy != nil { - rmnProxyView, err := v1_0.GenerateRMNProxyView(c.RMNProxy) + if c.RMNProxyNew != nil { + rmnProxyView, err := v1_0.GenerateRMNProxyView(c.RMNProxyNew) if err != nil { return chainView, err } - chainView.RMNProxy[c.RMNProxy.Address().Hex()] = rmnProxyView + chainView.RMNProxy[c.RMNProxyNew.Address().Hex()] = rmnProxyView } if c.CapabilityRegistry != nil { capRegView, err := common_v1_0.GenerateCapabilityRegistryView(c.CapabilityRegistry) @@ -284,7 +287,25 @@ func LoadChainState(chain deployment.Chain, addresses map[string]deployment.Type if err != nil { return state, err } - state.RMNProxy = armProxy + state.RMNProxyExisting = armProxy + case deployment.NewTypeAndVersion(ARMProxy, deployment.Version1_6_0_dev).String(): + armProxy, err := rmn_proxy_contract.NewRMNProxyContract(common.HexToAddress(address), chain.Client) + if err != nil { + return state, err + } + state.RMNProxyNew = armProxy + case deployment.NewTypeAndVersion(ARMProxy, deployment.Version1_6_0_dev).String(): + armProxy, err := rmn_proxy_contract.NewRMNProxyContract(common.HexToAddress(address), chain.Client) + if err != nil { + return state, err + } + state.RMNProxyNew = armProxy + case deployment.NewTypeAndVersion(MockRMN, deployment.Version1_0_0).String(): + mockRMN, err := mock_rmn_contract.NewMockRMNContract(common.HexToAddress(address), chain.Client) + if err != nil { + return state, err + } + state.MockRMN = mockRMN case deployment.NewTypeAndVersion(RMNRemote, deployment.Version1_6_0_dev).String(): rmnRemote, err := rmn_remote.NewRMNRemote(common.HexToAddress(address), chain.Client) if err != nil { diff --git a/deployment/ccip/test_helpers.go b/deployment/ccip/test_helpers.go index 70be57b2f38..bdf8ab35e78 100644 --- a/deployment/ccip/test_helpers.go +++ b/deployment/ccip/test_helpers.go @@ -128,8 +128,6 @@ func DeployTestContracts(t *testing.T, require.NoError(t, err) _, err = DeployFeeds(lggr, ab, chains[feedChainSel]) require.NoError(t, err) - err = DeployFeeTokensToChains(lggr, ab, chains) - require.NoError(t, err) evmChainID, err := chainsel.ChainIdFromSelector(homeChainSel) require.NoError(t, err) return deployment.CapabilityRegistryConfig{ diff --git a/integration-tests/go.mod b/integration-tests/go.mod index b5948028f32..2a8d9eebf07 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -36,7 +36,6 @@ require ( github.com/slack-go/slack v0.15.0 github.com/smartcontractkit/chain-selectors v1.0.29 github.com/smartcontractkit/chainlink-automation v0.8.1 - github.com/smartcontractkit/chainlink-ccip v0.0.0-20241112095015-3e85d9f1898b github.com/smartcontractkit/chainlink-common v0.3.1-0.20241114134822-aadff98ef068 github.com/smartcontractkit/chainlink-protos/job-distributor v0.4.0 github.com/smartcontractkit/chainlink-testing-framework/havoc v1.50.2 @@ -414,6 +413,7 @@ require ( github.com/shoenig/go-m1cpu v0.1.6 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/smartcontractkit/ccip-owner-contracts v0.0.0-20240926212305-a6deabdfce86 // indirect + github.com/smartcontractkit/chainlink-ccip v0.0.0-20241112095015-3e85d9f1898b // indirect github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20241017133723-5277829bd53f // indirect github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20241018134907-a00ba3729b5e // indirect github.com/smartcontractkit/chainlink-feeds v0.1.1 // indirect diff --git a/integration-tests/smoke/ccip_messaging_test.go b/integration-tests/smoke/ccip_messaging_test.go index 55309598c8c..8a193249303 100644 --- a/integration-tests/smoke/ccip_messaging_test.go +++ b/integration-tests/smoke/ccip_messaging_test.go @@ -11,6 +11,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" jobv1 "github.com/smartcontractkit/chainlink-protos/job-distributor/v1/job" + "github.com/smartcontractkit/chainlink/deployment" ccdeploy "github.com/smartcontractkit/chainlink/deployment/ccip" ccipdeployment "github.com/smartcontractkit/chainlink/deployment/ccip" @@ -58,10 +59,15 @@ func Test_CCIPMessaging(t *testing.T) { ", source chain selector:", sourceChain, ", dest chain selector:", destChain, ) + output, err := changeset.DeployPrerequisites(e.Env, changeset.DeployPrerequisiteConfig{ + ChainSelectors: e.Env.AllChainSelectors(), + }) + require.NoError(t, err) + require.NoError(t, e.Env.ExistingAddresses.Merge(output.AddressBook)) tokenConfig := ccipdeployment.NewTestTokenConfig(state.Chains[e.FeedChainSel].USDFeeds) // Apply migration - output, err := changeset.InitialDeploy(e.Env, ccdeploy.DeployCCIPContractConfig{ + output, err = changeset.InitialDeploy(e.Env, ccdeploy.DeployCCIPContractConfig{ HomeChainSel: e.HomeChainSel, FeedChainSel: e.FeedChainSel, ChainsToDeploy: allChainSelectors, diff --git a/integration-tests/smoke/ccip_test.go b/integration-tests/smoke/ccip_test.go index 5b0ba285527..30e66f292a0 100644 --- a/integration-tests/smoke/ccip_test.go +++ b/integration-tests/smoke/ccip_test.go @@ -7,8 +7,6 @@ import ( "github.com/ethereum/go-ethereum/common" "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" @@ -21,6 +19,7 @@ import ( ) func TestInitialDeployOnLocal(t *testing.T) { + t.Parallel() lggr := logger.TestLogger(t) ctx := ccdeploy.Context(t) tenv, _, _ := testsetups.NewLocalDevEnvironment(t, lggr) @@ -30,20 +29,18 @@ func TestInitialDeployOnLocal(t *testing.T) { 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(tenv.Env, ccdeploy.DeployCCIPContractConfig{ + output, err = changeset.InitialDeploy(tenv.Env, ccdeploy.DeployCCIPContractConfig{ HomeChainSel: tenv.HomeChainSel, FeedChainSel: tenv.FeedChainSel, ChainsToDeploy: tenv.Env.AllChainSelectors(), - TokenConfig: tokenConfig, + TokenConfig: ccdeploy.NewTestTokenConfig(feeds), MCMSConfig: ccdeploy.NewTestMCMSConfig(t, e), OCRSecrets: deployment.XXXGenerateTestOCRSecrets(), }) @@ -114,6 +111,7 @@ func TestInitialDeployOnLocal(t *testing.T) { } func TestTokenTransfer(t *testing.T) { + t.Parallel() lggr := logger.TestLogger(t) ctx := ccdeploy.Context(t) tenv, _, _ := testsetups.NewLocalDevEnvironment(t, lggr) @@ -122,22 +120,18 @@ func TestTokenTransfer(t *testing.T) { 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), - }, - ) + output, err := changeset.DeployPrerequisites(e, changeset.DeployPrerequisiteConfig{ + ChainSelectors: e.AllChainSelectors(), + }) + require.NoError(t, err) + require.NoError(t, e.ExistingAddresses.Merge(output.AddressBook)) // Apply migration - output, err := changeset.InitialDeploy(e, ccdeploy.DeployCCIPContractConfig{ + output, err = changeset.InitialDeploy(e, ccdeploy.DeployCCIPContractConfig{ HomeChainSel: tenv.HomeChainSel, FeedChainSel: tenv.FeedChainSel, ChainsToDeploy: e.AllChainSelectors(), - TokenConfig: tokenConfig, + TokenConfig: ccdeploy.NewTestTokenConfig(state.Chains[tenv.FeedChainSel].USDFeeds), MCMSConfig: ccdeploy.NewTestMCMSConfig(t, e), OCRSecrets: deployment.XXXGenerateTestOCRSecrets(), })