Skip to content

Commit 75dbc64

Browse files
authored
Add 3x MCMS structure to deployer/reader/state (#601)
* Add 3x MCMS structure to deployer/reader/state * Refactor common DeployMCMS seq * Add ton/ops/mcms/set-config op * Remove unused MCMS cs/test * Polish & fix lint * go mod tidy * Fix tlbe.Cell[T] marshalling * Use tvm.Getter in test, check output addr * Add MCMS to transfer ownership test * Fix full message plan vs body * Check MCMS config post deployemnt * Fix MCMS deploy seq addrs state * Fix tests/env, add setConfig op test * Fix/imporve CLDF idempotency - use unique series ID * Fix lint * Add wait option to ton/ops/send-messages * PR feedback
1 parent b181acd commit 75dbc64

35 files changed

Lines changed: 981 additions & 729 deletions

File tree

.github/workflows/ccip-integration-test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ env:
1616
DOCKER_CACHE_TAR_NAME: ccip-e2e-docker-images.tar
1717
# mylocalton docker image / CCIP E2E test database image
1818
DOCKER_IMAGES: >-
19-
ghcr.io/neodix42/mylocalton-docker:v3.99
19+
ghcr.io/neodix42/mylocalton-docker:v4.0.0
2020
postgres:16-alpine
2121
jobs:
2222
prepare-images:

deployment/ccip/1_6_0/sequences/mcms.go

Lines changed: 60 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -2,89 +2,89 @@ package sequences
22

33
import (
44
"fmt"
5-
"math"
65

76
"github.com/Masterminds/semver/v3"
8-
97
"github.com/xssnick/tonutils-go/address"
108

11-
cldf_chain "github.com/smartcontractkit/chainlink-deployments-framework/chain"
12-
"github.com/smartcontractkit/chainlink-deployments-framework/chain/ton"
13-
"github.com/smartcontractkit/chainlink-deployments-framework/datastore"
14-
"github.com/smartcontractkit/chainlink-deployments-framework/operations"
15-
16-
"github.com/smartcontractkit/chainlink-ccip/deployment/deploy"
17-
cciputils "github.com/smartcontractkit/chainlink-ccip/deployment/utils"
18-
"github.com/smartcontractkit/chainlink-ccip/deployment/utils/sequences"
9+
cldfchain "github.com/smartcontractkit/chainlink-deployments-framework/chain"
10+
cldfton "github.com/smartcontractkit/chainlink-deployments-framework/chain/ton"
11+
cldfds "github.com/smartcontractkit/chainlink-deployments-framework/datastore"
12+
cldfops "github.com/smartcontractkit/chainlink-deployments-framework/operations"
1913

20-
"github.com/smartcontractkit/chainlink-ton/pkg/bindings/mcms/timelock"
14+
ccipddeploy "github.com/smartcontractkit/chainlink-ccip/deployment/deploy"
15+
ccipdutils "github.com/smartcontractkit/chainlink-ccip/deployment/utils"
16+
ccipdseq "github.com/smartcontractkit/chainlink-ccip/deployment/utils/sequences"
2117

22-
tonops "github.com/smartcontractkit/chainlink-ton/deployment/ccip"
23-
mcmsConfig "github.com/smartcontractkit/chainlink-ton/deployment/mcms/config"
24-
mcmsSeq "github.com/smartcontractkit/chainlink-ton/deployment/mcms/sequence"
2518
"github.com/smartcontractkit/chainlink-ton/deployment/pkg/dep"
19+
opsmcms "github.com/smartcontractkit/chainlink-ton/deployment/pkg/ops/mcms"
2620
"github.com/smartcontractkit/chainlink-ton/deployment/state"
27-
)
2821

29-
// defaultMCMSContractCoin is the default amount of TON coins to allocate for MCMS contract deployment.
30-
// MCMS contracts require more storage and operational capacity, hence the higher allocation compared to CCIP contracts.
31-
const defaultMCMSContractCoin = "1.5"
22+
"github.com/smartcontractkit/chainlink-ton/pkg/ton/tvm"
23+
)
3224

