From 8fd8898f5334a68cdca9579a250b5f3e82c3a2b5 Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Wed, 7 May 2025 15:58:59 -0300 Subject: [PATCH 1/6] feat(aptos): Add CCIP deployment changeset --- deployment/ccip/changeset/aptos/aptos_test.go | 38 --- .../aptos/config/deploy_aptos_chain.go | 108 +++++++ .../changeset/aptos/cs_deploy_aptos_chain.go | 126 +++++++++ .../aptos/cs_deploy_aptos_chain_test.go | 248 ++++++++++++++++ .../ccip/changeset/aptos/operation/ccip.go | 264 ++++++++++++++++++ .../changeset/aptos/operation/dependencies.go | 12 + .../ccip/changeset/aptos/operation/mcms.go | 168 +++++++++++ .../ccip/changeset/aptos/operation/version.go | 6 + .../changeset/aptos/sequence/deploy_ccip.go | 96 +++++++ .../changeset/aptos/sequence/deploy_mcms.go | 82 ++++++ .../ccip/changeset/aptos/test_helpers.go | 77 +++++ deployment/ccip/changeset/aptos/utils/mcms.go | 214 ++++++++++++++ deployment/go.mod | 2 +- deployment/go.sum | 4 +- 14 files changed, 1404 insertions(+), 41 deletions(-) delete mode 100644 deployment/ccip/changeset/aptos/aptos_test.go create mode 100644 deployment/ccip/changeset/aptos/config/deploy_aptos_chain.go create mode 100644 deployment/ccip/changeset/aptos/cs_deploy_aptos_chain.go create mode 100644 deployment/ccip/changeset/aptos/cs_deploy_aptos_chain_test.go create mode 100644 deployment/ccip/changeset/aptos/operation/ccip.go create mode 100644 deployment/ccip/changeset/aptos/operation/dependencies.go create mode 100644 deployment/ccip/changeset/aptos/operation/mcms.go create mode 100644 deployment/ccip/changeset/aptos/operation/version.go create mode 100644 deployment/ccip/changeset/aptos/sequence/deploy_ccip.go create mode 100644 deployment/ccip/changeset/aptos/sequence/deploy_mcms.go create mode 100644 deployment/ccip/changeset/aptos/test_helpers.go create mode 100644 deployment/ccip/changeset/aptos/utils/mcms.go diff --git a/deployment/ccip/changeset/aptos/aptos_test.go b/deployment/ccip/changeset/aptos/aptos_test.go deleted file mode 100644 index 8b7973bdf28..00000000000 --- a/deployment/ccip/changeset/aptos/aptos_test.go +++ /dev/null @@ -1,38 +0,0 @@ -package aptos - -import ( - "testing" - - "github.com/stretchr/testify/require" - "go.uber.org/zap/zapcore" - - "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/testhelpers" - "github.com/smartcontractkit/chainlink/deployment/environment/memory" - "github.com/smartcontractkit/chainlink/v2/core/logger" -) - -// TODO: This is to test the implementation of Aptos chains in memory environment -// To be deleted after changesets tests are added -func TestAptosMemoryEnv(t *testing.T) { - lggr := logger.TestLogger(t) - env := memory.NewMemoryEnvironment(t, lggr, zapcore.InfoLevel, memory.MemoryEnvironmentConfig{ - AptosChains: 1, - }) - aptosChainSelectors := env.AllChainSelectorsAptos() - require.Len(t, aptosChainSelectors, 1) - require.NotEqual(t, 0, env.AptosChains[0].Selector) -} - -// TODO: This is to test the implementation of Aptos chains in memory environment -// To be deleted after changesets tests are added -func TestAptosHelperMemoryEnv(t *testing.T) { - depEvn, testEnv := testhelpers.NewMemoryEnvironment( - t, - testhelpers.WithAptosChains(1), - testhelpers.WithNoJobsAndContracts(), // currently not supporting jobs and contracts - ) - aptosChainSelectors := depEvn.Env.AllChainSelectorsAptos() - require.Len(t, aptosChainSelectors, 1) - aptosChainSelectors2 := testEnv.DeployedEnvironment().Env.AllChainSelectorsAptos() - require.Len(t, aptosChainSelectors2, 1) -} diff --git a/deployment/ccip/changeset/aptos/config/deploy_aptos_chain.go b/deployment/ccip/changeset/aptos/config/deploy_aptos_chain.go new file mode 100644 index 00000000000..c59470ad260 --- /dev/null +++ b/deployment/ccip/changeset/aptos/config/deploy_aptos_chain.go @@ -0,0 +1,108 @@ +package config + +import ( + "fmt" + + "github.com/aptos-labs/aptos-go-sdk" + "github.com/smartcontractkit/chainlink/deployment" + "github.com/smartcontractkit/chainlink/deployment/common/proposalutils" + "github.com/smartcontractkit/chainlink/deployment/common/types" +) + +// DeployAptosChainConfig is a configuration for deploying CCIP Package for Aptos chains +type DeployAptosChainConfig struct { + MCMSDeployConfigPerChain map[uint64]types.MCMSWithTimelockConfigV2 + MCMSTimelockConfigPerChain map[uint64]proposalutils.TimelockConfig + ContractParamsPerChain map[uint64]ChainContractParams +} + +func (c DeployAptosChainConfig) Validate() error { + for cs, args := range c.ContractParamsPerChain { + if err := deployment.IsValidChainSelector(cs); err != nil { + return fmt.Errorf("invalid chain selector: %d - %w", cs, err) + } + if err := args.Validate(); err != nil { + return fmt.Errorf("invalid contract args for chain %d: %w", cs, err) + } + } + return nil +} + +// ChainContractParams stores configuration to call initialize in CCIP contracts +type ChainContractParams struct { + FeeQuoterParams FeeQuoterParams + OffRampParams OffRampParams + OnRampParams OnRampParams +} + +func (c ChainContractParams) Validate() error { + // Validate every field + if err := c.FeeQuoterParams.Validate(); err != nil { + return fmt.Errorf("invalid FeeQuoterParams: %w", err) + } + if err := c.OffRampParams.Validate(); err != nil { + return fmt.Errorf("invalid OffRampParams: %w", err) + } + if err := c.OnRampParams.Validate(); err != nil { + return fmt.Errorf("invalid OnRampParams: %w", err) + } + return nil +} + +type FeeQuoterParams struct { + MaxFeeJuelsPerMsg uint64 + LinkToken aptos.AccountAddress + TokenPriceStalenessThreshold uint64 + FeeTokens []aptos.AccountAddress +} + +func (f FeeQuoterParams) Validate() error { + if f.LinkToken == (aptos.AccountAddress{}) { + return fmt.Errorf("LinkToken is required") + } + if f.TokenPriceStalenessThreshold == 0 { + return fmt.Errorf("TokenPriceStalenessThreshold can't be 0") + } + if len(f.FeeTokens) == 0 { + return fmt.Errorf("at least one FeeTokens is required") + } + return nil +} + +type OffRampParams struct { + ChainSelector uint64 + PermissionlessExecutionThreshold uint32 + IsRMNVerificationDisabled []bool + SourceChainSelectors []uint64 + SourceChainIsEnabled []bool + SourceChainsOnRamp [][]byte +} + +func (o OffRampParams) Validate() error { + if err := deployment.IsValidChainSelector(o.ChainSelector); err != nil { + return fmt.Errorf("invalid chain selector: %d - %w", o.ChainSelector, err) + } + if o.PermissionlessExecutionThreshold == 0 { + return fmt.Errorf("PermissionlessExecutionThreshold can't be 0") + } + if len(o.SourceChainSelectors) != len(o.SourceChainIsEnabled) { + return fmt.Errorf("SourceChainSelectors and SourceChainIsEnabled must have the same length") + } + return nil +} + +type OnRampParams struct { + ChainSelector uint64 + AllowlistAdmin aptos.AccountAddress + FeeAggregator aptos.AccountAddress +} + +func (o OnRampParams) Validate() error { + if err := deployment.IsValidChainSelector(o.ChainSelector); err != nil { + return fmt.Errorf("invalid chain selector: %d - %w", o.ChainSelector, err) + } + if o.AllowlistAdmin == (aptos.AccountAddress{}) { + return fmt.Errorf("AllowlistAdmin is required") + } + return nil +} diff --git a/deployment/ccip/changeset/aptos/cs_deploy_aptos_chain.go b/deployment/ccip/changeset/aptos/cs_deploy_aptos_chain.go new file mode 100644 index 00000000000..8176668501d --- /dev/null +++ b/deployment/ccip/changeset/aptos/cs_deploy_aptos_chain.go @@ -0,0 +1,126 @@ +package aptos + +import ( + "errors" + "fmt" + + "github.com/aptos-labs/aptos-go-sdk" + + "github.com/smartcontractkit/chainlink-deployments-framework/operations" + "github.com/smartcontractkit/chainlink/deployment" + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset" + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/aptos/config" + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/aptos/operation" + seq "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/aptos/sequence" + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/aptos/utils" + "github.com/smartcontractkit/mcms" + mcmstypes "github.com/smartcontractkit/mcms/types" +) + +var _ deployment.ChangeSetV2[config.DeployAptosChainConfig] = DeployAptosChain{} + +// DeployAptosChain deploys Aptos chain packages and modules +type DeployAptosChain struct{} + +func (cs DeployAptosChain) VerifyPreconditions(env deployment.Environment, config config.DeployAptosChainConfig) error { + // Validate env and prerequisite contracts + state, err := changeset.LoadOnchainStateAptos(env) + if err != nil { + return fmt.Errorf("failed to load existing Aptos onchain state: %w", err) + } + var errs []error + for chainSel := range config.ContractParamsPerChain { + if err := config.Validate(); err != nil { + errs = append(errs, fmt.Errorf("invalid config for Aptos chain %d: %w", chainSel, err)) + continue + } + if _, ok := env.AptosChains[chainSel]; !ok { + errs = append(errs, fmt.Errorf("aptos chain %d not found in env", chainSel)) + } + chainState, ok := state[chainSel] + if !ok { + errs = append(errs, fmt.Errorf("aptos chain %d not found in state", chainSel)) + continue + } + if chainState.MCMSAddress == (aptos.AccountAddress{}) { + mcmsConfig := config.MCMSDeployConfigPerChain[chainSel] + for _, cfg := range []mcmstypes.Config{mcmsConfig.Bypasser, mcmsConfig.Canceller, mcmsConfig.Proposer} { + if err := cfg.Validate(); err != nil { + errs = append(errs, fmt.Errorf("invalid mcms configs for Aptos chain %d: %w", chainSel, err)) + } + } + } + } + + return errors.Join(errs...) +} + +func (cs DeployAptosChain) Apply(env deployment.Environment, config config.DeployAptosChainConfig) (deployment.ChangesetOutput, error) { + state, err := changeset.LoadOnchainState(env) + if err != nil { + return deployment.ChangesetOutput{}, fmt.Errorf("failed to load Aptos onchain state: %w", err) + } + + ab := deployment.NewMemoryAddressBook() + seqReports := make([]operations.Report[any, any], 0) + proposals := make([]mcms.TimelockProposal, 0) + + // Deploy CCIP on each Aptos chain in config + for chainSel := range config.ContractParamsPerChain { + mcmsOperations := []mcmstypes.BatchOperation{} + aptosChain := env.AptosChains[chainSel] + + deps := operation.AptosDeps{ + AB: ab, + AptosChain: aptosChain, + CCIPOnChainState: state, + } + + // MCMS Deploy operations + mcmsSeqReport, err := operations.ExecuteSequence(env.OperationsBundle, seq.DeployMCMSSequence, deps, config.MCMSDeployConfigPerChain[chainSel]) + if err != nil { + return deployment.ChangesetOutput{}, err + } + seqReports = append(seqReports, mcmsSeqReport.ExecutionReports...) + mcmsOperations = append(mcmsOperations, mcmsSeqReport.Output.MCMSOperation) + + // Save MCMS address + typeAndVersion := deployment.NewTypeAndVersion(changeset.AptosMCMSType, deployment.Version1_6_0) + deps.AB.Save(deps.AptosChain.Selector, mcmsSeqReport.Output.MCMSAddress.String(), typeAndVersion) + + // CCIP Deploy operations + ccipSeqInput := seq.DeployCCIPSeqInput{ + MCMSAddress: mcmsSeqReport.Output.MCMSAddress, + CCIPConfig: config.ContractParamsPerChain[chainSel], + } + ccipSeqReport, err := operations.ExecuteSequence(env.OperationsBundle, seq.DeployCCIPSequence, deps, ccipSeqInput) + if err != nil { + return deployment.ChangesetOutput{}, fmt.Errorf("failed to deploy CCIP for Aptos chain %d: %w", chainSel, err) + } + seqReports = append(seqReports, ccipSeqReport.ExecutionReports...) + mcmsOperations = append(mcmsOperations, ccipSeqReport.Output.MCMSOperations...) + + // Save the address of the CCIP object + typeAndVersion = deployment.NewTypeAndVersion(changeset.AptosCCIPType, deployment.Version1_6_0) + deps.AB.Save(deps.AptosChain.Selector, ccipSeqReport.Output.CCIPAddress.String(), typeAndVersion) + + // Generate MCMS proposals + proposal, err := utils.GenerateProposal( + aptosChain.Client, + mcmsSeqReport.Output.MCMSAddress, + chainSel, + mcmsOperations, + "Deploy Aptos MCMS and CCIP", + config.MCMSTimelockConfigPerChain[chainSel], + ) + if err != nil { + return deployment.ChangesetOutput{}, fmt.Errorf("failed to generate MCMS proposal for Aptos chain %d: %w", chainSel, err) + } + proposals = append(proposals, *proposal) + } + return deployment.ChangesetOutput{ + AddressBook: ab, + MCMSTimelockProposals: proposals, + Reports: seqReports, + }, nil +} diff --git a/deployment/ccip/changeset/aptos/cs_deploy_aptos_chain_test.go b/deployment/ccip/changeset/aptos/cs_deploy_aptos_chain_test.go new file mode 100644 index 00000000000..0f22da17add --- /dev/null +++ b/deployment/ccip/changeset/aptos/cs_deploy_aptos_chain_test.go @@ -0,0 +1,248 @@ +package aptos + +import ( + "math/big" + "testing" + "time" + + "github.com/smartcontractkit/chainlink-aptos/bindings/ccip_offramp" + "github.com/smartcontractkit/chainlink/deployment" + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset" + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/aptos/config" + commonchangeset "github.com/smartcontractkit/chainlink/deployment/common/changeset" + "github.com/smartcontractkit/chainlink/deployment/common/proposalutils" + "github.com/smartcontractkit/chainlink/deployment/common/types" + "github.com/smartcontractkit/chainlink/deployment/environment/memory" + "github.com/smartcontractkit/chainlink/v2/core/logger" + mcmstypes "github.com/smartcontractkit/mcms/types" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.uber.org/zap/zapcore" +) + +func TestDeployAptosChainImp_VerifyPreconditions(t *testing.T) { + tests := []struct { + name string + env deployment.Environment + config config.DeployAptosChainConfig + wantErrRe string + wantErr bool + }{ + { + name: "success - valid configs", + env: deployment.Environment{ + Name: "test", + Logger: logger.TestLogger(t), + AptosChains: map[uint64]deployment.AptosChain{ + 743186221051783445: {}, + 4457093679053095497: {}, + }, + ExistingAddresses: deployment.NewMemoryAddressBook(), + }, + config: config.DeployAptosChainConfig{ + ContractParamsPerChain: map[uint64]config.ChainContractParams{ + 4457093679053095497: GetMockChainContractParams(t, 4457093679053095497), + 743186221051783445: GetMockChainContractParams(t, 743186221051783445), + }, + MCMSDeployConfigPerChain: map[uint64]types.MCMSWithTimelockConfigV2{ + 4457093679053095497: getMockMCMSConfig(t), + 743186221051783445: getMockMCMSConfig(t), + }, + }, + wantErr: false, + }, + { + name: "success - valid config w MCMS deployed", + env: deployment.Environment{ + Name: "test", + Logger: logger.TestLogger(t), + AptosChains: map[uint64]deployment.AptosChain{ + 743186221051783445: {}, + 4457093679053095497: {}, + }, + ExistingAddresses: getTestAddressBook( + map[uint64]map[string]deployment.TypeAndVersion{ + 4457093679053095497: { + mockMCMSAddress: {Type: changeset.AptosMCMSType}, + }, + 743186221051783445: { + mockMCMSAddress: {Type: changeset.AptosMCMSType}, + }, + }, + ), + }, + config: config.DeployAptosChainConfig{ + ContractParamsPerChain: map[uint64]config.ChainContractParams{ + 4457093679053095497: GetMockChainContractParams(t, 4457093679053095497), + 743186221051783445: GetMockChainContractParams(t, 743186221051783445), + }, + }, + wantErr: false, + }, + { + name: "error - chain has no env", + env: deployment.Environment{ + Name: "test", + Logger: logger.TestLogger(t), + AptosChains: map[uint64]deployment.AptosChain{ + 4457093679053095497: {}, + }, + ExistingAddresses: getTestAddressBook( + map[uint64]map[string]deployment.TypeAndVersion{ + 4457093679053095497: { + mockMCMSAddress: {Type: changeset.AptosMCMSType}, + }, + 743186221051783445: { + mockMCMSAddress: {Type: changeset.AptosMCMSType}, + }, + }, + ), + }, + config: config.DeployAptosChainConfig{ + ContractParamsPerChain: map[uint64]config.ChainContractParams{ + 4457093679053095497: GetMockChainContractParams(t, 4457093679053095497), + 743186221051783445: GetMockChainContractParams(t, 743186221051783445), + }, + }, + wantErrRe: `chain 743186221051783445 not found in env`, + wantErr: true, + }, + { + name: "error - invalid config - chainSelector", + env: deployment.Environment{ + Name: "test", + Logger: logger.TestLogger(t), + ExistingAddresses: deployment.NewMemoryAddressBook(), + AptosChains: map[uint64]deployment.AptosChain{}, + }, + config: config.DeployAptosChainConfig{ + ContractParamsPerChain: map[uint64]config.ChainContractParams{ + 1: {}, + }, + }, + wantErrRe: "invalid chain selector:", + wantErr: true, + }, + { + name: "error - missing MCMS config for chain without MCMS deployed", + env: deployment.Environment{ + Name: "test", + Logger: logger.TestLogger(t), + AptosChains: map[uint64]deployment.AptosChain{ + 4457093679053095497: {}, + }, + ExistingAddresses: getTestAddressBook( + map[uint64]map[string]deployment.TypeAndVersion{ + 4457093679053095497: {}, // No MCMS address in state + }, + ), + }, + config: config.DeployAptosChainConfig{ + ContractParamsPerChain: map[uint64]config.ChainContractParams{ + 4457093679053095497: GetMockChainContractParams(t, 4457093679053095497), + }, + // MCMSDeployConfigPerChain is missing needed configs + }, + wantErrRe: `invalid mcms configs for chain 4457093679053095497`, + wantErr: true, + }, + { + name: "error - invalid config for chain", + env: deployment.Environment{ + Name: "test", + Logger: logger.TestLogger(t), + AptosChains: map[uint64]deployment.AptosChain{ + 4457093679053095497: {}, + }, + ExistingAddresses: getTestAddressBook( + map[uint64]map[string]deployment.TypeAndVersion{ + 4457093679053095497: { + mockMCMSAddress: {Type: changeset.AptosMCMSType}, // MCMS already deployed + }, + }, + ), + }, + config: config.DeployAptosChainConfig{ + ContractParamsPerChain: map[uint64]config.ChainContractParams{ + 4457093679053095497: { + FeeQuoterParams: config.FeeQuoterParams{ + TokenPriceStalenessThreshold: 0, // Invalid gas limit (assuming 0 is invalid) + }, + }, + }, + }, + wantErrRe: `invalid config for chain 4457093679053095497`, + wantErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + cs := DeployAptosChain{} + err := cs.VerifyPreconditions(tt.env, tt.config) + if tt.wantErr { + assert.Error(t, err) + errStr := err.Error() + assert.Regexp(t, tt.wantErrRe, errStr) + } else { + assert.NoError(t, err) + } + }) + } +} + +func TestDeployAptosChain_Apply(t *testing.T) { + lggr := logger.TestLogger(t) + + // Setup memory environment with 1 Aptos chain + env := memory.NewMemoryEnvironment(t, lggr, zapcore.InfoLevel, memory.MemoryEnvironmentConfig{ + AptosChains: 1, + }) + + // Get chain selectors + aptosChainSelectors := env.AllChainSelectorsAptos() + require.Equal(t, 1, len(aptosChainSelectors), "Expected exactly 1 Aptos chain") + chainSelector := aptosChainSelectors[0] + t.Log("Deployer: ", env.AptosChains[chainSelector].DeployerSigner) + + // Deploy CCIP to Aptos chain + mockCCIPParams := GetMockChainContractParams(t, chainSelector) + ccipConfig := config.DeployAptosChainConfig{ + ContractParamsPerChain: map[uint64]config.ChainContractParams{ + chainSelector: mockCCIPParams, + }, + MCMSDeployConfigPerChain: map[uint64]types.MCMSWithTimelockConfigV2{ + chainSelector: { + Canceller: proposalutils.SingleGroupMCMSV2(t), + Proposer: proposalutils.SingleGroupMCMSV2(t), + Bypasser: proposalutils.SingleGroupMCMSV2(t), + TimelockMinDelay: big.NewInt(0), + }, + }, + MCMSTimelockConfigPerChain: map[uint64]proposalutils.TimelockConfig{ + chainSelector: { + MinDelay: time.Duration(1) * time.Second, + MCMSAction: mcmstypes.TimelockActionSchedule, + OverrideRoot: false, + }, + }, + } + env, _, err := commonchangeset.ApplyChangesetsV2(t, env, []commonchangeset.ConfiguredChangeSet{ + commonchangeset.Configure(DeployAptosChain{}, ccipConfig), + }) + require.NoError(t, err) + + // Verify CCIP deployment state by binding ccip contract and checking if it's deployed + state, err := changeset.LoadOnchainStateAptos(env) + require.NoError(t, err) + require.NotNil(t, state[chainSelector], "No state found for chain") + + ccipAddr := state[chainSelector].CCIPAddress + require.NotEmpty(t, ccipAddr, "CCIP address should not be empty") + + // Bind CCIP contract + offrampBind := ccip_offramp.Bind(ccipAddr, env.AptosChains[chainSelector].Client) + offRampSourceConfig, err := offrampBind.Offramp().GetSourceChainConfig(nil, mockCCIPParams.OffRampParams.SourceChainSelectors[0]) + require.NoError(t, err) + require.Equal(t, true, offRampSourceConfig.IsEnabled, "contracts were not initialized correctly") +} diff --git a/deployment/ccip/changeset/aptos/operation/ccip.go b/deployment/ccip/changeset/aptos/operation/ccip.go new file mode 100644 index 00000000000..f54b985c2dd --- /dev/null +++ b/deployment/ccip/changeset/aptos/operation/ccip.go @@ -0,0 +1,264 @@ +package operation + +import ( + "fmt" + + "github.com/aptos-labs/aptos-go-sdk" + "github.com/smartcontractkit/chainlink-aptos/bindings/ccip" + "github.com/smartcontractkit/chainlink-aptos/bindings/ccip_offramp" + "github.com/smartcontractkit/chainlink-aptos/bindings/ccip_onramp" + "github.com/smartcontractkit/chainlink-aptos/bindings/ccip_router" + mcmsbind "github.com/smartcontractkit/chainlink-aptos/bindings/mcms" + "github.com/smartcontractkit/chainlink-deployments-framework/operations" + aptoscfg "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/aptos/config" + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/aptos/utils" + "github.com/smartcontractkit/mcms/types" +) + +// OP: DeployCCIPOp deploys the CCIP package on Aptos chain +type DeployCCIPInput struct { + MCMSAddress aptos.AccountAddress + IsUpdate bool +} + +type DeployCCIPOutput struct { + CCIPAddress aptos.AccountAddress + MCMSOperations []types.Operation +} + +var DeployCCIPOp = operations.NewOperation( + "deploy-ccip-op", + Version1_0_0, + "Deploys CCIP Package for Aptos Chain", + deployCCIP, +) + +func deployCCIP(b operations.Bundle, deps AptosDeps, in DeployCCIPInput) (DeployCCIPOutput, error) { + onChainState := deps.CCIPOnChainState.AptosChains[deps.AptosChain.Selector] + // Validate there's no package deployed XOR is update + if (onChainState.CCIPAddress == (aptos.AccountAddress{})) == (in.IsUpdate) { + if in.IsUpdate { + b.Logger.Infow("Trying to update a non-deployed package", "addr", onChainState.CCIPAddress.String()) + return DeployCCIPOutput{}, fmt.Errorf("CCIP package not deployed on Aptos chain %d", deps.AptosChain.Selector) + } else { + b.Logger.Infow("CCIP Package already deployed", "addr", onChainState.CCIPAddress.String()) + return DeployCCIPOutput{CCIPAddress: onChainState.CCIPAddress}, nil + } + } + + // Compile, chunk and get CCIP deploy operations + mcmsContract := mcmsbind.Bind(in.MCMSAddress, deps.AptosChain.Client) + ccipObjectAddress, operations, err := getCCIPDeployMCMSOps(mcmsContract, deps.AptosChain.Selector, onChainState.CCIPAddress) + if err != nil { + return DeployCCIPOutput{}, fmt.Errorf("failed to compile and create deploy operations: %w", err) + } + if in.IsUpdate { + return DeployCCIPOutput{ + MCMSOperations: operations, + }, nil + } + + return DeployCCIPOutput{ + CCIPAddress: ccipObjectAddress, + MCMSOperations: operations, + }, nil +} + +func getCCIPDeployMCMSOps(mcmsContract mcmsbind.MCMS, chainSel uint64, ccipAddress aptos.AccountAddress) (aptos.AccountAddress, []types.Operation, error) { + // Calculate addresses of the owner and the object + var ccipObjectAddress aptos.AccountAddress + var err error + if ccipAddress != (aptos.AccountAddress{}) { + ccipObjectAddress = ccipAddress + } else { + ccipObjectAddress, err = mcmsContract.MCMSRegistry().GetNewCodeObjectAddress(nil, []byte(ccip.DefaultSeed)) + if err != nil { + return ccipObjectAddress, []types.Operation{}, fmt.Errorf("failed to calculate object address: %w", err) + } + } + + // Compile Package + payload, err := ccip.Compile(ccipObjectAddress, mcmsContract.Address(), ccipAddress == aptos.AccountAddress{}) + if err != nil { + return ccipObjectAddress, []types.Operation{}, fmt.Errorf("failed to compile: %w", err) + } + + // Create chunks and stage operations + var operations []types.Operation + if ccipAddress == (aptos.AccountAddress{}) { + operations, err = utils.CreateChunksAndStage(payload, mcmsContract, chainSel, ccip.DefaultSeed, nil) + } else { + operations, err = utils.CreateChunksAndStage(payload, mcmsContract, chainSel, "", &ccipObjectAddress) + } + if err != nil { + return ccipObjectAddress, operations, fmt.Errorf("failed to create chunks and stage for %d: %w", chainSel, err) + } + + return ccipObjectAddress, operations, nil +} + +// DeployModulesInput is the input for every module deployment operation +type DeployModulesInput struct { + MCMSAddress aptos.AccountAddress + CCIPAddress aptos.AccountAddress +} + +// OP: DeployRouterOp generates deployment MCMS operations for the Router module +var DeployRouterOp = operations.NewOperation( + "deploy-router-op", + Version1_0_0, + "Generates MCMS proposals that deployes Router module on CCIP package", + deployRouter, +) + +func deployRouter(b operations.Bundle, deps AptosDeps, in DeployModulesInput) ([]types.Operation, error) { + // TODO: is there a way to check if module exists? + mcmsContract := mcmsbind.Bind(in.MCMSAddress, deps.AptosChain.Client) + // Compile Package + payload, err := ccip_router.Compile(in.CCIPAddress, mcmsContract.Address(), true) + if err != nil { + return []types.Operation{}, fmt.Errorf("failed to compile: %w", err) + } + // Create chunks and stage operations + operations, err := utils.CreateChunksAndStage(payload, mcmsContract, deps.AptosChain.Selector, "", &in.CCIPAddress) + if err != nil { + return operations, fmt.Errorf("failed to create chunks and stage for %d: %w", deps.AptosChain.Selector, err) + } + + return operations, nil +} + +// OP: DeployOffRampOp generates deployment MCMS operations for the OffRamp module +var DeployOffRampOp = operations.NewOperation( + "deploy-offramp-op", + Version1_0_0, + "Generates MCMS proposals that deployes OffRamp module on CCIP package", + deployOffRamp, +) + +func deployOffRamp(b operations.Bundle, deps AptosDeps, in DeployModulesInput) ([]types.Operation, error) { + mcmsContract := mcmsbind.Bind(in.MCMSAddress, deps.AptosChain.Client) + // Compile Package + payload, err := ccip_offramp.Compile(in.CCIPAddress, mcmsContract.Address(), true) + if err != nil { + return []types.Operation{}, fmt.Errorf("failed to compile: %w", err) + } + // Create chunks and stage operations + operations, err := utils.CreateChunksAndStage(payload, mcmsContract, deps.AptosChain.Selector, "", &in.CCIPAddress) + if err != nil { + return operations, fmt.Errorf("failed to create chunks and stage for %d: %w", deps.AptosChain.Selector, err) + } + return operations, nil +} + +// OP: DeployOnRampOp generates MCMS proposals for the OnRamp module deployment +var DeployOnRampOp = operations.NewOperation( + "deploy-onramp-op", + Version1_0_0, + "Generates MCMS proposals that deployes OnRamp module on CCIP package", + deployOnRamp, +) + +func deployOnRamp(b operations.Bundle, deps AptosDeps, in DeployModulesInput) ([]types.Operation, error) { + mcmsContract := mcmsbind.Bind(in.MCMSAddress, deps.AptosChain.Client) + // Compile Package + payload, err := ccip_onramp.Compile(in.CCIPAddress, mcmsContract.Address(), true) + if err != nil { + return []types.Operation{}, fmt.Errorf("failed to compile: %w", err) + } + // Create chunks and stage operations + operations, err := utils.CreateChunksAndStage(payload, mcmsContract, deps.AptosChain.Selector, "", &in.CCIPAddress) + if err != nil { + return operations, fmt.Errorf("failed to create chunks and stage for %d: %w", deps.AptosChain.Selector, err) + } + return operations, nil +} + +// OP: InitializeCCIP Operation +type InitializeCCIPInput struct { + MCMSAddress aptos.AccountAddress + CCIPAddress aptos.AccountAddress + CCIPConfig aptoscfg.ChainContractParams +} + +var InitializeCCIPOp = operations.NewOperation( + "initialize-ccip-op", + Version1_0_0, + "Initializes CCIP components with configuration parameters", + initializeCCIP, +) + +func initializeCCIP(b operations.Bundle, deps AptosDeps, in InitializeCCIPInput) (types.BatchOperation, error) { + var txs []types.Transaction + + // Config OnRamp with empty lane configs. We're only able to get router address after deploying the router module + onrampBind := ccip_onramp.Bind(in.CCIPAddress, deps.AptosChain.Client) + moduleInfo, function, _, args, err := onrampBind.Onramp().Encoder().Initialize( + deps.AptosChain.Selector, + in.CCIPConfig.OnRampParams.FeeAggregator, + in.CCIPConfig.OnRampParams.AllowlistAdmin, + []uint64{}, + []aptos.AccountAddress{}, + []bool{}, + ) + if err != nil { + return types.BatchOperation{}, fmt.Errorf("failed to encode onramp initialize: %w", err) + } + mcmsTx, err := utils.GenerateMCMSTx(in.CCIPAddress, moduleInfo, function, args) + if err != nil { + return types.BatchOperation{}, fmt.Errorf("failed to generate MCMS operations for OnRamp Initialize: %w", err) + } + txs = append(txs, mcmsTx) + + // Config OffRamp + offrampBind := ccip_offramp.Bind(in.CCIPAddress, deps.AptosChain.Client) + moduleInfo, function, _, args, err = offrampBind.Offramp().Encoder().Initialize( + deps.AptosChain.Selector, + in.CCIPConfig.OffRampParams.PermissionlessExecutionThreshold, + in.CCIPConfig.OffRampParams.SourceChainSelectors, + in.CCIPConfig.OffRampParams.SourceChainIsEnabled, + in.CCIPConfig.OffRampParams.IsRMNVerificationDisabled, + in.CCIPConfig.OffRampParams.SourceChainsOnRamp, + ) + if err != nil { + return types.BatchOperation{}, fmt.Errorf("failed to encode offramp initialize: %w", err) + } + mcmsTx, err = utils.GenerateMCMSTx(in.CCIPAddress, moduleInfo, function, args) + if err != nil { + return types.BatchOperation{}, fmt.Errorf("failed to generate MCMS operations for OffRamp Initialize: %w", err) + } + txs = append(txs, mcmsTx) + + // Config FeeQuoter and RMNRemote + ccipBind := ccip.Bind(in.CCIPAddress, deps.AptosChain.Client) + + moduleInfo, function, _, args, err = ccipBind.FeeQuoter().Encoder().Initialize( + deps.AptosChain.Selector, + in.CCIPConfig.FeeQuoterParams.LinkToken, + in.CCIPConfig.FeeQuoterParams.TokenPriceStalenessThreshold, + in.CCIPConfig.FeeQuoterParams.FeeTokens, + ) + if err != nil { + return types.BatchOperation{}, fmt.Errorf("failed to encode feequoter initialize: %w", err) + } + mcmsTx, err = utils.GenerateMCMSTx(in.CCIPAddress, moduleInfo, function, args) + if err != nil { + return types.BatchOperation{}, fmt.Errorf("failed to generate MCMS operations for FeeQuoter Initialize: %w", err) + } + txs = append(txs, mcmsTx) + + moduleInfo, function, _, args, err = ccipBind.RMNRemote().Encoder().Initialize(deps.AptosChain.Selector) + if err != nil { + return types.BatchOperation{}, fmt.Errorf("failed to encode rmnremote initialize: %w", err) + } + mcmsTx, err = utils.GenerateMCMSTx(in.CCIPAddress, moduleInfo, function, args) + if err != nil { + return types.BatchOperation{}, fmt.Errorf("failed to generate MCMS operations for RMNRemote Initialize: %w", err) + } + txs = append(txs, mcmsTx) + + return types.BatchOperation{ + ChainSelector: types.ChainSelector(deps.AptosChain.Selector), + Transactions: txs, + }, nil +} diff --git a/deployment/ccip/changeset/aptos/operation/dependencies.go b/deployment/ccip/changeset/aptos/operation/dependencies.go new file mode 100644 index 00000000000..a405395661d --- /dev/null +++ b/deployment/ccip/changeset/aptos/operation/dependencies.go @@ -0,0 +1,12 @@ +package operation + +import ( + "github.com/smartcontractkit/chainlink/deployment" + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset" +) + +type AptosDeps struct { + AB *deployment.AddressBookMap + AptosChain deployment.AptosChain + CCIPOnChainState changeset.CCIPOnChainState +} diff --git a/deployment/ccip/changeset/aptos/operation/mcms.go b/deployment/ccip/changeset/aptos/operation/mcms.go new file mode 100644 index 00000000000..5668eac6c4e --- /dev/null +++ b/deployment/ccip/changeset/aptos/operation/mcms.go @@ -0,0 +1,168 @@ +package operation + +import ( + "context" + "encoding/json" + "fmt" + "time" + + "github.com/aptos-labs/aptos-go-sdk" + "github.com/smartcontractkit/chainlink-aptos/bindings/bind" + mcmsbind "github.com/smartcontractkit/chainlink-aptos/bindings/mcms" + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/aptos/utils" + aptosmcms "github.com/smartcontractkit/mcms/sdk/aptos" + "github.com/smartcontractkit/mcms/types" + mcmstypes "github.com/smartcontractkit/mcms/types" + + "github.com/smartcontractkit/chainlink-deployments-framework/operations" +) + +// OP: Deploy MCMS Contract +var DeployMCMSOp = operations.NewOperation( + "deploy-mcms-op", + Version1_0_0, + "Deploys MCMS Contract Operation for Aptos Chain", + deployMCMS, +) + +func deployMCMS(b operations.Bundle, deps AptosDeps, _ operations.EmptyInput) (aptos.AccountAddress, error) { + mcmsSeed := mcmsbind.DefaultSeed + time.Now().String() + mcmsAddress, mcmsDeployTx, _, err := mcmsbind.DeployToResourceAccount(deps.AptosChain.DeployerSigner, deps.AptosChain.Client, mcmsSeed) + if err != nil { + return aptos.AccountAddress{}, fmt.Errorf("failed to deploy MCMS contract: %v", err) + } + if err := deps.AptosChain.Confirm(mcmsDeployTx.Hash); err != nil { + return aptos.AccountAddress{}, fmt.Errorf("failed to confirm MCMS deployment transaction: %v", err) + } + + return mcmsAddress, nil +} + +// OP: Configure MCMS Contract +type ConfigureMCMSInput struct { + MCMSAddress aptos.AccountAddress + MCMSConfigs mcmstypes.Config + MCMSRole aptosmcms.TimelockRole +} + +var ConfigureMCMSOp = operations.NewOperation( + "configure-mcms-op", + Version1_0_0, + "Configure MCMS Contract Operation for Aptos Chain", + configureMCMS, +) + +func configureMCMS(b operations.Bundle, deps AptosDeps, in ConfigureMCMSInput) (any, error) { + configurer := aptosmcms.NewConfigurer(deps.AptosChain.Client, deps.AptosChain.DeployerSigner, in.MCMSRole) + setCfgTx, err := configurer.SetConfig(context.Background(), in.MCMSAddress.StringLong(), &in.MCMSConfigs, false) + if err != nil { + return nil, fmt.Errorf("failed to setConfig in MCMS contract: %w", err) + } + if err := deps.AptosChain.Confirm(setCfgTx.Hash); err != nil { + return nil, fmt.Errorf("MCMS setConfig transaction failed: %w", err) + } + return nil, nil +} + +// OP: Transfer Ownership to Self +var TransferOwnershipToSelfOp = operations.NewOperation( + "transfer-ownership-to-self-op", + Version1_0_0, + "Transfer ownership to self", + transferOwnershipToSelf, +) + +func transferOwnershipToSelf(b operations.Bundle, deps AptosDeps, mcmsAddress aptos.AccountAddress) (any, error) { + opts := &bind.TransactOpts{Signer: deps.AptosChain.DeployerSigner} + contractMCMS := mcmsbind.Bind(mcmsAddress, deps.AptosChain.Client) + tx, err := contractMCMS.MCMSAccount().TransferOwnershipToSelf(opts) + if err != nil { + return nil, fmt.Errorf("failed to TransferOwnershipToSelf in MCMS contract: %w", err) + } + _, err = deps.AptosChain.Client.WaitForTransaction(tx.Hash) + if err != nil { + return nil, fmt.Errorf("MCMS TransferOwnershipToSelf transaction failed: %w", err) + } + return nil, nil +} + +// OP: Accept Ownership +var AcceptOwnershipOp = operations.NewOperation( + "accept-ownership-op", + Version1_0_0, + "Generate Accept Ownership BatchOperations for MCMS Contract", + acceptOwnership, +) + +func acceptOwnership(b operations.Bundle, deps AptosDeps, mcmsAddress aptos.AccountAddress) (mcmstypes.BatchOperation, error) { + contractMCMS := mcmsbind.Bind(mcmsAddress, deps.AptosChain.Client) + moduleInfo, function, _, args, err := contractMCMS.MCMSAccount().Encoder().AcceptOwnership() + if err != nil { + return mcmstypes.BatchOperation{}, fmt.Errorf("failed to encode AcceptOwnership: %w", err) + } + additionalFields := aptosmcms.AdditionalFields{ + PackageName: moduleInfo.PackageName, + ModuleName: moduleInfo.ModuleName, + Function: function, + } + callOneAdditionalFields, err := json.Marshal(additionalFields) + if err != nil { + return mcmstypes.BatchOperation{}, fmt.Errorf("failed to marshal additionalFields: %w", err) + } + + return mcmstypes.BatchOperation{ + ChainSelector: mcmstypes.ChainSelector(deps.AptosChain.Selector), + Transactions: []mcmstypes.Transaction{{ + To: mcmsAddress.StringLong(), + Data: aptosmcms.ArgsToData(args), + AdditionalFields: callOneAdditionalFields, + }}, + }, err +} + +// OP: CleanupStagingAreaOp generates a batch operation to clean up the staging area +var CleanupStagingAreaOp = operations.NewOperation( + "cleanup-staging-area-op", + Version1_0_0, + "Cleans up MCMS staging area if it's not already clean", + cleanupStagingArea, +) + +func cleanupStagingArea(b operations.Bundle, deps AptosDeps, mcmsAddress aptos.AccountAddress) (types.BatchOperation, error) { + // Check resources first to see if staging is clean + IsMCMSStagingAreaClean, err := utils.IsMCMSStagingAreaClean(deps.AptosChain.Client, mcmsAddress) + if err != nil { + return types.BatchOperation{}, fmt.Errorf("failed to check if MCMS staging area is clean: %w", err) + } + if IsMCMSStagingAreaClean { + b.Logger.Infow("MCMS Staging Area already clean", "addr", mcmsAddress.String()) + return types.BatchOperation{}, nil + } + + // Bind MCMS contract + mcmsContract := mcmsbind.Bind(mcmsAddress, deps.AptosChain.Client) + + // Get cleanup staging operations + moduleInfo, function, _, args, err := mcmsContract.MCMSDeployer().Encoder().CleanupStagingArea() + if err != nil { + return types.BatchOperation{}, fmt.Errorf("failed to EncodeCleanupStagingArea: %w", err) + } + additionalFields := aptosmcms.AdditionalFields{ + PackageName: moduleInfo.PackageName, + ModuleName: moduleInfo.ModuleName, + Function: function, + } + afBytes, err := json.Marshal(additionalFields) + if err != nil { + return types.BatchOperation{}, fmt.Errorf("failed to marshal additional fields: %w", err) + } + + return types.BatchOperation{ + ChainSelector: types.ChainSelector(deps.AptosChain.Selector), + Transactions: []types.Transaction{{ + To: mcmsAddress.StringLong(), + Data: aptosmcms.ArgsToData(args), + AdditionalFields: afBytes, + }}, + }, nil +} diff --git a/deployment/ccip/changeset/aptos/operation/version.go b/deployment/ccip/changeset/aptos/operation/version.go new file mode 100644 index 00000000000..aa2f2248147 --- /dev/null +++ b/deployment/ccip/changeset/aptos/operation/version.go @@ -0,0 +1,6 @@ +package operation + +import "github.com/Masterminds/semver/v3" + +// Holds versions for Aptos changeset/operations +var Version1_0_0 = semver.MustParse("1.0.0") diff --git a/deployment/ccip/changeset/aptos/sequence/deploy_ccip.go b/deployment/ccip/changeset/aptos/sequence/deploy_ccip.go new file mode 100644 index 00000000000..ae464fcf7c6 --- /dev/null +++ b/deployment/ccip/changeset/aptos/sequence/deploy_ccip.go @@ -0,0 +1,96 @@ +package sequence + +import ( + "github.com/aptos-labs/aptos-go-sdk" + + "github.com/smartcontractkit/chainlink-deployments-framework/operations" + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/aptos/config" + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/aptos/operation" + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/aptos/utils" + mcmstypes "github.com/smartcontractkit/mcms/types" +) + +type DeployCCIPSeqInput struct { + MCMSAddress aptos.AccountAddress + CCIPConfig config.ChainContractParams +} + +type DeployCCIPSeqOutput struct { + CCIPAddress aptos.AccountAddress + MCMSOperations []mcmstypes.BatchOperation +} + +var DeployCCIPSequence = operations.NewSequence( + "deploy-aptos-ccip-sequence", + operation.Version1_0_0, + "Deploy Aptos CCIP contracts and initialize them", + deployCCIPSequence, +) + +func deployCCIPSequence(b operations.Bundle, deps operation.AptosDeps, in DeployCCIPSeqInput) (DeployCCIPSeqOutput, error) { + var mcmsOperations []mcmstypes.BatchOperation + + // Cleanup MCMS staging area if not clear + cleanupReport, err := operations.ExecuteOperation(b, operation.CleanupStagingAreaOp, deps, in.MCMSAddress) + if err != nil { + return DeployCCIPSeqOutput{}, err + } + if len(cleanupReport.Output.Transactions) > 0 { + mcmsOperations = append(mcmsOperations, cleanupReport.Output) + } + + // Generate batch operations to deploy CCIP package + deployCCIPInput := operation.DeployCCIPInput{ + MCMSAddress: in.MCMSAddress, + IsUpdate: false, + } + deployCCIPReport, err := operations.ExecuteOperation(b, operation.DeployCCIPOp, deps, deployCCIPInput) + if err != nil { + return DeployCCIPSeqOutput{}, err + } + ccipAddress := deployCCIPReport.Output.CCIPAddress + // For CCIP deployment the txs cannot be batched - it'd exceed Aptos API limits + // so they're converted to batch operations with single transactions in each batch + mcmsOperations = append(mcmsOperations, utils.ToBatchOperations(deployCCIPReport.Output.MCMSOperations)...) + + // Generate batch operations to deploy CCIP modules + deployModulesInput := operation.DeployModulesInput{ + MCMSAddress: in.MCMSAddress, + CCIPAddress: ccipAddress, + } + // OnRamp module + deployOnRampReport, err := operations.ExecuteOperation(b, operation.DeployOnRampOp, deps, deployModulesInput) + if err != nil { + return DeployCCIPSeqOutput{}, err + } + mcmsOperations = append(mcmsOperations, utils.ToBatchOperations(deployOnRampReport.Output)...) + // OffRamp module + deployOffRampReport, err := operations.ExecuteOperation(b, operation.DeployOffRampOp, deps, deployModulesInput) + if err != nil { + return DeployCCIPSeqOutput{}, err + } + mcmsOperations = append(mcmsOperations, utils.ToBatchOperations(deployOffRampReport.Output)...) + // Router module + deployRouterReport, err := operations.ExecuteOperation(b, operation.DeployRouterOp, deps, deployModulesInput) + if err != nil { + return DeployCCIPSeqOutput{}, err + } + mcmsOperations = append(mcmsOperations, utils.ToBatchOperations(deployRouterReport.Output)...) + + // Generate batch operations to initialize CCIP + initCCIPInput := operation.InitializeCCIPInput{ + MCMSAddress: in.MCMSAddress, + CCIPAddress: ccipAddress, + CCIPConfig: in.CCIPConfig, + } + initCCIPReport, err := operations.ExecuteOperation(b, operation.InitializeCCIPOp, deps, initCCIPInput) + if err != nil { + return DeployCCIPSeqOutput{}, err + } + mcmsOperations = append(mcmsOperations, initCCIPReport.Output) + + return DeployCCIPSeqOutput{ + CCIPAddress: ccipAddress, + MCMSOperations: mcmsOperations, + }, nil +} diff --git a/deployment/ccip/changeset/aptos/sequence/deploy_mcms.go b/deployment/ccip/changeset/aptos/sequence/deploy_mcms.go new file mode 100644 index 00000000000..25d1617b6ce --- /dev/null +++ b/deployment/ccip/changeset/aptos/sequence/deploy_mcms.go @@ -0,0 +1,82 @@ +package sequence + +import ( + "github.com/aptos-labs/aptos-go-sdk" + + "github.com/smartcontractkit/chainlink-deployments-framework/operations" + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/aptos/operation" + "github.com/smartcontractkit/chainlink/deployment/common/types" + aptosmcms "github.com/smartcontractkit/mcms/sdk/aptos" + mcmstypes "github.com/smartcontractkit/mcms/types" +) + +// Deploy MCMS Sequence +type DeployMCMSSeqOutput struct { + MCMSAddress aptos.AccountAddress + MCMSOperation mcmstypes.BatchOperation +} + +var DeployMCMSSequence = operations.NewSequence( + "deploy-aptos-mcms-sequence", + operation.Version1_0_0, + "Deploy Aptos MCMS contract and configure it", + deployMCMSSequence, +) + +func deployMCMSSequence(b operations.Bundle, deps operation.AptosDeps, configMCMS types.MCMSWithTimelockConfigV2) (DeployMCMSSeqOutput, error) { + // Check if MCMS package is already deployed + onChainState := deps.CCIPOnChainState.AptosChains[deps.AptosChain.Selector] + if onChainState.MCMSAddress != (aptos.AccountAddress{}) { + b.Logger.Infow("MCMS Package already deployed", "addr", onChainState.MCMSAddress.String()) + return DeployMCMSSeqOutput{}, nil + } + // Deploy MCMS + deployMCMSReport, err := operations.ExecuteOperation(b, operation.DeployMCMSOp, deps, operations.EmptyInput{}) + if err != nil { + return DeployMCMSSeqOutput{}, err + } + // Configure MCMS + configureMCMSBypassers := operation.ConfigureMCMSInput{ + MCMSAddress: deployMCMSReport.Output, + MCMSConfigs: configMCMS.Bypasser, + MCMSRole: aptosmcms.TimelockRoleBypasser, + } + _, err = operations.ExecuteOperation(b, operation.ConfigureMCMSOp, deps, configureMCMSBypassers) + if err != nil { + return DeployMCMSSeqOutput{}, err + } + configureMCMSCancellers := operation.ConfigureMCMSInput{ + MCMSAddress: deployMCMSReport.Output, + MCMSConfigs: configMCMS.Canceller, + MCMSRole: aptosmcms.TimelockRoleCanceller, + } + _, err = operations.ExecuteOperation(b, operation.ConfigureMCMSOp, deps, configureMCMSCancellers) + if err != nil { + return DeployMCMSSeqOutput{}, err + } + configureMCMSProposers := operation.ConfigureMCMSInput{ + MCMSAddress: deployMCMSReport.Output, + MCMSConfigs: configMCMS.Proposer, + MCMSRole: aptosmcms.TimelockRoleProposer, + } + _, err = operations.ExecuteOperation(b, operation.ConfigureMCMSOp, deps, configureMCMSProposers) + if err != nil { + return DeployMCMSSeqOutput{}, err + } + // TODO: Should set MinDelay to timelock + // Transfer ownership to self + _, err = operations.ExecuteOperation(b, operation.TransferOwnershipToSelfOp, deps, deployMCMSReport.Output) + if err != nil { + return DeployMCMSSeqOutput{}, err + } + // Generate proposal to accept ownership + gaopReport, err := operations.ExecuteOperation(b, operation.AcceptOwnershipOp, deps, deployMCMSReport.Output) + if err != nil { + return DeployMCMSSeqOutput{}, err + } + + return DeployMCMSSeqOutput{ + MCMSAddress: deployMCMSReport.Output, + MCMSOperation: gaopReport.Output, + }, nil +} diff --git a/deployment/ccip/changeset/aptos/test_helpers.go b/deployment/ccip/changeset/aptos/test_helpers.go new file mode 100644 index 00000000000..091580aa091 --- /dev/null +++ b/deployment/ccip/changeset/aptos/test_helpers.go @@ -0,0 +1,77 @@ +package aptos + +import ( + "math/big" + "testing" + + "github.com/aptos-labs/aptos-go-sdk" + "github.com/ethereum/go-ethereum/common" + "github.com/smartcontractkit/chainlink/deployment" + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/aptos/config" + "github.com/smartcontractkit/chainlink/deployment/common/proposalutils" + "github.com/smartcontractkit/chainlink/deployment/common/types" + "github.com/stretchr/testify/assert" +) + +const ( + mockMCMSAddress = "0x3f20aa841a0eb5c038775bdb868924770df1ce377cc0013b3ba4ac9fd69a4f90" + mockAddress = "0x13a9f1a109368730f2e355d831ba8fbf5942fb82321863d55de54cb4ebe5d18f" + mockLinkAddress = "0xa" + + sepChainSelector = 11155111 + sepMockOnRampAddress = "0x0BF3dE8c5D3e8A2B34D2BEeB17ABfCeBaf363A59" +) + +func getTestAddressBook(addrByChain map[uint64]map[string]deployment.TypeAndVersion) deployment.AddressBook { + ab := deployment.NewMemoryAddressBook() + for chain, addrTypeAndVersion := range addrByChain { + for addr, typeAndVersion := range addrTypeAndVersion { + ab.Save(chain, addr, typeAndVersion) + } + } + return ab +} + +func mustParseAddress(t *testing.T, addr string) aptos.AccountAddress { + t.Helper() + var address aptos.AccountAddress + err := address.ParseStringRelaxed(addr) + assert.NoError(t, err) + return address +} + +func GetMockChainContractParams(t *testing.T, chainSelector uint64) config.ChainContractParams { + mockParsedAddress := mustParseAddress(t, mockAddress) + mockParsedLinkAddress := mustParseAddress(t, mockLinkAddress) + + return config.ChainContractParams{ + FeeQuoterParams: config.FeeQuoterParams{ + MaxFeeJuelsPerMsg: 1000000, + LinkToken: mockParsedLinkAddress, + TokenPriceStalenessThreshold: 1000000, + FeeTokens: []aptos.AccountAddress{mockParsedLinkAddress}, + }, + OffRampParams: config.OffRampParams{ + ChainSelector: chainSelector, + PermissionlessExecutionThreshold: uint32(60 * 60 * 8), + IsRMNVerificationDisabled: []bool{false}, + SourceChainSelectors: []uint64{sepChainSelector}, + SourceChainIsEnabled: []bool{true}, + SourceChainsOnRamp: [][]byte{common.HexToAddress(sepMockOnRampAddress).Bytes()}, + }, + OnRampParams: config.OnRampParams{ + ChainSelector: chainSelector, + AllowlistAdmin: mockParsedAddress, + FeeAggregator: mockParsedAddress, + }, + } +} + +func getMockMCMSConfig(t *testing.T) types.MCMSWithTimelockConfigV2 { + return types.MCMSWithTimelockConfigV2{ + Canceller: proposalutils.SingleGroupMCMSV2(t), + Proposer: proposalutils.SingleGroupMCMSV2(t), + Bypasser: proposalutils.SingleGroupMCMSV2(t), + TimelockMinDelay: big.NewInt(0), + } +} diff --git a/deployment/ccip/changeset/aptos/utils/mcms.go b/deployment/ccip/changeset/aptos/utils/mcms.go new file mode 100644 index 00000000000..cc46a927bb8 --- /dev/null +++ b/deployment/ccip/changeset/aptos/utils/mcms.go @@ -0,0 +1,214 @@ +package utils + +import ( + "context" + "encoding/json" + "fmt" + "strings" + "time" + + "github.com/aptos-labs/aptos-go-sdk" + "github.com/smartcontractkit/chainlink-aptos/bindings/bind" + "github.com/smartcontractkit/chainlink-aptos/bindings/compile" + mcmsbind "github.com/smartcontractkit/chainlink-aptos/bindings/mcms" + "github.com/smartcontractkit/chainlink/deployment/common/proposalutils" + "github.com/smartcontractkit/mcms" + aptosmcms "github.com/smartcontractkit/mcms/sdk/aptos" + "github.com/smartcontractkit/mcms/types" +) + +const MCMSProposalVersion = "v1" + +func GenerateProposal( + client aptos.AptosRpcClient, + mcmsAddress aptos.AccountAddress, + chainSel uint64, + operations []types.BatchOperation, + description string, + mcmsCfg proposalutils.TimelockConfig, +) (*mcms.TimelockProposal, error) { + // Get role from action + role, err := roleFromAction(mcmsCfg.MCMSAction) + if err != nil { + return nil, fmt.Errorf("failed to get role from action: %w", err) + } + jsonRole, _ := json.Marshal(aptosmcms.AdditionalFieldsMetadata{Role: role}) + var action = mcmsCfg.MCMSAction + if action == "" { + action = types.TimelockActionSchedule + } + // Create MCMS inspector + inspector := aptosmcms.NewInspector(client, role) + startingOpCount, err := inspector.GetOpCount(context.Background(), mcmsAddress.StringLong()) + if err != nil { + return nil, fmt.Errorf("failed to get starting op count: %w", err) + } + opCount := startingOpCount + + // Create proposal builder + validUntil := time.Now().Unix() + int64(proposalutils.DefaultValidUntil.Seconds()) + proposalBuilder := mcms.NewTimelockProposalBuilder(). + SetVersion(MCMSProposalVersion). + SetValidUntil(uint32(validUntil)). + SetDescription(description). + AddTimelockAddress(types.ChainSelector(chainSel), mcmsAddress.StringLong()). + SetOverridePreviousRoot(mcmsCfg.OverrideRoot). + AddChainMetadata( + types.ChainSelector(chainSel), + types.ChainMetadata{ + StartingOpCount: opCount, + MCMAddress: mcmsAddress.StringLong(), + AdditionalFields: jsonRole, + }, + ). + SetAction(action). + SetDelay(types.NewDuration(mcmsCfg.MinDelay)) + + // Add operations and build + for _, op := range operations { + proposalBuilder.AddOperation(op) + } + proposal, err := proposalBuilder.Build() + if err != nil { + return nil, fmt.Errorf("failed to build proposal: %w", err) + } + + return proposal, nil +} + +func roleFromAction(action types.TimelockAction) (aptosmcms.TimelockRole, error) { + switch action { + case types.TimelockActionSchedule: + return aptosmcms.TimelockRoleProposer, nil + case types.TimelockActionBypass: + return aptosmcms.TimelockRoleBypasser, nil + case types.TimelockActionCancel: + return aptosmcms.TimelockRoleCanceller, nil + case "": + return aptosmcms.TimelockRoleProposer, nil + default: + return aptosmcms.TimelockRoleProposer, fmt.Errorf("invalid action: %s", action) + } +} + +// ToBatchOperations converts Operations into BatchOperations with a single transaction each +func ToBatchOperations(ops []types.Operation) []types.BatchOperation { + batchOps := []types.BatchOperation{} + for _, op := range ops { + batchOps = append(batchOps, types.BatchOperation{ + ChainSelector: op.ChainSelector, + Transactions: []types.Transaction{op.Transaction}, + }) + } + return batchOps +} + +// IsMCMSStagingAreaClean checks if the MCMS staging area is clean +func IsMCMSStagingAreaClean(client aptos.AptosRpcClient, aptosMCMSObjAddr aptos.AccountAddress) (bool, error) { + resources, err := client.AccountResources(aptosMCMSObjAddr) + if err != nil { + return false, err + } + for _, resource := range resources { + if strings.Contains(resource.Type, "StagingArea") { + return false, nil + } + } + return true, nil +} + +// CreateChunksAndStage creates chunks from the compiled packages and build MCMS operations to stages them within the MCMS contract +func CreateChunksAndStage( + payload compile.CompiledPackage, + mcmsContract mcmsbind.MCMS, + chainSel uint64, + seed string, + codeObjectAddress *aptos.AccountAddress, +) ([]types.Operation, error) { + mcmsAddress := mcmsContract.Address() + // Validate seed XOR codeObjectAddress, one and only one must be provided + if (seed != "") == (codeObjectAddress != nil) { + return nil, fmt.Errorf("either provide seed to publishToObject or objectAddress to upgradeObjectCode") + } + + var operations []types.Operation + + // Create chunks + chunks, err := bind.CreateChunks(payload, bind.ChunkSizeInBytes) + if err != nil { + return operations, fmt.Errorf("failed to create chunks: %w", err) + } + + // Stage chunks with mcms_deployer module and execute with the last one + for i, chunk := range chunks { + var ( + moduleInfo bind.ModuleInformation + function string + args [][]byte + err error + ) + + // First chunks get staged, the last one gets published or upgraded + if i != len(chunks)-1 { + moduleInfo, function, _, args, err = mcmsContract.MCMSDeployer().Encoder().StageCodeChunk( + chunk.Metadata, + chunk.CodeIndices, + chunk.Chunks, + ) + } else if seed != "" { + moduleInfo, function, _, args, err = mcmsContract.MCMSDeployer().Encoder().StageCodeChunkAndPublishToObject( + chunk.Metadata, + chunk.CodeIndices, + chunk.Chunks, + []byte(seed), + ) + } else { + moduleInfo, function, _, args, err = mcmsContract.MCMSDeployer().Encoder().StageCodeChunkAndUpgradeObjectCode( + chunk.Metadata, + chunk.CodeIndices, + chunk.Chunks, + *codeObjectAddress, + ) + } + if err != nil { + return operations, fmt.Errorf("failed to encode chunk %d: %w", i, err) + } + additionalFields := aptosmcms.AdditionalFields{ + PackageName: moduleInfo.PackageName, + ModuleName: moduleInfo.ModuleName, + Function: function, + } + afBytes, err := json.Marshal(additionalFields) + if err != nil { + return operations, fmt.Errorf("failed to marshal additional fields: %w", err) + } + operations = append(operations, types.Operation{ + ChainSelector: types.ChainSelector(chainSel), + Transaction: types.Transaction{ + To: mcmsAddress.StringLong(), + Data: aptosmcms.ArgsToData(args), + AdditionalFields: afBytes, + }, + }) + } + + return operations, nil +} + +// GenerateMCMSTx is a helper function that generates a MCMS txs for the given parameters +func GenerateMCMSTx(toAddress aptos.AccountAddress, moduleInfo bind.ModuleInformation, function string, args [][]byte) (types.Transaction, error) { + additionalFields := aptosmcms.AdditionalFields{ + PackageName: moduleInfo.PackageName, + ModuleName: moduleInfo.ModuleName, + Function: function, + } + afBytes, err := json.Marshal(additionalFields) + if err != nil { + return types.Transaction{}, fmt.Errorf("failed to marshal additional fields: %w", err) + } + return types.Transaction{ + To: toAddress.StringLong(), + Data: aptosmcms.ArgsToData(args), + AdditionalFields: afBytes, + }, nil +} diff --git a/deployment/go.mod b/deployment/go.mod index 279de2021ec..c462d3bb200 100644 --- a/deployment/go.mod +++ b/deployment/go.mod @@ -31,7 +31,7 @@ require ( github.com/sethvargo/go-retry v0.2.4 github.com/smartcontractkit/ccip-owner-contracts v0.1.0 github.com/smartcontractkit/chain-selectors v1.0.55 - github.com/smartcontractkit/chainlink-aptos v0.0.0-20250414155853-651b4e583ee9 + github.com/smartcontractkit/chainlink-aptos v0.0.0-20250502091650-484cfa7ccddf github.com/smartcontractkit/chainlink-ccip v0.0.0-20250506195202-6a3f20db41c6 github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250425163923-16aa375957b7 github.com/smartcontractkit/chainlink-common v0.7.1-0.20250506185033-ea88ef405511 diff --git a/deployment/go.sum b/deployment/go.sum index 17b667700d2..4d8210091da 100644 --- a/deployment/go.sum +++ b/deployment/go.sum @@ -1232,8 +1232,8 @@ github.com/smartcontractkit/ccip-owner-contracts v0.1.0 h1:GiBDtlx7539o7AKlDV+9L github.com/smartcontractkit/ccip-owner-contracts v0.1.0/go.mod h1:NnT6w4Kj42OFFXhSx99LvJZWPpMjmo4+CpDEWfw61xY= github.com/smartcontractkit/chain-selectors v1.0.55 h1:jn8cwTBEzAi/eQRDO7EbFpZFn60yxygnSSPP2HPbYs0= github.com/smartcontractkit/chain-selectors v1.0.55/go.mod h1:xsKM0aN3YGcQKTPRPDDtPx2l4mlTN1Djmg0VVXV40b8= -github.com/smartcontractkit/chainlink-aptos v0.0.0-20250414155853-651b4e583ee9 h1:lw8RZ8IR4UX1M7djAB3IuMtcAqFX4Z4bzQczClfb8bs= -github.com/smartcontractkit/chainlink-aptos v0.0.0-20250414155853-651b4e583ee9/go.mod h1:Sq/ddMOYch6ZuAnW2k5u9V4+TlGKFzuHQnTM8JXEU+g= +github.com/smartcontractkit/chainlink-aptos v0.0.0-20250502091650-484cfa7ccddf h1:zzG5D68tGbDBW3mQW6sa50ga0kGRQp9S7F4vqZO0ZrU= +github.com/smartcontractkit/chainlink-aptos v0.0.0-20250502091650-484cfa7ccddf/go.mod h1:yj4d1XS6lBOXM1sDMP1ULCbRJgOuBYf2V7VtQ6Qgev8= github.com/smartcontractkit/chainlink-automation v0.8.1 h1:sTc9LKpBvcKPc1JDYAmgBc2xpDKBco/Q4h4ydl6+UUU= github.com/smartcontractkit/chainlink-automation v0.8.1/go.mod h1:Iij36PvWZ6blrdC5A/nrQUBuf3MH3JvsBB9sSyc9W08= github.com/smartcontractkit/chainlink-ccip v0.0.0-20250506195202-6a3f20db41c6 h1:9EAwDMu3nvLsgzC4kv58qvFP3OjWivYOxA21/QBsUdE= From e1b4edac8328ae66a1e89b1bb5812fadaef4a1b2 Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Wed, 7 May 2025 16:53:35 -0300 Subject: [PATCH 2/6] feat: set timelock delay --- .../ccip/changeset/aptos/operation/mcms.go | 57 +++++++++---------- .../changeset/aptos/sequence/deploy_mcms.go | 22 +++++-- 2 files changed, 45 insertions(+), 34 deletions(-) diff --git a/deployment/ccip/changeset/aptos/operation/mcms.go b/deployment/ccip/changeset/aptos/operation/mcms.go index 5668eac6c4e..f4193ab39e1 100644 --- a/deployment/ccip/changeset/aptos/operation/mcms.go +++ b/deployment/ccip/changeset/aptos/operation/mcms.go @@ -2,7 +2,6 @@ package operation import ( "context" - "encoding/json" "fmt" "time" @@ -94,30 +93,37 @@ var AcceptOwnershipOp = operations.NewOperation( acceptOwnership, ) -func acceptOwnership(b operations.Bundle, deps AptosDeps, mcmsAddress aptos.AccountAddress) (mcmstypes.BatchOperation, error) { +func acceptOwnership(b operations.Bundle, deps AptosDeps, mcmsAddress aptos.AccountAddress) (mcmstypes.Transaction, error) { contractMCMS := mcmsbind.Bind(mcmsAddress, deps.AptosChain.Client) moduleInfo, function, _, args, err := contractMCMS.MCMSAccount().Encoder().AcceptOwnership() if err != nil { - return mcmstypes.BatchOperation{}, fmt.Errorf("failed to encode AcceptOwnership: %w", err) + return mcmstypes.Transaction{}, fmt.Errorf("failed to encode AcceptOwnership: %w", err) } - additionalFields := aptosmcms.AdditionalFields{ - PackageName: moduleInfo.PackageName, - ModuleName: moduleInfo.ModuleName, - Function: function, - } - callOneAdditionalFields, err := json.Marshal(additionalFields) + + return utils.GenerateMCMSTx(mcmsAddress, moduleInfo, function, args) +} + +// OP: SetMinDelay +type TimelockMinDelayInput struct { + MCMSAddress aptos.AccountAddress + TimelockMinDelay uint64 +} + +var SetMinDelayOP = operations.NewOperation( + "set-timelock-min-delay-op", + Version1_0_0, + "Generate set timelock min delay MCMS BatchOperations", + setMinDelay, +) + +func setMinDelay(b operations.Bundle, deps AptosDeps, in TimelockMinDelayInput) (mcmstypes.Transaction, error) { + contractMCMS := mcmsbind.Bind(in.MCMSAddress, deps.AptosChain.Client) + moduleInfo, function, _, args, err := contractMCMS.MCMS().Encoder().TimelockUpdateMinDelay(in.TimelockMinDelay) if err != nil { - return mcmstypes.BatchOperation{}, fmt.Errorf("failed to marshal additionalFields: %w", err) + return mcmstypes.Transaction{}, fmt.Errorf("failed to encode AcceptOwnership: %w", err) } - return mcmstypes.BatchOperation{ - ChainSelector: mcmstypes.ChainSelector(deps.AptosChain.Selector), - Transactions: []mcmstypes.Transaction{{ - To: mcmsAddress.StringLong(), - Data: aptosmcms.ArgsToData(args), - AdditionalFields: callOneAdditionalFields, - }}, - }, err + return utils.GenerateMCMSTx(in.MCMSAddress, moduleInfo, function, args) } // OP: CleanupStagingAreaOp generates a batch operation to clean up the staging area @@ -147,22 +153,13 @@ func cleanupStagingArea(b operations.Bundle, deps AptosDeps, mcmsAddress aptos.A if err != nil { return types.BatchOperation{}, fmt.Errorf("failed to EncodeCleanupStagingArea: %w", err) } - additionalFields := aptosmcms.AdditionalFields{ - PackageName: moduleInfo.PackageName, - ModuleName: moduleInfo.ModuleName, - Function: function, - } - afBytes, err := json.Marshal(additionalFields) + mcmsTx, err := utils.GenerateMCMSTx(mcmsAddress, moduleInfo, function, args) if err != nil { - return types.BatchOperation{}, fmt.Errorf("failed to marshal additional fields: %w", err) + return types.BatchOperation{}, fmt.Errorf("failed to generate MCMS operations for FeeQuoter Initialize: %w", err) } return types.BatchOperation{ ChainSelector: types.ChainSelector(deps.AptosChain.Selector), - Transactions: []types.Transaction{{ - To: mcmsAddress.StringLong(), - Data: aptosmcms.ArgsToData(args), - AdditionalFields: afBytes, - }}, + Transactions: []types.Transaction{mcmsTx}, }, nil } diff --git a/deployment/ccip/changeset/aptos/sequence/deploy_mcms.go b/deployment/ccip/changeset/aptos/sequence/deploy_mcms.go index 25d1617b6ce..b1911ed0554 100644 --- a/deployment/ccip/changeset/aptos/sequence/deploy_mcms.go +++ b/deployment/ccip/changeset/aptos/sequence/deploy_mcms.go @@ -63,20 +63,34 @@ func deployMCMSSequence(b operations.Bundle, deps operation.AptosDeps, configMCM if err != nil { return DeployMCMSSeqOutput{}, err } - // TODO: Should set MinDelay to timelock // Transfer ownership to self _, err = operations.ExecuteOperation(b, operation.TransferOwnershipToSelfOp, deps, deployMCMSReport.Output) if err != nil { return DeployMCMSSeqOutput{}, err } - // Generate proposal to accept ownership - gaopReport, err := operations.ExecuteOperation(b, operation.AcceptOwnershipOp, deps, deployMCMSReport.Output) + // Accept ownership + aoReport, err := operations.ExecuteOperation(b, operation.AcceptOwnershipOp, deps, deployMCMSReport.Output) if err != nil { return DeployMCMSSeqOutput{}, err } + // Set MinDelay + timelockMinDelayInput := operation.TimelockMinDelayInput{ + MCMSAddress: deployMCMSReport.Output, + TimelockMinDelay: (*configMCMS.TimelockMinDelay).Uint64(), + } + mdReport, err := operations.ExecuteOperation(b, operation.SetMinDelayOP, deps, timelockMinDelayInput) + if err != nil { + return DeployMCMSSeqOutput{}, err + } + + // Generate MCMS Batch Operation + mcmsOps := mcmstypes.BatchOperation{ + ChainSelector: mcmstypes.ChainSelector(deps.AptosChain.Selector), + Transactions: []mcmstypes.Transaction{aoReport.Output, mdReport.Output}, + } return DeployMCMSSeqOutput{ MCMSAddress: deployMCMSReport.Output, - MCMSOperation: gaopReport.Output, + MCMSOperation: mcmsOps, }, nil } From 86e4e4cf46e79d30617525de31679c667ff1fbcf Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Thu, 8 May 2025 17:31:04 -0300 Subject: [PATCH 3/6] fix: review comments | fix lint --- .../aptos/config/deploy_aptos_chain.go | 15 ++++++------- .../changeset/aptos/cs_deploy_aptos_chain.go | 16 +++++++++----- .../aptos/cs_deploy_aptos_chain_test.go | 21 +++++++++++------- .../ccip/changeset/aptos/operation/ccip.go | 8 +++---- .../ccip/changeset/aptos/operation/mcms.go | 13 ++++++----- .../changeset/aptos/sequence/deploy_ccip.go | 3 ++- .../changeset/aptos/sequence/deploy_mcms.go | 5 +++-- .../ccip/changeset/aptos/test_helpers.go | 9 +++++--- deployment/ccip/changeset/aptos/utils/mcms.go | 22 +++++++++++++------ 9 files changed, 68 insertions(+), 44 deletions(-) diff --git a/deployment/ccip/changeset/aptos/config/deploy_aptos_chain.go b/deployment/ccip/changeset/aptos/config/deploy_aptos_chain.go index c59470ad260..a5a9b784208 100644 --- a/deployment/ccip/changeset/aptos/config/deploy_aptos_chain.go +++ b/deployment/ccip/changeset/aptos/config/deploy_aptos_chain.go @@ -1,9 +1,11 @@ package config import ( + "errors" "fmt" "github.com/aptos-labs/aptos-go-sdk" + "github.com/smartcontractkit/chainlink/deployment" "github.com/smartcontractkit/chainlink/deployment/common/proposalutils" "github.com/smartcontractkit/chainlink/deployment/common/types" @@ -58,13 +60,13 @@ type FeeQuoterParams struct { func (f FeeQuoterParams) Validate() error { if f.LinkToken == (aptos.AccountAddress{}) { - return fmt.Errorf("LinkToken is required") + return errors.New("LinkToken is required") } if f.TokenPriceStalenessThreshold == 0 { - return fmt.Errorf("TokenPriceStalenessThreshold can't be 0") + return errors.New("TokenPriceStalenessThreshold can't be 0") } if len(f.FeeTokens) == 0 { - return fmt.Errorf("at least one FeeTokens is required") + return errors.New("at least one FeeTokens is required") } return nil } @@ -83,10 +85,10 @@ func (o OffRampParams) Validate() error { return fmt.Errorf("invalid chain selector: %d - %w", o.ChainSelector, err) } if o.PermissionlessExecutionThreshold == 0 { - return fmt.Errorf("PermissionlessExecutionThreshold can't be 0") + return errors.New("PermissionlessExecutionThreshold can't be 0") } if len(o.SourceChainSelectors) != len(o.SourceChainIsEnabled) { - return fmt.Errorf("SourceChainSelectors and SourceChainIsEnabled must have the same length") + return errors.New("SourceChainSelectors and SourceChainIsEnabled must have the same length") } return nil } @@ -101,8 +103,5 @@ func (o OnRampParams) Validate() error { if err := deployment.IsValidChainSelector(o.ChainSelector); err != nil { return fmt.Errorf("invalid chain selector: %d - %w", o.ChainSelector, err) } - if o.AllowlistAdmin == (aptos.AccountAddress{}) { - return fmt.Errorf("AllowlistAdmin is required") - } return nil } diff --git a/deployment/ccip/changeset/aptos/cs_deploy_aptos_chain.go b/deployment/ccip/changeset/aptos/cs_deploy_aptos_chain.go index 8176668501d..ca1bd5f540b 100644 --- a/deployment/ccip/changeset/aptos/cs_deploy_aptos_chain.go +++ b/deployment/ccip/changeset/aptos/cs_deploy_aptos_chain.go @@ -6,6 +6,9 @@ import ( "github.com/aptos-labs/aptos-go-sdk" + "github.com/smartcontractkit/mcms" + mcmstypes "github.com/smartcontractkit/mcms/types" + "github.com/smartcontractkit/chainlink-deployments-framework/operations" "github.com/smartcontractkit/chainlink/deployment" "github.com/smartcontractkit/chainlink/deployment/ccip/changeset" @@ -13,8 +16,6 @@ import ( "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/aptos/operation" seq "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/aptos/sequence" "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/aptos/utils" - "github.com/smartcontractkit/mcms" - mcmstypes "github.com/smartcontractkit/mcms/types" ) var _ deployment.ChangeSetV2[config.DeployAptosChainConfig] = DeployAptosChain{} @@ -86,8 +87,10 @@ func (cs DeployAptosChain) Apply(env deployment.Environment, config config.Deplo // Save MCMS address typeAndVersion := deployment.NewTypeAndVersion(changeset.AptosMCMSType, deployment.Version1_6_0) - deps.AB.Save(deps.AptosChain.Selector, mcmsSeqReport.Output.MCMSAddress.String(), typeAndVersion) - + err = deps.AB.Save(deps.AptosChain.Selector, mcmsSeqReport.Output.MCMSAddress.String(), typeAndVersion) + if err != nil { + return deployment.ChangesetOutput{}, fmt.Errorf("failed to save MCMS address %s for Aptos chain %d: %w", mcmsSeqReport.Output.MCMSAddress.String(), chainSel, err) + } // CCIP Deploy operations ccipSeqInput := seq.DeployCCIPSeqInput{ MCMSAddress: mcmsSeqReport.Output.MCMSAddress, @@ -102,7 +105,10 @@ func (cs DeployAptosChain) Apply(env deployment.Environment, config config.Deplo // Save the address of the CCIP object typeAndVersion = deployment.NewTypeAndVersion(changeset.AptosCCIPType, deployment.Version1_6_0) - deps.AB.Save(deps.AptosChain.Selector, ccipSeqReport.Output.CCIPAddress.String(), typeAndVersion) + err = deps.AB.Save(deps.AptosChain.Selector, ccipSeqReport.Output.CCIPAddress.String(), typeAndVersion) + if err != nil { + return deployment.ChangesetOutput{}, fmt.Errorf("failed to save CCIP address %s for Aptos chain %d: %w", ccipSeqReport.Output.CCIPAddress.String(), chainSel, err) + } // Generate MCMS proposals proposal, err := utils.GenerateProposal( diff --git a/deployment/ccip/changeset/aptos/cs_deploy_aptos_chain_test.go b/deployment/ccip/changeset/aptos/cs_deploy_aptos_chain_test.go index 0f22da17add..5d818be3689 100644 --- a/deployment/ccip/changeset/aptos/cs_deploy_aptos_chain_test.go +++ b/deployment/ccip/changeset/aptos/cs_deploy_aptos_chain_test.go @@ -5,6 +5,11 @@ import ( "testing" "time" + mcmstypes "github.com/smartcontractkit/mcms/types" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.uber.org/zap/zapcore" + "github.com/smartcontractkit/chainlink-aptos/bindings/ccip_offramp" "github.com/smartcontractkit/chainlink/deployment" "github.com/smartcontractkit/chainlink/deployment/ccip/changeset" @@ -14,10 +19,6 @@ import ( "github.com/smartcontractkit/chainlink/deployment/common/types" "github.com/smartcontractkit/chainlink/deployment/environment/memory" "github.com/smartcontractkit/chainlink/v2/core/logger" - mcmstypes "github.com/smartcontractkit/mcms/types" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "go.uber.org/zap/zapcore" ) func TestDeployAptosChainImp_VerifyPreconditions(t *testing.T) { @@ -61,6 +62,7 @@ func TestDeployAptosChainImp_VerifyPreconditions(t *testing.T) { 4457093679053095497: {}, }, ExistingAddresses: getTestAddressBook( + t, map[uint64]map[string]deployment.TypeAndVersion{ 4457093679053095497: { mockMCMSAddress: {Type: changeset.AptosMCMSType}, @@ -88,6 +90,7 @@ func TestDeployAptosChainImp_VerifyPreconditions(t *testing.T) { 4457093679053095497: {}, }, ExistingAddresses: getTestAddressBook( + t, map[uint64]map[string]deployment.TypeAndVersion{ 4457093679053095497: { mockMCMSAddress: {Type: changeset.AptosMCMSType}, @@ -132,6 +135,7 @@ func TestDeployAptosChainImp_VerifyPreconditions(t *testing.T) { 4457093679053095497: {}, }, ExistingAddresses: getTestAddressBook( + t, map[uint64]map[string]deployment.TypeAndVersion{ 4457093679053095497: {}, // No MCMS address in state }, @@ -155,6 +159,7 @@ func TestDeployAptosChainImp_VerifyPreconditions(t *testing.T) { 4457093679053095497: {}, }, ExistingAddresses: getTestAddressBook( + t, map[uint64]map[string]deployment.TypeAndVersion{ 4457093679053095497: { mockMCMSAddress: {Type: changeset.AptosMCMSType}, // MCMS already deployed @@ -181,11 +186,11 @@ func TestDeployAptosChainImp_VerifyPreconditions(t *testing.T) { cs := DeployAptosChain{} err := cs.VerifyPreconditions(tt.env, tt.config) if tt.wantErr { - assert.Error(t, err) + require.Error(t, err) errStr := err.Error() assert.Regexp(t, tt.wantErrRe, errStr) } else { - assert.NoError(t, err) + require.NoError(t, err) } }) } @@ -201,7 +206,7 @@ func TestDeployAptosChain_Apply(t *testing.T) { // Get chain selectors aptosChainSelectors := env.AllChainSelectorsAptos() - require.Equal(t, 1, len(aptosChainSelectors), "Expected exactly 1 Aptos chain") + require.Len(t, aptosChainSelectors, 1, "Expected exactly 1 Aptos chain") chainSelector := aptosChainSelectors[0] t.Log("Deployer: ", env.AptosChains[chainSelector].DeployerSigner) @@ -244,5 +249,5 @@ func TestDeployAptosChain_Apply(t *testing.T) { offrampBind := ccip_offramp.Bind(ccipAddr, env.AptosChains[chainSelector].Client) offRampSourceConfig, err := offrampBind.Offramp().GetSourceChainConfig(nil, mockCCIPParams.OffRampParams.SourceChainSelectors[0]) require.NoError(t, err) - require.Equal(t, true, offRampSourceConfig.IsEnabled, "contracts were not initialized correctly") + require.True(t, offRampSourceConfig.IsEnabled, "contracts were not initialized correctly") } diff --git a/deployment/ccip/changeset/aptos/operation/ccip.go b/deployment/ccip/changeset/aptos/operation/ccip.go index f54b985c2dd..ce6026547e4 100644 --- a/deployment/ccip/changeset/aptos/operation/ccip.go +++ b/deployment/ccip/changeset/aptos/operation/ccip.go @@ -4,6 +4,8 @@ import ( "fmt" "github.com/aptos-labs/aptos-go-sdk" + "github.com/smartcontractkit/mcms/types" + "github.com/smartcontractkit/chainlink-aptos/bindings/ccip" "github.com/smartcontractkit/chainlink-aptos/bindings/ccip_offramp" "github.com/smartcontractkit/chainlink-aptos/bindings/ccip_onramp" @@ -12,7 +14,6 @@ import ( "github.com/smartcontractkit/chainlink-deployments-framework/operations" aptoscfg "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/aptos/config" "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/aptos/utils" - "github.com/smartcontractkit/mcms/types" ) // OP: DeployCCIPOp deploys the CCIP package on Aptos chain @@ -40,10 +41,9 @@ func deployCCIP(b operations.Bundle, deps AptosDeps, in DeployCCIPInput) (Deploy if in.IsUpdate { b.Logger.Infow("Trying to update a non-deployed package", "addr", onChainState.CCIPAddress.String()) return DeployCCIPOutput{}, fmt.Errorf("CCIP package not deployed on Aptos chain %d", deps.AptosChain.Selector) - } else { - b.Logger.Infow("CCIP Package already deployed", "addr", onChainState.CCIPAddress.String()) - return DeployCCIPOutput{CCIPAddress: onChainState.CCIPAddress}, nil } + b.Logger.Infow("CCIP Package already deployed", "addr", onChainState.CCIPAddress.String()) + return DeployCCIPOutput{CCIPAddress: onChainState.CCIPAddress}, nil } // Compile, chunk and get CCIP deploy operations diff --git a/deployment/ccip/changeset/aptos/operation/mcms.go b/deployment/ccip/changeset/aptos/operation/mcms.go index f4193ab39e1..d3f8a096d7a 100644 --- a/deployment/ccip/changeset/aptos/operation/mcms.go +++ b/deployment/ccip/changeset/aptos/operation/mcms.go @@ -6,13 +6,14 @@ import ( "time" "github.com/aptos-labs/aptos-go-sdk" - "github.com/smartcontractkit/chainlink-aptos/bindings/bind" - mcmsbind "github.com/smartcontractkit/chainlink-aptos/bindings/mcms" - "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/aptos/utils" aptosmcms "github.com/smartcontractkit/mcms/sdk/aptos" "github.com/smartcontractkit/mcms/types" mcmstypes "github.com/smartcontractkit/mcms/types" + "github.com/smartcontractkit/chainlink-aptos/bindings/bind" + mcmsbind "github.com/smartcontractkit/chainlink-aptos/bindings/mcms" + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/aptos/utils" + "github.com/smartcontractkit/chainlink-deployments-framework/operations" ) @@ -28,10 +29,10 @@ func deployMCMS(b operations.Bundle, deps AptosDeps, _ operations.EmptyInput) (a mcmsSeed := mcmsbind.DefaultSeed + time.Now().String() mcmsAddress, mcmsDeployTx, _, err := mcmsbind.DeployToResourceAccount(deps.AptosChain.DeployerSigner, deps.AptosChain.Client, mcmsSeed) if err != nil { - return aptos.AccountAddress{}, fmt.Errorf("failed to deploy MCMS contract: %v", err) + return aptos.AccountAddress{}, fmt.Errorf("failed to deploy MCMS contract: %w", err) } if err := deps.AptosChain.Confirm(mcmsDeployTx.Hash); err != nil { - return aptos.AccountAddress{}, fmt.Errorf("failed to confirm MCMS deployment transaction: %v", err) + return aptos.AccountAddress{}, fmt.Errorf("failed to confirm MCMS deployment transaction: %w", err) } return mcmsAddress, nil @@ -78,7 +79,7 @@ func transferOwnershipToSelf(b operations.Bundle, deps AptosDeps, mcmsAddress ap if err != nil { return nil, fmt.Errorf("failed to TransferOwnershipToSelf in MCMS contract: %w", err) } - _, err = deps.AptosChain.Client.WaitForTransaction(tx.Hash) + err = deps.AptosChain.Confirm(tx.Hash) if err != nil { return nil, fmt.Errorf("MCMS TransferOwnershipToSelf transaction failed: %w", err) } diff --git a/deployment/ccip/changeset/aptos/sequence/deploy_ccip.go b/deployment/ccip/changeset/aptos/sequence/deploy_ccip.go index ae464fcf7c6..5d07fcf2a20 100644 --- a/deployment/ccip/changeset/aptos/sequence/deploy_ccip.go +++ b/deployment/ccip/changeset/aptos/sequence/deploy_ccip.go @@ -3,11 +3,12 @@ package sequence import ( "github.com/aptos-labs/aptos-go-sdk" + mcmstypes "github.com/smartcontractkit/mcms/types" + "github.com/smartcontractkit/chainlink-deployments-framework/operations" "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/aptos/config" "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/aptos/operation" "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/aptos/utils" - mcmstypes "github.com/smartcontractkit/mcms/types" ) type DeployCCIPSeqInput struct { diff --git a/deployment/ccip/changeset/aptos/sequence/deploy_mcms.go b/deployment/ccip/changeset/aptos/sequence/deploy_mcms.go index b1911ed0554..b33a9c98087 100644 --- a/deployment/ccip/changeset/aptos/sequence/deploy_mcms.go +++ b/deployment/ccip/changeset/aptos/sequence/deploy_mcms.go @@ -3,11 +3,12 @@ package sequence import ( "github.com/aptos-labs/aptos-go-sdk" + aptosmcms "github.com/smartcontractkit/mcms/sdk/aptos" + mcmstypes "github.com/smartcontractkit/mcms/types" + "github.com/smartcontractkit/chainlink-deployments-framework/operations" "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/aptos/operation" "github.com/smartcontractkit/chainlink/deployment/common/types" - aptosmcms "github.com/smartcontractkit/mcms/sdk/aptos" - mcmstypes "github.com/smartcontractkit/mcms/types" ) // Deploy MCMS Sequence diff --git a/deployment/ccip/changeset/aptos/test_helpers.go b/deployment/ccip/changeset/aptos/test_helpers.go index 091580aa091..5e04a61c34f 100644 --- a/deployment/ccip/changeset/aptos/test_helpers.go +++ b/deployment/ccip/changeset/aptos/test_helpers.go @@ -6,11 +6,13 @@ import ( "github.com/aptos-labs/aptos-go-sdk" "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink/deployment" "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/aptos/config" "github.com/smartcontractkit/chainlink/deployment/common/proposalutils" "github.com/smartcontractkit/chainlink/deployment/common/types" - "github.com/stretchr/testify/assert" ) const ( @@ -22,11 +24,12 @@ const ( sepMockOnRampAddress = "0x0BF3dE8c5D3e8A2B34D2BEeB17ABfCeBaf363A59" ) -func getTestAddressBook(addrByChain map[uint64]map[string]deployment.TypeAndVersion) deployment.AddressBook { +func getTestAddressBook(t *testing.T, addrByChain map[uint64]map[string]deployment.TypeAndVersion) deployment.AddressBook { ab := deployment.NewMemoryAddressBook() for chain, addrTypeAndVersion := range addrByChain { for addr, typeAndVersion := range addrTypeAndVersion { - ab.Save(chain, addr, typeAndVersion) + err := ab.Save(chain, addr, typeAndVersion) + require.NoError(t, err) } } return ab diff --git a/deployment/ccip/changeset/aptos/utils/mcms.go b/deployment/ccip/changeset/aptos/utils/mcms.go index cc46a927bb8..be76e8fb204 100644 --- a/deployment/ccip/changeset/aptos/utils/mcms.go +++ b/deployment/ccip/changeset/aptos/utils/mcms.go @@ -3,18 +3,21 @@ package utils import ( "context" "encoding/json" + "errors" "fmt" + "math" "strings" "time" "github.com/aptos-labs/aptos-go-sdk" + "github.com/smartcontractkit/mcms" + aptosmcms "github.com/smartcontractkit/mcms/sdk/aptos" + "github.com/smartcontractkit/mcms/types" + "github.com/smartcontractkit/chainlink-aptos/bindings/bind" "github.com/smartcontractkit/chainlink-aptos/bindings/compile" mcmsbind "github.com/smartcontractkit/chainlink-aptos/bindings/mcms" "github.com/smartcontractkit/chainlink/deployment/common/proposalutils" - "github.com/smartcontractkit/mcms" - aptosmcms "github.com/smartcontractkit/mcms/sdk/aptos" - "github.com/smartcontractkit/mcms/types" ) const MCMSProposalVersion = "v1" @@ -47,6 +50,10 @@ func GenerateProposal( // Create proposal builder validUntil := time.Now().Unix() + int64(proposalutils.DefaultValidUntil.Seconds()) + if validUntil < 0 || validUntil > math.MaxUint32 { + return nil, fmt.Errorf("validUntil value out of range for uint32: %d", validUntil) + } + proposalBuilder := mcms.NewTimelockProposalBuilder(). SetVersion(MCMSProposalVersion). SetValidUntil(uint32(validUntil)). @@ -128,7 +135,7 @@ func CreateChunksAndStage( mcmsAddress := mcmsContract.Address() // Validate seed XOR codeObjectAddress, one and only one must be provided if (seed != "") == (codeObjectAddress != nil) { - return nil, fmt.Errorf("either provide seed to publishToObject or objectAddress to upgradeObjectCode") + return nil, errors.New("either provide seed to publishToObject or objectAddress to upgradeObjectCode") } var operations []types.Operation @@ -149,20 +156,21 @@ func CreateChunksAndStage( ) // First chunks get staged, the last one gets published or upgraded - if i != len(chunks)-1 { + switch { + case i != len(chunks)-1: moduleInfo, function, _, args, err = mcmsContract.MCMSDeployer().Encoder().StageCodeChunk( chunk.Metadata, chunk.CodeIndices, chunk.Chunks, ) - } else if seed != "" { + case seed != "": moduleInfo, function, _, args, err = mcmsContract.MCMSDeployer().Encoder().StageCodeChunkAndPublishToObject( chunk.Metadata, chunk.CodeIndices, chunk.Chunks, []byte(seed), ) - } else { + default: moduleInfo, function, _, args, err = mcmsContract.MCMSDeployer().Encoder().StageCodeChunkAndUpgradeObjectCode( chunk.Metadata, chunk.CodeIndices, From 8a1f1c972094d274df997bbe958be0dedde69b0f Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Thu, 8 May 2025 17:35:38 -0300 Subject: [PATCH 4/6] fix: go mod tidy --- core/scripts/go.mod | 2 +- core/scripts/go.sum | 4 ++-- integration-tests/go.mod | 2 +- integration-tests/go.sum | 4 ++-- integration-tests/load/go.mod | 2 +- integration-tests/load/go.sum | 4 ++-- system-tests/lib/go.mod | 2 +- system-tests/lib/go.sum | 4 ++-- system-tests/tests/go.mod | 2 +- system-tests/tests/go.sum | 4 ++-- 10 files changed, 15 insertions(+), 15 deletions(-) diff --git a/core/scripts/go.mod b/core/scripts/go.mod index c82fb9892e6..bfc32649f5d 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -353,7 +353,7 @@ require ( github.com/sirupsen/logrus v1.9.3 // indirect github.com/smartcontractkit/ccip-owner-contracts v0.1.0 // indirect github.com/smartcontractkit/chain-selectors v1.0.55 // indirect - github.com/smartcontractkit/chainlink-aptos v0.0.0-20250414155853-651b4e583ee9 // indirect + github.com/smartcontractkit/chainlink-aptos v0.0.0-20250502091650-484cfa7ccddf // indirect github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250425163923-16aa375957b7 // indirect github.com/smartcontractkit/chainlink-feeds v0.1.2-0.20250227211209-7cd000095135 // indirect github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250502210357-2df484128afa // indirect diff --git a/core/scripts/go.sum b/core/scripts/go.sum index 781261025ed..3323a9233ea 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -1183,8 +1183,8 @@ github.com/smartcontractkit/ccip-owner-contracts v0.1.0 h1:GiBDtlx7539o7AKlDV+9L github.com/smartcontractkit/ccip-owner-contracts v0.1.0/go.mod h1:NnT6w4Kj42OFFXhSx99LvJZWPpMjmo4+CpDEWfw61xY= github.com/smartcontractkit/chain-selectors v1.0.55 h1:jn8cwTBEzAi/eQRDO7EbFpZFn60yxygnSSPP2HPbYs0= github.com/smartcontractkit/chain-selectors v1.0.55/go.mod h1:xsKM0aN3YGcQKTPRPDDtPx2l4mlTN1Djmg0VVXV40b8= -github.com/smartcontractkit/chainlink-aptos v0.0.0-20250414155853-651b4e583ee9 h1:lw8RZ8IR4UX1M7djAB3IuMtcAqFX4Z4bzQczClfb8bs= -github.com/smartcontractkit/chainlink-aptos v0.0.0-20250414155853-651b4e583ee9/go.mod h1:Sq/ddMOYch6ZuAnW2k5u9V4+TlGKFzuHQnTM8JXEU+g= +github.com/smartcontractkit/chainlink-aptos v0.0.0-20250502091650-484cfa7ccddf h1:zzG5D68tGbDBW3mQW6sa50ga0kGRQp9S7F4vqZO0ZrU= +github.com/smartcontractkit/chainlink-aptos v0.0.0-20250502091650-484cfa7ccddf/go.mod h1:yj4d1XS6lBOXM1sDMP1ULCbRJgOuBYf2V7VtQ6Qgev8= github.com/smartcontractkit/chainlink-automation v0.8.1 h1:sTc9LKpBvcKPc1JDYAmgBc2xpDKBco/Q4h4ydl6+UUU= github.com/smartcontractkit/chainlink-automation v0.8.1/go.mod h1:Iij36PvWZ6blrdC5A/nrQUBuf3MH3JvsBB9sSyc9W08= github.com/smartcontractkit/chainlink-ccip v0.0.0-20250506195202-6a3f20db41c6 h1:9EAwDMu3nvLsgzC4kv58qvFP3OjWivYOxA21/QBsUdE= diff --git a/integration-tests/go.mod b/integration-tests/go.mod index f3f63406a76..c4ce4b3b6f5 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -450,7 +450,7 @@ require ( github.com/shirou/gopsutil/v4 v4.25.1 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/smartcontractkit/ccip-owner-contracts v0.1.0 // indirect - github.com/smartcontractkit/chainlink-aptos v0.0.0-20250414155853-651b4e583ee9 // indirect + github.com/smartcontractkit/chainlink-aptos v0.0.0-20250502091650-484cfa7ccddf // indirect github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250417193446-eeb0a7d1e049 // indirect github.com/smartcontractkit/chainlink-feeds v0.1.2-0.20250227211209-7cd000095135 // indirect github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250502210357-2df484128afa // indirect diff --git a/integration-tests/go.sum b/integration-tests/go.sum index b3770bec9f1..62481765164 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -1466,8 +1466,8 @@ github.com/smartcontractkit/ccip-owner-contracts v0.1.0 h1:GiBDtlx7539o7AKlDV+9L github.com/smartcontractkit/ccip-owner-contracts v0.1.0/go.mod h1:NnT6w4Kj42OFFXhSx99LvJZWPpMjmo4+CpDEWfw61xY= github.com/smartcontractkit/chain-selectors v1.0.55 h1:jn8cwTBEzAi/eQRDO7EbFpZFn60yxygnSSPP2HPbYs0= github.com/smartcontractkit/chain-selectors v1.0.55/go.mod h1:xsKM0aN3YGcQKTPRPDDtPx2l4mlTN1Djmg0VVXV40b8= -github.com/smartcontractkit/chainlink-aptos v0.0.0-20250414155853-651b4e583ee9 h1:lw8RZ8IR4UX1M7djAB3IuMtcAqFX4Z4bzQczClfb8bs= -github.com/smartcontractkit/chainlink-aptos v0.0.0-20250414155853-651b4e583ee9/go.mod h1:Sq/ddMOYch6ZuAnW2k5u9V4+TlGKFzuHQnTM8JXEU+g= +github.com/smartcontractkit/chainlink-aptos v0.0.0-20250502091650-484cfa7ccddf h1:zzG5D68tGbDBW3mQW6sa50ga0kGRQp9S7F4vqZO0ZrU= +github.com/smartcontractkit/chainlink-aptos v0.0.0-20250502091650-484cfa7ccddf/go.mod h1:yj4d1XS6lBOXM1sDMP1ULCbRJgOuBYf2V7VtQ6Qgev8= github.com/smartcontractkit/chainlink-automation v0.8.1 h1:sTc9LKpBvcKPc1JDYAmgBc2xpDKBco/Q4h4ydl6+UUU= github.com/smartcontractkit/chainlink-automation v0.8.1/go.mod h1:Iij36PvWZ6blrdC5A/nrQUBuf3MH3JvsBB9sSyc9W08= github.com/smartcontractkit/chainlink-ccip v0.0.0-20250506195202-6a3f20db41c6 h1:9EAwDMu3nvLsgzC4kv58qvFP3OjWivYOxA21/QBsUdE= diff --git a/integration-tests/load/go.mod b/integration-tests/load/go.mod index 6050b2d99c5..692c0e4662b 100644 --- a/integration-tests/load/go.mod +++ b/integration-tests/load/go.mod @@ -437,7 +437,7 @@ require ( github.com/shopspring/decimal v1.4.0 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/smartcontractkit/ccip-owner-contracts v0.1.0 // indirect - github.com/smartcontractkit/chainlink-aptos v0.0.0-20250414155853-651b4e583ee9 // indirect + github.com/smartcontractkit/chainlink-aptos v0.0.0-20250502091650-484cfa7ccddf // indirect github.com/smartcontractkit/chainlink-automation v0.8.1 // indirect github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250417193446-eeb0a7d1e049 // indirect github.com/smartcontractkit/chainlink-deployments-framework v0.0.13 // indirect diff --git a/integration-tests/load/go.sum b/integration-tests/load/go.sum index 38e38d5f7e7..bd8ef7d0a9c 100644 --- a/integration-tests/load/go.sum +++ b/integration-tests/load/go.sum @@ -1447,8 +1447,8 @@ github.com/smartcontractkit/ccip-owner-contracts v0.1.0 h1:GiBDtlx7539o7AKlDV+9L github.com/smartcontractkit/ccip-owner-contracts v0.1.0/go.mod h1:NnT6w4Kj42OFFXhSx99LvJZWPpMjmo4+CpDEWfw61xY= github.com/smartcontractkit/chain-selectors v1.0.55 h1:jn8cwTBEzAi/eQRDO7EbFpZFn60yxygnSSPP2HPbYs0= github.com/smartcontractkit/chain-selectors v1.0.55/go.mod h1:xsKM0aN3YGcQKTPRPDDtPx2l4mlTN1Djmg0VVXV40b8= -github.com/smartcontractkit/chainlink-aptos v0.0.0-20250414155853-651b4e583ee9 h1:lw8RZ8IR4UX1M7djAB3IuMtcAqFX4Z4bzQczClfb8bs= -github.com/smartcontractkit/chainlink-aptos v0.0.0-20250414155853-651b4e583ee9/go.mod h1:Sq/ddMOYch6ZuAnW2k5u9V4+TlGKFzuHQnTM8JXEU+g= +github.com/smartcontractkit/chainlink-aptos v0.0.0-20250502091650-484cfa7ccddf h1:zzG5D68tGbDBW3mQW6sa50ga0kGRQp9S7F4vqZO0ZrU= +github.com/smartcontractkit/chainlink-aptos v0.0.0-20250502091650-484cfa7ccddf/go.mod h1:yj4d1XS6lBOXM1sDMP1ULCbRJgOuBYf2V7VtQ6Qgev8= github.com/smartcontractkit/chainlink-automation v0.8.1 h1:sTc9LKpBvcKPc1JDYAmgBc2xpDKBco/Q4h4ydl6+UUU= github.com/smartcontractkit/chainlink-automation v0.8.1/go.mod h1:Iij36PvWZ6blrdC5A/nrQUBuf3MH3JvsBB9sSyc9W08= github.com/smartcontractkit/chainlink-ccip v0.0.0-20250506195202-6a3f20db41c6 h1:9EAwDMu3nvLsgzC4kv58qvFP3OjWivYOxA21/QBsUdE= diff --git a/system-tests/lib/go.mod b/system-tests/lib/go.mod index 74fb4e422d8..a699c14fc70 100644 --- a/system-tests/lib/go.mod +++ b/system-tests/lib/go.mod @@ -354,7 +354,7 @@ require ( github.com/shopspring/decimal v1.4.0 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/smartcontractkit/ccip-owner-contracts v0.1.0 // indirect - github.com/smartcontractkit/chainlink-aptos v0.0.0-20250414155853-651b4e583ee9 // indirect + github.com/smartcontractkit/chainlink-aptos v0.0.0-20250502091650-484cfa7ccddf // indirect github.com/smartcontractkit/chainlink-automation v0.8.1 // indirect github.com/smartcontractkit/chainlink-ccip v0.0.0-20250506195202-6a3f20db41c6 // indirect github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250425163923-16aa375957b7 // indirect diff --git a/system-tests/lib/go.sum b/system-tests/lib/go.sum index 0a6fb66ab6c..49d89a8ab79 100644 --- a/system-tests/lib/go.sum +++ b/system-tests/lib/go.sum @@ -1220,8 +1220,8 @@ github.com/smartcontractkit/ccip-owner-contracts v0.1.0 h1:GiBDtlx7539o7AKlDV+9L github.com/smartcontractkit/ccip-owner-contracts v0.1.0/go.mod h1:NnT6w4Kj42OFFXhSx99LvJZWPpMjmo4+CpDEWfw61xY= github.com/smartcontractkit/chain-selectors v1.0.55 h1:jn8cwTBEzAi/eQRDO7EbFpZFn60yxygnSSPP2HPbYs0= github.com/smartcontractkit/chain-selectors v1.0.55/go.mod h1:xsKM0aN3YGcQKTPRPDDtPx2l4mlTN1Djmg0VVXV40b8= -github.com/smartcontractkit/chainlink-aptos v0.0.0-20250414155853-651b4e583ee9 h1:lw8RZ8IR4UX1M7djAB3IuMtcAqFX4Z4bzQczClfb8bs= -github.com/smartcontractkit/chainlink-aptos v0.0.0-20250414155853-651b4e583ee9/go.mod h1:Sq/ddMOYch6ZuAnW2k5u9V4+TlGKFzuHQnTM8JXEU+g= +github.com/smartcontractkit/chainlink-aptos v0.0.0-20250502091650-484cfa7ccddf h1:zzG5D68tGbDBW3mQW6sa50ga0kGRQp9S7F4vqZO0ZrU= +github.com/smartcontractkit/chainlink-aptos v0.0.0-20250502091650-484cfa7ccddf/go.mod h1:yj4d1XS6lBOXM1sDMP1ULCbRJgOuBYf2V7VtQ6Qgev8= github.com/smartcontractkit/chainlink-automation v0.8.1 h1:sTc9LKpBvcKPc1JDYAmgBc2xpDKBco/Q4h4ydl6+UUU= github.com/smartcontractkit/chainlink-automation v0.8.1/go.mod h1:Iij36PvWZ6blrdC5A/nrQUBuf3MH3JvsBB9sSyc9W08= github.com/smartcontractkit/chainlink-ccip v0.0.0-20250506195202-6a3f20db41c6 h1:9EAwDMu3nvLsgzC4kv58qvFP3OjWivYOxA21/QBsUdE= diff --git a/system-tests/tests/go.mod b/system-tests/tests/go.mod index ac84b54ca52..0c268bdeca9 100644 --- a/system-tests/tests/go.mod +++ b/system-tests/tests/go.mod @@ -426,7 +426,7 @@ require ( github.com/sirupsen/logrus v1.9.3 // indirect github.com/smartcontractkit/ccip-owner-contracts v0.1.0 // indirect github.com/smartcontractkit/chain-selectors v1.0.55 // indirect - github.com/smartcontractkit/chainlink-aptos v0.0.0-20250414155853-651b4e583ee9 // indirect + github.com/smartcontractkit/chainlink-aptos v0.0.0-20250502091650-484cfa7ccddf // indirect github.com/smartcontractkit/chainlink-automation v0.8.1 // indirect github.com/smartcontractkit/chainlink-ccip v0.0.0-20250506195202-6a3f20db41c6 // indirect github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250425163923-16aa375957b7 // indirect diff --git a/system-tests/tests/go.sum b/system-tests/tests/go.sum index 2e3b2c73c4b..98268cb7f83 100644 --- a/system-tests/tests/go.sum +++ b/system-tests/tests/go.sum @@ -1422,8 +1422,8 @@ github.com/smartcontractkit/ccip-owner-contracts v0.1.0 h1:GiBDtlx7539o7AKlDV+9L github.com/smartcontractkit/ccip-owner-contracts v0.1.0/go.mod h1:NnT6w4Kj42OFFXhSx99LvJZWPpMjmo4+CpDEWfw61xY= github.com/smartcontractkit/chain-selectors v1.0.55 h1:jn8cwTBEzAi/eQRDO7EbFpZFn60yxygnSSPP2HPbYs0= github.com/smartcontractkit/chain-selectors v1.0.55/go.mod h1:xsKM0aN3YGcQKTPRPDDtPx2l4mlTN1Djmg0VVXV40b8= -github.com/smartcontractkit/chainlink-aptos v0.0.0-20250414155853-651b4e583ee9 h1:lw8RZ8IR4UX1M7djAB3IuMtcAqFX4Z4bzQczClfb8bs= -github.com/smartcontractkit/chainlink-aptos v0.0.0-20250414155853-651b4e583ee9/go.mod h1:Sq/ddMOYch6ZuAnW2k5u9V4+TlGKFzuHQnTM8JXEU+g= +github.com/smartcontractkit/chainlink-aptos v0.0.0-20250502091650-484cfa7ccddf h1:zzG5D68tGbDBW3mQW6sa50ga0kGRQp9S7F4vqZO0ZrU= +github.com/smartcontractkit/chainlink-aptos v0.0.0-20250502091650-484cfa7ccddf/go.mod h1:yj4d1XS6lBOXM1sDMP1ULCbRJgOuBYf2V7VtQ6Qgev8= github.com/smartcontractkit/chainlink-automation v0.8.1 h1:sTc9LKpBvcKPc1JDYAmgBc2xpDKBco/Q4h4ydl6+UUU= github.com/smartcontractkit/chainlink-automation v0.8.1/go.mod h1:Iij36PvWZ6blrdC5A/nrQUBuf3MH3JvsBB9sSyc9W08= github.com/smartcontractkit/chainlink-ccip v0.0.0-20250506195202-6a3f20db41c6 h1:9EAwDMu3nvLsgzC4kv58qvFP3OjWivYOxA21/QBsUdE= From 603ae24547f42c564d5e233b2bf16a8fe0d0d2b3 Mon Sep 17 00:00:00 2001 From: Erik Burton Date: Wed, 14 May 2025 12:05:40 -0700 Subject: [PATCH 5/6] feat: install aptos CLI for ccip unit tests --- .github/workflows/ci-core.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/ci-core.yml b/.github/workflows/ci-core.yml index 617666d0b6b..3b62fd2a3a7 100644 --- a/.github/workflows/ci-core.yml +++ b/.github/workflows/ci-core.yml @@ -197,6 +197,7 @@ jobs: is-self-hosted: ${{ needs.runner-config.outputs.deployment-tests-is-self-hosted }} should-run: ${{ needs.filter.outputs.should-run-deployment-tests }} setup-solana: "true" + setup-aptos: "true" use-flakeguard: ${{ github.event_name == 'merge_group' && 'true' || 'false' }} name: Core Tests (${{ matrix.type.cmd }}) @@ -267,6 +268,12 @@ jobs: if: ${{ matrix.type.should-run == 'true' && matrix.type.setup-solana == 'true' }} uses: ./.github/actions/setup-solana + - name: Setup Aptos + if: ${{ matrix.type.should-run == 'true' && matrix.type.setup-aptos == 'true' }} + uses: aptos-labs/actions/install-aptos-cli@63740b290d839b87ecfafbcf75ed03a36a54a29f # jan 15, 2025 + with: + CLI_VERSION: 7.2.0 + - name: Setup wasmd if: ${{ matrix.type.should-run == 'true' }} uses: ./.github/actions/setup-wasmd From 4db85a32dd3a140e9fda237b4e8ac7fe5574e140 Mon Sep 17 00:00:00 2001 From: Erik Burton Date: Wed, 14 May 2025 12:16:17 -0700 Subject: [PATCH 6/6] enable flakeguard --- .github/workflows/ci-core.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-core.yml b/.github/workflows/ci-core.yml index 3b62fd2a3a7..8881e2f65df 100644 --- a/.github/workflows/ci-core.yml +++ b/.github/workflows/ci-core.yml @@ -198,7 +198,7 @@ jobs: should-run: ${{ needs.filter.outputs.should-run-deployment-tests }} setup-solana: "true" setup-aptos: "true" - use-flakeguard: ${{ github.event_name == 'merge_group' && 'true' || 'false' }} + use-flakeguard: "true" name: Core Tests (${{ matrix.type.cmd }}) # We don't directly merge dependabot PRs, so let's not waste the resources