Skip to content

Commit 8d0e96d

Browse files
nicolasgnrCopilot
andauthored
Improve deploy chain sequence by creating a generic deploy contract operation (#265)
* generic deploy contract operation * self-review-I * self-review-II * self-review-III * Update deployment/ccip/sequence/retrieve_compiled_ton_contracts.go Co-authored-by: Copilot <[email protected]> * Update deployment/ccip/sequence/retrieve_compiled_ton_contracts.go Co-authored-by: Copilot <[email protected]> * Update deployment/ccip/sequence/retrieve_compiled_ton_contracts.go Co-authored-by: Copilot <[email protected]> --------- Co-authored-by: Copilot <[email protected]>
1 parent d2cae9b commit 8d0e96d

File tree

5 files changed

+544
-223
lines changed

5 files changed

+544
-223
lines changed

deployment/ccip/cs_deploy_ton_chain.go

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package ops
22

33
import (
44
"fmt"
5+
56
"github.com/Masterminds/semver/v3"
67
ds "github.com/smartcontractkit/chainlink-deployments-framework/datastore"
78

@@ -69,9 +70,10 @@ func (cs DeployCCIPContracts) Apply(env cldf.Environment, config DeployCCIPContr
6970
ccipSeqInput := sequence.DeployCCIPSeqInput{
7071
// MCMSAddress: mcmsSeqReport.Output.MCMSAddress,
7172
// LinkTokenAddress: linkTokenAddress,
72-
CCIPConfig: config.Params,
73-
ContractsVersion: config.ContractsVersion,
74-
ChainSelector: selector,
73+
CCIPConfig: config.Params,
74+
ContractsVersionSha: config.ContractsVersion,
75+
ContractsSemver: semver.MustParse("1.6.0"), // TODO Move to the change input. Will do in a later PR given that this will be a breaking change for CLD
76+
ChainSelector: selector,
7577
}
7678
ccipSeqReport, err := operations.ExecuteSequence(env.OperationsBundle, sequence.DeployCCIPSequence, deps, ccipSeqInput)
7779
if err != nil {
@@ -86,38 +88,29 @@ func (cs DeployCCIPContracts) Apply(env cldf.Environment, config DeployCCIPContr
8688

8789
// Use data store to track new deployed addresses
8890
dataStore := ds.NewMemoryDataStore()
89-
// Keep address book for backward compatibility. TODO remove it once we adopted this version in CLD
90-
ab := cldf.NewMemoryAddressBook()
91-
contractsVersion := *semver.MustParse("1.6.0")
9291
if ccipSeqReport.Output.RouterAddress != nil {
9392
// FYI Add method will never fail given that the dataStore is empty
9493
_ = dataStore.Addresses().Add(ccipSeqReport.Output.RouterAddress.CLDFAddressRef)
95-
_ = ab.Save(selector, state.Router.String(), cldf.NewTypeAndVersion(cldf.ContractType(state.Router.String()), contractsVersion))
9694
s.Router = ccipSeqReport.Output.RouterAddress.TONAddress
9795
}
9896
if ccipSeqReport.Output.FeeQuoterAddress != nil {
9997
_ = dataStore.Addresses().Add(ccipSeqReport.Output.FeeQuoterAddress.CLDFAddressRef)
100-
_ = ab.Save(selector, state.FeeQuoter.String(), cldf.NewTypeAndVersion(cldf.ContractType(state.FeeQuoter.String()), contractsVersion))
10198
s.FeeQuoter = ccipSeqReport.Output.FeeQuoterAddress.TONAddress
10299
}
103100
if ccipSeqReport.Output.OnRampAddress != nil {
104101
_ = dataStore.Addresses().Add(ccipSeqReport.Output.OnRampAddress.CLDFAddressRef)
105-
_ = ab.Save(selector, state.OnRamp.String(), cldf.NewTypeAndVersion(cldf.ContractType(state.OnRamp.String()), contractsVersion))
106102
s.OnRamp = ccipSeqReport.Output.OnRampAddress.TONAddress
107103
}
108104
if ccipSeqReport.Output.OffRampAddress != nil {
109105
_ = dataStore.Addresses().Add(ccipSeqReport.Output.OffRampAddress.CLDFAddressRef)
110-
_ = ab.Save(selector, state.OffRamp.String(), cldf.NewTypeAndVersion(cldf.ContractType(state.OffRamp.String()), contractsVersion))
111106
s.OffRamp = ccipSeqReport.Output.OffRampAddress.TONAddress
112107
}
113108
if ccipSeqReport.Output.ReceiverAddress != nil {
114109
_ = dataStore.Addresses().Add(ccipSeqReport.Output.ReceiverAddress.CLDFAddressRef)
115-
_ = ab.Save(selector, state.TonReceiver.String(), cldf.NewTypeAndVersion(cldf.ContractType(state.TonReceiver.String()), contractsVersion))
116110
s.ReceiverAddress = ccipSeqReport.Output.ReceiverAddress.TONAddress
117111
}
118112
if ccipSeqReport.Output.TimelockAddress != nil {
119113
_ = dataStore.Addresses().Add(ccipSeqReport.Output.TimelockAddress.CLDFAddressRef)
120-
_ = ab.Save(selector, state.Timelock.String(), cldf.NewTypeAndVersion(cldf.ContractType(state.Timelock.String()), contractsVersion))
121114
s.Timelock = ccipSeqReport.Output.TimelockAddress.TONAddress
122115
}
123116

@@ -148,6 +141,9 @@ func (cs DeployCCIPContracts) Apply(env cldf.Environment, config DeployCCIPContr
148141
return cldf.ChangesetOutput{}, err
149142
}
150143

144+
// Keep address book for backward compatibility. TODO remove it once we adopted this version in CLD
145+
ab, _ := dataStoreToAddressBook(dataStore)
146+
151147
// TODO: generate MCMS proposal or execute
152148
return cldf.ChangesetOutput{
153149
MCMSTimelockProposals: proposals,
@@ -156,3 +152,20 @@ func (cs DeployCCIPContracts) Apply(env cldf.Environment, config DeployCCIPContr
156152
AddressBook: ab,
157153
}, nil
158154
}
155+
156+
// Temp function to transform a DataStore to the legacy AddressBook. Couldn't find any utility function to do this.
157+
// Once we adopt this new change set in CLD we can remove returning AddressBook at all :)
158+
func dataStoreToAddressBook(ds *ds.MemoryDataStore) (*cldf.AddressBookMap, error) {
159+
ab := cldf.NewMemoryAddressBook()
160+
addresses, err := ds.Addresses().Fetch()
161+
if err != nil {
162+
return nil, fmt.Errorf("failed to list addresses from datastore: %w", err)
163+
}
164+
for _, addrRef := range addresses {
165+
err := ab.Save(addrRef.ChainSelector, addrRef.Address, cldf.NewTypeAndVersion(cldf.ContractType(addrRef.Type), *addrRef.Version))
166+
if err != nil {
167+
return nil, fmt.Errorf("failed to save address %s to address book: %w", addrRef.Type, err)
168+
}
169+
}
170+
return ab, nil
171+
}
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
package operation
2+
3+
import (
4+
"encoding/hex"
5+
"errors"
6+
"fmt"
7+
"math/big"
8+
"strings"
9+
10+
"github.com/xssnick/tonutils-go/tvm/cell"
11+
12+
"github.com/Masterminds/semver/v3"
13+
"github.com/xssnick/tonutils-go/address"
14+
"github.com/xssnick/tonutils-go/tlb"
15+
16+
"github.com/smartcontractkit/chainlink-deployments-framework/operations"
17+
18+
"github.com/smartcontractkit/chainlink-ton/pkg/ton/tracetracking"
19+
"github.com/smartcontractkit/chainlink-ton/pkg/ton/wrappers"
20+
)
21+
22+
type DeployContractInput struct {
23+
Name string
24+
Storage any
25+
MessageBody any
26+
ContractCode *cell.Cell
27+
Coins string
28+
}
29+
30+
type DeployContractOutput struct {
31+
Address *address.Address
32+
}
33+
34+
var DeployTONContractOp = operations.NewOperation(
35+
"deploy-ton-contract-op",
36+
semver.MustParse("0.1.0"),
37+
"Deploys a TON contract in a generic way",
38+
deployTONContract,
39+
)
40+
41+
func (i *DeployContractInput) Validate() error {
42+
if strings.TrimSpace(i.Name) == "" {
43+
return errors.New("name field is required")
44+
}
45+
if i.ContractCode == nil {
46+
return errors.New("contract code field is required")
47+
}
48+
if i.Storage == nil {
49+
return errors.New("storage field is required")
50+
}
51+
if _, ok := new(big.Rat).SetString(i.Coins); !ok {
52+
return fmt.Errorf("invalid TON amount %s", i.Coins)
53+
}
54+
55+
return nil
56+
}
57+
58+
func deployTONContract(b operations.Bundle, deps TonDeps, in DeployContractInput) (DeployContractOutput, error) {
59+
output := DeployContractOutput{}
60+
61+
if err := in.Validate(); err != nil {
62+
return output, err
63+
}
64+
65+
b.Logger.Infow("Deploy contract with generic deploy operation", "contract name", in.Name)
66+
67+
conn := tracetracking.NewSignedAPIClient(deps.TonChain.Client, *deps.TonChain.Wallet)
68+
69+
initData, err := tlb.ToCell(in.Storage)
70+
if err != nil {
71+
return output, fmt.Errorf("failed to pack initData: %w", err)
72+
}
73+
b.Logger.Infow("Setting initial storage for contract", "contract name", in.Name, "storage data hash", hex.EncodeToString(initData.Hash()), "storage bits size", initData.BitsSize())
74+
75+
bodyCell := cell.BeginCell().EndCell()
76+
77+
if in.MessageBody != nil {
78+
bodyCell, err = tlb.ToCell(in.MessageBody)
79+
if err != nil {
80+
return output, fmt.Errorf("failed to pack message body: %w", err)
81+
}
82+
}
83+
84+
b.Logger.Infow("Initializing contract with body", "contract name", in.Name, "body data hash", hex.EncodeToString(bodyCell.Hash()), "body bits size", bodyCell.BitsSize())
85+
86+
contract, _, err := wrappers.Deploy(
87+
&conn,
88+
in.ContractCode,
89+
initData,
90+
tlb.MustFromTON(in.Coins),
91+
bodyCell,
92+
)
93+
if err != nil {
94+
return output, fmt.Errorf("failed to deploy contract: %w", err)
95+
}
96+
b.Logger.Infow("Contract deployed", "contract name", in.Name, "addr", contract.Address, "deployer wallet addr", deps.TonChain.WalletAddress.String())
97+
98+
output.Address = contract.Address
99+
return output, nil
100+
}

0 commit comments

Comments
 (0)