Skip to content

Commit 43b43e3

Browse files
feat: add changeset tx type (#189)
* feat: add changeset ty type * feat: add changeset for linkowner * gomod fix * feat: add changeset for workflows ops * refactor * skip mcms if config not found * update deps * add changeset for secrets commands * refactor * fix merged code in secrets delete
1 parent be4ba9c commit 43b43e3

File tree

30 files changed

+980
-192
lines changed

30 files changed

+980
-192
lines changed

cmd/account/link_key/link_key.go

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,15 @@ import (
2121
"github.com/spf13/viper"
2222

2323
"github.com/smartcontractkit/cre-cli/cmd/client"
24+
cmdCommon "github.com/smartcontractkit/cre-cli/cmd/common"
2425
"github.com/smartcontractkit/cre-cli/internal/client/graphqlclient"
2526
"github.com/smartcontractkit/cre-cli/internal/constants"
2627
"github.com/smartcontractkit/cre-cli/internal/credentials"
2728
"github.com/smartcontractkit/cre-cli/internal/environments"
2829
"github.com/smartcontractkit/cre-cli/internal/prompt"
2930
"github.com/smartcontractkit/cre-cli/internal/runtime"
3031
"github.com/smartcontractkit/cre-cli/internal/settings"
32+
"github.com/smartcontractkit/cre-cli/internal/types"
3133
"github.com/smartcontractkit/cre-cli/internal/validation"
3234
)
3335

@@ -84,7 +86,7 @@ func New(runtimeContext *runtime.Context) *cobra.Command {
8486
return h.Execute(inputs)
8587
},
8688
}
87-
settings.AddRawTxFlag(cmd)
89+
settings.AddTxnTypeFlags(cmd)
8890
settings.AddSkipConfirmation(cmd)
8991
cmd.Flags().StringP("owner-label", "l", "", "Label for the workflow owner")
9092

@@ -328,6 +330,42 @@ func (h *handler) linkOwner(resp initiateLinkingResponse) error {
328330
fmt.Println("")
329331
fmt.Printf(" %x\n", txOut.RawTx.Data)
330332
fmt.Println("")
333+
334+
case client.Changeset:
335+
chainSelector, err := settings.GetChainSelectorByChainName(h.environmentSet.WorkflowRegistryChainName)
336+
if err != nil {
337+
return fmt.Errorf("failed to get chain selector for chain %q: %w", h.environmentSet.WorkflowRegistryChainName, err)
338+
}
339+
mcmsConfig, err := settings.GetMCMSConfig(h.settings, chainSelector)
340+
if err != nil {
341+
fmt.Println("\nMCMS config not found or is incorrect, skipping MCMS config in changeset")
342+
}
343+
cldSettings := h.settings.CLDSettings
344+
changesets := []types.Changeset{
345+
{
346+
LinkOwner: &types.LinkOwner{
347+
Payload: types.UserLinkOwnerInput{
348+
ValidityTimestamp: ts,
349+
Proof: common.Bytes2Hex(proofBytes[:]),
350+
Signature: common.Bytes2Hex(sigBytes),
351+
ChainSelector: chainSelector,
352+
MCMSConfig: mcmsConfig,
353+
WorkflowRegistryQualifier: cldSettings.WorkflowRegistryQualifier,
354+
},
355+
},
356+
},
357+
}
358+
csFile := types.NewChangesetFile(cldSettings.Environment, cldSettings.Domain, cldSettings.MergeProposals, changesets)
359+
360+
var fileName string
361+
if cldSettings.ChangesetFile != "" {
362+
fileName = cldSettings.ChangesetFile
363+
} else {
364+
fileName = fmt.Sprintf("LinkOwner_%s_%s.yaml", h.settings.Workflow.UserWorkflowSettings.WorkflowOwnerAddress, time.Now().Format("20060102_150405"))
365+
}
366+
367+
return cmdCommon.WriteChangesetFile(fileName, csFile, h.settings)
368+
331369
default:
332370
h.log.Warn().Msgf("Unsupported transaction type: %s", txOut.Type)
333371
}

cmd/account/unlink_key/unlink_key.go

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,14 @@ import (
2020
"github.com/spf13/viper"
2121

2222
"github.com/smartcontractkit/cre-cli/cmd/client"
23+
cmdCommon "github.com/smartcontractkit/cre-cli/cmd/common"
2324
"github.com/smartcontractkit/cre-cli/internal/client/graphqlclient"
2425
"github.com/smartcontractkit/cre-cli/internal/credentials"
2526
"github.com/smartcontractkit/cre-cli/internal/environments"
2627
"github.com/smartcontractkit/cre-cli/internal/prompt"
2728
"github.com/smartcontractkit/cre-cli/internal/runtime"
2829
"github.com/smartcontractkit/cre-cli/internal/settings"
30+
"github.com/smartcontractkit/cre-cli/internal/types"
2931
"github.com/smartcontractkit/cre-cli/internal/validation"
3032
)
3133

