Conversation
# Conflicts: # go.mod # go.sum # pkg/family/solana/legacy/testutils/datastore.go # pkg/family/solana/legacy/testutils/fund.go # pkg/family/solana/legacy/utils/fund.go
There was a problem hiding this comment.
Pull request overview
Ports MCMS-with-Timelock deployment logic (originally from core) into this repo, introducing new Solana/EVM deployment sequences & operations, and reorganizing older code under legacy/ packages to unblock upcoming changeset refactors.
Changes:
- Added Solana Operations/Sequence flow for deploying AccessController + MCM program + Timelock program and initializing accounts/roles.
- Added EVM Operations/Sequences/Changeset code for deploying MCMS contracts, Timelock, CallProxy, and granting roles (with gas-boost retry helpers and proposal generation helpers).
- Refactored/relocated prior state/helpers into
legacypackages and updated module/toolchain dependencies (Go version bump, new deps, etc.).
Reviewed changes
Copilot reviewed 58 out of 62 changed files in this pull request and generated 14 comments.
Show a summary per file
| File | Description |
|---|---|
| pkg/family/solana/sequences/sequence.go | New Solana sequence to deploy/init AccessController, MCM, Timelock, and set up roles. |
| pkg/family/solana/operations/operation.go | New Solana operations for init/config flows (AccessController/MCM/Timelock + role grants). |
| pkg/family/solana/operations/common.go | Shared Solana deploy operation implementation. |
| pkg/family/solana/mcms_pda.go | Switch PDA helpers to use legacy.PDASeed. |
| pkg/family/solana/mcms_pda_test.go | Update PDA tests for legacy.PDASeed. |
| pkg/family/solana/legacy/testutils/preload.go | Update test preload helper imports for legacy solutils. |
| pkg/family/solana/legacy/testutils/fund.go | Update funding helper to use legacy state + PDA helpers. |
| pkg/family/solana/legacy/testutils/datastore.go | Update Solana legacy datastore test utilities and imports. |
| pkg/family/solana/legacy/testutils/artifacts.go | Update artifact helper imports for legacy solutils. |
| pkg/family/solana/legacy/state.go | Rename package to legacy and support AddressBook/DataStore loading paths. |
| pkg/family/solana/legacy/state_test.go | Update tests for legacy package naming. |
| pkg/family/solana/legacy/solutils/fund.go | New Solana airdrop funding helper (polls for signature finalization). |
| pkg/family/solana/legacy/solutils/directory.go | Add lint suppression for legacy package naming. |
| pkg/family/solana/legacy/solutils/artifacts.go | Add artifact download/extract utilities for Solana program artifacts. |
| pkg/family/solana/legacy/solutils/artifacts_test.go | Add unit tests for artifact download/extraction. |
| pkg/family/solana/legacy/proposal_adapter.go | Update Solana legacy proposal adapter receiver/package. |
| pkg/family/solana/legacy/fund.go | Update Solana legacy funding helper package name. |
| pkg/family/solana/legacy/fund_test.go | Update Solana legacy funding tests package name. |
| pkg/family/solana/changesets/legacy/deploy_timelock.go | Port legacy Solana timelock deploy/init logic. |
| pkg/family/solana/changesets/legacy/deploy_mcms_with_timelock.go | Port legacy Solana “deploy MCMS with timelock” (plus V2 operations-based path). |
| pkg/family/solana/changesets/legacy/deploy_mcm.go | Port legacy Solana MCM deploy/init logic. |
| pkg/family/solana/changesets/legacy/access_controller.go | Port legacy Solana access controller deploy/init + role setup logic. |
| pkg/family/evm/sequences/mcm_with_config.go | New EVM sequence to deploy MCM contract and set config. |
| pkg/family/evm/sequences/grant_roles_for_timelock.go | New EVM sequence to grant timelock roles (direct or proposal/no-send). |
| pkg/family/evm/operations/utils.go | New EVM operation helpers: call/deploy scaffolding, gas boost retry, proposal aggregation helpers, zk deploy helper. |
| pkg/family/evm/operations/timelock_deploy.go | New EVM deploy op for Timelock (EVM + zk bytecode). |
| pkg/family/evm/operations/mcm_set_config.go | New EVM call op for setting MCM config. |
| pkg/family/evm/operations/mcm_deploy.go | New EVM deploy ops for proposer/bypasser/canceller MCM. |
| pkg/family/evm/operations/grant_role.go | New EVM call op for granting roles on timelock. |
| pkg/family/evm/operations/callproxy_deploy.go | New EVM deploy op for CallProxy. |
| pkg/family/evm/legacy/state.go | Rename EVM legacy state package and update link view import path. |
| pkg/family/evm/legacy/state_test.go | Update tests around datastore version requirements and package rename. |
| pkg/family/evm/legacy/proposal_adapter.go | Update EVM legacy proposal adapter receiver/package. |
| pkg/family/evm/legacy/ownable.go | Introduce Ownable interface for ownership validation helpers. |
| pkg/family/evm/changesets/deploy_mcms_with_timelock.go | New EVM changeset to deploy MCMS+Timelock+CallProxy and grant roles. |
| pkg/family/aptos/legacy/state.go | Rename Aptos legacy state package. |
| pkg/family/aptos/legacy/state_test.go | Update Aptos legacy tests and common import aliasing. |
| pkg/contract/mcms/view/v1_0/mcms.go | Add lint suppression for versioned package name. |
| pkg/contract/link/view/v10/static_link_token.go | Fix package name to v10. |
| pkg/contract/link/view/v10/static_link_token_test.go | Fix package name to v10 and add lint suppression. |
| pkg/contract/link/view/v10/link_token.go | Fix package name to v10. |
| pkg/contract/link/view/v10/link_token_test.go | Fix package name to v10. |
| pkg/common/version.go | Add lint suppression for public common package name. |
| pkg/common/changeset/test_helpers.go | Add test helpers for applying changesets and executing proposals in tests. |
| mcms/operations/grant_role_timelock.go | Update Solana PDA usage and switch to legacy Solana state import. |
| mcms/operations/firedrill.go | Switch imports to legacy proposeutils and legacy state packages. |
| mcms/operations/firedrill_test.go | Update legacy EVM state import. |
| mcms/legacy/proposeutils/propose.go | Rename package and add multi-family proposal aggregation (EVM/Solana/Aptos/TON). |
| mcms/legacy/proposeutils/propose_test.go | Update tests for new proposeutils package. |
| mcms/changesets/legacy/grant_role_timelock.go | Rename package to legacy and update proposeutils import. |
| mcms/changesets/legacy/grant_role_timelock_test.go | Update tests for legacy package rename. |
| mcms/changesets/legacy/fund_mcm_pdas.go | Rename package to legacy and use legacy Solana state loading/funding. |
| mcms/changesets/legacy/fund_mcm_pdas_test.go | Update tests for legacy Solana state types/seeds. |
| mcms/changesets/legacy/firedrill.go | Rename package to legacy and update legacy EVM state import. |
| mcms/changesets/legacy/firedrill_test.go | Update tests for legacy package rename. |
| mcms/changesets/legacy/deploy_mcms_with_timelock.go | Add changeset orchestration for deploying MCMS+Timelock across families + role/ownership validation helpers. |
| mcms/changesets/legacy/deploy_mcms_with_timelock_test.go | Add comprehensive integration tests for deploy + grant role flows (EVM/Solana). |
| link/changesets/deploy_link_token_test.go | Update import to legacy EVM state and remove nil-version datastore test case. |
| go.mod | Bump Go version and update/add many dependencies required for ported code. |
| .tool-versions | Bump Go toolchain version to match module. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| func GasBoostConfigsForChainMap[T any](chainMap map[uint64]T, gasBoostConfigs map[uint64]cldfproposalutils.GasBoostConfig) map[uint64]*cldfproposalutils.GasBoostConfig { | ||
| cfgs := make(map[uint64]*cldfproposalutils.GasBoostConfig, len(chainMap)) | ||
| if gasBoostConfigs == nil || chainMap == nil { // in either case, gas boosting should be empty | ||
| return cfgs | ||
| } | ||
|
|
||
| for chainSelector := range chainMap { | ||
| if _, ok := gasBoostConfigs[chainSelector]; ok { | ||
| cfgs[chainSelector] = new(gasBoostConfigs[chainSelector]) | ||
| } else { | ||
| cfgs[chainSelector] = nil |
| import ( | ||
| "github.com/Masterminds/semver/v3" | ||
| "github.com/ethereum/go-ethereum/accounts/abi/bind/v2" | ||
| "github.com/ethereum/go-ethereum/common" |
| for _, roleAndAddress := range in.RolesAndAddresses { | ||
| switch roleAndAddress.Role { | ||
| case v1_0.PROPOSER_ROLE.ID: | ||
| addressesInInspector, err2 = timelockInspector.GetProposers(b.GetContext(), in.Timelock.Hex()) | ||
| case v1_0.CANCELLER_ROLE.ID: | ||
| addressesInInspector, err2 = timelockInspector.GetCancellers(b.GetContext(), in.Timelock.Hex()) | ||
| case v1_0.BYPASSER_ROLE.ID: | ||
| addressesInInspector, err2 = timelockInspector.GetBypassers(b.GetContext(), in.Timelock.Hex()) | ||
| case v1_0.EXECUTOR_ROLE.ID: | ||
| addressesInInspector, err2 = timelockInspector.GetExecutors(b.GetContext(), in.Timelock.Hex()) | ||
| case v1_0.ADMIN_ROLE.ID: | ||
| addressesInInspector = []string{} | ||
| } |
| contract, err := constructor(input.Address, chain.Client) | ||
| if err != nil { | ||
| return EVMCallOutput{}, fmt.Errorf("failed to create contract instance for %s at %s on %s: %w", name, input.Address, chain, err) | ||
| } | ||
| tx, err := call(contract, opts, input.CallInput) | ||
| confirmed := false | ||
| if !input.NoSend { | ||
| // If the call has actually been sent, we need check the call error and confirm the transaction. | ||
| if _, err = cldf.ConfirmIfNoErrorWithABI(chain, tx, abi, err); err != nil { | ||
| return EVMCallOutput{}, fmt.Errorf("failed to confirm %s tx against %s on %s: %w", name, input.Address, chain, err) | ||
| } | ||
| b.Logger.Debugw(fmt.Sprintf("Confirmed %s tx against %s on %s", name, input.Address, chain), "hash", tx.Hash().Hex(), "input", input.CallInput) | ||
| confirmed = true | ||
| } else { | ||
| b.Logger.Debugw(fmt.Sprintf("Prepared %s tx against %s on %s", name, input.Address, chain), "input", input.CallInput) | ||
| } | ||
|
|
||
| return EVMCallOutput{ | ||
| To: input.Address, | ||
| Data: tx.Data(), | ||
| ContractType: contractType, | ||
| Confirmed: confirmed, | ||
| }, err |
| err = deps.Datastore.Addresses().Add(datastore.AddressRef{ | ||
| ChainSelector: deps.Chain.ChainSelector(), | ||
| Address: programID.String(), | ||
| Version: &cldchangesetscommon.Version1_0_0, | ||
| Type: datastore.ContractType(mcmscontracts.ManyChainMultisig), | ||
| }) |
| func initTimelock(b operations.Bundle, deps solops.Deps, minDelay *big.Int) error { | ||
| if deps.State.TimelockProgram.IsZero() { | ||
| return errors.New("mcm program is not deployed") | ||
| } |
| DeployMCMSWithTimelockSeq = operations.NewSequence( | ||
| "deploy-access-controller-seq", | ||
| &cldchangesetscommon.Version1_0_0, | ||
| "Deploy AccessController,MCM and Timelock programs, Initialize them, set up role", | ||
| deployMCMSWithTimelock, | ||
| ) |
| if deps.State.TimelockProgram.IsZero() { | ||
| return out, errors.New("mcm program is not deployed") | ||
| } |
| // Add the new proposal to the ChangesetOutput. | ||
| if csOutput.MCMSTimelockProposals == nil { | ||
| csOutput.MCMSTimelockProposals = make([]mcmslib.TimelockProposal, 1) | ||
| } | ||
| csOutput.MCMSTimelockProposals = append(csOutput.MCMSTimelockProposals, *proposal) | ||
| // Aggregate the proposals into a single proposal. |
| adminAddresses := make([]string, 0, numAddresses.Uint64()) | ||
| for i := range numAddresses.Uint64() { | ||
| if i > math.MaxUint32 { | ||
| return nil, fmt.Errorf("value %d exceeds uint32 range", i) | ||
| } | ||
| idx, err := cast.ToInt64E(i) | ||
| if err != nil { |
gustavogama-cll
left a comment
There was a problem hiding this comment.
approving but I think James suggested a single top-level legacy package, not several legacy subpackages. I don't have a strong opinion but maybe check with him before merging.
Yea maybe we can have just separate legacy dir with same structure inside just everything in one place so its kinda isolated from the rest. With that you would have current code cleaner. Still a nit but seems like a small life improvement. |
Yeah we had a call and I pitched the idea and was fine with it, in any case tagging @jkongie to confirm |
Sure, if you guys prefer it I can make a followup to set the final structure |
🤖 I have created a release *beep* *boop* --- ## [0.3.0](v0.2.0...v0.3.0) (2026-05-08) ### Features * add catalog create address refs changeset ([#38](#38)) ([c22ad31](c22ad31)) * add catalog update address refs changeset ([#43](#43)) ([a9de479](a9de479)) * add catalog update env metadata changeset ([#46](#46)) ([5a793ef](5a793ef)) * add sonar properties file ([#44](#44)) ([cbc2fa5](cbc2fa5)) * port deploy mcms with timelock ([#28](#28)) ([39a62f2](39a62f2)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). Co-authored-by: app-token-issuer-ops-platform[bot] <275822481+app-token-issuer-ops-platform[bot]@users.noreply.github.com>
legacypkgs for code that will be deprecated when refactor of changesets is done.AI Summary
This pull request updates the project's dependencies in the
go.modfile. The main changes include upgrading the Go version, updating several direct and indirect dependencies to newer versions, adding new dependencies, and replacing a module with a local path. These updates help keep the codebase up-to-date with the latest features, security patches, and compatibility improvements.Dependency and Version Updates:
1.25.7to1.26.2ingo.mod.github.com/aptos-labs/aptos-go-sdk,github.com/deckarep/golang-set/v2,github.com/ethereum/go-ethereum,github.com/smartcontractkit/chain-selectors,github.com/smartcontractkit/chainlink-ccip/chains/solana,github.com/smartcontractkit/chainlink-common, and many others.Module Replacement and Additions:
github.com/smartcontractkit/chainlink-deployments-frameworkmodule with a local path to../chainlink-deployments-framework, likely to use a local development version.github.com/smartcontractkit/chainlink-ton/deployment,github.com/smartcontractkit/chainlink/deployment,github.com/smartcontractkit/quarantine, andgithub.com/smartcontractkit/wsrpc.General Maintenance:
These changes collectively help maintain and improve the stability, security, and feature set of the project.