Skip to content

feat(aptos): Add CCIP deployment changeset #17730

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 6 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion .github/workflows/ci-core.yml
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,8 @@ 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"
use-flakeguard: ${{ github.event_name == 'merge_group' && 'true' || 'false' }}
setup-aptos: "true"
use-flakeguard: "true"

name: Core Tests (${{ matrix.type.cmd }})
# We don't directly merge dependabot PRs, so let's not waste the resources
Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion core/scripts/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions core/scripts/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -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=
Expand Down
38 changes: 0 additions & 38 deletions deployment/ccip/changeset/aptos/aptos_test.go

This file was deleted.

107 changes: 107 additions & 0 deletions deployment/ccip/changeset/aptos/config/deploy_aptos_chain.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
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"
)

// 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 errors.New("LinkToken is required")
}
if f.TokenPriceStalenessThreshold == 0 {
return errors.New("TokenPriceStalenessThreshold can't be 0")
}
if len(f.FeeTokens) == 0 {
return errors.New("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 errors.New("PermissionlessExecutionThreshold can't be 0")
}
if len(o.SourceChainSelectors) != len(o.SourceChainIsEnabled) {
return errors.New("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)
}
return nil
}
132 changes: 132 additions & 0 deletions deployment/ccip/changeset/aptos/cs_deploy_aptos_chain.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
package aptos

import (
"errors"
"fmt"

"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"
"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"
)

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)
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,
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)
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(
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
}
Loading
Loading