@@ -83,7 +85,7 @@ func New(runtimeContext *runtime.Context) *cobra.Command {
8385
return h.Execute(in)
8486
},
8587
}
86-
settings.AddRawTxFlag(cmd)
88+
settings.AddTxnTypeFlags(cmd)
8789
settings.AddSkipConfirmation(cmd)
8890
return cmd
8991
}
@@ -287,6 +289,41 @@ func (h *handler) unlinkOwner(owner string, resp initiateUnlinkingResponse) erro
287289
fmt.Println("")
288290
fmt.Printf(" %s\n", resp.TransactionData)
289291
fmt.Println("")
292+
293+
case client.Changeset:
294+
chainSelector, err := settings.GetChainSelectorByChainName(h.environmentSet.WorkflowRegistryChainName)
295+
if err != nil {
296+
return fmt.Errorf("failed to get chain selector for chain %q: %w", h.environmentSet.WorkflowRegistryChainName, err)
297+
}
298+
mcmsConfig, err := settings.GetMCMSConfig(h.settings, chainSelector)
299+
if err != nil {
300+
fmt.Println("\nMCMS config not found or is incorrect, skipping MCMS config in changeset")
301+
}
302+
cldSettings := h.settings.CLDSettings
303+
changesets := []types.Changeset{
304+
{
305+
UnlinkOwner: &types.UnlinkOwner{
306+
Payload: types.UserUnlinkOwnerInput{
307+
ValidityTimestamp: ts,
308+
Signature: common.Bytes2Hex(sigBytes),
309+
ChainSelector: chainSelector,
310+
MCMSConfig: mcmsConfig,
311+
WorkflowRegistryQualifier: cldSettings.WorkflowRegistryQualifier,
312+
},
313+
},
314+
},
315+
}
316+
csFile := types.NewChangesetFile(cldSettings.Environment, cldSettings.Domain, cldSettings.MergeProposals, changesets)
317+
318+
var fileName string
319+
if cldSettings.ChangesetFile != "" {
320+
fileName = cldSettings.ChangesetFile
321+
} else {
322+
fileName = fmt.Sprintf("UnlinkOwner_%s_%s.yaml", h.settings.Workflow.UserWorkflowSettings.WorkflowOwnerAddress, time.Now().Format("20060102_150405"))
323+
}
324+
325+
return cmdCommon.WriteChangesetFile(fileName, csFile, h.settings)
326+
290327
default:
291328
h.log.Warn().Msgf("Unsupported transaction type: %s", txOut.Type)
292329
}

cmd/client/client_factory.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,8 @@ func (f *factoryImpl) GetTxType() TxType {
8888
return Raw
8989
} else if f.viper.GetBool(settings.Flags.Ledger.Name) {
9090
return Ledger
91+
} else if f.viper.GetBool(settings.Flags.Changeset.Name) {
92+
return Changeset
9193
}
9294
return Regular
9395
}

cmd/client/tx.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ const (
3131
Regular TxType = iota
3232
Raw
3333
Ledger
34+
Changeset
3435
)
3536

3637
type TxClientConfig struct {
@@ -223,6 +224,20 @@ func (c *TxClient) executeTransactionByTxType(txFn func(opts *bind.TransactOpts)
223224
Args: cmdCommon.ToStringSlice(args),
224225
},
225226
}, nil
227+
case Changeset:
228+
tx, err := txFn(cmdCommon.SimTransactOpts())
229+
if err != nil {
230+
return TxOutput{Type: Changeset}, err
231+
}
232+
return TxOutput{
233+
Type: Changeset,
234+
RawTx: RawTx{
235+
To: tx.To().Hex(),
236+
Data: []byte{},
237+
Function: funName,
238+
Args: cmdCommon.ToStringSlice(args),
239+
},
240+
}, nil
226241
//case Ledger:
227242
// txOpts, err := c.ledgerOpts(c.ledgerConfig)
228243
// if err != nil {

