From 4b348d6273ffabe2856d5dee0e8b9c4e23c25e82 Mon Sep 17 00:00:00 2001 From: stackman27 Date: Sun, 31 May 2026 14:14:11 -0700 Subject: [PATCH 1/7] fix mcms reader --- deployment/adapters/mcms_chain_metadata.go | 51 +++++++++++++++++++ deployment/adapters/mcms_reader.go | 45 +++++++++++++++- deployment/utils/mcms/proposal.go | 4 +- integration-tests/mcms/changeset_mcms_test.go | 2 +- 4 files changed, 98 insertions(+), 4 deletions(-) create mode 100644 deployment/adapters/mcms_chain_metadata.go diff --git a/deployment/adapters/mcms_chain_metadata.go b/deployment/adapters/mcms_chain_metadata.go new file mode 100644 index 000000000..4106599ee --- /dev/null +++ b/deployment/adapters/mcms_chain_metadata.go @@ -0,0 +1,51 @@ +package adapters + +import ( + "context" + "fmt" + "strings" + + apiv2 "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2" + cantonsdk "github.com/smartcontractkit/mcms/sdk/canton" + mcms_types "github.com/smartcontractkit/mcms/types" +) + +// buildCantonChainMetadata queries live MCMS state and builds proposal chain metadata +// with Canton additionalFields (pre/post op counts, multisigId, instanceId, etc.). +func buildCantonChainMetadata( + ctx context.Context, + stateClient apiv2.StateServiceClient, + partyID string, + mcmsAddrHex string, + role cantonsdk.TimelockRole, + txCount uint64, + overridePreviousRoot bool, +) (mcms_types.ChainMetadata, error) { + inspector := cantonsdk.NewInspector(stateClient, []string{partyID}, role) + + opCount, err := inspector.GetOpCount(ctx, mcmsAddrHex) + if err != nil { + return mcms_types.ChainMetadata{}, fmt.Errorf("get op count: %w", err) + } + + mcmsContract, err := cantonsdk.GetMCMSContract(ctx, stateClient, []string{partyID}, mcmsAddrHex) + if err != nil { + return mcms_types.ChainMetadata{}, fmt.Errorf("get MCMS contract: %w", err) + } + + multisigID := cantonMultisigID(string(mcmsContract.InstanceId), string(mcmsContract.Owner), role) + + return cantonsdk.NewChainMetadata( + opCount, + opCount+txCount, + int64(mcmsContract.ChainId), + multisigID, + mcmsAddrHex, + overridePreviousRoot, + string(mcmsContract.InstanceId), + ) +} + +func cantonMultisigID(instanceID, party string, role cantonsdk.TimelockRole) string { + return fmt.Sprintf("%s@%s-%s", instanceID, party, strings.ToLower(role.String())) +} diff --git a/deployment/adapters/mcms_reader.go b/deployment/adapters/mcms_reader.go index d200f36da..783a7d715 100644 --- a/deployment/adapters/mcms_reader.go +++ b/deployment/adapters/mcms_reader.go @@ -21,6 +21,17 @@ func (r *CantonMCMSReader) GetChainMetadata( e cldf.Environment, chainSelector uint64, input ccipmcms.Input, +) (mcms_types.ChainMetadata, error) { + return r.getRootMetadata(e, chainSelector, input) +} + +// GetChainMetadataForBatch implements changesets.mcmsBatchMetadataReader. +// Uses live ledger op count and the proposal batch size for Canton additionalFields. +func (r *CantonMCMSReader) GetChainMetadataForBatch( + e cldf.Environment, + chainSelector uint64, + input ccipmcms.Input, + batch mcms_types.BatchOperation, ) (mcms_types.ChainMetadata, error) { mcmsRef, err := r.GetMCMSRef(e, chainSelector, input) if err != nil { @@ -38,9 +49,41 @@ func (r *CantonMCMSReader) GetChainMetadata( ctx = e.GetContext() } - inspector := cantonsdk.NewInspector( + return buildCantonChainMetadata( + ctx, participant.LedgerServices.State, participant.PartyID, + mcmsRef.Address, + timelockRoleForAction(input.TimelockAction), + uint64(len(batch.Transactions)), + input.OverridePreviousRoot, + ) +} + +func (r *CantonMCMSReader) getRootMetadata( + e cldf.Environment, + chainSelector uint64, + input ccipmcms.Input, +) (mcms_types.ChainMetadata, error) { + mcmsRef, err := r.GetMCMSRef(e, chainSelector, input) + if err != nil { + return mcms_types.ChainMetadata{}, err + } + + chain, ok := e.BlockChains.CantonChains()[chainSelector] + if !ok || len(chain.Participants) == 0 { + return mcms_types.ChainMetadata{}, fmt.Errorf("canton chain %d not found or has no participants", chainSelector) + } + + participant := chain.Participants[0] + ctx := context.Background() + if e.GetContext != nil { + ctx = e.GetContext() + } + + inspector := cantonsdk.NewInspector( + participant.LedgerServices.State, + []string{participant.PartyID}, timelockRoleForAction(input.TimelockAction), ) diff --git a/deployment/utils/mcms/proposal.go b/deployment/utils/mcms/proposal.go index 8e40e365a..1f42e3977 100644 --- a/deployment/utils/mcms/proposal.go +++ b/deployment/utils/mcms/proposal.go @@ -63,13 +63,13 @@ func GenerateTimelockProposal( mcmsAddrHex := config.MCMSContract.InstanceAddress.Hex() - inspector := cantonsdk.NewInspector(stateClient, party, config.Role) + inspector := cantonsdk.NewInspector(stateClient, []string{party}, config.Role) opCount, err := inspector.GetOpCount(ctx, mcmsAddrHex) if err != nil { return nil, fmt.Errorf("failed to get op count: %w", err) } - mcmsContract, err := cantonsdk.GetMCMSContract(ctx, stateClient, party, mcmsAddrHex) + mcmsContract, err := cantonsdk.GetMCMSContract(ctx, stateClient, []string{party}, mcmsAddrHex) if err != nil { return nil, fmt.Errorf("failed to get MCMS contract state: %w", err) } diff --git a/integration-tests/mcms/changeset_mcms_test.go b/integration-tests/mcms/changeset_mcms_test.go index 8010f3fb4..23fbf58b9 100644 --- a/integration-tests/mcms/changeset_mcms_test.go +++ b/integration-tests/mcms/changeset_mcms_test.go @@ -223,7 +223,7 @@ func TestMCMS_ChangesetProposalE2E(t *testing.T) { // Step 3b: Sign via SDK (2-of-3 quorum) t.Log("Signing proposal via SDK...") - inspector := cantonsdk.NewInspector(participant.LedgerServices.State, party, cantonsdk.TimelockRoleProposer) + inspector := cantonsdk.NewInspector(participant.LedgerServices.State, []string{party}, cantonsdk.TimelockRoleProposer) inspectorsMap := map[mcms_types.ChainSelector]sdk.Inspector{ mcms_types.ChainSelector(chainSelector): inspector, } From f55227a27c9b92f8095e4e0030813e6ef1a2b6b4 Mon Sep 17 00:00:00 2001 From: stackman27 Date: Wed, 3 Jun 2026 19:14:03 -0700 Subject: [PATCH 2/7] mcms reader --- deployment/adapters/mcms_chain_metadata.go | 51 ----- deployment/adapters/mcms_reader.go | 43 ----- go.mod | 1 + scripts/upload-localnet-dars.sh | 41 ++++ scripts/upload-localnet-dars/main.go | 207 +++++++++++++++++++++ 5 files changed, 249 insertions(+), 94 deletions(-) delete mode 100644 deployment/adapters/mcms_chain_metadata.go create mode 100644 scripts/upload-localnet-dars.sh create mode 100644 scripts/upload-localnet-dars/main.go diff --git a/deployment/adapters/mcms_chain_metadata.go b/deployment/adapters/mcms_chain_metadata.go deleted file mode 100644 index 4106599ee..000000000 --- a/deployment/adapters/mcms_chain_metadata.go +++ /dev/null @@ -1,51 +0,0 @@ -package adapters - -import ( - "context" - "fmt" - "strings" - - apiv2 "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2" - cantonsdk "github.com/smartcontractkit/mcms/sdk/canton" - mcms_types "github.com/smartcontractkit/mcms/types" -) - -// buildCantonChainMetadata queries live MCMS state and builds proposal chain metadata -// with Canton additionalFields (pre/post op counts, multisigId, instanceId, etc.). -func buildCantonChainMetadata( - ctx context.Context, - stateClient apiv2.StateServiceClient, - partyID string, - mcmsAddrHex string, - role cantonsdk.TimelockRole, - txCount uint64, - overridePreviousRoot bool, -) (mcms_types.ChainMetadata, error) { - inspector := cantonsdk.NewInspector(stateClient, []string{partyID}, role) - - opCount, err := inspector.GetOpCount(ctx, mcmsAddrHex) - if err != nil { - return mcms_types.ChainMetadata{}, fmt.Errorf("get op count: %w", err) - } - - mcmsContract, err := cantonsdk.GetMCMSContract(ctx, stateClient, []string{partyID}, mcmsAddrHex) - if err != nil { - return mcms_types.ChainMetadata{}, fmt.Errorf("get MCMS contract: %w", err) - } - - multisigID := cantonMultisigID(string(mcmsContract.InstanceId), string(mcmsContract.Owner), role) - - return cantonsdk.NewChainMetadata( - opCount, - opCount+txCount, - int64(mcmsContract.ChainId), - multisigID, - mcmsAddrHex, - overridePreviousRoot, - string(mcmsContract.InstanceId), - ) -} - -func cantonMultisigID(instanceID, party string, role cantonsdk.TimelockRole) string { - return fmt.Sprintf("%s@%s-%s", instanceID, party, strings.ToLower(role.String())) -} diff --git a/deployment/adapters/mcms_reader.go b/deployment/adapters/mcms_reader.go index 783a7d715..f99ff2d81 100644 --- a/deployment/adapters/mcms_reader.go +++ b/deployment/adapters/mcms_reader.go @@ -21,49 +21,6 @@ func (r *CantonMCMSReader) GetChainMetadata( e cldf.Environment, chainSelector uint64, input ccipmcms.Input, -) (mcms_types.ChainMetadata, error) { - return r.getRootMetadata(e, chainSelector, input) -} - -// GetChainMetadataForBatch implements changesets.mcmsBatchMetadataReader. -// Uses live ledger op count and the proposal batch size for Canton additionalFields. -func (r *CantonMCMSReader) GetChainMetadataForBatch( - e cldf.Environment, - chainSelector uint64, - input ccipmcms.Input, - batch mcms_types.BatchOperation, -) (mcms_types.ChainMetadata, error) { - mcmsRef, err := r.GetMCMSRef(e, chainSelector, input) - if err != nil { - return mcms_types.ChainMetadata{}, err - } - - chain, ok := e.BlockChains.CantonChains()[chainSelector] - if !ok || len(chain.Participants) == 0 { - return mcms_types.ChainMetadata{}, fmt.Errorf("canton chain %d not found or has no participants", chainSelector) - } - - participant := chain.Participants[0] - ctx := context.Background() - if e.GetContext != nil { - ctx = e.GetContext() - } - - return buildCantonChainMetadata( - ctx, - participant.LedgerServices.State, - participant.PartyID, - mcmsRef.Address, - timelockRoleForAction(input.TimelockAction), - uint64(len(batch.Transactions)), - input.OverridePreviousRoot, - ) -} - -func (r *CantonMCMSReader) getRootMetadata( - e cldf.Environment, - chainSelector uint64, - input ccipmcms.Input, ) (mcms_types.ChainMetadata, error) { mcmsRef, err := r.GetMCMSRef(e, chainSelector, input) if err != nil { diff --git a/go.mod b/go.mod index a1301fbe2..4d280df4f 100644 --- a/go.mod +++ b/go.mod @@ -544,4 +544,5 @@ tool github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen replace ( github.com/smartcontractkit/chainlink-ccip/chains/evm => github.com/smartcontractkit/chainlink-ccip/chains/evm v0.0.0-20260519201156-791d8279a3ad github.com/smartcontractkit/chainlink-ccip/deployment => github.com/smartcontractkit/chainlink-ccip/deployment v0.0.0-20260519201156-791d8279a3ad + github.com/smartcontractkit/mcms => ../mcms ) diff --git a/scripts/upload-localnet-dars.sh b/scripts/upload-localnet-dars.sh new file mode 100644 index 000000000..98e34cb61 --- /dev/null +++ b/scripts/upload-localnet-dars.sh @@ -0,0 +1,41 @@ +#!/usr/bin/env bash +# Upload all *-1.0.0.dar files from contracts/dars to local compose participant1. +# Prereqs: docker compose up in compose/localnet; grpcurl; python3. +set -euo pipefail + +REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +DARS_DIR="${REPO_ROOT}/contracts/dars" +ADMIN="${CANTON_ADMIN_API:-participant1.admin-api.localhost:8080}" +CONFIG="${CANTON_CONFIG:-${REPO_ROOT}/integration-tests/local-docker-compose.toml}" + +if [[ -z "${ONCHAIN_CANTON_JWT_TOKEN:-}" ]]; then + ONCHAIN_CANTON_JWT_TOKEN="$(python3 -c " +import re, pathlib +t = pathlib.Path('${CONFIG}').read_text() +m = re.search(r'^jwt=\"([^\"]+)\"', t, re.M) +print(m.group(1) if m else '') +")" + export ONCHAIN_CANTON_JWT_TOKEN +fi +if [[ -z "${ONCHAIN_CANTON_JWT_TOKEN}" ]]; then + echo "Set ONCHAIN_CANTON_JWT_TOKEN or add jwt to ${CONFIG}" >&2 + exit 1 +fi + +for f in "${DARS_DIR}"/*-1.0.0.dar; do + echo "=== $(basename "$f") ===" + python3 -c " +import json, base64, sys +b = base64.b64encode(open(sys.argv[1], 'rb').read()).decode() +sys.stdout.write(json.dumps({ + 'dars': [{'bytes': b}], + 'vetAllPackages': True, + 'synchronizeVetting': True, +})) +" "$f" | grpcurl -plaintext \ + -H "authorization: Bearer ${ONCHAIN_CANTON_JWT_TOKEN}" \ + -d @ "${ADMIN}" \ + com.digitalasset.canton.admin.participant.v30.PackageService/UploadDar +done + +echo "Done: uploaded $(ls -1 "${DARS_DIR}"/*-1.0.0.dar | wc -l | tr -d ' ') DAR(s) to ${ADMIN}" diff --git a/scripts/upload-localnet-dars/main.go b/scripts/upload-localnet-dars/main.go new file mode 100644 index 000000000..87174df4d --- /dev/null +++ b/scripts/upload-localnet-dars/main.go @@ -0,0 +1,207 @@ +// Upload all *-1.0.0.dar packages to a local Docker Compose Canton participant. +// +// Usage (from chainlink-canton-fcr repo root): +// +// export ONCHAIN_CANTON_JWT_TOKEN="" # or rely on jwt in -config TOML +// go run ./scripts/upload-localnet-dars +// go run ./scripts/upload-localnet-dars -all-participants +package main + +import ( + "context" + "flag" + "fmt" + "log" + "os" + "path/filepath" + "sort" + "strings" + + "github.com/BurntSushi/toml" + participantv30 "github.com/digital-asset/dazl-client/v8/go/api/com/digitalasset/canton/admin/participant/v30" + adminv2 "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2/admin" + "google.golang.org/grpc" + "google.golang.org/grpc/status" + + chainsel "github.com/smartcontractkit/chain-selectors" + "github.com/smartcontractkit/chainlink-deployments-framework/chain/canton" + cantonProvider "github.com/smartcontractkit/chainlink-deployments-framework/chain/canton/provider" + "github.com/smartcontractkit/chainlink-deployments-framework/chain/canton/provider/authentication" + + "github.com/smartcontractkit/chainlink-canton/testhelpers" +) + +func main() { + configPath := flag.String("config", "integration-tests/local-docker-compose.toml", "participant TOML (chain_selector + participants)") + participantIdx := flag.Int("participant", 0, "participant index in TOML (0 = participant1)") + allParticipants := flag.Bool("all-participants", false, "upload to every participant in the TOML") + repoRoot := flag.String("repo", ".", "chainlink-canton-fcr repo root (contracts/dars and contracts/dependencies)") + flag.Parse() + + jwt := strings.TrimSpace(os.Getenv("ONCHAIN_CANTON_JWT_TOKEN")) + + darPaths, err := collectDARs(*repoRoot) + if err != nil { + log.Fatal(err) + } + if len(darPaths) == 0 { + log.Fatal("no *-1.0.0.dar files found under contracts/dars or contracts/dependencies") + } + + input, err := loadParticipantInput(*configPath) + if err != nil { + log.Fatal(err) + } + + indices := []int{*participantIdx} + if *allParticipants { + indices = make([]int, len(input.Participants)) + for i := range input.Participants { + indices[i] = i + } + } + + ctx := context.Background() + for _, idx := range indices { + if idx < 0 || idx >= len(input.Participants) { + log.Fatalf("participant index %d out of range (have %d participants)", idx, len(input.Participants)) + } + cfg := input.Participants[idx] + token := jwt + if token == "" { + token = cfg.JWT + } + if token == "" { + log.Fatal("JWT required: set ONCHAIN_CANTON_JWT_TOKEN or jwt in config TOML") + } + + chain, err := buildChain(ctx, input.Selector, cfg, token) + if err != nil { + log.Fatalf("participant %d (%s): %v", idx, nameOrDefault(cfg, idx), err) + } + participant := chain.Participants[0] + if cfg.Party != "" { + log.Printf("participant %d (%s) party_id=%s", idx, nameOrDefault(cfg, idx), cfg.Party) + } else { + log.Printf("participant %d (%s) primary party=%s", idx, nameOrDefault(cfg, idx), participant.PartyID) + } + + for _, darPath := range darPaths { + darBytes, err := os.ReadFile(darPath) //nolint:gosec // local dev script, user-controlled repo path + if err != nil { + log.Fatalf("read %s: %v", darPath, err) + } + res, err := participant.AdminServices.Package.UploadDar(ctx, &participantv30.UploadDarRequest{ + Dars: []*participantv30.UploadDarRequest_UploadDarData{{Bytes: darBytes}}, + VetAllPackages: true, + SynchronizeVetting: true, + }) + if err != nil { + if s, ok := status.FromError(err); ok { + log.Printf("gRPC code=%s message=%s", s.Code(), s.Message()) + } + log.Fatalf("upload %s to %s: %v", filepath.Base(darPath), nameOrDefault(cfg, idx), err) + } + log.Printf("uploaded %s -> dar_ids=%v", filepath.Base(darPath), res.GetDarIds()) + } + } + + log.Printf("done: uploaded %d DAR(s)", len(darPaths)) +} + +func collectDARs(repoRoot string) ([]string, error) { + dirs := []string{ + filepath.Join(repoRoot, "contracts", "dependencies"), + filepath.Join(repoRoot, "contracts", "dars"), + } + var paths []string + for _, dir := range dirs { + entries, err := os.ReadDir(dir) + if err != nil { + if os.IsNotExist(err) { + continue + } + return nil, err + } + for _, e := range entries { + if e.IsDir() { + continue + } + name := e.Name() + if strings.HasSuffix(name, "-1.0.0.dar") { + paths = append(paths, filepath.Join(dir, name)) + } + } + } + sort.Strings(paths) + return paths, nil +} + +func loadParticipantInput(path string) (testhelpers.ParticipantInput, error) { + content, err := os.ReadFile(path) //nolint:gosec // config path from flag + if err != nil { + return testhelpers.ParticipantInput{}, err + } + var input testhelpers.ParticipantInput + if err := toml.Unmarshal(content, &input); err != nil { + return testhelpers.ParticipantInput{}, err + } + if input.Selector == 0 { + input.Selector = chainsel.CANTON_LOCALNET.Selector + } + return input, nil +} + +func buildChain(ctx context.Context, selector uint64, cfg testhelpers.ParticipantConfig, jwt string) (*canton.Chain, error) { + auth := authentication.NewInsecureStaticProvider(jwt) + party := cfg.Party + if party == "" { + conn, err := grpc.NewClient( + cfg.GRPCLedgerAPIURL, + grpc.WithTransportCredentials(auth.TransportCredentials()), + grpc.WithPerRPCCredentials(auth.PerRPCCredentials()), + ) + if err != nil { + return nil, fmt.Errorf("ledger grpc dial: %w", err) + } + defer conn.Close() + user, err := adminv2.NewUserManagementServiceClient(conn).GetUser(ctx, &adminv2.GetUserRequest{UserId: cfg.UserName}) + if err != nil { + return nil, fmt.Errorf("get user %q: %w", cfg.UserName, err) + } + if len(user.GetUser().GetPrimaryParty()) == 0 { + return nil, fmt.Errorf("no primary party for user %q", cfg.UserName) + } + party = user.GetUser().GetPrimaryParty() + } + + provider := cantonProvider.NewRPCChainProvider(selector, cantonProvider.RPCChainProviderConfig{ + Participants: []cantonProvider.ParticipantConfig{{ + Endpoints: cantonProvider.Endpoints{ + JSONLedgerAPIURL: cfg.JSONLedgerAPIURL, + GRPCLedgerAPIURL: cfg.GRPCLedgerAPIURL, + AdminAPIURL: cfg.AdminAPIURL, + ValidatorAPIURL: cfg.ValidatorAPIURL, + }, + UserID: cfg.UserName, + PartyID: party, + AuthProvider: auth, + }}, + }) + bc, err := provider.Initialize(ctx) + if err != nil { + return nil, err + } + chain, ok := bc.(*canton.Chain) + if !ok { + return nil, fmt.Errorf("unexpected chain type %T", bc) + } + return chain, nil +} + +func nameOrDefault(cfg testhelpers.ParticipantConfig, idx int) string { + if cfg.Name != "" { + return cfg.Name + } + return fmt.Sprintf("participant%d", idx+1) +} From 0b2d58cc0e2895286d6f1d40f4bc25e1eeded298 Mon Sep 17 00:00:00 2001 From: stackman27 Date: Wed, 3 Jun 2026 23:44:35 -0700 Subject: [PATCH 3/7] fix hex encode --- .../ccip/committeeverifier/committeeverifier.go | 2 +- bindings/generated/latest/ccip/core/core.go | 12 ++++++------ contracts/cmd/bindings/main.go | 3 +++ deployment/utils/mcms/proposal.go | 5 ++--- go.mod | 3 +-- go.sum | 4 ++-- integration-tests/go.mod | 2 +- integration-tests/go.sum | 4 ++-- 8 files changed, 18 insertions(+), 17 deletions(-) diff --git a/bindings/generated/latest/ccip/committeeverifier/committeeverifier.go b/bindings/generated/latest/ccip/committeeverifier/committeeverifier.go index 7eabe0f8a..4a1033e3e 100644 --- a/bindings/generated/latest/ccip/committeeverifier/committeeverifier.go +++ b/bindings/generated/latest/ccip/committeeverifier/committeeverifier.go @@ -1570,7 +1570,7 @@ func (t *SetDynamicConfigParams) UnmarshalHex(data string) error { type SignatureConfig struct { SourceChainSelector types.NUMERIC `json:"sourceChainSelector"` Threshold types.INT64 `json:"threshold"` - SignerKeys []types.TEXT `json:"signerKeys"` + SignerKeys []types.TEXT `json:"signerKeys" hex:"[]bytes"` } // ToMap converts SignatureConfig to a map for DAML arguments diff --git a/bindings/generated/latest/ccip/core/core.go b/bindings/generated/latest/ccip/core/core.go index cbc0affc6..f3b64efea 100644 --- a/bindings/generated/latest/ccip/core/core.go +++ b/bindings/generated/latest/ccip/core/core.go @@ -2001,7 +2001,7 @@ type DestChainConfig struct { AddressBytesLength types.INT64 `json:"addressBytesLength"` TokenReceiverAllowed types.BOOL `json:"tokenReceiverAllowed"` BaseExecutionGasCost types.INT64 `json:"baseExecutionGasCost"` - OffRampAddress types.TEXT `json:"offRampAddress"` + OffRampAddress types.TEXT `json:"offRampAddress" hex:"bytes"` DefaultExecutor *chainlinkapi.RawInstanceAddress `json:"defaultExecutor" hex:"optional"` LaneMandatedCCVs []chainlinkapi.RawInstanceAddress `json:"laneMandatedCCVs"` DefaultCCVs []chainlinkapi.RawInstanceAddress `json:"defaultCCVs"` @@ -2087,7 +2087,7 @@ type DestChainConfigArgs struct { AddressBytesLength types.INT64 `json:"addressBytesLength"` TokenReceiverAllowed types.BOOL `json:"tokenReceiverAllowed"` BaseExecutionGasCost types.INT64 `json:"baseExecutionGasCost"` - OffRampAddress types.TEXT `json:"offRampAddress"` + OffRampAddress types.TEXT `json:"offRampAddress" hex:"bytes"` DefaultExecutor *chainlinkapi.RawInstanceAddress `json:"defaultExecutor" hex:"optional"` LaneMandatedCCVs []chainlinkapi.RawInstanceAddress `json:"laneMandatedCCVs"` DefaultCCVs []chainlinkapi.RawInstanceAddress `json:"defaultCCVs"` @@ -5341,7 +5341,7 @@ type MessageV1 struct { Finality DecodedFinality `json:"finality"` CcvAndExecutorHash types.TEXT `json:"ccvAndExecutorHash"` OnRampAddress types.TEXT `json:"onRampAddress"` - OffRampAddress types.TEXT `json:"offRampAddress"` + OffRampAddress types.TEXT `json:"offRampAddress" hex:"bytes"` Sender types.TEXT `json:"sender"` Receiver types.TEXT `json:"receiver"` DestBlob types.TEXT `json:"destBlob"` @@ -6975,7 +6975,7 @@ type SendingMessageV1 struct { CcipReceiveGasLimit types.INT64 `json:"ccipReceiveGasLimit"` CcvAndExecutorHash types.TEXT `json:"ccvAndExecutorHash"` OnRampAddress types.TEXT `json:"onRampAddress"` - OffRampAddress types.TEXT `json:"offRampAddress"` + OffRampAddress types.TEXT `json:"offRampAddress" hex:"bytes"` TokenReceiver types.TEXT `json:"tokenReceiver"` TokenArgs types.TEXT `json:"tokenArgs"` FeeToken splice_api_token_holding_v1.InstrumentId `json:"feeToken"` @@ -8296,7 +8296,7 @@ func (t *SetTransferFactoryParams) UnmarshalHex(data string) error { // SourceChainConfig is a Record type type SourceChainConfig struct { IsEnabled types.BOOL `json:"isEnabled"` - OnRampAddresses []types.TEXT `json:"onRampAddresses"` + OnRampAddresses []types.TEXT `json:"onRampAddresses" hex:"[]bytes"` DefaultCCVs []chainlinkapi.RawInstanceAddress `json:"defaultCCVs"` LaneMandatedCCVs []chainlinkapi.RawInstanceAddress `json:"laneMandatedCCVs"` } @@ -8360,7 +8360,7 @@ func (t *SourceChainConfig) UnmarshalHex(data string) error { type SourceChainConfigArgs struct { SourceChainSelector types.NUMERIC `json:"sourceChainSelector"` IsEnabled types.BOOL `json:"isEnabled"` - OnRampAddresses []types.TEXT `json:"onRampAddresses"` + OnRampAddresses []types.TEXT `json:"onRampAddresses" hex:"[]bytes"` DefaultCCVs []chainlinkapi.RawInstanceAddress `json:"defaultCCVs"` LaneMandatedCCVs []chainlinkapi.RawInstanceAddress `json:"laneMandatedCCVs"` } diff --git a/contracts/cmd/bindings/main.go b/contracts/cmd/bindings/main.go index 350fcc5f7..769fe8a0a 100644 --- a/contracts/cmd/bindings/main.go +++ b/contracts/cmd/bindings/main.go @@ -70,6 +70,9 @@ func main() { "root": true, // Merkle root hash (32 bytes) "newRoot": true, // New merkle root hash (32 bytes) "versionTag": true, // CCV version tag is a 4-byte BytesHex field + "onRampAddresses": true, // Daml [BytesHex] → hex:"[]bytes" on []types.TEXT + "signerKeys": true, // Daml [BytesHex] → hex:"[]bytes" on []types.TEXT + "offRampAddress": true, // Daml BytesHex scalar → hex:"bytes" on types.TEXT }, // hex:"bytes16" — fields that may exceed 255 bytes (uint16 length prefix) BytesHexFields: map[string]bool{ diff --git a/deployment/utils/mcms/proposal.go b/deployment/utils/mcms/proposal.go index 1f42e3977..9565fb2ab 100644 --- a/deployment/utils/mcms/proposal.go +++ b/deployment/utils/mcms/proposal.go @@ -74,16 +74,14 @@ func GenerateTimelockProposal( return nil, fmt.Errorf("failed to get MCMS contract state: %w", err) } - txCount := countTransactions(batchOps) multisigId := makeMultisigId(string(mcmsContract.InstanceId), string(mcmsContract.Owner), config.Role) + // postOpCount and overridePreviousRoot are applied at sign/execute time by mcms (encoder + executor), not in chainMetadata. metadata, err := cantonsdk.NewChainMetadata( opCount, - opCount+txCount, int64(mcmsContract.ChainId), multisigId, mcmsAddrHex, - config.OverridePreviousRoot, string(mcmsContract.InstanceId), ) if err != nil { @@ -109,6 +107,7 @@ func GenerateTimelockProposal( SetVersion("v1"). SetValidUntil(validUntil). SetDescription(config.Description). + SetOverridePreviousRoot(config.OverridePreviousRoot). AddTimelockAddress(config.ChainSelector, timelockAddr). AddChainMetadata(config.ChainSelector, metadata). SetAction(config.Action) diff --git a/go.mod b/go.mod index 4d280df4f..9ea8c64d7 100644 --- a/go.mod +++ b/go.mod @@ -451,7 +451,7 @@ require ( github.com/smartcontractkit/freeport v0.1.3-0.20250828155247-add56fa28aad // indirect github.com/smartcontractkit/grpc-proxy v0.0.0-20240830132753-a7e17fec5ab7 // indirect github.com/smartcontractkit/libocr v0.0.0-20260304194147-a03701e2c02e // indirect - github.com/smartcontractkit/mcms v0.45.2-0.20260602204056-81248906ce6a + github.com/smartcontractkit/mcms v0.45.2-0.20260604053848-48d8a8691ced github.com/smartcontractkit/wsrpc v0.8.5-0.20250502134807-c57d3d995945 // indirect github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect github.com/speakeasy-api/jsonpath v0.6.0 // indirect @@ -544,5 +544,4 @@ tool github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen replace ( github.com/smartcontractkit/chainlink-ccip/chains/evm => github.com/smartcontractkit/chainlink-ccip/chains/evm v0.0.0-20260519201156-791d8279a3ad github.com/smartcontractkit/chainlink-ccip/deployment => github.com/smartcontractkit/chainlink-ccip/deployment v0.0.0-20260519201156-791d8279a3ad - github.com/smartcontractkit/mcms => ../mcms ) diff --git a/go.sum b/go.sum index 687fb1e8f..1fd1971fb 100644 --- a/go.sum +++ b/go.sum @@ -1236,8 +1236,8 @@ github.com/smartcontractkit/grpc-proxy v0.0.0-20240830132753-a7e17fec5ab7 h1:12i github.com/smartcontractkit/grpc-proxy v0.0.0-20240830132753-a7e17fec5ab7/go.mod h1:FX7/bVdoep147QQhsOPkYsPEXhGZjeYx6lBSaSXtZOA= github.com/smartcontractkit/libocr v0.0.0-20260304194147-a03701e2c02e h1:poXTj5cFVM6XfC4HICIDYkDVc/A6OYB0eeID0wU2JQE= github.com/smartcontractkit/libocr v0.0.0-20260304194147-a03701e2c02e/go.mod h1:PLdNK6GlqfxIWXzziPkU7dCAVlVFeYkyyW7AQY0R+4Q= -github.com/smartcontractkit/mcms v0.45.2-0.20260602204056-81248906ce6a h1:iUSbJqRa4pqmm4v4yvRUqFB4I9mW1zj/yNkkd6I/k0w= -github.com/smartcontractkit/mcms v0.45.2-0.20260602204056-81248906ce6a/go.mod h1:asEx9cQTOCz6p6KJececNlqVdVS72IX3x8Xpha9+nqw= +github.com/smartcontractkit/mcms v0.45.2-0.20260604053848-48d8a8691ced h1:pGCTXKk/EwBO5qgwR4LM9B+aWJA0hZj0JIj0Y3bME3w= +github.com/smartcontractkit/mcms v0.45.2-0.20260604053848-48d8a8691ced/go.mod h1:asEx9cQTOCz6p6KJececNlqVdVS72IX3x8Xpha9+nqw= github.com/smartcontractkit/wsrpc v0.8.5-0.20250502134807-c57d3d995945 h1:zxcODLrFytOKmAd8ty8S/XK6WcIEJEgRBaL7sY/7l4Y= github.com/smartcontractkit/wsrpc v0.8.5-0.20250502134807-c57d3d995945/go.mod h1:m3pdp17i4bD50XgktkzWetcV5yaLsi7Gunbv4ZgN6qg= github.com/sony/gobreaker/v2 v2.1.0 h1:av2BnjtRmVPWBvy5gSFPytm1J8BmN5AGhq875FfGKDM= diff --git a/integration-tests/go.mod b/integration-tests/go.mod index 3100902fc..882371680 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -33,7 +33,7 @@ require ( github.com/smartcontractkit/chainlink-deployments-framework v0.108.0 github.com/smartcontractkit/freeport v0.1.3-0.20250828155247-add56fa28aad github.com/smartcontractkit/go-daml v0.0.0-20260601190909-414e6d9dc2bd - github.com/smartcontractkit/mcms v0.45.2-0.20260602204056-81248906ce6a + github.com/smartcontractkit/mcms v0.45.2-0.20260604053848-48d8a8691ced github.com/stretchr/testify v1.11.1 google.golang.org/protobuf v1.36.11 ) diff --git a/integration-tests/go.sum b/integration-tests/go.sum index a7bab67b3..950b582b8 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -776,8 +776,8 @@ github.com/smartcontractkit/grpc-proxy v0.0.0-20240830132753-a7e17fec5ab7 h1:12i github.com/smartcontractkit/grpc-proxy v0.0.0-20240830132753-a7e17fec5ab7/go.mod h1:FX7/bVdoep147QQhsOPkYsPEXhGZjeYx6lBSaSXtZOA= github.com/smartcontractkit/libocr v0.0.0-20260304194147-a03701e2c02e h1:poXTj5cFVM6XfC4HICIDYkDVc/A6OYB0eeID0wU2JQE= github.com/smartcontractkit/libocr v0.0.0-20260304194147-a03701e2c02e/go.mod h1:PLdNK6GlqfxIWXzziPkU7dCAVlVFeYkyyW7AQY0R+4Q= -github.com/smartcontractkit/mcms v0.45.2-0.20260602204056-81248906ce6a h1:iUSbJqRa4pqmm4v4yvRUqFB4I9mW1zj/yNkkd6I/k0w= -github.com/smartcontractkit/mcms v0.45.2-0.20260602204056-81248906ce6a/go.mod h1:asEx9cQTOCz6p6KJececNlqVdVS72IX3x8Xpha9+nqw= +github.com/smartcontractkit/mcms v0.45.2-0.20260604053848-48d8a8691ced h1:pGCTXKk/EwBO5qgwR4LM9B+aWJA0hZj0JIj0Y3bME3w= +github.com/smartcontractkit/mcms v0.45.2-0.20260604053848-48d8a8691ced/go.mod h1:asEx9cQTOCz6p6KJececNlqVdVS72IX3x8Xpha9+nqw= github.com/smartcontractkit/wsrpc v0.8.5-0.20250502134807-c57d3d995945 h1:zxcODLrFytOKmAd8ty8S/XK6WcIEJEgRBaL7sY/7l4Y= github.com/smartcontractkit/wsrpc v0.8.5-0.20250502134807-c57d3d995945/go.mod h1:m3pdp17i4bD50XgktkzWetcV5yaLsi7Gunbv4ZgN6qg= github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 h1:+jumHNA0Wrelhe64i8F6HNlS8pkoyMv5sreGx2Ry5Rw= From 7777e098ce42cc8ce0d97d8ec1882c36e6a62e35 Mon Sep 17 00:00:00 2001 From: stackman27 Date: Wed, 3 Jun 2026 23:47:44 -0700 Subject: [PATCH 4/7] Remove scripts that should not be tracked Co-authored-by: Cursor --- .../archive_active_canton_contracts/main.go | 344 ------------------ scripts/upload-localnet-dars.sh | 41 --- scripts/upload-localnet-dars/main.go | 207 ----------- 3 files changed, 592 deletions(-) delete mode 100644 scripts/archive_active_canton_contracts/main.go delete mode 100644 scripts/upload-localnet-dars.sh delete mode 100644 scripts/upload-localnet-dars/main.go diff --git a/scripts/archive_active_canton_contracts/main.go b/scripts/archive_active_canton_contracts/main.go deleted file mode 100644 index b86356be7..000000000 --- a/scripts/archive_active_canton_contracts/main.go +++ /dev/null @@ -1,344 +0,0 @@ -package main - -import ( - "context" - "errors" - "flag" - "fmt" - "io" - "os" - "slices" - "strings" - "time" - - apiv2 "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2" - adminv2 "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2/admin" - "github.com/google/uuid" - "google.golang.org/grpc" - - "github.com/smartcontractkit/chainlink-canton/commonconfig" - "github.com/smartcontractkit/chainlink-canton/contracts" -) - -const defaultJWTEnv = "ONCHAIN_CANTON_JWT_TOKEN" - -type multiFlag []string - -func (m *multiFlag) String() string { - return strings.Join(*m, ",") -} - -func (m *multiFlag) Set(v string) error { - v = strings.TrimSpace(v) - if v == "" { - return fmt.Errorf("value cannot be empty") - } - *m = append(*m, v) - - return nil -} - -type activeContractMatch struct { - Template contracts.TemplateID - ContractID string - CreatedAt time.Time -} - -func main() { - var ( - grpcURL string - authority string - jwt string - jwtEnv string - party string - userID string - insecure bool - dryRun bool - timeout time.Duration - - templates multiFlag - contractIDs multiFlag - ) - - flag.StringVar(&grpcURL, "grpc-url", "", "Canton ledger gRPC endpoint, e.g. canton-devnet.bcy-v.metalhosts.com:443") - flag.StringVar(&authority, "authority", "", "Optional gRPC authority override") - flag.StringVar(&jwt, "jwt", "", "JWT for the ledger API; defaults to the env var specified by --jwt-env") - flag.StringVar(&jwtEnv, "jwt-env", defaultJWTEnv, "Environment variable to read JWT from when --jwt is not set") - flag.StringVar(&party, "party", "", "Party to query and act as when archiving") - flag.StringVar(&userID, "user-id", "", "Optional user ID to resolve primary party from when --party is omitted") - flag.BoolVar(&insecure, "insecure", false, "Use insecureStatic auth instead of static auth") - flag.BoolVar(&dryRun, "dry-run", false, "List matching active contracts without archiving them") - flag.DurationVar(&timeout, "timeout", 30*time.Second, "Per-request timeout") - flag.Var(&templates, "template", "Template selector in packageId:Module:Entity form; repeat the flag for multiple templates") - flag.Var(&contractIDs, "contract-id", "Optional contract ID filter; repeat the flag for multiple IDs") - flag.Usage = func() { - _, _ = fmt.Fprintf(flag.CommandLine.Output(), "Usage:\n") - _, _ = fmt.Fprintf(flag.CommandLine.Output(), " go run ./scripts/archive_active_canton_contracts --grpc-url --party --template [--template ...] [--dry-run]\n\n") - _, _ = fmt.Fprintf(flag.CommandLine.Output(), "Archives every active contract matching the provided templates for a single Canton party.\n") - _, _ = fmt.Fprintf(flag.CommandLine.Output(), "Use --dry-run first to inspect the ACS matches before archiving.\n\n") - flag.PrintDefaults() - } - flag.Parse() - - if grpcURL == "" { - fatalf("--grpc-url is required") - } - if len(templates) == 0 { - fatalf("at least one --template is required") - } - if jwt == "" { - jwt = strings.TrimSpace(os.Getenv(jwtEnv)) - } - if jwt == "" { - fatalf("JWT is required; set --jwt or %s", jwtEnv) - } - if party == "" && userID == "" { - fatalf("either --party or --user-id is required") - } - - ctx := context.Background() - authType := commonconfig.AuthTypeStatic - if insecure { - authType = commonconfig.AuthTypeInsecureStatic - } - provider, err := (&commonconfig.AuthConfig{Type: authType, JWT: jwt}).NewProvider(ctx) - if err != nil { - fatalf("build auth provider: %v", err) - } - - dialOpts := []grpc.DialOption{ - grpc.WithTransportCredentials(provider.TransportCredentials()), - grpc.WithPerRPCCredentials(provider.PerRPCCredentials()), - } - if authority != "" { - dialOpts = append(dialOpts, grpc.WithAuthority(authority)) - } - - conn, err := grpc.NewClient(grpcURL, dialOpts...) - if err != nil { - fatalf("connect to ledger API: %v", err) - } - defer conn.Close() - - stateClient := apiv2.NewStateServiceClient(conn) - commandClient := apiv2.NewCommandServiceClient(conn) - userClient := adminv2.NewUserManagementServiceClient(conn) - - if party == "" { - resolvedParty, err := resolvePrimaryParty(ctx, timeout, userClient, userID) - if err != nil { - fatalf("resolve primary party for user %s: %v", userID, err) - } - party = resolvedParty - } - - parsedTemplates, err := parseTemplates(templates) - if err != nil { - fatalf("parse templates: %v", err) - } - - contractIDSet := make(map[string]struct{}, len(contractIDs)) - for _, cid := range contractIDs { - contractIDSet[cid] = struct{}{} - } - - fmt.Printf("Using party: %s\n", party) - - var totalFound int - var totalArchived int - for _, template := range parsedTemplates { - matches, err := listActiveContracts(ctx, timeout, stateClient, party, template) - if err != nil { - fatalf("list active contracts for %s: %v", template.String(), err) - } - if len(contractIDSet) > 0 { - matches = filterByContractID(matches, contractIDSet) - } - totalFound += len(matches) - - fmt.Printf("\nTemplate %s\n", template.String()) - if len(matches) == 0 { - fmt.Println(" no matching active contracts") - continue - } - - for _, match := range matches { - fmt.Printf(" %s created_at=%s\n", match.ContractID, match.CreatedAt.Format(time.RFC3339Nano)) - } - if dryRun { - continue - } - - for _, match := range matches { - updateID, err := archiveContract(ctx, timeout, commandClient, party, match) - if err != nil { - fatalf("archive %s (%s): %v", match.ContractID, match.Template.String(), err) - } - totalArchived++ - fmt.Printf(" archived update_id=%s\n", updateID) - } - } - - fmt.Printf("\nMatched %d active contracts\n", totalFound) - if dryRun { - fmt.Println("Dry run complete; no contracts were archived") - return - } - fmt.Printf("Archived %d contracts\n", totalArchived) -} - -func resolvePrimaryParty(ctx context.Context, timeout time.Duration, userClient adminv2.UserManagementServiceClient, userID string) (string, error) { - callCtx, cancel := context.WithTimeout(ctx, timeout) - defer cancel() - - resp, err := userClient.GetUser(callCtx, &adminv2.GetUserRequest{UserId: userID}) - if err != nil { - return "", err - } - - party := strings.TrimSpace(resp.GetUser().GetPrimaryParty()) - if party == "" { - return "", fmt.Errorf("user %s has no primary party", userID) - } - - return party, nil -} - -func parseTemplates(inputs []string) ([]contracts.TemplateID, error) { - seen := make(map[string]struct{}, len(inputs)) - out := make([]contracts.TemplateID, 0, len(inputs)) - for _, input := range inputs { - parts := strings.Split(input, ":") - if len(parts) != 3 { - return nil, fmt.Errorf("template %q must have format packageId:Module:Entity", input) - } - - tpl := contracts.TemplateID{ - PackageID: strings.TrimSpace(parts[0]), - ModuleName: strings.TrimSpace(parts[1]), - EntityName: strings.TrimSpace(parts[2]), - } - if tpl.PackageID == "" || tpl.ModuleName == "" || tpl.EntityName == "" { - return nil, fmt.Errorf("template %q must not contain empty components", input) - } - - if _, ok := seen[tpl.String()]; ok { - continue - } - seen[tpl.String()] = struct{}{} - out = append(out, tpl) - } - - return out, nil -} - -func listActiveContracts(ctx context.Context, timeout time.Duration, stateClient apiv2.StateServiceClient, party string, template contracts.TemplateID) ([]activeContractMatch, error) { - callCtx, cancel := context.WithTimeout(ctx, timeout) - defer cancel() - - ledgerEndResp, err := stateClient.GetLedgerEnd(callCtx, &apiv2.GetLedgerEndRequest{}) - if err != nil { - return nil, fmt.Errorf("get ledger end: %w", err) - } - - stream, err := stateClient.GetActiveContracts(callCtx, &apiv2.GetActiveContractsRequest{ - ActiveAtOffset: ledgerEndResp.GetOffset(), - EventFormat: &apiv2.EventFormat{ - FiltersByParty: map[string]*apiv2.Filters{ - party: { - Cumulative: []*apiv2.CumulativeFilter{{ - IdentifierFilter: &apiv2.CumulativeFilter_TemplateFilter{TemplateFilter: &apiv2.TemplateFilter{ - TemplateId: template.ToLedgerIdentifier(), - IncludeCreatedEventBlob: true, - }}, - }}, - }, - }, - Verbose: true, - }, - }) - if err != nil { - return nil, fmt.Errorf("get active contracts: %w", err) - } - defer stream.CloseSend() - - var matches []activeContractMatch - for { - resp, err := stream.Recv() - if err != nil { - if errors.Is(err, io.EOF) { - break - } - - return nil, fmt.Errorf("recv active contracts: %w", err) - } - - entry, ok := resp.GetContractEntry().(*apiv2.GetActiveContractsResponse_ActiveContract) - if !ok || entry.ActiveContract == nil || entry.ActiveContract.GetCreatedEvent() == nil { - continue - } - - created := entry.ActiveContract.GetCreatedEvent() - matches = append(matches, activeContractMatch{ - Template: contracts.TemplateID{ - PackageID: created.GetTemplateId().GetPackageId(), - ModuleName: created.GetTemplateId().GetModuleName(), - EntityName: created.GetTemplateId().GetEntityName(), - }, - ContractID: created.GetContractId(), - CreatedAt: created.GetCreatedAt().AsTime(), - }) - } - - slices.SortFunc(matches, func(a, b activeContractMatch) int { - return a.CreatedAt.Compare(b.CreatedAt) - }) - - return matches, nil -} - -func filterByContractID(matches []activeContractMatch, contractIDs map[string]struct{}) []activeContractMatch { - filtered := make([]activeContractMatch, 0, len(matches)) - for _, match := range matches { - if _, ok := contractIDs[match.ContractID]; ok { - filtered = append(filtered, match) - } - } - - return filtered -} - -func archiveContract(ctx context.Context, timeout time.Duration, commandClient apiv2.CommandServiceClient, party string, match activeContractMatch) (string, error) { - callCtx, cancel := context.WithTimeout(ctx, timeout) - defer cancel() - - resp, err := commandClient.SubmitAndWaitForTransaction(callCtx, &apiv2.SubmitAndWaitForTransactionRequest{ - Commands: &apiv2.Commands{ - CommandId: uuid.New().String(), - Commands: []*apiv2.Command{{ - Command: &apiv2.Command_Exercise{Exercise: &apiv2.ExerciseCommand{ - TemplateId: match.Template.ToLedgerIdentifier(), - ContractId: match.ContractID, - Choice: "Archive", - ChoiceArgument: &apiv2.Value{ - Sum: &apiv2.Value_Record{Record: &apiv2.Record{}}, - }, - }}, - }}, - ActAs: []string{party}, - }, - }) - if err != nil { - return "", err - } - if resp.GetTransaction() == nil { - return "", nil - } - - return resp.GetTransaction().GetUpdateId(), nil -} - -func fatalf(format string, args ...any) { - fmt.Fprintf(os.Stderr, format+"\n", args...) - os.Exit(1) -} diff --git a/scripts/upload-localnet-dars.sh b/scripts/upload-localnet-dars.sh deleted file mode 100644 index 98e34cb61..000000000 --- a/scripts/upload-localnet-dars.sh +++ /dev/null @@ -1,41 +0,0 @@ -#!/usr/bin/env bash -# Upload all *-1.0.0.dar files from contracts/dars to local compose participant1. -# Prereqs: docker compose up in compose/localnet; grpcurl; python3. -set -euo pipefail - -REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" -DARS_DIR="${REPO_ROOT}/contracts/dars" -ADMIN="${CANTON_ADMIN_API:-participant1.admin-api.localhost:8080}" -CONFIG="${CANTON_CONFIG:-${REPO_ROOT}/integration-tests/local-docker-compose.toml}" - -if [[ -z "${ONCHAIN_CANTON_JWT_TOKEN:-}" ]]; then - ONCHAIN_CANTON_JWT_TOKEN="$(python3 -c " -import re, pathlib -t = pathlib.Path('${CONFIG}').read_text() -m = re.search(r'^jwt=\"([^\"]+)\"', t, re.M) -print(m.group(1) if m else '') -")" - export ONCHAIN_CANTON_JWT_TOKEN -fi -if [[ -z "${ONCHAIN_CANTON_JWT_TOKEN}" ]]; then - echo "Set ONCHAIN_CANTON_JWT_TOKEN or add jwt to ${CONFIG}" >&2 - exit 1 -fi - -for f in "${DARS_DIR}"/*-1.0.0.dar; do - echo "=== $(basename "$f") ===" - python3 -c " -import json, base64, sys -b = base64.b64encode(open(sys.argv[1], 'rb').read()).decode() -sys.stdout.write(json.dumps({ - 'dars': [{'bytes': b}], - 'vetAllPackages': True, - 'synchronizeVetting': True, -})) -" "$f" | grpcurl -plaintext \ - -H "authorization: Bearer ${ONCHAIN_CANTON_JWT_TOKEN}" \ - -d @ "${ADMIN}" \ - com.digitalasset.canton.admin.participant.v30.PackageService/UploadDar -done - -echo "Done: uploaded $(ls -1 "${DARS_DIR}"/*-1.0.0.dar | wc -l | tr -d ' ') DAR(s) to ${ADMIN}" diff --git a/scripts/upload-localnet-dars/main.go b/scripts/upload-localnet-dars/main.go deleted file mode 100644 index 87174df4d..000000000 --- a/scripts/upload-localnet-dars/main.go +++ /dev/null @@ -1,207 +0,0 @@ -// Upload all *-1.0.0.dar packages to a local Docker Compose Canton participant. -// -// Usage (from chainlink-canton-fcr repo root): -// -// export ONCHAIN_CANTON_JWT_TOKEN="" # or rely on jwt in -config TOML -// go run ./scripts/upload-localnet-dars -// go run ./scripts/upload-localnet-dars -all-participants -package main - -import ( - "context" - "flag" - "fmt" - "log" - "os" - "path/filepath" - "sort" - "strings" - - "github.com/BurntSushi/toml" - participantv30 "github.com/digital-asset/dazl-client/v8/go/api/com/digitalasset/canton/admin/participant/v30" - adminv2 "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2/admin" - "google.golang.org/grpc" - "google.golang.org/grpc/status" - - chainsel "github.com/smartcontractkit/chain-selectors" - "github.com/smartcontractkit/chainlink-deployments-framework/chain/canton" - cantonProvider "github.com/smartcontractkit/chainlink-deployments-framework/chain/canton/provider" - "github.com/smartcontractkit/chainlink-deployments-framework/chain/canton/provider/authentication" - - "github.com/smartcontractkit/chainlink-canton/testhelpers" -) - -func main() { - configPath := flag.String("config", "integration-tests/local-docker-compose.toml", "participant TOML (chain_selector + participants)") - participantIdx := flag.Int("participant", 0, "participant index in TOML (0 = participant1)") - allParticipants := flag.Bool("all-participants", false, "upload to every participant in the TOML") - repoRoot := flag.String("repo", ".", "chainlink-canton-fcr repo root (contracts/dars and contracts/dependencies)") - flag.Parse() - - jwt := strings.TrimSpace(os.Getenv("ONCHAIN_CANTON_JWT_TOKEN")) - - darPaths, err := collectDARs(*repoRoot) - if err != nil { - log.Fatal(err) - } - if len(darPaths) == 0 { - log.Fatal("no *-1.0.0.dar files found under contracts/dars or contracts/dependencies") - } - - input, err := loadParticipantInput(*configPath) - if err != nil { - log.Fatal(err) - } - - indices := []int{*participantIdx} - if *allParticipants { - indices = make([]int, len(input.Participants)) - for i := range input.Participants { - indices[i] = i - } - } - - ctx := context.Background() - for _, idx := range indices { - if idx < 0 || idx >= len(input.Participants) { - log.Fatalf("participant index %d out of range (have %d participants)", idx, len(input.Participants)) - } - cfg := input.Participants[idx] - token := jwt - if token == "" { - token = cfg.JWT - } - if token == "" { - log.Fatal("JWT required: set ONCHAIN_CANTON_JWT_TOKEN or jwt in config TOML") - } - - chain, err := buildChain(ctx, input.Selector, cfg, token) - if err != nil { - log.Fatalf("participant %d (%s): %v", idx, nameOrDefault(cfg, idx), err) - } - participant := chain.Participants[0] - if cfg.Party != "" { - log.Printf("participant %d (%s) party_id=%s", idx, nameOrDefault(cfg, idx), cfg.Party) - } else { - log.Printf("participant %d (%s) primary party=%s", idx, nameOrDefault(cfg, idx), participant.PartyID) - } - - for _, darPath := range darPaths { - darBytes, err := os.ReadFile(darPath) //nolint:gosec // local dev script, user-controlled repo path - if err != nil { - log.Fatalf("read %s: %v", darPath, err) - } - res, err := participant.AdminServices.Package.UploadDar(ctx, &participantv30.UploadDarRequest{ - Dars: []*participantv30.UploadDarRequest_UploadDarData{{Bytes: darBytes}}, - VetAllPackages: true, - SynchronizeVetting: true, - }) - if err != nil { - if s, ok := status.FromError(err); ok { - log.Printf("gRPC code=%s message=%s", s.Code(), s.Message()) - } - log.Fatalf("upload %s to %s: %v", filepath.Base(darPath), nameOrDefault(cfg, idx), err) - } - log.Printf("uploaded %s -> dar_ids=%v", filepath.Base(darPath), res.GetDarIds()) - } - } - - log.Printf("done: uploaded %d DAR(s)", len(darPaths)) -} - -func collectDARs(repoRoot string) ([]string, error) { - dirs := []string{ - filepath.Join(repoRoot, "contracts", "dependencies"), - filepath.Join(repoRoot, "contracts", "dars"), - } - var paths []string - for _, dir := range dirs { - entries, err := os.ReadDir(dir) - if err != nil { - if os.IsNotExist(err) { - continue - } - return nil, err - } - for _, e := range entries { - if e.IsDir() { - continue - } - name := e.Name() - if strings.HasSuffix(name, "-1.0.0.dar") { - paths = append(paths, filepath.Join(dir, name)) - } - } - } - sort.Strings(paths) - return paths, nil -} - -func loadParticipantInput(path string) (testhelpers.ParticipantInput, error) { - content, err := os.ReadFile(path) //nolint:gosec // config path from flag - if err != nil { - return testhelpers.ParticipantInput{}, err - } - var input testhelpers.ParticipantInput - if err := toml.Unmarshal(content, &input); err != nil { - return testhelpers.ParticipantInput{}, err - } - if input.Selector == 0 { - input.Selector = chainsel.CANTON_LOCALNET.Selector - } - return input, nil -} - -func buildChain(ctx context.Context, selector uint64, cfg testhelpers.ParticipantConfig, jwt string) (*canton.Chain, error) { - auth := authentication.NewInsecureStaticProvider(jwt) - party := cfg.Party - if party == "" { - conn, err := grpc.NewClient( - cfg.GRPCLedgerAPIURL, - grpc.WithTransportCredentials(auth.TransportCredentials()), - grpc.WithPerRPCCredentials(auth.PerRPCCredentials()), - ) - if err != nil { - return nil, fmt.Errorf("ledger grpc dial: %w", err) - } - defer conn.Close() - user, err := adminv2.NewUserManagementServiceClient(conn).GetUser(ctx, &adminv2.GetUserRequest{UserId: cfg.UserName}) - if err != nil { - return nil, fmt.Errorf("get user %q: %w", cfg.UserName, err) - } - if len(user.GetUser().GetPrimaryParty()) == 0 { - return nil, fmt.Errorf("no primary party for user %q", cfg.UserName) - } - party = user.GetUser().GetPrimaryParty() - } - - provider := cantonProvider.NewRPCChainProvider(selector, cantonProvider.RPCChainProviderConfig{ - Participants: []cantonProvider.ParticipantConfig{{ - Endpoints: cantonProvider.Endpoints{ - JSONLedgerAPIURL: cfg.JSONLedgerAPIURL, - GRPCLedgerAPIURL: cfg.GRPCLedgerAPIURL, - AdminAPIURL: cfg.AdminAPIURL, - ValidatorAPIURL: cfg.ValidatorAPIURL, - }, - UserID: cfg.UserName, - PartyID: party, - AuthProvider: auth, - }}, - }) - bc, err := provider.Initialize(ctx) - if err != nil { - return nil, err - } - chain, ok := bc.(*canton.Chain) - if !ok { - return nil, fmt.Errorf("unexpected chain type %T", bc) - } - return chain, nil -} - -func nameOrDefault(cfg testhelpers.ParticipantConfig, idx int) string { - if cfg.Name != "" { - return cfg.Name - } - return fmt.Sprintf("participant%d", idx+1) -} From 44a1afd800fbcffc20eced7a7df1fcc0031edd9e Mon Sep 17 00:00:00 2001 From: stackman27 Date: Wed, 3 Jun 2026 23:48:59 -0700 Subject: [PATCH 5/7] Restore scripts/ to match main; drop accidental upload-localnet-dars additions. Co-authored-by: Cursor --- .../archive_active_canton_contracts/main.go | 344 ++++++++++++++++++ 1 file changed, 344 insertions(+) create mode 100644 scripts/archive_active_canton_contracts/main.go diff --git a/scripts/archive_active_canton_contracts/main.go b/scripts/archive_active_canton_contracts/main.go new file mode 100644 index 000000000..b86356be7 --- /dev/null +++ b/scripts/archive_active_canton_contracts/main.go @@ -0,0 +1,344 @@ +package main + +import ( + "context" + "errors" + "flag" + "fmt" + "io" + "os" + "slices" + "strings" + "time" + + apiv2 "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2" + adminv2 "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2/admin" + "github.com/google/uuid" + "google.golang.org/grpc" + + "github.com/smartcontractkit/chainlink-canton/commonconfig" + "github.com/smartcontractkit/chainlink-canton/contracts" +) + +const defaultJWTEnv = "ONCHAIN_CANTON_JWT_TOKEN" + +type multiFlag []string + +func (m *multiFlag) String() string { + return strings.Join(*m, ",") +} + +func (m *multiFlag) Set(v string) error { + v = strings.TrimSpace(v) + if v == "" { + return fmt.Errorf("value cannot be empty") + } + *m = append(*m, v) + + return nil +} + +type activeContractMatch struct { + Template contracts.TemplateID + ContractID string + CreatedAt time.Time +} + +func main() { + var ( + grpcURL string + authority string + jwt string + jwtEnv string + party string + userID string + insecure bool + dryRun bool + timeout time.Duration + + templates multiFlag + contractIDs multiFlag + ) + + flag.StringVar(&grpcURL, "grpc-url", "", "Canton ledger gRPC endpoint, e.g. canton-devnet.bcy-v.metalhosts.com:443") + flag.StringVar(&authority, "authority", "", "Optional gRPC authority override") + flag.StringVar(&jwt, "jwt", "", "JWT for the ledger API; defaults to the env var specified by --jwt-env") + flag.StringVar(&jwtEnv, "jwt-env", defaultJWTEnv, "Environment variable to read JWT from when --jwt is not set") + flag.StringVar(&party, "party", "", "Party to query and act as when archiving") + flag.StringVar(&userID, "user-id", "", "Optional user ID to resolve primary party from when --party is omitted") + flag.BoolVar(&insecure, "insecure", false, "Use insecureStatic auth instead of static auth") + flag.BoolVar(&dryRun, "dry-run", false, "List matching active contracts without archiving them") + flag.DurationVar(&timeout, "timeout", 30*time.Second, "Per-request timeout") + flag.Var(&templates, "template", "Template selector in packageId:Module:Entity form; repeat the flag for multiple templates") + flag.Var(&contractIDs, "contract-id", "Optional contract ID filter; repeat the flag for multiple IDs") + flag.Usage = func() { + _, _ = fmt.Fprintf(flag.CommandLine.Output(), "Usage:\n") + _, _ = fmt.Fprintf(flag.CommandLine.Output(), " go run ./scripts/archive_active_canton_contracts --grpc-url --party --template [--template ...] [--dry-run]\n\n") + _, _ = fmt.Fprintf(flag.CommandLine.Output(), "Archives every active contract matching the provided templates for a single Canton party.\n") + _, _ = fmt.Fprintf(flag.CommandLine.Output(), "Use --dry-run first to inspect the ACS matches before archiving.\n\n") + flag.PrintDefaults() + } + flag.Parse() + + if grpcURL == "" { + fatalf("--grpc-url is required") + } + if len(templates) == 0 { + fatalf("at least one --template is required") + } + if jwt == "" { + jwt = strings.TrimSpace(os.Getenv(jwtEnv)) + } + if jwt == "" { + fatalf("JWT is required; set --jwt or %s", jwtEnv) + } + if party == "" && userID == "" { + fatalf("either --party or --user-id is required") + } + + ctx := context.Background() + authType := commonconfig.AuthTypeStatic + if insecure { + authType = commonconfig.AuthTypeInsecureStatic + } + provider, err := (&commonconfig.AuthConfig{Type: authType, JWT: jwt}).NewProvider(ctx) + if err != nil { + fatalf("build auth provider: %v", err) + } + + dialOpts := []grpc.DialOption{ + grpc.WithTransportCredentials(provider.TransportCredentials()), + grpc.WithPerRPCCredentials(provider.PerRPCCredentials()), + } + if authority != "" { + dialOpts = append(dialOpts, grpc.WithAuthority(authority)) + } + + conn, err := grpc.NewClient(grpcURL, dialOpts...) + if err != nil { + fatalf("connect to ledger API: %v", err) + } + defer conn.Close() + + stateClient := apiv2.NewStateServiceClient(conn) + commandClient := apiv2.NewCommandServiceClient(conn) + userClient := adminv2.NewUserManagementServiceClient(conn) + + if party == "" { + resolvedParty, err := resolvePrimaryParty(ctx, timeout, userClient, userID) + if err != nil { + fatalf("resolve primary party for user %s: %v", userID, err) + } + party = resolvedParty + } + + parsedTemplates, err := parseTemplates(templates) + if err != nil { + fatalf("parse templates: %v", err) + } + + contractIDSet := make(map[string]struct{}, len(contractIDs)) + for _, cid := range contractIDs { + contractIDSet[cid] = struct{}{} + } + + fmt.Printf("Using party: %s\n", party) + + var totalFound int + var totalArchived int + for _, template := range parsedTemplates { + matches, err := listActiveContracts(ctx, timeout, stateClient, party, template) + if err != nil { + fatalf("list active contracts for %s: %v", template.String(), err) + } + if len(contractIDSet) > 0 { + matches = filterByContractID(matches, contractIDSet) + } + totalFound += len(matches) + + fmt.Printf("\nTemplate %s\n", template.String()) + if len(matches) == 0 { + fmt.Println(" no matching active contracts") + continue + } + + for _, match := range matches { + fmt.Printf(" %s created_at=%s\n", match.ContractID, match.CreatedAt.Format(time.RFC3339Nano)) + } + if dryRun { + continue + } + + for _, match := range matches { + updateID, err := archiveContract(ctx, timeout, commandClient, party, match) + if err != nil { + fatalf("archive %s (%s): %v", match.ContractID, match.Template.String(), err) + } + totalArchived++ + fmt.Printf(" archived update_id=%s\n", updateID) + } + } + + fmt.Printf("\nMatched %d active contracts\n", totalFound) + if dryRun { + fmt.Println("Dry run complete; no contracts were archived") + return + } + fmt.Printf("Archived %d contracts\n", totalArchived) +} + +func resolvePrimaryParty(ctx context.Context, timeout time.Duration, userClient adminv2.UserManagementServiceClient, userID string) (string, error) { + callCtx, cancel := context.WithTimeout(ctx, timeout) + defer cancel() + + resp, err := userClient.GetUser(callCtx, &adminv2.GetUserRequest{UserId: userID}) + if err != nil { + return "", err + } + + party := strings.TrimSpace(resp.GetUser().GetPrimaryParty()) + if party == "" { + return "", fmt.Errorf("user %s has no primary party", userID) + } + + return party, nil +} + +func parseTemplates(inputs []string) ([]contracts.TemplateID, error) { + seen := make(map[string]struct{}, len(inputs)) + out := make([]contracts.TemplateID, 0, len(inputs)) + for _, input := range inputs { + parts := strings.Split(input, ":") + if len(parts) != 3 { + return nil, fmt.Errorf("template %q must have format packageId:Module:Entity", input) + } + + tpl := contracts.TemplateID{ + PackageID: strings.TrimSpace(parts[0]), + ModuleName: strings.TrimSpace(parts[1]), + EntityName: strings.TrimSpace(parts[2]), + } + if tpl.PackageID == "" || tpl.ModuleName == "" || tpl.EntityName == "" { + return nil, fmt.Errorf("template %q must not contain empty components", input) + } + + if _, ok := seen[tpl.String()]; ok { + continue + } + seen[tpl.String()] = struct{}{} + out = append(out, tpl) + } + + return out, nil +} + +func listActiveContracts(ctx context.Context, timeout time.Duration, stateClient apiv2.StateServiceClient, party string, template contracts.TemplateID) ([]activeContractMatch, error) { + callCtx, cancel := context.WithTimeout(ctx, timeout) + defer cancel() + + ledgerEndResp, err := stateClient.GetLedgerEnd(callCtx, &apiv2.GetLedgerEndRequest{}) + if err != nil { + return nil, fmt.Errorf("get ledger end: %w", err) + } + + stream, err := stateClient.GetActiveContracts(callCtx, &apiv2.GetActiveContractsRequest{ + ActiveAtOffset: ledgerEndResp.GetOffset(), + EventFormat: &apiv2.EventFormat{ + FiltersByParty: map[string]*apiv2.Filters{ + party: { + Cumulative: []*apiv2.CumulativeFilter{{ + IdentifierFilter: &apiv2.CumulativeFilter_TemplateFilter{TemplateFilter: &apiv2.TemplateFilter{ + TemplateId: template.ToLedgerIdentifier(), + IncludeCreatedEventBlob: true, + }}, + }}, + }, + }, + Verbose: true, + }, + }) + if err != nil { + return nil, fmt.Errorf("get active contracts: %w", err) + } + defer stream.CloseSend() + + var matches []activeContractMatch + for { + resp, err := stream.Recv() + if err != nil { + if errors.Is(err, io.EOF) { + break + } + + return nil, fmt.Errorf("recv active contracts: %w", err) + } + + entry, ok := resp.GetContractEntry().(*apiv2.GetActiveContractsResponse_ActiveContract) + if !ok || entry.ActiveContract == nil || entry.ActiveContract.GetCreatedEvent() == nil { + continue + } + + created := entry.ActiveContract.GetCreatedEvent() + matches = append(matches, activeContractMatch{ + Template: contracts.TemplateID{ + PackageID: created.GetTemplateId().GetPackageId(), + ModuleName: created.GetTemplateId().GetModuleName(), + EntityName: created.GetTemplateId().GetEntityName(), + }, + ContractID: created.GetContractId(), + CreatedAt: created.GetCreatedAt().AsTime(), + }) + } + + slices.SortFunc(matches, func(a, b activeContractMatch) int { + return a.CreatedAt.Compare(b.CreatedAt) + }) + + return matches, nil +} + +func filterByContractID(matches []activeContractMatch, contractIDs map[string]struct{}) []activeContractMatch { + filtered := make([]activeContractMatch, 0, len(matches)) + for _, match := range matches { + if _, ok := contractIDs[match.ContractID]; ok { + filtered = append(filtered, match) + } + } + + return filtered +} + +func archiveContract(ctx context.Context, timeout time.Duration, commandClient apiv2.CommandServiceClient, party string, match activeContractMatch) (string, error) { + callCtx, cancel := context.WithTimeout(ctx, timeout) + defer cancel() + + resp, err := commandClient.SubmitAndWaitForTransaction(callCtx, &apiv2.SubmitAndWaitForTransactionRequest{ + Commands: &apiv2.Commands{ + CommandId: uuid.New().String(), + Commands: []*apiv2.Command{{ + Command: &apiv2.Command_Exercise{Exercise: &apiv2.ExerciseCommand{ + TemplateId: match.Template.ToLedgerIdentifier(), + ContractId: match.ContractID, + Choice: "Archive", + ChoiceArgument: &apiv2.Value{ + Sum: &apiv2.Value_Record{Record: &apiv2.Record{}}, + }, + }}, + }}, + ActAs: []string{party}, + }, + }) + if err != nil { + return "", err + } + if resp.GetTransaction() == nil { + return "", nil + } + + return resp.GetTransaction().GetUpdateId(), nil +} + +func fatalf(format string, args ...any) { + fmt.Fprintf(os.Stderr, format+"\n", args...) + os.Exit(1) +} From b469a711af197d8b8f9a5c37489ceb85d1432875 Mon Sep 17 00:00:00 2001 From: stackman27 Date: Thu, 4 Jun 2026 08:07:17 -0700 Subject: [PATCH 6/7] use bytex for other fields --- .../burnminttokenpool/burnminttokenpool.go | 8 ++++---- bindings/generated/latest/ccip/core/core.go | 18 +++++++++--------- .../generated/latest/ccip/factory/factory.go | 2 +- .../lockreleasetokenpool.go | 8 ++++---- contracts/cmd/bindings/main.go | 11 ++++++++--- 5 files changed, 26 insertions(+), 21 deletions(-) diff --git a/bindings/generated/latest/ccip/burnminttokenpool/burnminttokenpool.go b/bindings/generated/latest/ccip/burnminttokenpool/burnminttokenpool.go index a704d3274..22136e362 100644 --- a/bindings/generated/latest/ccip/burnminttokenpool/burnminttokenpool.go +++ b/bindings/generated/latest/ccip/burnminttokenpool/burnminttokenpool.go @@ -1271,8 +1271,8 @@ func (t *CalculateFeeMCMSParams) UnmarshalHex(data string) error { // ChainUpdate is a Record type type ChainUpdate struct { RemoteChainSelector types.NUMERIC `json:"remoteChainSelector"` - RemotePools []types.TEXT `json:"remotePools"` - RemoteTokenAddress types.TEXT `json:"remoteTokenAddress"` + RemotePools []types.TEXT `json:"remotePools" hex:"[]bytes"` + RemoteTokenAddress types.TEXT `json:"remoteTokenAddress" hex:"bytes"` InboundCCVs []chainlinkapi.RawInstanceAddress `json:"inboundCCVs"` OutboundCCVs []chainlinkapi.RawInstanceAddress `json:"outboundCCVs"` FinalityConfig core.FinalityConfig `json:"finalityConfig"` @@ -1723,8 +1723,8 @@ func (t *ReleaseFromTicketMCMSParams) UnmarshalHex(data string) error { // RemoteChainConfig is a Record type type RemoteChainConfig struct { - RemotePools []types.TEXT `json:"remotePools"` - RemoteTokenAddress types.TEXT `json:"remoteTokenAddress"` + RemotePools []types.TEXT `json:"remotePools" hex:"[]bytes"` + RemoteTokenAddress types.TEXT `json:"remoteTokenAddress" hex:"bytes"` InboundCCVs []chainlinkapi.RawInstanceAddress `json:"inboundCCVs"` OutboundCCVs []chainlinkapi.RawInstanceAddress `json:"outboundCCVs"` FinalityConfig core.FinalityConfig `json:"finalityConfig"` diff --git a/bindings/generated/latest/ccip/core/core.go b/bindings/generated/latest/ccip/core/core.go index f3b64efea..406a5cbe5 100644 --- a/bindings/generated/latest/ccip/core/core.go +++ b/bindings/generated/latest/ccip/core/core.go @@ -1698,7 +1698,7 @@ func (t *ConsumeReceiveTicketMCMSParams) UnmarshalHex(data string) error { // Curse is a Record type type Curse struct { - Subject types.TEXT `json:"subject"` + Subject types.TEXT `json:"subject" hex:"bytes"` } // ToMap converts Curse to a map for DAML arguments @@ -1838,7 +1838,7 @@ func (t *CurseGlobal) UnmarshalHex(data string) error { // CurseMultiple is a Record type type CurseMultiple struct { - Subjects []types.TEXT `json:"subjects"` + Subjects []types.TEXT `json:"subjects" hex:"[]bytes"` } // ToMap converts CurseMultiple to a map for DAML arguments @@ -1880,7 +1880,7 @@ func (t *CurseMultiple) UnmarshalHex(data string) error { // CurseMultipleParams is a Record type type CurseMultipleParams struct { - Subjects []types.TEXT `json:"subjects"` + Subjects []types.TEXT `json:"subjects" hex:"[]bytes"` } // ToMap converts CurseMultipleParams to a map for DAML arguments @@ -1922,7 +1922,7 @@ func (t *CurseMultipleParams) UnmarshalHex(data string) error { // CurseParams is a Record type type CurseParams struct { - Subject types.TEXT `json:"subject"` + Subject types.TEXT `json:"subject" hex:"bytes"` } // ToMap converts CurseParams to a map for DAML arguments @@ -5785,7 +5785,7 @@ type RMNRemote struct { RmnOwner types.PARTY `json:"rmnOwner"` CcipOwner types.PARTY `json:"ccipOwner"` CustomObservers []types.PARTY `json:"customObservers"` - CursedSubjects []types.TEXT `json:"cursedSubjects"` + CursedSubjects []types.TEXT `json:"cursedSubjects" hex:"[]bytes"` } // GetTemplateID returns the template ID for this template using the package name @@ -10119,7 +10119,7 @@ func (t *TransferAdminRoleMCMSParams) UnmarshalHex(data string) error { // Uncurse is a Record type type Uncurse struct { - Subject types.TEXT `json:"subject"` + Subject types.TEXT `json:"subject" hex:"bytes"` } // ToMap converts Uncurse to a map for DAML arguments @@ -10259,7 +10259,7 @@ func (t *UncurseGlobal) UnmarshalHex(data string) error { // UncurseMultiple is a Record type type UncurseMultiple struct { - Subjects []types.TEXT `json:"subjects"` + Subjects []types.TEXT `json:"subjects" hex:"[]bytes"` } // ToMap converts UncurseMultiple to a map for DAML arguments @@ -10301,7 +10301,7 @@ func (t *UncurseMultiple) UnmarshalHex(data string) error { // UncurseMultipleParams is a Record type type UncurseMultipleParams struct { - Subjects []types.TEXT `json:"subjects"` + Subjects []types.TEXT `json:"subjects" hex:"[]bytes"` } // ToMap converts UncurseMultipleParams to a map for DAML arguments @@ -10343,7 +10343,7 @@ func (t *UncurseMultipleParams) UnmarshalHex(data string) error { // UncurseParams is a Record type type UncurseParams struct { - Subject types.TEXT `json:"subject"` + Subject types.TEXT `json:"subject" hex:"bytes"` } // ToMap converts UncurseParams to a map for DAML arguments diff --git a/bindings/generated/latest/ccip/factory/factory.go b/bindings/generated/latest/ccip/factory/factory.go index 2bcc7aee3..2c29a9865 100644 --- a/bindings/generated/latest/ccip/factory/factory.go +++ b/bindings/generated/latest/ccip/factory/factory.go @@ -1500,7 +1500,7 @@ type DeployRMNRemoteParams struct { RmnOwner types.PARTY `json:"rmnOwner"` CcipOwner types.PARTY `json:"ccipOwner"` CustomObservers []types.PARTY `json:"customObservers"` - CursedSubjects []types.TEXT `json:"cursedSubjects"` + CursedSubjects []types.TEXT `json:"cursedSubjects" hex:"[]bytes"` } // ToMap converts DeployRMNRemoteParams to a map for DAML arguments diff --git a/bindings/generated/latest/ccip/lockreleasetokenpool/lockreleasetokenpool.go b/bindings/generated/latest/ccip/lockreleasetokenpool/lockreleasetokenpool.go index 38b772534..58006ee7b 100644 --- a/bindings/generated/latest/ccip/lockreleasetokenpool/lockreleasetokenpool.go +++ b/bindings/generated/latest/ccip/lockreleasetokenpool/lockreleasetokenpool.go @@ -505,8 +505,8 @@ func (t *CalculateFeeMCMSParams) UnmarshalHex(data string) error { // ChainUpdate is a Record type type ChainUpdate struct { RemoteChainSelector types.NUMERIC `json:"remoteChainSelector"` - RemotePools []types.TEXT `json:"remotePools"` - RemoteTokenAddress types.TEXT `json:"remoteTokenAddress"` + RemotePools []types.TEXT `json:"remotePools" hex:"[]bytes"` + RemoteTokenAddress types.TEXT `json:"remoteTokenAddress" hex:"bytes"` InboundCCVs []chainlinkapi.RawInstanceAddress `json:"inboundCCVs"` OutboundCCVs []chainlinkapi.RawInstanceAddress `json:"outboundCCVs"` FinalityConfig core.FinalityConfig `json:"finalityConfig"` @@ -1724,8 +1724,8 @@ func (t *ReleaseFromTicketMCMSParams) UnmarshalHex(data string) error { // RemoteChainConfig is a Record type type RemoteChainConfig struct { - RemotePools []types.TEXT `json:"remotePools"` - RemoteTokenAddress types.TEXT `json:"remoteTokenAddress"` + RemotePools []types.TEXT `json:"remotePools" hex:"[]bytes"` + RemoteTokenAddress types.TEXT `json:"remoteTokenAddress" hex:"bytes"` InboundCCVs []chainlinkapi.RawInstanceAddress `json:"inboundCCVs"` OutboundCCVs []chainlinkapi.RawInstanceAddress `json:"outboundCCVs"` FinalityConfig core.FinalityConfig `json:"finalityConfig"` diff --git a/contracts/cmd/bindings/main.go b/contracts/cmd/bindings/main.go index 769fe8a0a..0c46b0bb6 100644 --- a/contracts/cmd/bindings/main.go +++ b/contracts/cmd/bindings/main.go @@ -70,9 +70,14 @@ func main() { "root": true, // Merkle root hash (32 bytes) "newRoot": true, // New merkle root hash (32 bytes) "versionTag": true, // CCV version tag is a 4-byte BytesHex field - "onRampAddresses": true, // Daml [BytesHex] → hex:"[]bytes" on []types.TEXT - "signerKeys": true, // Daml [BytesHex] → hex:"[]bytes" on []types.TEXT - "offRampAddress": true, // Daml BytesHex scalar → hex:"bytes" on types.TEXT + "onRampAddresses": true, // Daml [BytesHex] → hex:"[]bytes" on []types.TEXT + "signerKeys": true, // Daml [BytesHex] → hex:"[]bytes" on []types.TEXT + "offRampAddress": true, // Daml BytesHex scalar → hex:"bytes" on types.TEXT + "subject": true, // Daml BytesHex scalar → hex:"bytes"; RMNRemote Curse/Uncurse subject (chain selector hash) + "remoteTokenAddress": true, // Daml BytesHex scalar → hex:"bytes"; token pool remote token address on dest chain + "subjects": true, // Daml [BytesHex] → hex:"[]bytes"; RMNRemote CurseMultiple/UncurseMultiple + "cursedSubjects": true, // Daml [BytesHex] → hex:"[]bytes"; Factory DeployRMNRemote initial cursed subjects + "remotePools": true, // Daml [BytesHex] → hex:"[]bytes"; token pool allowed remote pool addresses per chain }, // hex:"bytes16" — fields that may exceed 255 bytes (uint16 length prefix) BytesHexFields: map[string]bool{ From 932342d633bd41cacca7d130d3fe87fda822d5e3 Mon Sep 17 00:00:00 2001 From: stackman27 Date: Thu, 4 Jun 2026 08:18:09 -0700 Subject: [PATCH 7/7] bump go-daml --- go.mod | 2 +- go.sum | 4 ++-- integration-tests/go.mod | 2 +- integration-tests/go.sum | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 9ea8c64d7..8917da87b 100644 --- a/go.mod +++ b/go.mod @@ -41,7 +41,7 @@ require ( github.com/smartcontractkit/chainlink-deployments-framework v0.108.0 github.com/smartcontractkit/chainlink-testing-framework/framework v0.16.4 github.com/smartcontractkit/chainlink-testing-framework/wasp v1.51.3 - github.com/smartcontractkit/go-daml v0.0.0-20260601190909-414e6d9dc2bd + github.com/smartcontractkit/go-daml v0.0.0-20260604143752-c6f6567940ba github.com/stretchr/testify v1.11.1 github.com/testcontainers/testcontainers-go v0.42.0 go.opentelemetry.io/otel v1.44.0 diff --git a/go.sum b/go.sum index 1fd1971fb..90e892061 100644 --- a/go.sum +++ b/go.sum @@ -1230,8 +1230,8 @@ github.com/smartcontractkit/chainlink/v2 v2.29.0 h1:MyvQ/LAhHw//yDXgo2EvH7jq4NH3 github.com/smartcontractkit/chainlink/v2 v2.29.0/go.mod h1:6SHH9QHlKh1mKuEhG8Y7nGutUzhQwu1Qrpp/0qLzaR0= github.com/smartcontractkit/freeport v0.1.3-0.20250828155247-add56fa28aad h1:lgHxTHuzJIF3Vj6LSMOnjhqKgRqYW+0MV2SExtCYL1Q= github.com/smartcontractkit/freeport v0.1.3-0.20250828155247-add56fa28aad/go.mod h1:T4zH9R8R8lVWKfU7tUvYz2o2jMv1OpGCdpY2j2QZXzU= -github.com/smartcontractkit/go-daml v0.0.0-20260601190909-414e6d9dc2bd h1:t8V2eqMZFoVXFMf+BHeti0zHeMDQ2ss4QngGtyFbGMs= -github.com/smartcontractkit/go-daml v0.0.0-20260601190909-414e6d9dc2bd/go.mod h1:SqWfl3Bp9NleC9jhzFUaOGzOZeKfldpY4QOW6A6NSNM= +github.com/smartcontractkit/go-daml v0.0.0-20260604143752-c6f6567940ba h1:peYJwUWOv54aigdk1VFzkmXdZmZK4xixfxv0Af1l6/I= +github.com/smartcontractkit/go-daml v0.0.0-20260604143752-c6f6567940ba/go.mod h1:SqWfl3Bp9NleC9jhzFUaOGzOZeKfldpY4QOW6A6NSNM= github.com/smartcontractkit/grpc-proxy v0.0.0-20240830132753-a7e17fec5ab7 h1:12ijqMM9tvYVEm+nR826WsrNi6zCKpwBhuApq127wHs= github.com/smartcontractkit/grpc-proxy v0.0.0-20240830132753-a7e17fec5ab7/go.mod h1:FX7/bVdoep147QQhsOPkYsPEXhGZjeYx6lBSaSXtZOA= github.com/smartcontractkit/libocr v0.0.0-20260304194147-a03701e2c02e h1:poXTj5cFVM6XfC4HICIDYkDVc/A6OYB0eeID0wU2JQE= diff --git a/integration-tests/go.mod b/integration-tests/go.mod index 882371680..f6dc11f16 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -32,7 +32,7 @@ require ( github.com/smartcontractkit/chainlink-common v0.11.2-0.20260506120607-7f10be016c89 github.com/smartcontractkit/chainlink-deployments-framework v0.108.0 github.com/smartcontractkit/freeport v0.1.3-0.20250828155247-add56fa28aad - github.com/smartcontractkit/go-daml v0.0.0-20260601190909-414e6d9dc2bd + github.com/smartcontractkit/go-daml v0.0.0-20260604143752-c6f6567940ba github.com/smartcontractkit/mcms v0.45.2-0.20260604053848-48d8a8691ced github.com/stretchr/testify v1.11.1 google.golang.org/protobuf v1.36.11 diff --git a/integration-tests/go.sum b/integration-tests/go.sum index 950b582b8..ffc901815 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -770,8 +770,8 @@ github.com/smartcontractkit/chainlink-tron/relayer/gotron-sdk v0.0.5-0.202510141 github.com/smartcontractkit/chainlink-tron/relayer/gotron-sdk v0.0.5-0.20251014120029-d73d15cc23f7/go.mod h1:ea1LESxlSSOgc2zZBqf1RTkXTMthHaspdqUHd7W4lF0= github.com/smartcontractkit/freeport v0.1.3-0.20250828155247-add56fa28aad h1:lgHxTHuzJIF3Vj6LSMOnjhqKgRqYW+0MV2SExtCYL1Q= github.com/smartcontractkit/freeport v0.1.3-0.20250828155247-add56fa28aad/go.mod h1:T4zH9R8R8lVWKfU7tUvYz2o2jMv1OpGCdpY2j2QZXzU= -github.com/smartcontractkit/go-daml v0.0.0-20260601190909-414e6d9dc2bd h1:t8V2eqMZFoVXFMf+BHeti0zHeMDQ2ss4QngGtyFbGMs= -github.com/smartcontractkit/go-daml v0.0.0-20260601190909-414e6d9dc2bd/go.mod h1:SqWfl3Bp9NleC9jhzFUaOGzOZeKfldpY4QOW6A6NSNM= +github.com/smartcontractkit/go-daml v0.0.0-20260604143752-c6f6567940ba h1:peYJwUWOv54aigdk1VFzkmXdZmZK4xixfxv0Af1l6/I= +github.com/smartcontractkit/go-daml v0.0.0-20260604143752-c6f6567940ba/go.mod h1:SqWfl3Bp9NleC9jhzFUaOGzOZeKfldpY4QOW6A6NSNM= github.com/smartcontractkit/grpc-proxy v0.0.0-20240830132753-a7e17fec5ab7 h1:12ijqMM9tvYVEm+nR826WsrNi6zCKpwBhuApq127wHs= github.com/smartcontractkit/grpc-proxy v0.0.0-20240830132753-a7e17fec5ab7/go.mod h1:FX7/bVdoep147QQhsOPkYsPEXhGZjeYx6lBSaSXtZOA= github.com/smartcontractkit/libocr v0.0.0-20260304194147-a03701e2c02e h1:poXTj5cFVM6XfC4HICIDYkDVc/A6OYB0eeID0wU2JQE=