33-
func (a *TonDeployAdapter) DeployMCMS() *operations.Sequence[deploy.MCMSDeploymentConfigPerChainWithAddress, sequences.OnChainOutput, cldf_chain.BlockChains] {
25+
func (a *TonDeployAdapter) DeployMCMS() *cldfops.Sequence[ccipddeploy.MCMSDeploymentConfigPerChainWithAddress, ccipdseq.OnChainOutput, cldfchain.BlockChains] {
3426
return DeployMCMSContracts
3527
}
3628

37-
var DeployMCMSContracts = operations.NewSequence(
29+
var DeployMCMSContracts = cldfops.NewSequence(
3830
"ton/sequences/ccip/tooling-api/deploy-mcms",
3931
semver.MustParse("0.0.4"), // TODO mcms and timelock has different versions, can we pick mcms version here?
4032
"Deploys all MCM contracts with config",
41-
func(b operations.Bundle, chains cldf_chain.BlockChains, input deploy.MCMSDeploymentConfigPerChainWithAddress) (output sequences.OnChainOutput, err error) {
33+
func(b cldfops.Bundle, chains cldfchain.BlockChains, input ccipddeploy.MCMSDeploymentConfigPerChainWithAddress) (output ccipdseq.OnChainOutput, err error) {
4234
chain := chains.TonChains()[input.ChainSelector]
4335

44-
qualifier := cciputils.CLLQualifier // default
45-
if input.Qualifier != nil {
46-
qualifier = *input.Qualifier
36+
defaultQualifier := ccipdutils.CLLQualifier
37+
if input.Qualifier == nil {
38+
input.Qualifier = &defaultQualifier
4739
}
4840

49-
stateMCMS, err := extractMCMSChainStateFromMCMSDeploymentInput(chain, input.ExistingAddresses, qualifier)
41+
stateMCMS, err := extractMCMSChainStateFromMCMSDeploymentInput(chain, input.ExistingAddresses, *input.Qualifier)
5042
if err != nil {
51-
return sequences.OnChainOutput{}, err
43+
return ccipdseq.OnChainOutput{}, err
5244
}
45+
5346
dp, err := dep.NewDependencyProvider(
5447
dep.Provide(chain),
5548
dep.Provide(stateMCMS[input.ChainSelector]),
5649
)
5750
if err != nil {
58-
return sequences.OnChainOutput{}, fmt.Errorf("failed to create dependency provider: %w", err)
51+
return ccipdseq.OnChainOutput{}, fmt.Errorf("failed to create dependency provider: %w", err)
5952
}
6053

61-
_input, err := intoDeployMCMSSeqInput(input, chain.WalletAddress)
54+
// Generate a random contract ID used for contracts in this deployment
55+
contractID, err := tvm.RandomQueryID()
6256
if err != nil {
63-
return sequences.OnChainOutput{}, err
64-
}
65-
r, err := operations.ExecuteSequence(b, mcmsSeq.DeployMCMSSequence, dp, _input)
66-
if err != nil {
67-
return sequences.OnChainOutput{}, fmt.Errorf("failed to deploy MCMS for TON chain %d: %w", input.ChainSelector, err)
57+
return ccipdseq.OnChainOutput{}, fmt.Errorf("failed to generate random contract ID: %w", err)
6858
}
6959

70-
// Attach the qualifier to the output (to be stored in DS)
71-
for i := range r.Output.Addresses {
72-
r.Output.Addresses[i].Qualifier = qualifier
60+
b.Logger.Info("in.TimelockAdmin - skipping param (EVM specific type - 20 bytes, not compatible with TON address format)")
61+
b.Logger.Infof("in.TimelockAdmin - using deployer address %s as initial admin", chain.WalletAddress)
62+
63+
r, err := cldfops.ExecuteSequence(b, opsmcms.DeployMCMSSequence, dp, opsmcms.DeployMCMSSeqInput{
64+
Config: input.MCMSDeploymentConfigPerChain,
65+
ContractID: uint32(contractID),
66+
ContractsSemverMCMS: &state.MCMSVersion,
67+
ContractsSemverTimelock: &state.TimelockVersion,
68+
})
69+
if err != nil {
70+
return ccipdseq.OnChainOutput{}, fmt.Errorf("failed to deploy MCMS for TON chain %d: %w", input.ChainSelector, err)
7371
}
7472

75-
return sequences.OnChainOutput{
76-
Addresses: r.Output.Addresses,
77-
BatchOps: r.Output.BatchOps,
78-
}, nil
73+
return r.Output, nil
7974
},
8075
)
8176

8277
// TODO: unify and deduplicate with state.LoadMCMSOnChainState
83-
func extractMCMSChainStateFromMCMSDeploymentInput(chain ton.Chain, existing []datastore.AddressRef, qualifier string) (map[uint64]state.MCMSChainState, error) {
84-
noneAddr := address.NewAddressNone()
78+
func extractMCMSChainStateFromMCMSDeploymentInput(chain cldfton.Chain, existing []cldfds.AddressRef, qualifier string) (map[uint64]state.MCMSChainState, error) {
79+
none := address.NewAddressNone()
8580
s := state.MCMSChainState{
8681
ByQualifier: map[string]*state.MCMSSuiteState{
87-
qualifier: {Timelock: noneAddr, MCMS: noneAddr},
82+
qualifier: {
83+
Proposer: none,
84+
Bypasser: none,
85+
Canceller: none,
86+
Timelock: none,
87+
},
8888
},
8989
}
9090

@@ -100,10 +100,14 @@ func extractMCMSChainStateFromMCMSDeploymentInput(chain ton.Chain, existing []da
100100
}
101101

102102
switch e.Type {
103-
case state.Timelock:
103+
case cldfds.ContractType(ccipdutils.RBACTimelock):
104104
s.ByQualifier[qualifier].Timelock = tonAddr
105-
case state.MCMS:
106-
s.ByQualifier[qualifier].MCMS = tonAddr
105+
case cldfds.ContractType(ccipdutils.ProposerManyChainMultisig):
106+
s.ByQualifier[qualifier].Proposer = tonAddr
107+
case cldfds.ContractType(ccipdutils.BypasserManyChainMultisig):
108+
s.ByQualifier[qualifier].Bypasser = tonAddr
109+
case cldfds.ContractType(ccipdutils.CancellerManyChainMultisig):
110+
s.ByQualifier[qualifier].Canceller = tonAddr
107111
default:
108112
// ignore unknown types
109113
}
@@ -112,63 +116,26 @@ func extractMCMSChainStateFromMCMSDeploymentInput(chain ton.Chain, existing []da
112116
return map[uint64]state.MCMSChainState{chain.Selector: s}, nil
113117
}
114118

115-
func intoDeployMCMSSeqInput(cfg deploy.MCMSDeploymentConfigPerChainWithAddress, deployer *address.Address) (mcmsSeq.DeployMCMSSeqInput, error) {
116-
// Generate a random contract ID for all contracts in this deployment
117-
contractID, err := tonops.RandomUint32()
118-
if err != nil {
119-
return mcmsSeq.DeployMCMSSeqInput{}, fmt.Errorf("failed to generate random contract ID: %w", err)
120-
}
121-
122-
// MinDelay from cfg.TimelockMinDelay (big.Int) to uint32 safely
123-
var minDelay uint32
124-
if cfg.TimelockMinDelay != nil && cfg.TimelockMinDelay.IsUint64() {
125-
val := cfg.TimelockMinDelay.Uint64()
126-
if val <= math.MaxUint32 {
127-
minDelay = uint32(val)
128-
} else {
129-
// overflow, set to max
130-
minDelay = math.MaxUint32
131-
}
132-
}
133-
134-
return mcmsSeq.DeployMCMSSeqInput{
135-
ContractsVersionSha: cfg.ContractVersion,
136-
ContractsParams: mcmsConfig.ChainContractParams{
137-
Timelock: mcmsConfig.TimelockParams{
138-
ID: contractID,
139-
Coin: defaultMCMSContractCoin,
140-
ContractsSemver: &state.TimelockVersion,
141-
InitMessage: timelock.Init{
142-
MinDelay: minDelay,
143-
Admin: deployer,
144-
},
145-
},
146-
MCMS: mcmsConfig.MCMSParams{
147-
ID: contractID,
148-
Coin: defaultMCMSContractCoin,
149-
ContractsSemver: &state.MCMSVersion,
150-
},
151-
},
152-
ChainSelector: cfg.ChainSelector,
153-
}, nil
154-
}
155-
156-
func (a *TonDeployAdapter) FinalizeDeployMCMS() *operations.Sequence[deploy.MCMSDeploymentConfigPerChainWithAddress, sequences.OnChainOutput, cldf_chain.BlockChains] {
157-
return operations.NewSequence(
119+
func (a *TonDeployAdapter) FinalizeDeployMCMS() *cldfops.Sequence[ccipddeploy.MCMSDeploymentConfigPerChainWithAddress, ccipdseq.OnChainOutput, cldfchain.BlockChains] {
120+
return cldfops.NewSequence(
158121
"ton/sequences/ccip/tooling-api/finalize-deploy-mcms",
159122
semver.MustParse("1.0.0"),
160123
"On TON, finalizing MCM deployment is a no-op",
161-
func(b operations.Bundle, chains cldf_chain.BlockChains, in deploy.MCMSDeploymentConfigPerChainWithAddress) (output sequences.OnChainOutput, err error) {
124+
func(b cldfops.Bundle, chains cldfchain.BlockChains, in ccipddeploy.MCMSDeploymentConfigPerChainWithAddress) (output ccipdseq.OnChainOutput, err error) {
162125
return output, nil
163126
})
164127
}
165128

166-
func (a *TonDeployAdapter) GrantAdminRoleToTimelock() *operations.Sequence[deploy.GrantAdminRoleToTimelockConfigPerChainWithSelector, sequences.OnChainOutput, cldf_chain.BlockChains] {
167-
return operations.NewSequence(
129+
func (a *TonDeployAdapter) GrantAdminRoleToTimelock() *cldfops.Sequence[ccipddeploy.GrantAdminRoleToTimelockConfigPerChainWithSelector, ccipdseq.OnChainOutput, cldfchain.BlockChains] {
130+
return cldfops.NewSequence(
168131
"ton/sequences/ccip/tooling-api/grant-admin-role-to-timelock",
169132
semver.MustParse("1.0.0"),
170133
"On TON, GrantAdminRoleToTimelock is a no-op",
171-
func(b operations.Bundle, chains cldf_chain.BlockChains, in deploy.GrantAdminRoleToTimelockConfigPerChainWithSelector) (output sequences.OnChainOutput, err error) {
134+
func(b cldfops.Bundle, chains cldfchain.BlockChains, in ccipddeploy.GrantAdminRoleToTimelockConfigPerChainWithSelector) (output ccipdseq.OnChainOutput, err error) {
135+
// TODO:
136+
// - grant role to timelock
137+
// - renounce role from deployer key
138+
172139
return output, nil
173140
})
174141
}

deployment/ccip/1_6_0/sequences/mcms_reader.go

Lines changed: 41 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -3,37 +3,40 @@ package sequences
33
import (
44
"fmt"
55

6-
mcms_ton "github.com/smartcontractkit/mcms/sdk/ton"
6+
mcmston "github.com/smartcontractkit/mcms/sdk/ton"
77
"github.com/smartcontractkit/mcms/types"
88

9-
"github.com/smartcontractkit/chainlink-deployments-framework/datastore"
10-
"github.com/smartcontractkit/chainlink-deployments-framework/deployment"
9+
cldfds "github.com/smartcontractkit/chainlink-deployments-framework/datastore"
10+
cldf "github.com/smartcontractkit/chainlink-deployments-framework/deployment"
1111

12-
"github.com/smartcontractkit/chainlink-ccip/deployment/utils/changesets"
13-
datastore_utils "github.com/smartcontractkit/chainlink-ccip/deployment/utils/datastore"
14-
mcms_utils "github.com/smartcontractkit/chainlink-ccip/deployment/utils/mcms"
12+
ccipdutils "github.com/smartcontractkit/chainlink-ccip/deployment/utils"
13+
ccipdcs "github.com/smartcontractkit/chainlink-ccip/deployment/utils/changesets"
14+
ccipdds "github.com/smartcontractkit/chainlink-ccip/deployment/utils/datastore"
15+
ccipdmcms "github.com/smartcontractkit/chainlink-ccip/deployment/utils/mcms"
1516

1617
"github.com/smartcontractkit/chainlink-ton/deployment/state"
1718
)
1819

20+
var _ ccipdcs.MCMSReader = &MCMSReaderAdapter{}
21+
1922
type MCMSReaderAdapter struct{}
2023

2124
// GetChainMetadata returns the chain metadata for a given MCMS input.
22-
func (r *MCMSReaderAdapter) GetChainMetadata(e deployment.Environment, chainSelector uint64, input mcms_utils.Input) (types.ChainMetadata, error) {
23-
chain, ok := e.BlockChains.TonChains()[chainSelector]
25+
func (r *MCMSReaderAdapter) GetChainMetadata(e cldf.Environment, cs uint64, input ccipdmcms.Input) (types.ChainMetadata, error) {
26+
chain, ok := e.BlockChains.TonChains()[cs]
2427
if !ok {
25-
return types.ChainMetadata{}, fmt.Errorf("chain with selector %d not found in environment", chainSelector)
28+
return types.ChainMetadata{}, fmt.Errorf("chain with selector %d not found in environment", cs)
2629
}
2730

28-
mcmsAddr, err := r.GetMCMSRef(e, chainSelector, input)
31+
mcmsAddr, err := r.GetMCMSRef(e, cs, input)
2932
if err != nil {
30-
return types.ChainMetadata{}, fmt.Errorf("failed to get MCMS address for chain %d: %w", chainSelector, err)
33+
return types.ChainMetadata{}, fmt.Errorf("failed to get MCMS address for chain %d: %w", cs, err)
3134
}
3235

33-
inspector := mcms_ton.NewInspector(chain.Client)
36+
inspector := mcmston.NewInspector(chain.Client)
3437
counts, err := inspector.GetOpCount(e.GetContext(), mcmsAddr.Address)
3538
if err != nil {
36-
return types.ChainMetadata{}, fmt.Errorf("failed to get opCount for MCMS at address %s on chain %d: %w", mcmsAddr.Address, chainSelector, err)
39+
return types.ChainMetadata{}, fmt.Errorf("failed to get opCount for MCMS at address %s on chain %d: %w", mcmsAddr.Address, cs, err)
3740
}
3841

3942
return types.ChainMetadata{
@@ -44,33 +47,38 @@ func (r *MCMSReaderAdapter) GetChainMetadata(e deployment.Environment, chainSele
4447
}
4548

4649
// GetTimelockRef returns the timelock contract address reference for a given MCMS input.
47-
func (r *MCMSReaderAdapter) GetTimelockRef(e deployment.Environment, chainSelector uint64, input mcms_utils.Input) (datastore.AddressRef, error) {
48-
ref := datastore_utils.GetAddressRef(
49-
e.DataStore.Addresses().Filter(),
50-
chainSelector,
51-
deployment.ContractType(state.Timelock),
52-
&state.TimelockVersion,
53-
input.Qualifier,
54-
)
50+
func (r *MCMSReaderAdapter) GetTimelockRef(e cldf.Environment, cs uint64, input ccipdmcms.Input) (cldfds.AddressRef, error) {
51+
t := ccipdutils.RBACTimelock
52+
version := state.TimelockVersion
53+
ref := ccipdds.GetAddressRef(e.DataStore.Addresses().Filter(), cs, t, &version, input.Qualifier)
5554
if ref.Address == "" {
56-
return datastore.AddressRef{}, fmt.Errorf("timelock contract not found for chain selector %d", chainSelector)
55+
return cldfds.AddressRef{}, fmt.Errorf("timelock contract not found for chain selector %d", cs)
5756
}
57+
5858
return ref, nil
5959
}
6060

6161
// GetMCMSRef returns the MCMS contract address reference for a given MCMS input.
62-
func (r *MCMSReaderAdapter) GetMCMSRef(e deployment.Environment, chainSelector uint64, input mcms_utils.Input) (datastore.AddressRef, error) {
63-
ref := datastore_utils.GetAddressRef(
64-
e.DataStore.Addresses().Filter(),
65-
chainSelector,
66-
deployment.ContractType(state.MCMS),
67-
&state.MCMSVersion,
68-
input.Qualifier,
69-
)
62+
func (r *MCMSReaderAdapter) GetMCMSRef(e cldf.Environment, cs uint64, input ccipdmcms.Input) (cldfds.AddressRef, error) {
63+
// find mcms address
64+
// populate contract type from TimelockAction
65+
var t cldf.ContractType
66+
switch input.TimelockAction {
67+
case types.TimelockActionSchedule:
68+
t = ccipdutils.ProposerManyChainMultisig
69+
case types.TimelockActionBypass:
70+
t = ccipdutils.BypasserManyChainMultisig
71+
case types.TimelockActionCancel:
72+
t = ccipdutils.CancellerManyChainMultisig
73+
default:
74+
return cldfds.AddressRef{}, fmt.Errorf("unsupported timelock action type: %s", input.TimelockAction)
75+
}
76+
77+
version := state.MCMSVersion
78+
ref := ccipdds.GetAddressRef(e.DataStore.Addresses().Filter(), cs, t, &version, input.Qualifier)
7079
if ref.Address == "" {
71-
return datastore.AddressRef{}, fmt.Errorf("MCMS contract not found for chain selector %d", chainSelector)
80+
return cldfds.AddressRef{}, fmt.Errorf("MCMS contract not found for chain selector %d", cs)
7281
}
82+
7383
return ref, nil
7484
}
75-
76-
var _ changesets.MCMSReader = &MCMSReaderAdapter{}

0 commit comments

Comments
 (0)