cmd/client/workflow_registry_v2_client.go

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -678,42 +678,38 @@ func (wrc *WorkflowRegistryV2Client) IsRequestAllowlisted(owner common.Address,
678678

679679
// AllowlistRequest sends the request digest to the WorkflowRegistry allowlist with a default expiry of now + 10 minutes.
680680
// `requestDigestHex` should be the hex string produced by utils.CalculateRequestDigest(...), with or without "0x".
681-
func (wrc *WorkflowRegistryV2Client) AllowlistRequest(requestDigest [32]byte, duration time.Duration) error {
681+
func (wrc *WorkflowRegistryV2Client) AllowlistRequest(requestDigest [32]byte, duration time.Duration) (*TxOutput, error) {
682682
var contract workflowRegistryV2Contract
683683
if wrc.Wr != nil {
684684
contract = wrc.Wr
685685
} else {
686686
c, err := workflow_registry_v2_wrapper.NewWorkflowRegistry(wrc.ContractAddress, wrc.EthClient.Client)
687687
if err != nil {
688688
wrc.Logger.Error().Err(err).Msg("Failed to connect for AllowlistRequest")
689-
return err
689+
return nil, err
690690
}
691691
contract = c
692692
}
693693

694694
// #nosec G115 -- int64 to uint32 conversion; Unix() returns seconds since epoch, which fits in uint32 until 2106
695695
deadline := uint32(time.Now().Add(duration).Unix())
696696

697-
// Send tx; keep the same "callContractMethodV2" pattern you used for read-only calls.
698-
// Here we return the tx hash string to the helper (it may log/track it).
699-
_, err := callContractMethodV2(wrc, func() (string, error) {
700-
tx, txErr := contract.AllowlistRequest(wrc.EthClient.NewTXOpts(), requestDigest, deadline)
701-
if txErr != nil {
702-
return "", txErr
703-
}
704-
// Return the tx hash string for visibility through the helper
705-
return tx.Hash().Hex(), nil
706-
})
697+
txFn := func(opts *bind.TransactOpts) (*types.Transaction, error) {
698+
return contract.AllowlistRequest(opts, requestDigest, deadline)
699+
}
700+
txOut, err := wrc.executeTransactionByTxType(txFn, "AllowlistRequest", "RequestAllowlisted", requestDigest, duration)
707701
if err != nil {
708-
wrc.Logger.Error().Err(err).Msg("AllowlistRequest tx failed")
709-
return err
702+
wrc.Logger.Error().
703+
Str("contract", wrc.ContractAddress.Hex()).
704+
Err(err).
705+
Msg("Failed to call AllowlistRequest")
706+
return nil, err
710707
}
711-
712708
wrc.Logger.Debug().
713709
Str("digest", hex.EncodeToString(requestDigest[:])).
714710
Str("deadline", time.Unix(int64(deadline), 0).UTC().Format(time.RFC3339)).
715711
Msg("AllowlistRequest submitted")
716-
return nil
712+
return &txOut, nil
717713
}
718714

719715
func callContractMethodV2[T any](wrc *WorkflowRegistryV2Client, contractMethod func() (T, error)) (T, error) {

cmd/common/utils.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,14 @@ import (
1717
"github.com/ethereum/go-ethereum/core/types"
1818
"github.com/ethereum/go-ethereum/crypto"
1919
"github.com/rs/zerolog"
20+
"sigs.k8s.io/yaml"
2021

2122
"github.com/smartcontractkit/chainlink-testing-framework/seth"
2223

2324
"github.com/smartcontractkit/cre-cli/internal/constants"
2425
"github.com/smartcontractkit/cre-cli/internal/logger"
26+
"github.com/smartcontractkit/cre-cli/internal/settings"
27+
inttypes "github.com/smartcontractkit/cre-cli/internal/types"
2528
)
2629

2730
func ValidateEventSignature(l *zerolog.Logger, tx *seth.DecodedTransaction, e abi.Event) (bool, int) {
@@ -214,3 +217,47 @@ func GetBuildCmd(inputFile string, outputFile string, rootFolder string) *exec.C
214217

215218
return buildCmd
216219
}
220+
221+
func WriteChangesetFile(fileName string, changesetFile *inttypes.ChangesetFile, settings *settings.Settings) error {
222+
fullFilePath := filepath.Join(
223+
filepath.Clean(settings.CLDSettings.CLDPath),
224+
"domains",
225+
settings.CLDSettings.Domain,
226+
settings.CLDSettings.Environment,
227+
"durable_pipelines",
228+
"inputs",
229+
fileName,
230+
)
231+
232+
// if file exists, read it and append the new changesets
233+
if _, err := os.Stat(fullFilePath); err == nil {
234+
existingYamlData, err := os.ReadFile(fullFilePath)
235+
if err != nil {
236+
return fmt.Errorf("failed to read existing changeset yaml file: %w", err)
237+
}
238+
239+
var existingChangesetFile inttypes.ChangesetFile
240+
if err := yaml.Unmarshal(existingYamlData, &existingChangesetFile); err != nil {
241+
return fmt.Errorf("failed to unmarshal existing changeset yaml: %w", err)
242+
}
243+
244+
// Append new changesets to the existing ones
245+
existingChangesetFile.Changesets = append(existingChangesetFile.Changesets, changesetFile.Changesets...)
246+
changesetFile = &existingChangesetFile
247+
}
248+
249+
yamlData, err := yaml.Marshal(&changesetFile)
250+
if err != nil {
251+
return fmt.Errorf("failed to marshal changeset to yaml: %w", err)
252+
}
253+
254+
if err := os.WriteFile(fullFilePath, yamlData, 0600); err != nil {
255+
return fmt.Errorf("failed to write changeset yaml file: %w", err)
256+
}
257+
258+
fmt.Println("")
259+
fmt.Println("Changeset YAML file generated!")
260+
fmt.Printf("File: %s\n", fullFilePath)
261+
fmt.Println("")
262+
return nil
263+
}

0 commit comments

Comments
 (0)