Skip to content
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
package contracts

import (
"errors"
"fmt"

"github.com/Masterminds/semver/v3"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/core/types"
mcmslib "github.com/smartcontractkit/mcms"

cldf "github.com/smartcontractkit/chainlink-deployments-framework/deployment"
"github.com/smartcontractkit/chainlink-deployments-framework/operations"
capabilities_registry_v2 "github.com/smartcontractkit/chainlink-evm/gethwrappers/workflow/generated/capabilities_registry_wrapper_v2"

commonchangeset "github.com/smartcontractkit/chainlink/deployment/common/changeset/state"
"github.com/smartcontractkit/chainlink/deployment/cre/common/strategies"
"github.com/smartcontractkit/chainlink/deployment/cre/ocr3"
)

type SetDONFamiliesDeps struct {
Env *cldf.Environment
CapabilitiesRegistry *capabilities_registry_v2.CapabilitiesRegistry
MCMSContracts *commonchangeset.MCMSWithTimelockState // Required if MCMSConfig is not nil
}

type SetDONFamiliesInput struct {
DonName string
AddToFamilies []string
RemoveFromFamilies []string

RegistryChainSel uint64

MCMSConfig *ocr3.MCMSConfig
}

func (i *SetDONFamiliesInput) Validate() error {
if i.DonName == "" {
return errors.New("must specify DonName")
}

if len(i.AddToFamilies) == 0 && len(i.RemoveFromFamilies) == 0 {
return errors.New("must specify at least one family to add or remove")
}

return nil
}

type SetDONFamiliesOutput struct {
DonInfo capabilities_registry_v2.CapabilitiesRegistryDONInfo
Proposals []mcmslib.TimelockProposal
}

var SetDONFamilies = operations.NewOperation[SetDONFamiliesInput, SetDONFamiliesOutput, SetDONFamiliesDeps](
"set-don-families-op",
semver.MustParse("1.0.0"),
"Set DON Families in Capabilities Registry",
func(b operations.Bundle, deps SetDONFamiliesDeps, input SetDONFamiliesInput) (SetDONFamiliesOutput, error) {
if err := input.Validate(); err != nil {
return SetDONFamiliesOutput{}, err
}

chain, ok := deps.Env.BlockChains.EVMChains()[input.RegistryChainSel]
if !ok {
return SetDONFamiliesOutput{}, cldf.ErrChainNotFound
}

// Fetch the DON to get the ID. We don't want callers using the ID, since the name is more user-friendly.
don, err := deps.CapabilitiesRegistry.GetDONByName(&bind.CallOpts{}, input.DonName)
if err != nil {
err = cldf.DecodeErr(capabilities_registry_v2.CapabilitiesRegistryABI, err)
return SetDONFamiliesOutput{}, fmt.Errorf("failed to call GetDONByName: %w", err)
}

strategy, err := strategies.CreateStrategy(
chain,
*deps.Env,
input.MCMSConfig,
deps.MCMSContracts,
deps.CapabilitiesRegistry.Address(),
SetDONFamiliesDescription,
)
if err != nil {
return SetDONFamiliesOutput{}, fmt.Errorf("failed to create strategy: %w", err)
}

var resultDon capabilities_registry_v2.CapabilitiesRegistryDONInfo

// Execute the transaction using the strategy
proposals, err := strategy.Apply(func(opts *bind.TransactOpts) (*types.Transaction, error) {
tx, err := deps.CapabilitiesRegistry.SetDONFamilies(opts, don.Id, input.AddToFamilies, input.RemoveFromFamilies)
if err != nil {
err = cldf.DecodeErr(capabilities_registry_v2.CapabilitiesRegistryABI, err)
return nil, fmt.Errorf("failed to call SetDONFamilies: %w", err)
}

// For direct execution, we can confirm and get the updated DON info
if input.MCMSConfig == nil {
// Confirm transaction
_, err = chain.Confirm(tx)
if err != nil {
return nil, fmt.Errorf("failed to confirm SetDONFamilies transaction %s: %w", tx.Hash().String(), err)
}

ctx := b.GetContext()
_, err = bind.WaitMined(ctx, chain.Client, tx)
if err != nil {
return nil, fmt.Errorf("failed to mine SetDONFamilies transaction %s: %w", tx.Hash().String(), err)
}

latestDON, err := deps.CapabilitiesRegistry.GetDON(&bind.CallOpts{}, don.Id)
if err != nil {
err = cldf.DecodeErr(capabilities_registry_v2.CapabilitiesRegistryABI, err)
return nil, fmt.Errorf("failed to call GetDONByName: %w", err)
}

// Get the updated DON info
resultDon = latestDON
}

return tx, nil
})
if err != nil {
return SetDONFamiliesOutput{}, fmt.Errorf("failed to execute SetDONFamilies: %w", err)
}

if input.MCMSConfig != nil {
deps.Env.Logger.Infof("Created MCMS proposal for SetDONFamilies '%s' on chain %d", input.DonName, input.RegistryChainSel)
} else {
deps.Env.Logger.Infof("Successfully set DON families '%s' on chain %d", input.DonName, input.RegistryChainSel)
}

return SetDONFamiliesOutput{
DonInfo: resultDon,
Proposals: proposals,
}, nil
},
)
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ const (
UpdateDONDescription = "update DON"
UpdateNodeDescription = "update node"
UpdateNodesDescription = "update nodes"
SetDONFamiliesDescription = "set DON families"
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package sequences

import (
"errors"
"fmt"

"github.com/Masterminds/semver/v3"
"github.com/ethereum/go-ethereum/common"
mcmslib "github.com/smartcontractkit/mcms"

"github.com/smartcontractkit/chainlink-deployments-framework/datastore"
cldf "github.com/smartcontractkit/chainlink-deployments-framework/deployment"
"github.com/smartcontractkit/chainlink-deployments-framework/operations"
capabilities_registry_v2 "github.com/smartcontractkit/chainlink-evm/gethwrappers/workflow/generated/capabilities_registry_wrapper_v2"

commonchangeset "github.com/smartcontractkit/chainlink/deployment/common/changeset/state"
"github.com/smartcontractkit/chainlink/deployment/cre/capabilities_registry/v2/changeset/operations/contracts"
"github.com/smartcontractkit/chainlink/deployment/cre/ocr3"
)

type SetDONsFamiliesDeps struct {
Env *cldf.Environment
MCMSContracts *commonchangeset.MCMSWithTimelockState // Required if MCMSConfig is not nil
}

type SetDONsFamiliesInput struct {
DONsChanges []DONFamiliesChange

RegistryRef datastore.AddressRefKey

MCMSConfig *ocr3.MCMSConfig
}

func (i *SetDONsFamiliesInput) Validate() error {
if len(i.DONsChanges) == 0 {
return errors.New("must specify at least one DON change")
}
return nil
}

type DONFamiliesChange struct {
DonName string
AddToFamilies []string
RemoveFromFamilies []string
}

type SetDONsFamiliesOutput struct {
DonsInfo []capabilities_registry_v2.CapabilitiesRegistryDONInfo
Proposals []mcmslib.TimelockProposal
}

var SetDONsFamilies = operations.NewSequence[SetDONsFamiliesInput, SetDONsFamiliesOutput, SetDONsFamiliesDeps](
"set-dons-families-seq",
semver.MustParse("1.0.0"),
"Set DONs Families in Capabilities Registry",
func(b operations.Bundle, deps SetDONsFamiliesDeps, input SetDONsFamiliesInput) (SetDONsFamiliesOutput, error) {
if err := input.Validate(); err != nil {
return SetDONsFamiliesOutput{}, err
}

chain, ok := deps.Env.BlockChains.EVMChains()[input.RegistryRef.ChainSelector()]
if !ok {
return SetDONsFamiliesOutput{}, cldf.ErrChainNotFound
}

registryAddressRef, err := deps.Env.DataStore.Addresses().Get(input.RegistryRef)
if err != nil {
return SetDONsFamiliesOutput{}, fmt.Errorf("failed to get registry address: %w", err)
}

capReg, err := capabilities_registry_v2.NewCapabilitiesRegistry(
common.HexToAddress(registryAddressRef.Address), chain.Client,
)
if err != nil {
return SetDONsFamiliesOutput{}, fmt.Errorf("failed to create CapabilitiesRegistry: %w", err)
}

var proposals []mcmslib.TimelockProposal
var donsInfo []capabilities_registry_v2.CapabilitiesRegistryDONInfo

for _, change := range input.DONsChanges {
report, err := operations.ExecuteOperation(
b,
contracts.SetDONFamilies,
contracts.SetDONFamiliesDeps{Env: deps.Env, CapabilitiesRegistry: capReg, MCMSContracts: deps.MCMSContracts},
contracts.SetDONFamiliesInput{
DonName: change.DonName,
AddToFamilies: change.AddToFamilies,
RemoveFromFamilies: change.RemoveFromFamilies,
MCMSConfig: input.MCMSConfig,
RegistryChainSel: input.RegistryRef.ChainSelector(),
},
)
if err != nil {
return SetDONsFamiliesOutput{}, fmt.Errorf("failed to set families for DON %s: %w", change.DonName, err)
}

donsInfo = append(donsInfo, report.Output.DonInfo)
proposals = append(proposals, report.Output.Proposals...)
}

return SetDONsFamiliesOutput{
DonsInfo: donsInfo,
Proposals: proposals,
}, nil
},
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package changeset

import (
"errors"
"fmt"

cldf "github.com/smartcontractkit/chainlink-deployments-framework/deployment"
"github.com/smartcontractkit/chainlink-deployments-framework/operations"

commonchangeset "github.com/smartcontractkit/chainlink/deployment/common/changeset/state"
"github.com/smartcontractkit/chainlink/deployment/cre/capabilities_registry/v2/changeset/pkg"
"github.com/smartcontractkit/chainlink/deployment/cre/capabilities_registry/v2/changeset/sequences"
"github.com/smartcontractkit/chainlink/deployment/cre/common/strategies"
"github.com/smartcontractkit/chainlink/deployment/cre/ocr3"
)

var _ cldf.ChangeSetV2[SetDONsFamiliesInput] = SetDONsFamilies{}

type SetDONsFamiliesInput struct {
RegistrySelector uint64
RegistryQualifier string

DONsFamiliesChanges []sequences.DONFamiliesChange

MCMSConfig *ocr3.MCMSConfig
}

type SetDONsFamilies struct{}

func (l SetDONsFamilies) VerifyPreconditions(e cldf.Environment, config SetDONsFamiliesInput) error {
if config.RegistrySelector <= 0 {
return errors.New("RegistrySelector must be provided")
}
if config.RegistryQualifier == "" {
return errors.New("RegistryQualifier must be provided")
}
if len(config.DONsFamiliesChanges) == 0 {
return errors.New("must specify at least one DON family change")
}
return nil
}

func (l SetDONsFamilies) Apply(e cldf.Environment, config SetDONsFamiliesInput) (cldf.ChangesetOutput, error) {
var mcmsContracts *commonchangeset.MCMSWithTimelockState
if config.MCMSConfig != nil {
var err error
mcmsContracts, err = strategies.GetMCMSContracts(e, config.RegistrySelector, emptyQualifier)
if err != nil {
return cldf.ChangesetOutput{}, fmt.Errorf("failed to get MCMS contracts: %w", err)
}
}

registryRef := pkg.GetCapRegV2AddressRefKey(config.RegistrySelector, config.RegistryQualifier)

report, err := operations.ExecuteSequence(
e.OperationsBundle,
sequences.SetDONsFamilies,
sequences.SetDONsFamiliesDeps{
Env: &e,
MCMSContracts: mcmsContracts,
},
sequences.SetDONsFamiliesInput{
RegistryRef: registryRef,
DONsChanges: config.DONsFamiliesChanges,
MCMSConfig: config.MCMSConfig,
},
)
if err != nil {
return cldf.ChangesetOutput{}, fmt.Errorf("failed to execute SetDONsFamilies sequence: %w", err)
}

return cldf.ChangesetOutput{
Reports: report.ExecutionReports,
MCMSTimelockProposals: report.Output.Proposals,
}, nil
}
Loading
Loading