From 226bd7fcc3e60b59d229b32c85351379f97ed86a Mon Sep 17 00:00:00 2001 From: Rodrigo Ariza <15104916+RodrigoAD@users.noreply.github.com> Date: Wed, 4 Feb 2026 10:19:22 +0100 Subject: [PATCH 1/6] Add Canton Configurer (#598) - Adds Canton configurer implementation, unit and e2e tests --- e2e/config.canton.toml | 10 +++ e2e/tests/canton/common.go | 154 ++++++++++++++++++++++++++++++++ e2e/tests/canton/configurer.go | 125 ++++++++++++++++++++++++++ e2e/tests/runner_test.go | 5 ++ e2e/tests/setup.go | 18 ++++ go.mod | 66 +++++++++----- go.sum | 157 +++++++++++++++++++++++++-------- sdk/canton/configurer.go | 140 +++++++++++++++++++++++++++++ sdk/canton/helpers.go | 17 ++++ taskfiles/test/Taskfile.yml | 7 ++ 10 files changed, 642 insertions(+), 57 deletions(-) create mode 100644 e2e/config.canton.toml create mode 100644 e2e/tests/canton/common.go create mode 100644 e2e/tests/canton/configurer.go create mode 100644 sdk/canton/configurer.go create mode 100644 sdk/canton/helpers.go diff --git a/e2e/config.canton.toml b/e2e/config.canton.toml new file mode 100644 index 000000000..bae2f4da3 --- /dev/null +++ b/e2e/config.canton.toml @@ -0,0 +1,10 @@ +[settings] +private_keys = [ + "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80", + "0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d", + "0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a" +] + +[canton_config] +type = "canton" +number_of_canton_validators = 1 diff --git a/e2e/tests/canton/common.go b/e2e/tests/canton/common.go new file mode 100644 index 000000000..b57600247 --- /dev/null +++ b/e2e/tests/canton/common.go @@ -0,0 +1,154 @@ +//go:build e2e + +package canton + +import ( + "context" + "fmt" + "time" + + "github.com/google/uuid" + "github.com/noders-team/go-daml/pkg/client" + "github.com/noders-team/go-daml/pkg/model" + "github.com/noders-team/go-daml/pkg/types" + "github.com/smartcontractkit/chainlink-canton/bindings/mcms" + "github.com/smartcontractkit/chainlink-canton/contracts" + "github.com/smartcontractkit/chainlink-canton/integration-tests/testhelpers" + + e2e "github.com/smartcontractkit/mcms/e2e/tests" + cantonsdk "github.com/smartcontractkit/mcms/sdk/canton" + "github.com/stretchr/testify/suite" +) + +type TestSuite struct { + suite.Suite + e2e.TestSetup + + env testhelpers.TestEnvironment + + client *client.DamlBindingClient + participant testhelpers.Participant + + packageIDs []string + mcmsContractID string +} + +func NewBindingClient(ctx context.Context, jwtToken, ledgerAPIURL, adminAPIURL string) (*client.DamlBindingClient, error) { + bindingClient, err := client.NewDamlClient(jwtToken, ledgerAPIURL). + WithAdminAddress(adminAPIURL). + Build(ctx) + if err != nil { + return nil, fmt.Errorf("failed to create DAML binding client: %w", err) + } + + return bindingClient, nil +} + +func (s *TestSuite) SetupSuite() { + s.T().Log("Spinning up Canton test environment...") + s.env = testhelpers.NewTestEnvironment(s.T(), testhelpers.WithNumberOfParticipants(1)) + jwt, err := s.env.Participant(1).GetToken(s.T().Context()) + s.Require().NoError(err) + participant := s.env.Participant(1) + config := participant.GetConfig() + s.client, err = NewBindingClient(s.T().Context(), jwt, config.GRPCLedgerAPIURL, config.AdminAPIURL) + s.Require().NoError(err) + s.participant = participant +} + +const NumGroups = 32 + +func (s *TestSuite) DeployMCMSContract() { + s.T().Log("Uploading MCMS DAR...") + + mcmsDar, err := contracts.GetDar(contracts.MCMS, contracts.CurrentVersion) + s.Require().NoError(err) + + packageIDs, err := testhelpers.UploadDARstoMultipleParticipants(s.T().Context(), [][]byte{mcmsDar}, s.participant) + s.Require().NoError(err) + s.packageIDs = packageIDs + + mcmsOwner := s.participant.Party + chainId := 1 + baseMcmsId := "mcms-test-001" + mcmsId := makeMcmsId(baseMcmsId, "proposer") + + mcmsContractId := s.createMCMS(s.T().Context(), s.participant, mcmsOwner, chainId, mcmsId, mcms.RoleProposer) + s.mcmsContractID = mcmsContractId +} + +func (s *TestSuite) createMCMS(ctx context.Context, participant testhelpers.Participant, owner string, chainId int, mcmsId string, role mcms.Role) string { + // Create empty expiring root + emptyExpiringRoot := mcms.ExpiringRoot{ + Root: types.TEXT(""), + ValidUntil: types.TIMESTAMP(time.Unix(0, 0).UTC()), + OpCount: types.INT64(0), + } + + // Create empty root metadata + emptyRootMetadata := mcms.RootMetadata{ + ChainId: types.INT64(0), + MultisigId: types.TEXT(""), + PreOpCount: types.INT64(0), + PostOpCount: types.INT64(0), + OverridePreviousRoot: types.BOOL(false), + } + + // Create MCMS contract + mcmsContract := mcms.MCMS{ + Owner: types.PARTY(participant.Party), + Role: role, + ChainId: types.INT64(chainId), + McmsId: types.TEXT(mcmsId), + Config: mcms.MultisigConfig{ + Signers: []mcms.SignerInfo{}, + GroupQuorums: []types.INT64{types.INT64(1)}, + GroupParents: []types.INT64{types.INT64(1)}, + }, + SeenHashes: types.GENMAP{}, // Empty map + ExpiringRoot: emptyExpiringRoot, + RootMetadata: emptyRootMetadata, + } + + // Submit via binding client's CommandService + commandID := uuid.Must(uuid.NewUUID()).String() + cmds := &model.SubmitAndWaitRequest{ + Commands: &model.Commands{ + WorkflowID: "mcms-deploy", + UserID: participant.UserName, + CommandID: commandID, + ActAs: []string{participant.Party}, + Commands: []*model.Command{{Command: mcmsContract.CreateCommand()}}, + }, + } + + submitResp, err := s.client.CommandService.SubmitAndWaitForTransaction(ctx, cmds) + s.Require().NoError(err, "failed to submit MCMS deploy transaction") + + // Retrieve the contract ID and template ID from the create event + mcmsContractID := "" + mcmsTemplateID := "" + for _, event := range submitResp.Transaction.Events { + if event.Created == nil { + continue + } + + normalizedTemplateID := cantonsdk.NormalizeTemplateKey(event.Created.TemplateID) + if normalizedTemplateID == cantonsdk.MCMSTemplateKey { + mcmsContractID = event.Created.ContractID + mcmsTemplateID = event.Created.TemplateID + + break + } + } + + s.Require().NotEmpty(mcmsContractID, "failed to find MCMS contract in transaction events") + s.Require().NotEmpty(mcmsTemplateID, "failed to find MCMS template ID in transaction events") + + return mcmsContractID +} + +// TODO: Use right role types +func makeMcmsId(baseId string, role string) string { + return baseId + "-" + role +} diff --git a/e2e/tests/canton/configurer.go b/e2e/tests/canton/configurer.go new file mode 100644 index 000000000..8f85ef201 --- /dev/null +++ b/e2e/tests/canton/configurer.go @@ -0,0 +1,125 @@ +//go:build e2e + +package canton + +import ( + "slices" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" + "github.com/noders-team/go-daml/pkg/model" + + cantonsdk "github.com/smartcontractkit/mcms/sdk/canton" + + "github.com/smartcontractkit/mcms/types" +) + +type MCMSConfigurerTestSuite struct { + TestSuite +} + +// SetupSuite runs before the test suite +func (s *MCMSConfigurerTestSuite) SetupSuite() { + s.TestSuite.SetupSuite() + s.DeployMCMSContract() +} + +func (s *MCMSConfigurerTestSuite) TestSetConfig() { + // Signers in each group need to be sorted alphabetically + signers := [30]common.Address{} + for i := range signers { + key, _ := crypto.GenerateKey() + signers[i] = crypto.PubkeyToAddress(key.PublicKey) + } + slices.SortFunc(signers[:], func(a, b common.Address) int { + return a.Cmp(b) + }) + + proposerConfig := &types.Config{ + Quorum: 2, + Signers: []common.Address{ + signers[0], + signers[1], + signers[2], + }, + GroupSigners: []types.Config{ + { + Quorum: 4, + Signers: []common.Address{ + signers[3], + signers[4], + signers[5], + signers[6], + signers[7], + }, + GroupSigners: []types.Config{ + { + Quorum: 1, + Signers: []common.Address{ + signers[8], + signers[9], + }, + GroupSigners: []types.Config{}, + }, + }, + }, + { + Quorum: 3, + Signers: []common.Address{ + signers[10], + signers[11], + signers[12], + signers[13], + }, + GroupSigners: []types.Config{}, + }, + }, + } + + // Set config + { + configurer, err := cantonsdk.NewConfigurer(s.client, s.participant.UserName, s.participant.Party) + s.Require().NoError(err, "creating configurer for Canton mcms contract") + tx, err := configurer.SetConfig(s.T().Context(), s.mcmsContractID, proposerConfig, true) + s.Require().NoError(err, "setting config on Canton mcms contract") + + // Verify transaction result + rawData, ok := tx.RawData.(map[string]any) + s.Require().True(ok) + rawTx, ok := rawData["RawTx"] + s.Require().True(ok) + + submitResp, ok := rawTx.(*model.SubmitAndWaitForTransactionResponse) + s.Require().True(ok) + + // Verify CompletionOffset exists + s.Require().NotZero(submitResp.CompletionOffset, "transaction should have CompletionOffset") + + events := submitResp.Transaction.Events + s.Require().Len(events, 2, "transaction should have exactly 2 events (archived + created)") + + // Verify event[0] is Archived (old contract) + s.Require().NotNil(events[0].Archived, "first event should be Archived event") + s.Require().Nil(events[0].Created, "first event should not be Created event") + s.Require().Equal(s.mcmsContractID, events[0].Archived.ContractID, "archived contract should be the old MCMS contract") + + // Verify event[1] is Created (new contract) + s.Require().NotNil(events[1].Created, "second event should be Created event") + s.Require().Nil(events[1].Archived, "second event should not be Archived event") + + // Verify Template ID matches + rawData, ok = tx.RawData.(map[string]any) + s.Require().True(ok) + newMCMSTemplateID, ok := rawData["NewMCMSTemplateID"].(string) + s.Require().True(ok) + s.Require().Contains(newMCMSTemplateID, "MCMS.Main:MCMS", "template ID should match MCMS template") + s.Require().Equal(newMCMSTemplateID, events[1].Created.TemplateID, "created event template ID should match returned template ID") + + // Verify new contract ID is different from old + newMCMSContractID, ok := rawData["NewMCMSContractID"].(string) + s.Require().True(ok) + s.Require().NotEmpty(newMCMSContractID, "new contract ID should not be empty") + s.Require().NotEqual(s.mcmsContractID, newMCMSContractID, "new contract ID should be different from old contract ID") + s.Require().Equal(newMCMSContractID, events[1].Created.ContractID, "created event contract ID should match returned contract ID") + } +} diff --git a/e2e/tests/runner_test.go b/e2e/tests/runner_test.go index a04ff50e7..cd0aa434f 100644 --- a/e2e/tests/runner_test.go +++ b/e2e/tests/runner_test.go @@ -8,6 +8,7 @@ import ( "github.com/stretchr/testify/suite" aptose2e "github.com/smartcontractkit/mcms/e2e/tests/aptos" + cantone2e "github.com/smartcontractkit/mcms/e2e/tests/canton" evme2e "github.com/smartcontractkit/mcms/e2e/tests/evm" solanae2e "github.com/smartcontractkit/mcms/e2e/tests/solana" suie2e "github.com/smartcontractkit/mcms/e2e/tests/sui" @@ -49,3 +50,7 @@ func TestTONSuite(t *testing.T) { suite.Run(t, new(tone2e.ExecutionTestSuite)) suite.Run(t, new(tone2e.TimelockInspectionTestSuite)) } + +func TestCantonSuite(t *testing.T) { + suite.Run(t, new(cantone2e.MCMSConfigurerTestSuite)) +} diff --git a/e2e/tests/setup.go b/e2e/tests/setup.go index 65adf90f1..067cd3efc 100644 --- a/e2e/tests/setup.go +++ b/e2e/tests/setup.go @@ -43,6 +43,7 @@ type Config struct { AptosChain *blockchain.Input `toml:"aptos_config"` SuiChain *blockchain.Input `toml:"sui_config"` TonChain *blockchain.Input `toml:"ton_config"` + CantonChain *blockchain.Input `toml:"canton_config"` Settings struct { PrivateKeys []string `toml:"private_keys"` @@ -64,6 +65,7 @@ type TestSetup struct { SuiNodeURL string TonClient *ton.APIClient TonBlockchain *blockchain.Output + CantonBlockchain *blockchain.Output Config } @@ -236,6 +238,21 @@ func InitializeSharedTestSetup(t *testing.T) *TestSetup { t.Logf("Initialized TON RPC client @ %s", nodeURL) } + var ( + cantonBlockchainOutput *blockchain.Output + ) + if in.CantonChain != nil { + // Use blockchain network setup (fallback) + ports := freeport.GetN(t, 2) + port := ports[0] + faucetPort := ports[1] + in.CantonChain.Port = strconv.Itoa(port) + in.CantonChain.FaucetPort = strconv.Itoa(faucetPort) + + cantonBlockchainOutput, err = blockchain.NewBlockchainNetwork(in.CantonChain) + require.NoError(t, err, "Failed to initialize Canton blockchain") + } + sharedSetup = &TestSetup{ ClientA: ethClientA, ClientB: ethClientB, @@ -249,6 +266,7 @@ func InitializeSharedTestSetup(t *testing.T) *TestSetup { SuiNodeURL: suiNodeURL, TonClient: tonClient, TonBlockchain: tonBlockchainOutput, + CantonBlockchain: cantonBlockchainOutput, Config: *in, } }) diff --git a/go.mod b/go.mod index cb0d62c94..f186ebf06 100644 --- a/go.mod +++ b/go.mod @@ -1,10 +1,17 @@ module github.com/smartcontractkit/mcms -go 1.25.5 +go 1.25.6 //nolint:gomoddirectives // allow replace directive replace github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.3-alpha.regen.1 +// Coming from chainlink-deployments-framework +replace github.com/fbsobreira/gotron-sdk => github.com/smartcontractkit/chainlink-tron/relayer/gotron-sdk v0.0.5-0.20251014120029-d73d15cc23f7 + +replace github.com/digital-asset/dazl-client/v8 => github.com/noders-team/dazl-client/v8 v8.7.1-2 + +replace github.com/noders-team/go-daml => github.com/stackman27/go-daml v0.0.0-20260129035354-bee9c994446f + require ( github.com/aptos-labs/aptos-go-sdk v1.11.0 github.com/block-vision/sui-go-sdk v1.1.4 @@ -13,16 +20,24 @@ require ( github.com/gagliardetto/solana-go v1.13.0 github.com/go-playground/validator/v10 v10.28.0 github.com/google/go-cmp v0.7.0 + github.com/google/uuid v1.6.0 github.com/joho/godotenv v1.5.1 github.com/karalabe/hid v1.0.1-0.20240306101548-573246063e52 + github.com/noders-team/go-daml v0.6.0 github.com/samber/lo v1.52.0 - github.com/smartcontractkit/chain-selectors v1.0.89 + github.com/smartcontractkit/chain-selectors v1.0.91 github.com/smartcontractkit/chainlink-aptos v0.0.0-20251024142440-51f2ad2652a2 github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20260129103204-4c8453dd8139 github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings v0.0.0-20260129103204-4c8453dd8139 github.com/smartcontractkit/chainlink-sui v0.0.0-20260205175622-33e65031f9a9 github.com/smartcontractkit/chainlink-testing-framework/framework v0.12.1 github.com/smartcontractkit/chainlink-ton v0.0.0-20260204205804-642f6ebe4e7e + github.com/smartcontractkit/chainlink-canton v0.0.0-20260202190435-99f4e19d8d2e + github.com/smartcontractkit/chainlink-canton/integration-tests v0.0.0-20260202190435-99f4e19d8d2e + github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20260119161343-499241536dea + github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings v0.0.0-20250908144012-8184001834b5 + github.com/smartcontractkit/chainlink-testing-framework/framework v0.13.9 + github.com/smartcontractkit/chainlink-ton v0.0.0-20260130134551-8ebf4f73b668 github.com/smartcontractkit/freeport v0.1.3-0.20250716200817-cb5dfd0e369e github.com/spf13/cast v1.10.0 github.com/stretchr/testify v1.11.1 @@ -38,21 +53,23 @@ require ( dario.cat/mergo v1.0.2 // indirect filippo.io/edwards25519 v1.1.0 // indirect github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect - github.com/BurntSushi/toml v1.5.0 // indirect + github.com/BurntSushi/toml v1.6.0 // indirect github.com/DataDog/zstd v1.5.6 // indirect github.com/Masterminds/semver/v3 v3.4.0 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20251001021608-1fe7b43fc4d6 // indirect github.com/VictoriaMetrics/fastcache v1.13.0 // indirect github.com/XSAM/otelsql v0.37.0 // indirect + github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect + github.com/avast/retry-go/v4 v4.6.1 // indirect github.com/bahlo/generic-list-go v0.2.0 // indirect github.com/benbjohnson/clock v1.3.5 // indirect github.com/beorn7/perks v1.0.1 // indirect - github.com/bits-and-blooms/bitset v1.20.0 // indirect + github.com/bits-and-blooms/bitset v1.24.0 // indirect github.com/blendle/zapdriver v1.3.1 // indirect github.com/btcsuite/btcd v0.24.2 // indirect - github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect - github.com/btcsuite/btcd/btcutil v1.1.5 // indirect + github.com/btcsuite/btcd/btcec/v2 v2.3.4 // indirect + github.com/btcsuite/btcd/btcutil v1.1.6 // indirect github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0 // indirect github.com/btcsuite/btcutil v1.0.2 // indirect github.com/buger/jsonparser v1.1.1 // indirect @@ -82,16 +99,19 @@ require ( github.com/dchest/siphash v1.2.3 // indirect github.com/deckarep/golang-set/v2 v2.6.0 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect + github.com/deepmap/oapi-codegen v1.8.2 // indirect + github.com/digital-asset/dazl-client/v8 v8.7.1 // indirect github.com/distribution/reference v0.6.0 // indirect - github.com/docker/docker v28.3.3+incompatible // indirect - github.com/docker/go-connections v0.5.0 // indirect + github.com/docker/docker v28.5.1+incompatible // indirect + github.com/docker/go-connections v0.6.0 // indirect github.com/docker/go-units v0.5.0 // indirect - github.com/ebitengine/purego v0.8.4 // indirect + github.com/ebitengine/purego v0.9.0 // indirect github.com/emicklei/dot v1.6.2 // indirect github.com/ethereum/c-kzg-4844/v2 v2.1.5 // indirect github.com/ethereum/go-bigmodexpfix v0.0.0-20250911101455-f9e208c548ab // indirect github.com/ethereum/go-verkle v0.2.2 // indirect github.com/fatih/color v1.18.0 // indirect + github.com/fbsobreira/gotron-sdk v0.0.0-20250403083053-2943ce8c759b // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/ferranbt/fastssz v0.1.4 // indirect github.com/fsnotify/fsnotify v1.9.0 // indirect @@ -105,14 +125,14 @@ require ( github.com/go-ole/go-ole v1.3.0 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect - github.com/go-resty/resty/v2 v2.16.3 // indirect + github.com/go-resty/resty/v2 v2.17.1 // indirect github.com/go-viper/mapstructure/v2 v2.4.0 // indirect github.com/gofrs/flock v0.12.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang-jwt/jwt/v4 v4.5.2 // indirect + github.com/golang-jwt/jwt/v5 v5.3.1 // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/golang/snappy v1.0.0 // indirect - github.com/google/uuid v1.6.0 // indirect github.com/gorilla/rpc v1.2.0 // indirect github.com/gorilla/websocket v1.5.3 // indirect github.com/graph-gophers/graphql-go v1.5.0 // indirect @@ -143,14 +163,14 @@ require ( github.com/jmoiron/sqlx v1.4.0 // indirect github.com/jpillora/backoff v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/compress v1.18.1 // indirect + github.com/klauspost/compress v1.18.2 // indirect github.com/klauspost/cpuid/v2 v2.2.10 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/kr/text v0.2.0 // indirect github.com/leodido/go-urn v1.4.0 // indirect github.com/lib/pq v1.10.9 // indirect github.com/logrusorgru/aurora v2.0.3+incompatible // indirect - github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35 // indirect + github.com/lufia/plan9stats v0.0.0-20251013123823-9fd1530e3ec3 // indirect github.com/magiconair/properties v1.8.10 // indirect github.com/mailru/easyjson v0.9.0 // indirect github.com/mattn/go-colorable v0.1.14 // indirect @@ -173,9 +193,9 @@ require ( github.com/mostynb/zstdpool-freelist v0.0.0-20201229113212-927304c0c3b1 // indirect github.com/mr-tron/base58 v1.2.0 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/oapi-codegen/runtime v1.1.2 // indirect github.com/oklog/run v1.2.0 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect - github.com/onsi/gomega v1.34.2 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.1 // indirect github.com/pelletier/go-toml v1.9.5 // indirect @@ -195,19 +215,21 @@ require ( github.com/rivo/uniseg v0.4.7 // indirect github.com/rogpeppe/go-internal v1.14.1 // indirect github.com/rs/cors v1.11.1 // indirect - github.com/rs/zerolog v1.33.0 // indirect + github.com/rs/zerolog v1.34.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 // indirect github.com/scylladb/go-reflectx v1.0.1 // indirect github.com/shirou/gopsutil v3.21.11+incompatible // indirect - github.com/shirou/gopsutil/v4 v4.25.5 // indirect + github.com/shirou/gopsutil/v4 v4.25.9 // indirect github.com/shopspring/decimal v1.4.0 // indirect github.com/sigurn/crc16 v0.0.0-20211026045750-20ab5afb07e3 // indirect github.com/sirupsen/logrus v1.9.3 // indirect - github.com/smartcontractkit/chainlink-common v0.9.6-0.20260114142648-bd9e1b483e96 // indirect + github.com/smartcontractkit/chainlink-common v0.9.6-0.20260114190811-74301cd99dc3 // indirect github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.10 // indirect + github.com/smartcontractkit/chainlink-deployments-framework v0.78.0 // indirect github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20251124151448-0448aefdaab9 // indirect github.com/smartcontractkit/chainlink-protos/linking-service/go v0.0.0-20251002192024-d2ad9222409b // indirect + github.com/smartcontractkit/chainlink-tron/relayer v0.0.11-0.20250908203554-5bd9d2fe9513 // indirect github.com/smartcontractkit/grpc-proxy v0.0.0-20240830132753-a7e17fec5ab7 // indirect github.com/smartcontractkit/libocr v0.0.0-20250912173940-f3ab0246e23d // indirect github.com/stephenlacy/go-ethereum-hdwallet v0.0.0-20230913225845-a4fa94429863 // indirect @@ -215,9 +237,9 @@ require ( github.com/stretchr/objx v0.5.2 // indirect github.com/supranational/blst v0.3.16-0.20250831170142-f48500c1fdbe // indirect github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect - github.com/testcontainers/testcontainers-go v0.38.0 // indirect + github.com/testcontainers/testcontainers-go v0.39.0 // indirect github.com/tidwall/gjson v1.18.0 // indirect - github.com/tidwall/match v1.1.1 // indirect + github.com/tidwall/match v1.2.0 // indirect github.com/tidwall/pretty v1.2.1 // indirect github.com/tklauser/go-sysconf v0.3.15 // indirect github.com/tklauser/numcpus v0.10.0 // indirect @@ -231,7 +253,7 @@ require ( go.mongodb.org/mongo-driver v1.17.2 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0 // indirect go.opentelemetry.io/otel v1.38.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.12.2 // indirect go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.12.2 // indirect @@ -260,8 +282,8 @@ require ( golang.org/x/text v0.33.0 // indirect golang.org/x/time v0.12.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20260114163908-3f89685c29c3 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20251222181119-0a764e51fe1b // indirect - google.golang.org/grpc v1.77.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20260114163908-3f89685c29c3 // indirect + google.golang.org/grpc v1.78.0 // indirect google.golang.org/protobuf v1.36.11 // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect diff --git a/go.sum b/go.sum index 6ec8cf9cb..511be8c04 100644 --- a/go.sum +++ b/go.sum @@ -10,8 +10,8 @@ github.com/AlekSi/pointer v1.1.0/go.mod h1:y7BvfRI3wXPWKXEBhU71nbnIEEZX0QTSB2Bj4 github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg= github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg= -github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= +github.com/BurntSushi/toml v1.6.0 h1:dRaEfpa2VI55EwlIW72hMRHdWouJeRF7TPYhI+AUQjk= +github.com/BurntSushi/toml v1.6.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/DataDog/zstd v1.5.6 h1:LbEglqepa/ipmmQJUDnSsfvA8e8IStVcGaFWDuxvGOY= github.com/DataDog/zstd v1.5.6/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= @@ -19,8 +19,11 @@ github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1 github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= +github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= +github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20251001021608-1fe7b43fc4d6 h1:1zYrtlhrZ6/b6SAjLSfKzWtdgqK0U+HtH/VcBWh1BaU= github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20251001021608-1fe7b43fc4d6/go.mod h1:ioLG6R+5bUSO1oeGSDxOV3FADARuMoytZCSX6MEMQkI= +github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk= github.com/VictoriaMetrics/fastcache v1.13.0 h1:AW4mheMR5Vd9FkAPUv+NH6Nhw+fmbTMGMsNAoA/+4G0= github.com/VictoriaMetrics/fastcache v1.13.0/go.mod h1:hHXhl4DA2fTL2HTZDJFXWgW0LNjo6B+4aj2Wmng3TjU= github.com/XSAM/otelsql v0.37.0 h1:ya5RNw028JW0eJW8Ma4AmoKxAYsJSGuNVbC7F1J457A= @@ -30,6 +33,8 @@ github.com/allegro/bigcache v1.2.1 h1:hg1sY1raCwic3Vnsvje6TT7/pnZba83LeFck5NrFKS github.com/allegro/bigcache v1.2.1/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= github.com/apache/arrow-go/v18 v18.3.1 h1:oYZT8FqONiK74JhlH3WKVv+2NKYoyZ7C2ioD4Dj3ixk= github.com/apache/arrow-go/v18 v18.3.1/go.mod h1:12QBya5JZT6PnBihi5NJTzbACrDGXYkrgjujz3MRQXU= +github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7Dml6nw9rQ= +github.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP2+08jFMw88y4klk= github.com/aptos-labs/aptos-go-sdk v1.11.0 h1:vIL1hpjECUiu7zMl9Wz6VV8ttXsrDqKUj0HxoeaIER4= github.com/aptos-labs/aptos-go-sdk v1.11.0/go.mod h1:8YvYwRg93UcG6pTStCpZdYiscCtKh51sYfeLgIy/41c= github.com/avast/retry-go/v4 v4.6.1 h1:VkOLRubHdisGrHnTu89g08aQEWEgRU7LVEop3GbIcMk= @@ -41,8 +46,8 @@ github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz github.com/benbjohnson/clock v1.3.5/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/bits-and-blooms/bitset v1.20.0 h1:2F+rfL86jE2d/bmw7OhqUg2Sj/1rURkBn3MdfoPyRVU= -github.com/bits-and-blooms/bitset v1.20.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= +github.com/bits-and-blooms/bitset v1.24.0 h1:H4x4TuulnokZKvHLfzVRTHJfFfnHEeSYJizujEZvmAM= +github.com/bits-and-blooms/bitset v1.24.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= github.com/blendle/zapdriver v1.3.1 h1:C3dydBOWYRiOk+B8X9IVZ5IOe+7cl+tGOexN4QqHfpE= github.com/blendle/zapdriver v1.3.1/go.mod h1:mdXfREi6u5MArG4j9fewC+FGnXaBR+T4Ox4J2u4eHCc= github.com/block-vision/sui-go-sdk v1.1.4 h1:1PPgYxQjo1P9UCgFOPTvDCuGEglRL32NwjKPulR4FQk= @@ -54,12 +59,13 @@ github.com/btcsuite/btcd v0.24.2 h1:aLmxPguqxza+4ag8R1I2nnJjSu2iFn/kqtHTIImswcY= github.com/btcsuite/btcd v0.24.2/go.mod h1:5C8ChTkl5ejr3WHj8tkQSCmydiMEPB0ZhQhehpq7Dgg= github.com/btcsuite/btcd/btcec/v2 v2.1.0/go.mod h1:2VzYrv4Gm4apmbVVsSq5bqf1Ec8v56E48Vt0Y/umPgA= github.com/btcsuite/btcd/btcec/v2 v2.1.3/go.mod h1:ctjw4H1kknNJmRN4iP1R7bTQ+v3GJkZBd6mui8ZsAZE= -github.com/btcsuite/btcd/btcec/v2 v2.3.2 h1:5n0X6hX0Zk+6omWcihdYvdAlGf2DfasC0GMf7DClJ3U= -github.com/btcsuite/btcd/btcec/v2 v2.3.2/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= +github.com/btcsuite/btcd/btcec/v2 v2.3.4 h1:3EJjcN70HCu/mwqlUsGK8GcNVyLVxFDlWurTXGPFfiQ= +github.com/btcsuite/btcd/btcec/v2 v2.3.4/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= github.com/btcsuite/btcd/btcutil v1.0.0/go.mod h1:Uoxwv0pqYWhD//tfTiipkxNfdhG9UrLwaeswfjfdF0A= github.com/btcsuite/btcd/btcutil v1.1.0/go.mod h1:5OapHB7A2hBBWLm48mmw4MOHNJCcUBTwmWH/0Jn8VHE= -github.com/btcsuite/btcd/btcutil v1.1.5 h1:+wER79R5670vs/ZusMTF1yTcRYE5GUsFbdjdisflzM8= github.com/btcsuite/btcd/btcutil v1.1.5/go.mod h1:PSZZ4UitpLBWzxGd5VGOrLnmOjtPP/a6HaFo12zMs00= +github.com/btcsuite/btcd/btcutil v1.1.6 h1:zFL2+c3Lb9gEgqKNzowKUPQNb8jV7v5Oaodi/AYFd6c= +github.com/btcsuite/btcd/btcutil v1.1.6/go.mod h1:9dFymx8HpuLqBnsPELrImQeTQfKBQqzqGbbV3jK55aE= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0 h1:59Kx4K6lzOW5w6nFlA0v5+lk/6sjybR934QNHSJZPTQ= @@ -118,6 +124,8 @@ github.com/coder/websocket v1.8.14 h1:9L0p0iKiNOibykf283eHkKUHHrpG7f65OE3BhhO7v9 github.com/coder/websocket v1.8.14/go.mod h1:NX3SzP+inril6yawo5CQXx8+fk145lPDC6pumgx0mVg= github.com/consensys/gnark-crypto v0.19.2 h1:qrEAIXq3T4egxqiliFFoNrepkIWVEeIYwt3UL0fvS80= github.com/consensys/gnark-crypto v0.19.2/go.mod h1:rT23F0XSZqE0mUA0+pRtnL56IbPxs6gp4CeRsBk4XS0= +github.com/containerd/continuity v0.4.5 h1:ZRoN1sXq9u7V6QoHMcVWGhOwDFqZ4B9i5H6un1Wh0x4= +github.com/containerd/continuity v0.4.5/go.mod h1:/lNJvtJKUQStBzpVQ1+rasXO1LAWtUQssk28EZvJ3nE= github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI= github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M= github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE= @@ -149,6 +157,7 @@ github.com/cucumber/godog v0.15.1 h1:rb/6oHDdvVZKS66hrhpjFQFHjthFSrQBCOI1LwshNTI github.com/cucumber/godog v0.15.1/go.mod h1:qju+SQDewOljHuq9NSM66s0xEhogx0q30flfxL4WUk8= github.com/cucumber/messages/go/v21 v21.0.1 h1:wzA0LxwjlWQYZd32VTlAVDTkW6inOFmSM+RuOwHZiMI= github.com/cucumber/messages/go/v21 v21.0.1/go.mod h1:zheH/2HS9JLVFukdrsPWoPdmUtmYQAQPLk7w5vWsk5s= +github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4= github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -167,16 +176,19 @@ github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0/go.mod h1:ZXNYxsqcloTdSy/rNShjY github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= github.com/deepmap/oapi-codegen v1.8.2 h1:SegyeYGcdi0jLLrpbCMoJxnUUn8GBXHsvr4rbzjuhfU= github.com/deepmap/oapi-codegen v1.8.2/go.mod h1:YLgSKSDv/bZQB7N4ws6luhozi3cEdRktEqrX88CvjIw= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= -github.com/docker/docker v28.3.3+incompatible h1:Dypm25kh4rmk49v1eiVbsAtpAsYURjYkaKubwuBdxEI= -github.com/docker/docker v28.3.3+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= -github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= +github.com/docker/cli v27.4.1+incompatible h1:VzPiUlRJ/xh+otB75gva3r05isHMo5wXDfPRi5/b4hI= +github.com/docker/cli v27.4.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/docker v28.5.1+incompatible h1:Bm8DchhSD2J6PsFzxC35TZo4TLGR2PdW/E69rU45NhM= +github.com/docker/docker v28.5.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.6.0 h1:LlMG9azAe1TqfR7sO+NJttz1gy6KO7VJBh+pMmjSD94= +github.com/docker/go-connections v0.6.0/go.mod h1:AahvXYshr6JgfUJGdDCs2b5EZG/vmaMAntpSFH5BFKE= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -github.com/ebitengine/purego v0.8.4 h1:CF7LEKg5FFOsASUj0+QwaXf8Ht6TlFxg09+S9wz0omw= -github.com/ebitengine/purego v0.8.4/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= +github.com/ebitengine/purego v0.9.0 h1:mh0zpKBIXDceC63hpvPuGLiJ8ZAa3DfrFTudmfi8A4k= +github.com/ebitengine/purego v0.9.0/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= github.com/emicklei/dot v1.6.2 h1:08GN+DD79cy/tzN6uLCT84+2Wk9u+wvqP+Hkx/dIR8A= github.com/emicklei/dot v1.6.2/go.mod h1:DeV7GvQtIw4h2u73RKBkkFdvVAz0D9fzeJrgPW6gy/s= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= @@ -220,8 +232,13 @@ github.com/gagliardetto/treeout v0.1.4 h1:ozeYerrLCmCubo1TcIjFiOWTTGteOOHND1twdF github.com/gagliardetto/treeout v0.1.4/go.mod h1:loUefvXTrlRG5rYmJmExNryyBRh8f89VZhmMOyCyqok= github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 h1:f6D9Hr8xV8uYKlyuj8XIruxlh9WjVjdh1gIicAS7ays= github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= +github.com/getkin/kin-openapi v0.61.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4= +github.com/getkin/kin-openapi v0.133.0 h1:pJdmNohVIJ97r4AUFtEXRXwESr8b0bD721u/Tz6k8PQ= +github.com/getkin/kin-openapi v0.133.0/go.mod h1:boAciF6cXk5FhPqe/NQeBTeenbjqU4LhWBf09ILVvWE= github.com/getsentry/sentry-go v0.27.0 h1:Pv98CIbtB3LkMWmXi4Joa5OOcwbmnX88sF5qbK3r3Ps= github.com/getsentry/sentry-go v0.27.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-chi/chi/v5 v5.0.0/go.mod h1:BBug9lr0cqtdAhsu6R4AAdvufI0/XBzAQSsUqJpoZOs= github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= github.com/go-json-experiment/json v0.0.0-20250223041408-d3c622f1b874 h1:F8d1AJ6M9UQCavhwmO6ZsrYLfG8zVFWfEfMS2MXPkSY= @@ -237,6 +254,12 @@ github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= +github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= +github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= +github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= @@ -245,8 +268,8 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/validator/v10 v10.28.0 h1:Q7ibns33JjyW48gHkuFT91qX48KG0ktULL6FgHdG688= github.com/go-playground/validator/v10 v10.28.0/go.mod h1:GoI6I1SjPBh9p7ykNE/yj3fFYbyDOpwMn5KXd+m2hUU= -github.com/go-resty/resty/v2 v2.16.3 h1:zacNT7lt4b8M/io2Ahj6yPypL7bqx9n1iprfQuodV+E= -github.com/go-resty/resty/v2 v2.16.3/go.mod h1:hkJtXbA2iKHzJheXYvQ8snQES5ZLGKMwQ07xAwp/fiA= +github.com/go-resty/resty/v2 v2.17.1 h1:x3aMpHK1YM9e4va/TMDRlusDDoZiQ+ViDu/WpA6xTM4= +github.com/go-resty/resty/v2 v2.17.1/go.mod h1:kCKZ3wWmwJaNc7S29BRtUhJwy7iqmn+2mLtQrOyQlVA= github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= @@ -263,6 +286,8 @@ github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1 github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI= github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang-jwt/jwt/v5 v5.3.1 h1:kYf81DTWFe7t+1VvL7eS+jKFVWaUnK9cB1qbwn63YCY= +github.com/golang-jwt/jwt/v5 v5.3.1/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -284,6 +309,7 @@ github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6 github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs= github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219/go.mod h1:/X8TswGSh1pIozq4ZwCfxS0WA5JGXguxk94ar/4c87Y= github.com/google/flatbuffers v25.2.10+incompatible h1:F3vclr7C3HpB1k9mxCGRMXq6FdUalZ6H/pNX4FP1v0Q= github.com/google/flatbuffers v25.2.10+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -300,9 +326,12 @@ github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/rpc v1.2.0 h1:WvvdC2lNeT1SP32zrIce5l0ECBfbAlmrmSBsuc57wfk= github.com/gorilla/rpc v1.2.0/go.mod h1:V4h9r+4sF5HnzqbwIez0fKSpANP0zlYd3qR7p36jkTQ= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= @@ -415,19 +444,22 @@ github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o= github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/juju/gnuflag v0.0.0-20171113085948-2ce1bb71843d/go.mod h1:2PavIy+JPciBPrBUjwbNvtwB6RQlve+hkpll6QSNmOE= github.com/karalabe/hid v1.0.1-0.20240306101548-573246063e52 h1:msKODTL1m0wigztaqILOtla9HeW1ciscYG4xjLtvk5I= github.com/karalabe/hid v1.0.1-0.20240306101548-573246063e52/go.mod h1:qk1sX/IBgppQNcGCRoj90u6EGC056EBoIc1oEjCWla8= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= github.com/klauspost/compress v1.11.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= -github.com/klauspost/compress v1.18.1 h1:bcSGx7UbpBqMChDtsF28Lw6v/G94LPrrbMbdC3JH2co= -github.com/klauspost/compress v1.18.1/go.mod h1:ZQFFVG+MdnR0P+l6wpXgIL4NTtwiKIdBnrBd8Nrxr+0= +github.com/klauspost/compress v1.18.2 h1:iiPHWW0YrcFgpBYhsA6D1+fqHssJscY/Tm/y2Uqnapk= +github.com/klauspost/compress v1.18.2/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE= github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -443,6 +475,12 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/labstack/echo/v4 v4.2.1/go.mod h1:AA49e0DZ8kk5jTOOCKNuPR6oTnBS0dYiM4FW1e6jwpg= +github.com/labstack/echo/v4 v4.11.4 h1:vDZmA+qNeh1pd/cCkEicDMrjtrnMGQ1QFI9gWN1zGq8= +github.com/labstack/echo/v4 v4.11.4/go.mod h1:noh7EvLwqDsmh/X/HWKPUl1AjzJrhyptRyEbQJfxen8= +github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= +github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0= +github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU= github.com/leanovate/gopter v0.2.11 h1:vRjThO1EKPb/1NsDXuDrzldR28RLkBflWYcU9CvzWu4= github.com/leanovate/gopter v0.2.11/go.mod h1:aK3tzZP/C+p1m3SPRE4SYZFGP7jjkuSI4f7Xvpt0S9c= github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= @@ -455,16 +493,22 @@ github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8= github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= -github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35 h1:PpXWgLPs+Fqr325bN2FD2ISlRRztXibcX6e8f5FR5Dc= -github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg= +github.com/lufia/plan9stats v0.0.0-20251013123823-9fd1530e3ec3 h1:PwQumkgq4/acIiZhtifTV5OUqqiP82UAl0h87xj/l9k= +github.com/lufia/plan9stats v0.0.0-20251013123823-9fd1530e3ec3/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg= github.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE= github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4= github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= github.com/marcboeker/go-duckdb v1.8.5 h1:tkYp+TANippy0DaIOP5OEfBEwbUINqiFqgwMQ44jME0= github.com/marcboeker/go-duckdb v1.8.5/go.mod h1:6mK7+WQE4P4u5AFLvVBmhFxY5fvhymFptghgJX6B+/8= +github.com/matryer/moq v0.0.0-20190312154309-6cfb0558e1bd/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ= github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= +github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= @@ -472,6 +516,8 @@ github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHP github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= @@ -514,6 +560,8 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw= +github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/mostynb/zstdpool-freelist v0.0.0-20201229113212-927304c0c3b1 h1:mPMvm6X6tf4w8y7j9YIt6V9jfWhL6QlbEc7CCmeQlWk= @@ -522,9 +570,17 @@ github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/noders-team/dazl-client/v8 v8.7.1-2 h1:a8PXw76lE6ozb/MVW/Akw56qXrPM6xUnpz/rT2MXzTA= +github.com/noders-team/dazl-client/v8 v8.7.1-2/go.mod h1:q1KevCJ8FpH8je2MnnjN8/QUfhstB4fKpyKyqDtqFh0= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/oapi-codegen/runtime v1.1.2 h1:P2+CubHq8fO4Q6fV1tqDBZHCwpVpvPg7oKiYzQgXIyI= +github.com/oapi-codegen/runtime v1.1.2/go.mod h1:SK9X900oXmPWilYR5/WKPzt3Kqxn/uS/+lbpREv+eCg= +github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 h1:G7ERwszslrBzRxj//JalHPu/3yz+De2J+4aLtSRlHiY= +github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037/go.mod h1:2bpvgLBZEtENV5scfDFEtB/5+1M4hkQhDQrccEJ/qGw= +github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 h1:bQx3WeLcUWy+RletIKwUIt4x3t8n2SxavmoclizMb8c= +github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90/go.mod h1:y5+oSEHCPT/DGrS++Wc/479ERge0zTFxaF8PbGKcg2o= github.com/oklog/run v1.2.0 h1:O8x3yXwah4A73hJdlrwo/2X6J62gE5qTMusH0dvz60E= github.com/oklog/run v1.2.0/go.mod h1:mgDbKRSwPhJfesJ4PntqFUbKQRZ50NgmZTSPlFA0YFk= github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= @@ -543,17 +599,23 @@ github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7J github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= -github.com/onsi/gomega v1.34.2 h1:pNCwDkzrsv7MS9kpaQvVb1aVLahQXyJ/Tv5oAZMI3i8= -github.com/onsi/gomega v1.34.2/go.mod h1:v1xfxRgk0KIsG+QOdm7p8UosrOzPYRo60fd3B/1Dukc= +github.com/onsi/gomega v1.36.2 h1:koNYke6TVk6ZmnyHrCXba/T/MoLBXFjeC1PtvYgw0A8= +github.com/onsi/gomega v1.36.2/go.mod h1:DdwyADRjrc825LhMEkD76cHR5+pUnjhUN8GlHlRPHzY= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040= github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M= +github.com/opencontainers/runc v1.2.3 h1:fxE7amCzfZflJO2lHXf4y/y8M1BoAqp+FVmG19oYB80= +github.com/opencontainers/runc v1.2.3/go.mod h1:nSxcWUydXrsBZVYNSkTjoQ/N6rcyTtn+1SD5D4+kRIM= github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= +github.com/ory/dockertest/v3 v3.12.0 h1:3oV9d0sDzlSQfHtIaB5k6ghUCVMVLpAY8hwrqoCyRCw= +github.com/ory/dockertest/v3 v3.12.0/go.mod h1:aKNDTva3cp8dwOWwb9cWuX84aH5akkxXRvO7KCwWVjE= github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= +github.com/perimeterx/marshmallow v1.1.5 h1:a2LALqQ1BlHM8PZblsDdidgv1mWi1DgC2UmX50IvK2s= +github.com/perimeterx/marshmallow v1.1.5/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw= github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7 h1:oYW+YCJ1pachXTQmzR3rNLYGGz4g/UgFcjb28p/viDM= github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0= github.com/pierrec/lz4/v4 v4.1.22 h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU= @@ -605,11 +667,11 @@ github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7 github.com/rs/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA= github.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= -github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= +github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0= github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= -github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8= -github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= +github.com/rs/zerolog v1.34.0 h1:k43nTLIwcTVQAncfCw4KZ2VY6ukYoZaBPNOE8txlOeY= +github.com/rs/zerolog v1.34.0/go.mod h1:bJsvje4Z08ROH4Nhs5iH600c3IkWhwp44iRc54W6wYQ= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/samber/lo v1.52.0 h1:Rvi+3BFHES3A8meP33VPAxiBZX/Aws5RxrschYGjomw= @@ -621,8 +683,8 @@ github.com/scylladb/go-reflectx v1.0.1 h1:b917wZM7189pZdlND9PbIJ6NQxfDPfBvUaQ7cj github.com/scylladb/go-reflectx v1.0.1/go.mod h1:rWnOfDIRWBGN0miMLIcoPt/Dhi2doCMZqwMCJ3KupFc= github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI= github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= -github.com/shirou/gopsutil/v4 v4.25.5 h1:rtd9piuSMGeU8g1RMXjZs9y9luK5BwtnG7dZaQUJAsc= -github.com/shirou/gopsutil/v4 v4.25.5/go.mod h1:PfybzyydfZcN+JMMjkF6Zb8Mq1A/VcogFFg7hj50W9c= +github.com/shirou/gopsutil/v4 v4.25.9 h1:JImNpf6gCVhKgZhtaAHJ0serfFGtlfIlSC08eaKdTrU= +github.com/shirou/gopsutil/v4 v4.25.9/go.mod h1:gxIxoC+7nQRwUl/xNhutXlD8lq+jxTgpIkEf3rADHL8= github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= @@ -634,8 +696,8 @@ github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMB github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/smartcontractkit/chain-selectors v1.0.89 h1:L9oWZGqQXWyTPnC6ODXgu3b0DFyLmJ9eHv+uJrE9IZY= -github.com/smartcontractkit/chain-selectors v1.0.89/go.mod h1:qy7whtgG5g+7z0jt0nRyii9bLND9m15NZTzuQPkMZ5w= +github.com/smartcontractkit/chain-selectors v1.0.91 h1:Aip7IZTv40RtbHgZ9mTjm5KyhYrpPefG7iVMzLZ27M4= +github.com/smartcontractkit/chain-selectors v1.0.91/go.mod h1:qy7whtgG5g+7z0jt0nRyii9bLND9m15NZTzuQPkMZ5w= github.com/smartcontractkit/chainlink-aptos v0.0.0-20251024142440-51f2ad2652a2 h1:vGdeMwHO3ow88HvxfhA4DDPYNY0X9jmdux7L83UF/W8= github.com/smartcontractkit/chainlink-aptos v0.0.0-20251024142440-51f2ad2652a2/go.mod h1:iteU0WORHkArACVh/HoY/1bipV4TcNcJdTmom9uIT0E= github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20260129103204-4c8453dd8139 h1:jkChf04hhdiMBApbb+lLDxHMY62Md6UeM7v++GSw3K8= @@ -646,6 +708,8 @@ github.com/smartcontractkit/chainlink-common v0.9.6-0.20260114142648-bd9e1b483e9 github.com/smartcontractkit/chainlink-common v0.9.6-0.20260114142648-bd9e1b483e96/go.mod h1:DAwaVSiQMgAsCjHa8nOnIAM9GixuIQWsgEZFGpf3JxE= github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.10 h1:FJAFgXS9oqASnkS03RE1HQwYQQxrO4l46O5JSzxqLgg= github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.10/go.mod h1:oiDa54M0FwxevWwyAX773lwdWvFYYlYHHQV1LQ5HpWY= +github.com/smartcontractkit/chainlink-deployments-framework v0.78.0 h1:Wh2DXmYBnTunJ5+IqsGTLe5qFdbkK9nmgKKvF86Sagc= +github.com/smartcontractkit/chainlink-deployments-framework v0.78.0/go.mod h1:euAnbxZWRV78+xY/1mi23v+dzU+vhiD9/pJcs/Cyf/k= github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20251124151448-0448aefdaab9 h1:QRWXJusIj/IRY5Pl3JclNvDre0cZPd/5NbILwc4RV2M= github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20251124151448-0448aefdaab9/go.mod h1:jUC52kZzEnWF9tddHh85zolKybmLpbQ1oNA4FjOHt1Q= github.com/smartcontractkit/chainlink-protos/linking-service/go v0.0.0-20251002192024-d2ad9222409b h1:QuI6SmQFK/zyUlVWEf0GMkiUYBPY4lssn26nKSd/bOM= @@ -666,6 +730,9 @@ github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY= github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo= github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0= +github.com/stackman27/go-daml v0.0.0-20260129035354-bee9c994446f h1:I79FWYle5/t1QxAZHClHc8OWJoKeUc97PNEX0XV9meM= +github.com/stackman27/go-daml v0.0.0-20260129035354-bee9c994446f/go.mod h1:yi458NGE4dlDOhlyCZvQ2XgsIOdHHvepwoHRgEusbo8= github.com/stephenlacy/go-ethereum-hdwallet v0.0.0-20230913225845-a4fa94429863 h1:ba4VRWSkRzgdP5hB5OxexIzBXZbSwgcw8bEu06ivGQI= github.com/stephenlacy/go-ethereum-hdwallet v0.0.0-20230913225845-a4fa94429863/go.mod h1:oPTjPNrRucLv9mU27iNPj6n0CWWcNFhoXFOLVGJwHCA= github.com/streamingfast/logging v0.0.0-20230608130331-f22c91403091 h1:RN5mrigyirb8anBEtdjtHFIufXdacyTi6i4KBfeNXeo= @@ -698,12 +765,13 @@ github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d h1:vfofYNRScrDd github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48= github.com/test-go/testify v1.1.4 h1:Tf9lntrKUMHiXQ07qBScBTSA0dhYQlu83hswqelv1iE= github.com/test-go/testify v1.1.4/go.mod h1:rH7cfJo/47vWGdi4GPj16x3/t1xGOj2YxzmNQzk2ghU= -github.com/testcontainers/testcontainers-go v0.38.0 h1:d7uEapLcv2P8AvH8ahLqDMMxda2W9gQN1nRbHS28HBw= -github.com/testcontainers/testcontainers-go v0.38.0/go.mod h1:C52c9MoHpWO+C4aqmgSU+hxlR5jlEayWtgYrb8Pzz1w= +github.com/testcontainers/testcontainers-go v0.39.0 h1:uCUJ5tA+fcxbFAB0uP3pIK3EJ2IjjDUHFSZ1H1UxAts= +github.com/testcontainers/testcontainers-go v0.39.0/go.mod h1:qmHpkG7H5uPf/EvOORKvS6EuDkBUPE3zpVGaH9NL7f8= github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY= github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= -github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/match v1.2.0 h1:0pt8FlkOwjN2fPt4bIl4BoNxb98gGHN2ObFEDkrfZnM= +github.com/tidwall/match v1.2.0/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= @@ -719,11 +787,23 @@ github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6Kllzaw github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fastjson v1.6.4 h1:uAUNq9Z6ymTgGhcm0UynUAB6tlbakBrz6CQFax3BXVQ= github.com/valyala/fastjson v1.6.4/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY= +github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= +github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= +github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= +github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc= github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw= github.com/wlynxg/anet v0.0.3/go.mod h1:eay5PRQr7fIVAMbTbchTnO9gG65Hg/uYGdc7mguHxoA= +github.com/woodsbury/decimal128 v1.3.0 h1:8pffMNWIlC0O5vbyHWFZAt5yWvWcrHA+3ovIIjVWss0= +github.com/woodsbury/decimal128 v1.3.0/go.mod h1:C5UTmyTjW3JftjUFzOVhC20BEQa2a4ZKOB5I6Zjb+ds= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= +github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= +github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= +github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4= github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM= github.com/xssnick/tonutils-go v1.14.1 h1:zV/iVYl/h3hArS+tPsd9XrSFfGert3r21caMltPSeHg= @@ -745,8 +825,8 @@ go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0 h1:YH4g8lQroajqUwWbq/tr2QX1JFmEXaDLgG+ew9bLMWo= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0/go.mod h1:fvPi2qXDqFs8M4B4fmJhE92TyQs9Ydjlg3RvfUp+NbQ= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 h1:sbiXRNDSWJOTobXh5HyQKjq6wUC5tNybqjIqDpAY4CU= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0/go.mod h1:69uWxva0WgAA/4bu2Yy70SLDBwZXuQ6PbBpbsa5iZrQ= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0 h1:RbKq8BG0FI8OiXhBfcRtqqHcZcka+gU3cskNuf05R18= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0/go.mod h1:h06DGIukJOevXaj/xrNjhi/2098RZzcLTbc0jDAUbsg= go.opentelemetry.io/otel v1.6.3/go.mod h1:7BgNga5fNlF/iZjG06hM3yofffp0ofKCDwSXx1GC4dI= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= @@ -821,7 +901,9 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= @@ -863,7 +945,9 @@ golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210331212208-0fccb6fa2b5c/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= @@ -912,11 +996,13 @@ golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -984,6 +1070,7 @@ golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= @@ -1023,8 +1110,8 @@ google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQ google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM= -google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig= +google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc= +google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= diff --git a/sdk/canton/configurer.go b/sdk/canton/configurer.go new file mode 100644 index 000000000..edf7d3c43 --- /dev/null +++ b/sdk/canton/configurer.go @@ -0,0 +1,140 @@ +package canton + +import ( + "context" + "fmt" + "strings" + + "github.com/google/uuid" + "github.com/noders-team/go-daml/pkg/client" + "github.com/noders-team/go-daml/pkg/model" + cselectors "github.com/smartcontractkit/chain-selectors" + + cantontypes "github.com/noders-team/go-daml/pkg/types" + "github.com/smartcontractkit/chainlink-canton/bindings/mcms" + "github.com/smartcontractkit/mcms/sdk" + "github.com/smartcontractkit/mcms/types" +) + +var _ sdk.Configurer = &Configurer{} + +type Configurer struct { + client *client.DamlBindingClient + userId string + party string +} + +func NewConfigurer(client *client.DamlBindingClient, userId string, party string) (*Configurer, error) { + return &Configurer{ + client: client, + userId: userId, + party: party, + }, nil +} + +func (c Configurer) SetConfig(ctx context.Context, mcmsAddr string, cfg *types.Config, clearRoot bool) (types.TransactionResult, error) { + groupQuorum, groupParents, signerAddresses, signerGroups, err := sdk.ExtractSetConfigInputs(cfg) + if err != nil { + return types.TransactionResult{}, fmt.Errorf("unable to extract set config inputs: %w", err) + } + + signers := make([]mcms.SignerInfo, len(signerAddresses)) + for i, addr := range signerAddresses { + signers[i] = mcms.SignerInfo{ + SignerAddress: cantontypes.TEXT(addr.String()), + SignerGroup: cantontypes.INT64(signerGroups[i]), + SignerIndex: cantontypes.INT64(i), + } + } + + groupQuorumsTyped := make([]cantontypes.INT64, len(groupQuorum)) + for i, q := range groupQuorum { + groupQuorumsTyped[i] = cantontypes.INT64(q) + } + + groupParentsTyped := make([]cantontypes.INT64, len(groupParents)) + for i, p := range groupParents { + groupParentsTyped[i] = cantontypes.INT64(p) + } + + input := mcms.SetConfig{ + NewSigners: signers, + NewGroupQuorums: groupQuorumsTyped, + NewGroupParents: groupParentsTyped, + ClearRoot: cantontypes.BOOL(clearRoot), + } + // Build exercise command using generated bindings + mcmsContract := mcms.MCMS{} + exerciseCmd := mcmsContract.SetConfig(mcmsAddr, input) + + // List known packages to find the package ID for mcms + ListKnownPackagesResp, err := c.client.PackageMng.ListKnownPackages(ctx) + if err != nil { + return types.TransactionResult{}, fmt.Errorf("failed to list known packages: %w", err) + } + + var mcmsPkgID string + for _, p := range ListKnownPackagesResp { + if strings.Contains(strings.ToLower(p.Name), "mcms") { + mcmsPkgID = p.PackageID + break + } + } + if mcmsPkgID == "" { + return types.TransactionResult{}, fmt.Errorf("failed to find mcms package") + } + + commandID := uuid.Must(uuid.NewUUID()).String() + cmds := &model.SubmitAndWaitRequest{ + Commands: &model.Commands{ + WorkflowID: "mcms-set-config", + UserID: c.userId, + CommandID: commandID, + ActAs: []string{c.party}, + Commands: []*model.Command{{ + Command: &model.ExerciseCommand{ + TemplateID: fmt.Sprintf("%s:%s:%s", mcmsPkgID, "MCMS.Main", "MCMS"), + ContractID: exerciseCmd.ContractID, + Choice: exerciseCmd.Choice, + Arguments: exerciseCmd.Arguments, + }, + }}, + }, + } + + submitResp, err := c.client.CommandService.SubmitAndWaitForTransaction(ctx, cmds) + if err != nil { + return types.TransactionResult{}, fmt.Errorf("failed to set config: %w", err) + } + + // Extract NEW MCMS CID from Created event + newMCMSContractID := "" + newMCMSTemplateID := "" + for _, ev := range submitResp.Transaction.Events { + if ev.Created == nil { + continue + } + normalized := NormalizeTemplateKey(ev.Created.TemplateID) + if normalized == MCMSTemplateKey { + newMCMSContractID = ev.Created.ContractID + newMCMSTemplateID = ev.Created.TemplateID + + break + } + } + + if newMCMSContractID == "" { + return types.TransactionResult{}, fmt.Errorf("set-config tx had no Created MCMS event; refusing to continue with old CID=%s", mcmsAddr) + } + + return types.TransactionResult{ + Hash: "tx.Digest", + ChainFamily: cselectors.FamilyCanton, + RawData: map[string]any{ + "NewMCMSContractID": newMCMSContractID, + "NewMCMSTemplateID": newMCMSTemplateID, + "RawTx": submitResp, + }, + }, nil + +} diff --git a/sdk/canton/helpers.go b/sdk/canton/helpers.go new file mode 100644 index 000000000..78ec82d8f --- /dev/null +++ b/sdk/canton/helpers.go @@ -0,0 +1,17 @@ +package canton + +import "strings" + +const ( + MCMSTemplateKey = "MCMS.Main:MCMS" +) + +func NormalizeTemplateKey(tid string) string { + tid = strings.TrimPrefix(tid, "#") + parts := strings.Split(tid, ":") + if len(parts) < 3 { + return tid + } + + return parts[len(parts)-2] + ":" + parts[len(parts)-1] +} diff --git a/taskfiles/test/Taskfile.yml b/taskfiles/test/Taskfile.yml index 5289ec2b5..f4468e25d 100644 --- a/taskfiles/test/Taskfile.yml +++ b/taskfiles/test/Taskfile.yml @@ -57,6 +57,13 @@ tasks: cmds: - CTF_CONFIGS=$CTF_CONFIGS go test -v -tags=e2e -test.run TestTONSuite {{.CLI_ARGS}} ./e2e/tests... + e2e:canton: + desc: "Run Canton e2e tests" + env: + CTF_CONFIGS: '{{ .CTF_CONFIGS | default "../config.canton.toml" }}' + cmds: + - CTF_CONFIGS=$CTF_CONFIGS go test -v -tags=e2e -test.run TestCantonSuite {{.CLI_ARGS}} ./e2e/tests... + coverage: desc: "Run unit test suite with coverage" cmds: From 7c75c3108e9a497df27571f76239a5d61fa1622d Mon Sep 17 00:00:00 2001 From: RodrigoAD <15104916+RodrigoAD@users.noreply.github.com> Date: Fri, 6 Feb 2026 16:05:31 +0100 Subject: [PATCH 2/6] tidy mod --- go.mod | 10 +++------- go.sum | 23 +++++++++++++++++------ 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/go.mod b/go.mod index f186ebf06..f71ce75e7 100644 --- a/go.mod +++ b/go.mod @@ -27,17 +27,13 @@ require ( github.com/samber/lo v1.52.0 github.com/smartcontractkit/chain-selectors v1.0.91 github.com/smartcontractkit/chainlink-aptos v0.0.0-20251024142440-51f2ad2652a2 + github.com/smartcontractkit/chainlink-canton v0.0.0-20260202190435-99f4e19d8d2e + github.com/smartcontractkit/chainlink-canton/integration-tests v0.0.0-20260202190435-99f4e19d8d2e github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20260129103204-4c8453dd8139 github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings v0.0.0-20260129103204-4c8453dd8139 github.com/smartcontractkit/chainlink-sui v0.0.0-20260205175622-33e65031f9a9 - github.com/smartcontractkit/chainlink-testing-framework/framework v0.12.1 - github.com/smartcontractkit/chainlink-ton v0.0.0-20260204205804-642f6ebe4e7e - github.com/smartcontractkit/chainlink-canton v0.0.0-20260202190435-99f4e19d8d2e - github.com/smartcontractkit/chainlink-canton/integration-tests v0.0.0-20260202190435-99f4e19d8d2e - github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20260119161343-499241536dea - github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings v0.0.0-20250908144012-8184001834b5 github.com/smartcontractkit/chainlink-testing-framework/framework v0.13.9 - github.com/smartcontractkit/chainlink-ton v0.0.0-20260130134551-8ebf4f73b668 + github.com/smartcontractkit/chainlink-ton v0.0.0-20260204205804-642f6ebe4e7e github.com/smartcontractkit/freeport v0.1.3-0.20250716200817-cb5dfd0e369e github.com/spf13/cast v1.10.0 github.com/stretchr/testify v1.11.1 diff --git a/go.sum b/go.sum index 511be8c04..9283027a5 100644 --- a/go.sum +++ b/go.sum @@ -52,6 +52,7 @@ github.com/blendle/zapdriver v1.3.1 h1:C3dydBOWYRiOk+B8X9IVZ5IOe+7cl+tGOexN4QqHf github.com/blendle/zapdriver v1.3.1/go.mod h1:mdXfREi6u5MArG4j9fewC+FGnXaBR+T4Ox4J2u4eHCc= github.com/block-vision/sui-go-sdk v1.1.4 h1:1PPgYxQjo1P9UCgFOPTvDCuGEglRL32NwjKPulR4FQk= github.com/block-vision/sui-go-sdk v1.1.4/go.mod h1:t8mWASwfyv+EyqHGO9ZrcDiCJWGOFEXqq50TMJ8GQco= +github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w= github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= github.com/btcsuite/btcd v0.22.0-beta.0.20220111032746-97732e52810c/go.mod h1:tjmYdS6MLJ5/s0Fj4DbLgSbDHbEqLJrtnHecBFkdz5M= github.com/btcsuite/btcd v0.23.5-0.20231215221805-96c9fd8078fd/go.mod h1:nm3Bko6zh6bWP60UxwoT5LzdGJsQJaPo6HjduXq9p6A= @@ -700,12 +701,16 @@ github.com/smartcontractkit/chain-selectors v1.0.91 h1:Aip7IZTv40RtbHgZ9mTjm5Kyh github.com/smartcontractkit/chain-selectors v1.0.91/go.mod h1:qy7whtgG5g+7z0jt0nRyii9bLND9m15NZTzuQPkMZ5w= github.com/smartcontractkit/chainlink-aptos v0.0.0-20251024142440-51f2ad2652a2 h1:vGdeMwHO3ow88HvxfhA4DDPYNY0X9jmdux7L83UF/W8= github.com/smartcontractkit/chainlink-aptos v0.0.0-20251024142440-51f2ad2652a2/go.mod h1:iteU0WORHkArACVh/HoY/1bipV4TcNcJdTmom9uIT0E= +github.com/smartcontractkit/chainlink-canton v0.0.0-20260202190435-99f4e19d8d2e h1:SdU728rHhuq7+dnfUiEk3R0lOeWNFs+zfI2iws393w8= +github.com/smartcontractkit/chainlink-canton v0.0.0-20260202190435-99f4e19d8d2e/go.mod h1:IGY2/0rDoFyyGZvZ4cKb/pFzQ4h1lrgxoA4hHW2TdlI= +github.com/smartcontractkit/chainlink-canton/integration-tests v0.0.0-20260202190435-99f4e19d8d2e h1:g26x/dVdvH0kO4XK3iI4v308x9uJHMr7gwt/DPRSk3c= +github.com/smartcontractkit/chainlink-canton/integration-tests v0.0.0-20260202190435-99f4e19d8d2e/go.mod h1:8dyNC//HgLzGPm5ATPsCQ3PJ4DParxD3oaQiluzU3jw= github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20260129103204-4c8453dd8139 h1:jkChf04hhdiMBApbb+lLDxHMY62Md6UeM7v++GSw3K8= github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20260129103204-4c8453dd8139/go.mod h1:wuhagkM/lU0GbV2YcrROOH0GlsfXJYwm6qmpa4CK70w= github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings v0.0.0-20260129103204-4c8453dd8139 h1:tw3K4UkH5XfW5SoyYkvAlbzrccoGSLdz/XkxD6nyGC8= github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings v0.0.0-20260129103204-4c8453dd8139/go.mod h1:1WcontO9PeuKdUf5HXfs3nuICtzUvFNnyCmrHkTCF9Y= -github.com/smartcontractkit/chainlink-common v0.9.6-0.20260114142648-bd9e1b483e96 h1:ZnBBOLyMLJjgQQm7WRJl8sA9Q2RhwagJ+WR62VnA3MY= -github.com/smartcontractkit/chainlink-common v0.9.6-0.20260114142648-bd9e1b483e96/go.mod h1:DAwaVSiQMgAsCjHa8nOnIAM9GixuIQWsgEZFGpf3JxE= +github.com/smartcontractkit/chainlink-common v0.9.6-0.20260114190811-74301cd99dc3 h1:VINIWIvYhgbGJpaI7O3aBuBOAZgMEN6BGA61zQIqvFw= +github.com/smartcontractkit/chainlink-common v0.9.6-0.20260114190811-74301cd99dc3/go.mod h1:DAwaVSiQMgAsCjHa8nOnIAM9GixuIQWsgEZFGpf3JxE= github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.10 h1:FJAFgXS9oqASnkS03RE1HQwYQQxrO4l46O5JSzxqLgg= github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.10/go.mod h1:oiDa54M0FwxevWwyAX773lwdWvFYYlYHHQV1LQ5HpWY= github.com/smartcontractkit/chainlink-deployments-framework v0.78.0 h1:Wh2DXmYBnTunJ5+IqsGTLe5qFdbkK9nmgKKvF86Sagc= @@ -716,10 +721,14 @@ github.com/smartcontractkit/chainlink-protos/linking-service/go v0.0.0-202510021 github.com/smartcontractkit/chainlink-protos/linking-service/go v0.0.0-20251002192024-d2ad9222409b/go.mod h1:qSTSwX3cBP3FKQwQacdjArqv0g6QnukjV4XuzO6UyoY= github.com/smartcontractkit/chainlink-sui v0.0.0-20260205175622-33e65031f9a9 h1:KyPROV+v7P8VdiU7JhVuGLcDlEBsURSpQmSCgNBTY+s= github.com/smartcontractkit/chainlink-sui v0.0.0-20260205175622-33e65031f9a9/go.mod h1:KpEWZJMLwbdMHeHQz9rbkES0vRrx4nk6OQXyhlHb9/8= -github.com/smartcontractkit/chainlink-testing-framework/framework v0.12.1 h1:Ld3OrOQfLubJ+os0/oau2V6RISgsEdBg+Q002zkgXpQ= -github.com/smartcontractkit/chainlink-testing-framework/framework v0.12.1/go.mod h1:r6KXRM1u9ch5KFR2jspkgtyWEC1X+gxPCL8mR63U990= +github.com/smartcontractkit/chainlink-testing-framework/framework v0.13.9 h1:V4Uk2UJqySd+7jwcRuY2l0Xq6ni4zr52C9I8TawX3nM= +github.com/smartcontractkit/chainlink-testing-framework/framework v0.13.9/go.mod h1:RAr+u340HtgzqHcZhAR7qi3ILgaJmh3nNRqS9nOms6E= github.com/smartcontractkit/chainlink-ton v0.0.0-20260204205804-642f6ebe4e7e h1:0tN41HRIrNAVr5Chr8xynwpJNJaYMqGxqlIu+E7SOG8= github.com/smartcontractkit/chainlink-ton v0.0.0-20260204205804-642f6ebe4e7e/go.mod h1:IZvH2r16xcQvVLB7AtjU112wnHfEku+29OlI1vCQHCQ= +github.com/smartcontractkit/chainlink-tron/relayer v0.0.11-0.20250908203554-5bd9d2fe9513 h1:XRNxgcNqagXu6e4smJuS1crRK5cUAcCVd7u+iLduHDM= +github.com/smartcontractkit/chainlink-tron/relayer v0.0.11-0.20250908203554-5bd9d2fe9513/go.mod h1:ccjEgNeqOO+bjPddnL4lUrNLzyCvGCxgBjJdhFX3wa8= +github.com/smartcontractkit/chainlink-tron/relayer/gotron-sdk v0.0.5-0.20251014120029-d73d15cc23f7 h1:qPGcryHOEipripujMtsip++fmVbJhyqO6eAGEq85r48= +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.20250716200817-cb5dfd0e369e h1:Hv9Mww35LrufCdM9wtS9yVi/rEWGI1UnjHbcKKU0nVY= github.com/smartcontractkit/freeport v0.1.3-0.20250716200817-cb5dfd0e369e/go.mod h1:T4zH9R8R8lVWKfU7tUvYz2o2jMv1OpGCdpY2j2QZXzU= github.com/smartcontractkit/grpc-proxy v0.0.0-20240830132753-a7e17fec5ab7 h1:12ijqMM9tvYVEm+nR826WsrNi6zCKpwBhuApq127wHs= @@ -1057,6 +1066,8 @@ golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE= golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8= +golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE= golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -1102,8 +1113,8 @@ google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEY google.golang.org/genproto v0.0.0-20210401141331-865547bb08e2/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= google.golang.org/genproto/googleapis/api v0.0.0-20260114163908-3f89685c29c3 h1:X9z6obt+cWRX8XjDVOn+SZWhWe5kZHm46TThU9j+jss= google.golang.org/genproto/googleapis/api v0.0.0-20260114163908-3f89685c29c3/go.mod h1:dd646eSK+Dk9kxVBl1nChEOhJPtMXriCcVb4x3o6J+E= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251222181119-0a764e51fe1b h1:Mv8VFug0MP9e5vUxfBcE3vUkV6CImK3cMNMIDFjmzxU= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251222181119-0a764e51fe1b/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260114163908-3f89685c29c3 h1:C4WAdL+FbjnGlpp2S+HMVhBeCq2Lcib4xZqfPNF6OoQ= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260114163908-3f89685c29c3/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= From a28d73a24be1ab6fef2196baedce57d72e9e1b86 Mon Sep 17 00:00:00 2001 From: Rodrigo Ariza <15104916+RodrigoAD@users.noreply.github.com> Date: Fri, 6 Feb 2026 16:26:20 +0100 Subject: [PATCH 3/6] Bump canton (#612) --- e2e/tests/canton/common.go | 11 +-- go.mod | 59 ++++++++-------- go.sum | 137 +++++++++++++++++++------------------ 3 files changed, 106 insertions(+), 101 deletions(-) diff --git a/e2e/tests/canton/common.go b/e2e/tests/canton/common.go index b57600247..1f15a5156 100644 --- a/e2e/tests/canton/common.go +++ b/e2e/tests/canton/common.go @@ -96,10 +96,11 @@ func (s *TestSuite) createMCMS(ctx context.Context, participant testhelpers.Part // Create MCMS contract mcmsContract := mcms.MCMS{ - Owner: types.PARTY(participant.Party), - Role: role, - ChainId: types.INT64(chainId), - McmsId: types.TEXT(mcmsId), + Owner: types.PARTY(participant.Party), + InstanceId: types.TEXT(mcmsId), + Role: role, + ChainId: types.INT64(chainId), + McmsId: types.TEXT(mcmsId), Config: mcms.MultisigConfig{ Signers: []mcms.SignerInfo{}, GroupQuorums: []types.INT64{types.INT64(1)}, @@ -118,7 +119,7 @@ func (s *TestSuite) createMCMS(ctx context.Context, participant testhelpers.Part UserID: participant.UserName, CommandID: commandID, ActAs: []string{participant.Party}, - Commands: []*model.Command{{Command: mcmsContract.CreateCommand()}}, + Commands: []*model.Command{{Command: mcmsContract.CreateCommandWithPackageID(s.packageIDs[0])}}, }, } diff --git a/go.mod b/go.mod index f71ce75e7..682484f8a 100644 --- a/go.mod +++ b/go.mod @@ -25,10 +25,10 @@ require ( github.com/karalabe/hid v1.0.1-0.20240306101548-573246063e52 github.com/noders-team/go-daml v0.6.0 github.com/samber/lo v1.52.0 - github.com/smartcontractkit/chain-selectors v1.0.91 - github.com/smartcontractkit/chainlink-aptos v0.0.0-20251024142440-51f2ad2652a2 - github.com/smartcontractkit/chainlink-canton v0.0.0-20260202190435-99f4e19d8d2e - github.com/smartcontractkit/chainlink-canton/integration-tests v0.0.0-20260202190435-99f4e19d8d2e + github.com/smartcontractkit/chain-selectors v1.0.92 + github.com/smartcontractkit/chainlink-aptos v0.0.0-20251212131933-e5e85d6fa4d3 + github.com/smartcontractkit/chainlink-canton v0.0.0-20260205203303-a74a56b3565d + github.com/smartcontractkit/chainlink-canton/integration-tests v0.0.0-20260205203303-a74a56b3565d github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20260129103204-4c8453dd8139 github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings v0.0.0-20260129103204-4c8453dd8139 github.com/smartcontractkit/chainlink-sui v0.0.0-20260205175622-33e65031f9a9 @@ -41,7 +41,7 @@ require ( github.com/zksync-sdk/zksync2-go v1.1.1-0.20250620124214-2c742ee399c6 go.uber.org/zap v1.27.1 golang.org/x/crypto v0.47.0 - golang.org/x/tools v0.40.0 + golang.org/x/tools v0.41.0 gotest.tools/v3 v3.5.2 ) @@ -67,10 +67,10 @@ require ( github.com/btcsuite/btcd/btcec/v2 v2.3.4 // indirect github.com/btcsuite/btcd/btcutil v1.1.6 // indirect github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0 // indirect - github.com/btcsuite/btcutil v1.0.2 // indirect + github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce // indirect github.com/buger/jsonparser v1.1.1 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect - github.com/cenkalti/backoff/v5 v5.0.2 // indirect + github.com/cenkalti/backoff/v5 v5.0.3 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/cloudevents/sdk-go/binding/format/protobuf/v2 v2.16.1 // indirect github.com/cloudevents/sdk-go/v2 v2.16.1 // indirect @@ -96,7 +96,7 @@ require ( github.com/deckarep/golang-set/v2 v2.6.0 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect github.com/deepmap/oapi-codegen v1.8.2 // indirect - github.com/digital-asset/dazl-client/v8 v8.7.1 // indirect + github.com/digital-asset/dazl-client/v8 v8.8.0 // indirect github.com/distribution/reference v0.6.0 // indirect github.com/docker/docker v28.5.1+incompatible // indirect github.com/docker/go-connections v0.6.0 // indirect @@ -131,10 +131,11 @@ require ( github.com/golang/snappy v1.0.0 // indirect github.com/gorilla/rpc v1.2.0 // indirect github.com/gorilla/websocket v1.5.3 // indirect + github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc // indirect github.com/graph-gophers/graphql-go v1.5.0 // indirect github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1 // indirect github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.2 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 // indirect github.com/hashicorp/go-bexpr v0.1.10 // indirect github.com/hashicorp/go-hclog v1.6.3 // indirect github.com/hashicorp/go-plugin v1.7.0 // indirect @@ -160,7 +161,7 @@ require ( github.com/jpillora/backoff v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/compress v1.18.2 // indirect - github.com/klauspost/cpuid/v2 v2.2.10 // indirect + github.com/klauspost/cpuid/v2 v2.3.0 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/kr/text v0.2.0 // indirect github.com/leodido/go-urn v1.4.0 // indirect @@ -206,7 +207,7 @@ require ( github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect github.com/prometheus/client_golang v1.23.0 // indirect github.com/prometheus/client_model v0.6.2 // indirect - github.com/prometheus/common v0.65.0 // indirect + github.com/prometheus/common v1.20.99 // indirect github.com/prometheus/procfs v0.16.1 // indirect github.com/rivo/uniseg v0.4.7 // indirect github.com/rogpeppe/go-internal v1.14.1 // indirect @@ -220,14 +221,14 @@ require ( github.com/shopspring/decimal v1.4.0 // indirect github.com/sigurn/crc16 v0.0.0-20211026045750-20ab5afb07e3 // indirect github.com/sirupsen/logrus v1.9.3 // indirect - github.com/smartcontractkit/chainlink-common v0.9.6-0.20260114190811-74301cd99dc3 // indirect + github.com/smartcontractkit/chainlink-common v0.9.6-0.20260122165924-94e0fad14fe8 // indirect github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.10 // indirect - github.com/smartcontractkit/chainlink-deployments-framework v0.78.0 // indirect + github.com/smartcontractkit/chainlink-deployments-framework v0.79.0 // indirect github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20251124151448-0448aefdaab9 // indirect github.com/smartcontractkit/chainlink-protos/linking-service/go v0.0.0-20251002192024-d2ad9222409b // indirect - github.com/smartcontractkit/chainlink-tron/relayer v0.0.11-0.20250908203554-5bd9d2fe9513 // indirect + github.com/smartcontractkit/chainlink-tron/relayer v0.0.11-0.20251014143056-a0c6328c91e9 // indirect github.com/smartcontractkit/grpc-proxy v0.0.0-20240830132753-a7e17fec5ab7 // indirect - github.com/smartcontractkit/libocr v0.0.0-20250912173940-f3ab0246e23d // indirect + github.com/smartcontractkit/libocr v0.0.0-20251212213002-0a5e2f907dda // indirect github.com/stephenlacy/go-ethereum-hdwallet v0.0.0-20230913225845-a4fa94429863 // indirect github.com/streamingfast/logging v0.0.0-20230608130331-f22c91403091 // indirect github.com/stretchr/objx v0.5.2 // indirect @@ -250,33 +251,33 @@ require ( go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0 // indirect - go.opentelemetry.io/otel v1.38.0 // indirect + go.opentelemetry.io/otel v1.39.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.12.2 // indirect go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.12.2 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.36.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.36.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.36.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.36.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.36.0 // indirect go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.13.0 // indirect go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.36.0 // indirect go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.36.0 // indirect - go.opentelemetry.io/otel/log v0.13.0 // indirect - go.opentelemetry.io/otel/metric v1.38.0 // indirect - go.opentelemetry.io/otel/sdk v1.38.0 // indirect - go.opentelemetry.io/otel/sdk/log v0.13.0 // indirect - go.opentelemetry.io/otel/sdk/metric v1.38.0 // indirect - go.opentelemetry.io/otel/trace v1.38.0 // indirect - go.opentelemetry.io/proto/otlp v1.6.0 // indirect + go.opentelemetry.io/otel/log v0.15.0 // indirect + go.opentelemetry.io/otel/metric v1.39.0 // indirect + go.opentelemetry.io/otel/sdk v1.39.0 // indirect + go.opentelemetry.io/otel/sdk/log v0.15.0 // indirect + go.opentelemetry.io/otel/sdk/metric v1.39.0 // indirect + go.opentelemetry.io/otel/trace v1.39.0 // indirect + go.opentelemetry.io/proto/otlp v1.7.1 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/ratelimit v0.3.1 // indirect - golang.org/x/exp v0.0.0-20250711185948-6ae5c78190dc // indirect - golang.org/x/net v0.48.0 // indirect + golang.org/x/exp v0.0.0-20260112195511-716be5621a96 // indirect + golang.org/x/net v0.49.0 // indirect golang.org/x/sync v0.19.0 // indirect golang.org/x/sys v0.40.0 // indirect golang.org/x/term v0.39.0 // indirect golang.org/x/text v0.33.0 // indirect - golang.org/x/time v0.12.0 // indirect + golang.org/x/time v0.14.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20260114163908-3f89685c29c3 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20260114163908-3f89685c29c3 // indirect google.golang.org/grpc v1.78.0 // indirect diff --git a/go.sum b/go.sum index 9283027a5..2898866e9 100644 --- a/go.sum +++ b/go.sum @@ -73,8 +73,8 @@ github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0 h1:59Kx4K6lzOW5w6nFlA0v5+lk/6 github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= -github.com/btcsuite/btcutil v1.0.2 h1:9iZ1Terx9fMIOtq1VrwdqfsATL9MC2l8ZrUY6YZ2uts= -github.com/btcsuite/btcutil v1.0.2/go.mod h1:j9HUFwoQRsZL3V4n+qG+CUnEGHOarIxfC3Le2Yhbcts= +github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce h1:YtWJF7RHm2pYCvA5t0RPmAaLUhREsKuKd+SLhxFbFeQ= +github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce/go.mod h1:0DVlHczLPewLcPGEIeUEzfOJhqGPQ0mJJRDBtD307+o= github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= github.com/btcsuite/goleveldb v1.0.0/go.mod h1:QiK9vBlgftBg6rWQIj6wFzbPfRjiykIEhBH4obrXJ/I= @@ -88,8 +88,8 @@ github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMU github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= -github.com/cenkalti/backoff/v5 v5.0.2 h1:rIfFVxEf1QsI7E1ZHfp/B4DF/6QBAUhmgkxc0H7Zss8= -github.com/cenkalti/backoff/v5 v5.0.2/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= +github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= +github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/cp v1.1.1 h1:nCb6ZLdB7NRaqsm91JtQTAme2SKJzXVsdPIPkyJr1MU= github.com/cespare/cp v1.1.1/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= @@ -150,8 +150,8 @@ github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a h1:W8mUrRp6NOV github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a/go.mod h1:sTwzHBvIzm2RfVCGNEBZgRyjwK40bVoun3ZnGOCafNM= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= -github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= +github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s= +github.com/creack/pty v1.1.24/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE= github.com/cucumber/gherkin/go/v26 v26.2.0 h1:EgIjePLWiPeslwIWmNQ3XHcypPsWAHoMCz/YEBKP4GI= github.com/cucumber/gherkin/go/v26 v26.2.0/go.mod h1:t2GAPnB8maCT4lkHL99BDCVNzCh1d7dBhCLt150Nr/0= github.com/cucumber/godog v0.15.1 h1:rb/6oHDdvVZKS66hrhpjFQFHjthFSrQBCOI1LwshNTI= @@ -271,8 +271,9 @@ github.com/go-playground/validator/v10 v10.28.0 h1:Q7ibns33JjyW48gHkuFT91qX48KG0 github.com/go-playground/validator/v10 v10.28.0/go.mod h1:GoI6I1SjPBh9p7ykNE/yj3fFYbyDOpwMn5KXd+m2hUU= github.com/go-resty/resty/v2 v2.17.1 h1:x3aMpHK1YM9e4va/TMDRlusDDoZiQ+ViDu/WpA6xTM4= github.com/go-resty/resty/v2 v2.17.1/go.mod h1:kCKZ3wWmwJaNc7S29BRtUhJwy7iqmn+2mLtQrOyQlVA= -github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= +github.com/go-sql-driver/mysql v1.9.3 h1:U/N249h2WzJ3Ukj8SowVFjdtZKfu9vlLZxjPXV1aweo= +github.com/go-sql-driver/mysql v1.9.3/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= @@ -338,14 +339,16 @@ github.com/gorilla/rpc v1.2.0/go.mod h1:V4h9r+4sF5HnzqbwIez0fKSpANP0zlYd3qR7p36j github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc h1:GN2Lv3MGO7AS6PrRoT6yV5+wkrOpcszoIsO4+4ds248= +github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc/go.mod h1:+JKpmjMGhpgPL+rXZ5nsZieVzvarn86asRlBg4uNGnk= github.com/graph-gophers/graphql-go v1.5.0 h1:fDqblo50TEpD0LY7RXk/LFVYEVqo3+tXMNMPSVXA1yc= github.com/graph-gophers/graphql-go v1.5.0/go.mod h1:YtmJZDLbF1YYNrlNAuiO5zAStUWc3XZT07iGsVqe1Os= github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1 h1:qnpSQwGEnkcRpTqNOIR6bJbR0gAorgP9CSALpRcKoAA= github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.1/go.mod h1:lXGCsh6c22WGtjr+qGHj1otzZpV/1kwTMAqkwZsnWRU= github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.2 h1:sGm2vDRFUrQJO/Veii4h4zG2vvqG6uWNkBHSTqXOZk0= github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.2/go.mod h1:wd1YpapPLivG6nQgbf7ZkG1hhSOXDhhn4MLTknx2aAc= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 h1:5ZPtiqj0JL5oKWmcsq4VMaAW5ukBEgSGXEN89zeH1Jo= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3/go.mod h1:ndYquD05frm2vACXE1nsccT4oJzjhw2arTS2cpUD1PI= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 h1:8Tjv8EJ+pM1xP8mK6egEbD1OgnVTyacbefKhmbLhIhU= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2/go.mod h1:pkJQ2tZHJ0aFOVEEot6oZmaVEZcRme73eIFmhiVuRWs= github.com/hashicorp/go-bexpr v0.1.10 h1:9kuI5PFotCboP3dkDYFr/wi0gg0QVbSNz5oFRpxn4uE= github.com/hashicorp/go-bexpr v0.1.10/go.mod h1:oxlubA2vC/gFVfX1A6JGp7ls7uCDlfJn732ehYYg+g0= github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k= @@ -461,8 +464,8 @@ github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6 github.com/klauspost/compress v1.11.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.18.2 h1:iiPHWW0YrcFgpBYhsA6D1+fqHssJscY/Tm/y2Uqnapk= github.com/klauspost/compress v1.18.2/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= -github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE= -github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= +github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y= +github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= @@ -600,8 +603,8 @@ github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7J github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= -github.com/onsi/gomega v1.36.2 h1:koNYke6TVk6ZmnyHrCXba/T/MoLBXFjeC1PtvYgw0A8= -github.com/onsi/gomega v1.36.2/go.mod h1:DdwyADRjrc825LhMEkD76cHR5+pUnjhUN8GlHlRPHzY= +github.com/onsi/gomega v1.37.0 h1:CdEG8g0S133B4OswTDC/5XPSzE1OeP29QOioj2PID2Y= +github.com/onsi/gomega v1.37.0/go.mod h1:8D9+Txp43QWKhM24yyOBEdpkzN8FvJyAwecBgsU4KU0= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040= @@ -650,8 +653,8 @@ github.com/prometheus/client_golang v1.23.0/go.mod h1:i/o0R9ByOnHX0McrTMTyhYvKE4 github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= -github.com/prometheus/common v0.65.0 h1:QDwzd+G1twt//Kwj/Ww6E9FQq1iVMmODnILtW1t2VzE= -github.com/prometheus/common v0.65.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8= +github.com/prometheus/common v1.20.99 h1:vZEybF3CT0t6L0UjsOtHRML7vuIglHocmvJMMH/se4M= +github.com/prometheus/common v1.20.99/go.mod h1:VX44Tebe4qpuTK+MQWg25h4fJGKBqzObSdxuB7y8K/Y= github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= github.com/prysmaticlabs/gohashtree v0.0.4-beta h1:H/EbCuXPeTV3lpKeXGPpEV9gsUpkqOOVnWapUyeWro4= @@ -697,24 +700,24 @@ github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMB github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/smartcontractkit/chain-selectors v1.0.91 h1:Aip7IZTv40RtbHgZ9mTjm5KyhYrpPefG7iVMzLZ27M4= -github.com/smartcontractkit/chain-selectors v1.0.91/go.mod h1:qy7whtgG5g+7z0jt0nRyii9bLND9m15NZTzuQPkMZ5w= -github.com/smartcontractkit/chainlink-aptos v0.0.0-20251024142440-51f2ad2652a2 h1:vGdeMwHO3ow88HvxfhA4DDPYNY0X9jmdux7L83UF/W8= -github.com/smartcontractkit/chainlink-aptos v0.0.0-20251024142440-51f2ad2652a2/go.mod h1:iteU0WORHkArACVh/HoY/1bipV4TcNcJdTmom9uIT0E= -github.com/smartcontractkit/chainlink-canton v0.0.0-20260202190435-99f4e19d8d2e h1:SdU728rHhuq7+dnfUiEk3R0lOeWNFs+zfI2iws393w8= -github.com/smartcontractkit/chainlink-canton v0.0.0-20260202190435-99f4e19d8d2e/go.mod h1:IGY2/0rDoFyyGZvZ4cKb/pFzQ4h1lrgxoA4hHW2TdlI= -github.com/smartcontractkit/chainlink-canton/integration-tests v0.0.0-20260202190435-99f4e19d8d2e h1:g26x/dVdvH0kO4XK3iI4v308x9uJHMr7gwt/DPRSk3c= -github.com/smartcontractkit/chainlink-canton/integration-tests v0.0.0-20260202190435-99f4e19d8d2e/go.mod h1:8dyNC//HgLzGPm5ATPsCQ3PJ4DParxD3oaQiluzU3jw= +github.com/smartcontractkit/chain-selectors v1.0.92 h1:cEapBC3DBDKNAZddp01Xj1qAArBNUJdR/4JYhp1NKxY= +github.com/smartcontractkit/chain-selectors v1.0.92/go.mod h1:qy7whtgG5g+7z0jt0nRyii9bLND9m15NZTzuQPkMZ5w= +github.com/smartcontractkit/chainlink-aptos v0.0.0-20251212131933-e5e85d6fa4d3 h1:bbVSKb++R+rpLkydNvyS4nZPNkcjtolUuFC8YVwtMVk= +github.com/smartcontractkit/chainlink-aptos v0.0.0-20251212131933-e5e85d6fa4d3/go.mod h1:OywVThRaVXwknATT2B8QAwjOJ1LoYBB9bTsmRpf6RPw= +github.com/smartcontractkit/chainlink-canton v0.0.0-20260205203303-a74a56b3565d h1:Nr/kiMTtpHUuxbwz3gULcX4ijxg+fpofFgFhXfEjcTQ= +github.com/smartcontractkit/chainlink-canton v0.0.0-20260205203303-a74a56b3565d/go.mod h1:nFmWvUy8OOMdJiqFWbsicxp/UkGa72oEinn8+yPjPmY= +github.com/smartcontractkit/chainlink-canton/integration-tests v0.0.0-20260205203303-a74a56b3565d h1:dwG5CQ2Zh5OCNiccvS6QPEc5SuGyUxQTLo4X3cK93ME= +github.com/smartcontractkit/chainlink-canton/integration-tests v0.0.0-20260205203303-a74a56b3565d/go.mod h1:hIxBBlwFD5prwcA4Cbc7TW/Q1vrDuO7dsC0yvbdCF1I= github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20260129103204-4c8453dd8139 h1:jkChf04hhdiMBApbb+lLDxHMY62Md6UeM7v++GSw3K8= github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20260129103204-4c8453dd8139/go.mod h1:wuhagkM/lU0GbV2YcrROOH0GlsfXJYwm6qmpa4CK70w= github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings v0.0.0-20260129103204-4c8453dd8139 h1:tw3K4UkH5XfW5SoyYkvAlbzrccoGSLdz/XkxD6nyGC8= github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings v0.0.0-20260129103204-4c8453dd8139/go.mod h1:1WcontO9PeuKdUf5HXfs3nuICtzUvFNnyCmrHkTCF9Y= -github.com/smartcontractkit/chainlink-common v0.9.6-0.20260114190811-74301cd99dc3 h1:VINIWIvYhgbGJpaI7O3aBuBOAZgMEN6BGA61zQIqvFw= -github.com/smartcontractkit/chainlink-common v0.9.6-0.20260114190811-74301cd99dc3/go.mod h1:DAwaVSiQMgAsCjHa8nOnIAM9GixuIQWsgEZFGpf3JxE= +github.com/smartcontractkit/chainlink-common v0.9.6-0.20260122165924-94e0fad14fe8 h1:kDHw2ta45azZGdfLldVloLAbo+JS3zIXXRlAIO8f1js= +github.com/smartcontractkit/chainlink-common v0.9.6-0.20260122165924-94e0fad14fe8/go.mod h1:Eg5rz/fQINjR9H0TxHw7j+zGZeYxprUpEQZzC5JGHG4= github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.10 h1:FJAFgXS9oqASnkS03RE1HQwYQQxrO4l46O5JSzxqLgg= github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.10/go.mod h1:oiDa54M0FwxevWwyAX773lwdWvFYYlYHHQV1LQ5HpWY= -github.com/smartcontractkit/chainlink-deployments-framework v0.78.0 h1:Wh2DXmYBnTunJ5+IqsGTLe5qFdbkK9nmgKKvF86Sagc= -github.com/smartcontractkit/chainlink-deployments-framework v0.78.0/go.mod h1:euAnbxZWRV78+xY/1mi23v+dzU+vhiD9/pJcs/Cyf/k= +github.com/smartcontractkit/chainlink-deployments-framework v0.79.0 h1:+2chX5WzpkSNsazvPUMTJ2CCFNNt+yEWHiJAfPizaAA= +github.com/smartcontractkit/chainlink-deployments-framework v0.79.0/go.mod h1:mWB9sP9T6wWOTkrF19v7JYeZ5WRE7whhRd5dHDnxdUM= github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20251124151448-0448aefdaab9 h1:QRWXJusIj/IRY5Pl3JclNvDre0cZPd/5NbILwc4RV2M= github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20251124151448-0448aefdaab9/go.mod h1:jUC52kZzEnWF9tddHh85zolKybmLpbQ1oNA4FjOHt1Q= github.com/smartcontractkit/chainlink-protos/linking-service/go v0.0.0-20251002192024-d2ad9222409b h1:QuI6SmQFK/zyUlVWEf0GMkiUYBPY4lssn26nKSd/bOM= @@ -725,16 +728,16 @@ github.com/smartcontractkit/chainlink-testing-framework/framework v0.13.9 h1:V4U github.com/smartcontractkit/chainlink-testing-framework/framework v0.13.9/go.mod h1:RAr+u340HtgzqHcZhAR7qi3ILgaJmh3nNRqS9nOms6E= github.com/smartcontractkit/chainlink-ton v0.0.0-20260204205804-642f6ebe4e7e h1:0tN41HRIrNAVr5Chr8xynwpJNJaYMqGxqlIu+E7SOG8= github.com/smartcontractkit/chainlink-ton v0.0.0-20260204205804-642f6ebe4e7e/go.mod h1:IZvH2r16xcQvVLB7AtjU112wnHfEku+29OlI1vCQHCQ= -github.com/smartcontractkit/chainlink-tron/relayer v0.0.11-0.20250908203554-5bd9d2fe9513 h1:XRNxgcNqagXu6e4smJuS1crRK5cUAcCVd7u+iLduHDM= -github.com/smartcontractkit/chainlink-tron/relayer v0.0.11-0.20250908203554-5bd9d2fe9513/go.mod h1:ccjEgNeqOO+bjPddnL4lUrNLzyCvGCxgBjJdhFX3wa8= +github.com/smartcontractkit/chainlink-tron/relayer v0.0.11-0.20251014143056-a0c6328c91e9 h1:7Ut0g+Pdm+gcu2J/Xv8OpQOVf7uLGErMX8yhC4b4tIA= +github.com/smartcontractkit/chainlink-tron/relayer v0.0.11-0.20251014143056-a0c6328c91e9/go.mod h1:h9hMs6K4hT1+mjYnJD3/SW1o7yC/sKjNi0Qh8hLfiCE= github.com/smartcontractkit/chainlink-tron/relayer/gotron-sdk v0.0.5-0.20251014120029-d73d15cc23f7 h1:qPGcryHOEipripujMtsip++fmVbJhyqO6eAGEq85r48= 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.20250716200817-cb5dfd0e369e h1:Hv9Mww35LrufCdM9wtS9yVi/rEWGI1UnjHbcKKU0nVY= github.com/smartcontractkit/freeport v0.1.3-0.20250716200817-cb5dfd0e369e/go.mod h1:T4zH9R8R8lVWKfU7tUvYz2o2jMv1OpGCdpY2j2QZXzU= 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-20250912173940-f3ab0246e23d h1:LokA9PoCNb8mm8mDT52c3RECPMRsGz1eCQORq+J3n74= -github.com/smartcontractkit/libocr v0.0.0-20250912173940-f3ab0246e23d/go.mod h1:Acy3BTBxou83ooMESLO90s8PKSu7RvLCzwSTbxxfOK0= +github.com/smartcontractkit/libocr v0.0.0-20251212213002-0a5e2f907dda h1:OjM+79FRuVZlj0Qd4y+q8Xmz/tEn5y8npqmiQiMMj+w= +github.com/smartcontractkit/libocr v0.0.0-20251212213002-0a5e2f907dda/go.mod h1:oJkBKVn8zoBQm7Feah9CiuEHyCqAhnp1LJBzrvloQtM= github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY= github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo= github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= @@ -837,20 +840,20 @@ go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.6 go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0 h1:RbKq8BG0FI8OiXhBfcRtqqHcZcka+gU3cskNuf05R18= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0/go.mod h1:h06DGIukJOevXaj/xrNjhi/2098RZzcLTbc0jDAUbsg= go.opentelemetry.io/otel v1.6.3/go.mod h1:7BgNga5fNlF/iZjG06hM3yofffp0ofKCDwSXx1GC4dI= -go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= -go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= +go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48= +go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8= go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.12.2 h1:06ZeJRe5BnYXceSM9Vya83XXVaNGe3H1QqsvqRANQq8= go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.12.2/go.mod h1:DvPtKE63knkDVP88qpatBj81JxN+w1bqfVbsbCbj1WY= go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.12.2 h1:tPLwQlXbJ8NSOfZc4OkgU5h2A38M4c9kfHSVc4PFQGs= go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.12.2/go.mod h1:QTnxBwT/1rBIgAG1goq6xMydfYOBKU6KTiYF4fp5zL8= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.36.0 h1:zwdo1gS2eH26Rg+CoqVQpEK1h8gvt5qyU5Kk5Bixvow= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.36.0/go.mod h1:rUKCPscaRWWcqGT6HnEmYrK+YNe5+Sw64xgQTOJ5b30= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0 h1:vl9obrcoWVKp/lwl8tRE33853I8Xru9HFbw/skNeLs8= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0/go.mod h1:GAXRxmLJcVM3u22IjTg74zWBrRCKq8BnOqUVLodpcpw= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.36.0 h1:gAU726w9J8fwr4qRDqu1GYMNNs4gXrU+Pv20/N1UpB4= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.36.0/go.mod h1:RboSDkp7N292rgu+T0MgVt2qgFGu6qa1RpZDOtpL76w= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.36.0 h1:dNzwXjZKpMpE2JhmO+9HsPl42NIXFIFSUSSs0fiqra0= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.36.0/go.mod h1:90PoxvaEB5n6AOdZvi+yWJQoE95U8Dhhw2bSyRqnTD0= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.36.0 h1:JgtbA0xkWHnTmYk7YusopJFX6uleBmAuZ8n05NEh8nQ= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.36.0/go.mod h1:179AK5aar5R3eS9FucPy6rggvU0g52cvKId8pv4+v0c= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0 h1:Ahq7pZmv87yiyn3jeFz/LekZmPLLdKejuO3NcK9MssM= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0/go.mod h1:MJTqhM0im3mRLw1i8uGHnCvUEeS7VwRyxlLC78PA18M= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0 h1:EtFWSnwW9hGObjkIdmlnWSydO+Qs8OwzfzXLUPg4xOc= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0/go.mod h1:QjUEoiGCPkvFZ/MjK6ZZfNOS6mfVEVKYE99dFhuN2LI= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.36.0 h1:nRVXXvf78e00EwY6Wp0YII8ww2JVWshZ20HfTlE11AM= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.36.0/go.mod h1:r49hO7CgrxY9Voaj3Xe8pANWtr0Oq916d0XAmOoCZAQ= go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.13.0 h1:yEX3aC9KDgvYPhuKECHbOlr5GLwH6KTjLJ1sBSkkxkc= @@ -859,23 +862,23 @@ go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.36.0 h1:rixTyDGXFxRy1x go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.36.0/go.mod h1:dowW6UsM9MKbJq5JTz2AMVp3/5iW5I/TStsk8S+CfHw= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.36.0 h1:G8Xec/SgZQricwWBJF/mHZc7A02YHedfFDENwJEdRA0= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.36.0/go.mod h1:PD57idA/AiFD5aqoxGxCvT/ILJPeHy3MjqU/NS7KogY= -go.opentelemetry.io/otel/log v0.13.0 h1:yoxRoIZcohB6Xf0lNv9QIyCzQvrtGZklVbdCoyb7dls= -go.opentelemetry.io/otel/log v0.13.0/go.mod h1:INKfG4k1O9CL25BaM1qLe0zIedOpvlS5Z7XgSbmN83E= -go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= -go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= -go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= -go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= -go.opentelemetry.io/otel/sdk/log v0.13.0 h1:I3CGUszjM926OphK8ZdzF+kLqFvfRY/IIoFq/TjwfaQ= -go.opentelemetry.io/otel/sdk/log v0.13.0/go.mod h1:lOrQyCCXmpZdN7NchXb6DOZZa1N5G1R2tm5GMMTpDBw= +go.opentelemetry.io/otel/log v0.15.0 h1:0VqVnc3MgyYd7QqNVIldC3dsLFKgazR6P3P3+ypkyDY= +go.opentelemetry.io/otel/log v0.15.0/go.mod h1:9c/G1zbyZfgu1HmQD7Qj84QMmwTp2QCQsZH1aeoWDE4= +go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0= +go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs= +go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18= +go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE= +go.opentelemetry.io/otel/sdk/log v0.15.0 h1:WgMEHOUt5gjJE93yqfqJOkRflApNif84kxoHWS9VVHE= +go.opentelemetry.io/otel/sdk/log v0.15.0/go.mod h1:qDC/FlKQCXfH5hokGsNg9aUBGMJQsrUyeOiW5u+dKBQ= go.opentelemetry.io/otel/sdk/log/logtest v0.13.0 h1:9yio6AFZ3QD9j9oqshV1Ibm9gPLlHNxurno5BreMtIA= go.opentelemetry.io/otel/sdk/log/logtest v0.13.0/go.mod h1:QOGiAJHl+fob8Nu85ifXfuQYmJTFAvcrxL6w5/tu168= -go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= -go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= +go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8= +go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew= go.opentelemetry.io/otel/trace v1.6.3/go.mod h1:GNJQusJlUgZl9/TQBPKU/Y/ty+0iVB5fjhKeJGZPGFs= -go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= -go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= -go.opentelemetry.io/proto/otlp v1.6.0 h1:jQjP+AQyTf+Fe7OKj/MfkDrmK4MNVtw2NpXsf9fefDI= -go.opentelemetry.io/proto/otlp v1.6.0/go.mod h1:cicgGehlFuNdgZkcALOCh3VE6K/u2tAjzlRhDwmVpZc= +go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI= +go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA= +go.opentelemetry.io/proto/otlp v1.7.1 h1:gTOMpGDb0WTBOP8JaO72iL3auEZhVmAQg4ipjOVAtj4= +go.opentelemetry.io/proto/otlp v1.7.1/go.mod h1:b2rVh6rfI/s2pHWNlB7ILJcRALpcNDzKhACevjI+ZnE= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= @@ -925,8 +928,8 @@ golang.org/x/crypto v0.20.0/go.mod h1:Xwo95rrVNIoSMx9wa1JroENMToLWn3RNVrTBpLHgZP golang.org/x/crypto v0.47.0 h1:V6e3FRj+n4dbpw86FJ8Fv7XVOql7TEwpHapKoMJ/GO8= golang.org/x/crypto v0.47.0/go.mod h1:ff3Y9VzzKbwSSEzWqJsJVBnWmRwRSHt/6Op5n9bQc4A= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20250711185948-6ae5c78190dc h1:TS73t7x3KarrNd5qAipmspBDS1rkMcgVG/fS1aRb4Rc= -golang.org/x/exp v0.0.0-20250711185948-6ae5c78190dc/go.mod h1:A+z0yzpGtvnG90cToK5n2tu8UJVP2XUATh+r+sfOOOc= +golang.org/x/exp v0.0.0-20260112195511-716be5621a96 h1:Z/6YuSHTLOHfNFdb8zVZomZr7cqNgTJvA8+Qz75D8gU= +golang.org/x/exp v0.0.0-20260112195511-716be5621a96/go.mod h1:nzimsREAkjBCIEFtHiYkrJyT+2uy9YZJB7H1k68CXZU= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= @@ -939,8 +942,8 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.31.0 h1:HaW9xtz0+kOcWKwli0ZXy79Ix+UW/vOfmWI5QVd2tgI= -golang.org/x/mod v0.31.0/go.mod h1:43JraMp9cGx1Rx3AqioxrbrhNsLl2l/iNAvuBkrezpg= +golang.org/x/mod v0.32.0 h1:9F4d3PHLljb6x//jOyokMv3eX+YDeepZSEo3mFJy93c= +golang.org/x/mod v0.32.0/go.mod h1:SgipZ/3h2Ci89DlEtEXWUk/HteuRin+HHhN+WbNhguU= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -972,8 +975,8 @@ golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= -golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= -golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= +golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o= +golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1040,8 +1043,8 @@ golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/telemetry v0.0.0-20251208220230-2638a1023523 h1:H52Mhyrc44wBgLTGzq6+0cmuVuF3LURCSXsLMOqfFos= -golang.org/x/telemetry v0.0.0-20251208220230-2638a1023523/go.mod h1:ArQvPJS723nJQietgilmZA+shuB3CZxH1n2iXq9VSfs= +golang.org/x/telemetry v0.0.0-20260109210033-bd525da824e2 h1:O1cMQHRfwNpDfDJerqRoE2oD+AFlyid87D40L/OkkJo= +golang.org/x/telemetry v0.0.0-20260109210033-bd525da824e2/go.mod h1:b7fPSJ0pKZ3ccUh8gnTONJxhn3c/PS6tyzQvyqw4iA8= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -1068,8 +1071,8 @@ golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE= golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8= golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE= -golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= +golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= +golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -1091,8 +1094,8 @@ golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA= -golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc= +golang.org/x/tools v0.41.0 h1:a9b8iMweWG+S0OBnlU36rzLp20z1Rp10w+IY2czHTQc= +golang.org/x/tools v0.41.0/go.mod h1:XSY6eDqxVNiYgezAVqqCeihT4j1U2CCsqvH3WhQpnlg= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1102,8 +1105,8 @@ golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da h1:noIWHXmPHxILtqtCOPIhSt0ABwskkZKjD3bXGnZGpNY= golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= -gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= -gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= +gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4= +gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= From 2e3dae44c2176a757c08193c2caa59b91d2de5d1 Mon Sep 17 00:00:00 2001 From: Rodrigo Soares <38868277+rodrigombsoares@users.noreply.github.com> Date: Sat, 7 Feb 2026 00:00:12 -0300 Subject: [PATCH 4/6] feat(canton): implement inspector (#609) --- e2e/tests/canton/common.go | 2 +- e2e/tests/canton/inspector.go | 238 ++++++++++++++++++++++++++++++++++ e2e/tests/runner_test.go | 1 + go.mod | 4 +- go.sum | 4 +- sdk/canton/configurer.go | 2 +- sdk/canton/inspector.go | 233 +++++++++++++++++++++++++++++++++ sdk/canton/inspector_test.go | 193 +++++++++++++++++++++++++++ 8 files changed, 671 insertions(+), 6 deletions(-) create mode 100644 e2e/tests/canton/inspector.go create mode 100644 sdk/canton/inspector.go create mode 100644 sdk/canton/inspector_test.go diff --git a/e2e/tests/canton/common.go b/e2e/tests/canton/common.go index 1f15a5156..578a05618 100644 --- a/e2e/tests/canton/common.go +++ b/e2e/tests/canton/common.go @@ -119,7 +119,7 @@ func (s *TestSuite) createMCMS(ctx context.Context, participant testhelpers.Part UserID: participant.UserName, CommandID: commandID, ActAs: []string{participant.Party}, - Commands: []*model.Command{{Command: mcmsContract.CreateCommandWithPackageID(s.packageIDs[0])}}, + Commands: []*model.Command{{Command: mcmsContract.CreateCommand()}}, }, } diff --git a/e2e/tests/canton/inspector.go b/e2e/tests/canton/inspector.go new file mode 100644 index 000000000..cbcdc0086 --- /dev/null +++ b/e2e/tests/canton/inspector.go @@ -0,0 +1,238 @@ +//go:build e2e + +package canton + +import ( + "context" + "io" + "slices" + "testing" + + apiv2 "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" + "github.com/stretchr/testify/suite" + + cantonsdk "github.com/smartcontractkit/mcms/sdk/canton" + mcmstypes "github.com/smartcontractkit/mcms/types" +) + +type MCMSInspectorTestSuite struct { + TestSuite + inspector *cantonsdk.Inspector +} + +// SetupSuite runs before the test suite +func (s *MCMSInspectorTestSuite) SetupSuite() { + s.TestSuite.SetupSuite() + s.DeployMCMSContract() + + // Create inspector instance using participant's StateServiceClient + s.inspector = cantonsdk.NewInspector(s.participant.StateServiceClient, s.participant.Party) +} + +func (s *MCMSInspectorTestSuite) TestGetConfig() { + ctx := s.T().Context() + + // Signers in each group need to be sorted alphabetically + signers := [30]common.Address{} + for i := range signers { + key, _ := crypto.GenerateKey() + signers[i] = crypto.PubkeyToAddress(key.PublicKey) + } + slices.SortFunc(signers[:], func(a, b common.Address) int { + return a.Cmp(b) + }) + + expectedConfig := &mcmstypes.Config{ + Quorum: 2, + Signers: []common.Address{ + signers[0], + signers[1], + signers[2], + }, + GroupSigners: []mcmstypes.Config{ + { + Quorum: 4, + Signers: []common.Address{ + signers[3], + signers[4], + signers[5], + signers[6], + signers[7], + }, + GroupSigners: []mcmstypes.Config{ + { + Quorum: 1, + Signers: []common.Address{ + signers[8], + signers[9], + }, + GroupSigners: []mcmstypes.Config{}, + }, + }, + }, + { + Quorum: 3, + Signers: []common.Address{ + signers[10], + signers[11], + signers[12], + signers[13], + }, + GroupSigners: []mcmstypes.Config{}, + }, + }, + } + + // Set config using configurer + configurer, err := cantonsdk.NewConfigurer(s.client, s.participant.UserName, s.participant.Party) + s.Require().NoError(err, "creating configurer") + + _, err = configurer.SetConfig(ctx, s.mcmsContractID, expectedConfig, true) + s.Require().NoError(err, "setting config") + + // Get the new contract ID after SetConfig (which archives old and creates new) + newContractID, err := s.getLatestMCMSContractID(ctx) + s.Require().NoError(err, "getting latest MCMS contract ID") + + // Now test the inspector + actualConfig, err := s.inspector.GetConfig(ctx, newContractID) + s.Require().NoError(err, "getting config from inspector") + s.Require().NotNil(actualConfig, "config should not be nil") + + // Verify the config matches what we set + s.verifyConfigMatch(expectedConfig, actualConfig) +} + +func (s *MCMSInspectorTestSuite) TestGetOpCount() { + ctx := s.T().Context() + + // Get the latest contract ID + contractID, err := s.getLatestMCMSContractID(ctx) + s.Require().NoError(err, "getting latest MCMS contract ID") + + // Get op count + opCount, err := s.inspector.GetOpCount(ctx, contractID) + s.Require().NoError(err, "getting op count") + + // Initially should be 0 + s.Require().Equal(uint64(0), opCount, "initial op count should be 0") +} + +func (s *MCMSInspectorTestSuite) TestGetRoot() { + ctx := s.T().Context() + + // Get the latest contract ID + contractID, err := s.getLatestMCMSContractID(ctx) + s.Require().NoError(err, "getting latest MCMS contract ID") + + // Get root + root, validUntil, err := s.inspector.GetRoot(ctx, contractID) + s.Require().NoError(err, "getting root") + + // Initially root should be empty and validUntil should be 0 + s.Require().Equal(common.Hash{}, root, "initial root should be empty") + s.Require().Equal(uint32(0), validUntil, "initial validUntil should be 0") +} + +func (s *MCMSInspectorTestSuite) TestGetRootMetadata() { + ctx := s.T().Context() + + // Get the latest contract ID + contractID, err := s.getLatestMCMSContractID(ctx) + s.Require().NoError(err, "getting latest MCMS contract ID") + + // Get root metadata + metadata, err := s.inspector.GetRootMetadata(ctx, contractID) + s.Require().NoError(err, "getting root metadata") + + // Verify metadata structure + s.Require().Equal(uint64(0), metadata.StartingOpCount, "initial starting op count should be 0") + s.Require().NotEmpty(metadata.MCMAddress, "MCM address should not be empty") +} + +// Helper function to get the latest MCMS contract ID +func (s *MCMSInspectorTestSuite) getLatestMCMSContractID(ctx context.Context) (string, error) { + // Get current ledger offset + ledgerEndResp, err := s.participant.StateServiceClient.GetLedgerEnd(ctx, &apiv2.GetLedgerEndRequest{}) + if err != nil { + return "", err + } + + // Query active contracts + activeContractsResp, err := s.participant.StateServiceClient.GetActiveContracts(ctx, &apiv2.GetActiveContractsRequest{ + ActiveAtOffset: ledgerEndResp.GetOffset(), + EventFormat: &apiv2.EventFormat{ + FiltersByParty: map[string]*apiv2.Filters{ + s.participant.Party: { + Cumulative: []*apiv2.CumulativeFilter{ + { + IdentifierFilter: &apiv2.CumulativeFilter_TemplateFilter{ + TemplateFilter: &apiv2.TemplateFilter{ + TemplateId: &apiv2.Identifier{ + PackageId: "#mcms", + ModuleName: "MCMS.Main", + EntityName: "MCMS", + }, + IncludeCreatedEventBlob: false, + }, + }, + }, + }, + }, + }, + Verbose: true, + }, + }) + if err != nil { + return "", err + } + defer activeContractsResp.CloseSend() + + // Get the first (and should be only) active MCMS contract + for { + resp, err := activeContractsResp.Recv() + if err == io.EOF { + break + } + if err != nil { + return "", err + } + + activeContract, ok := resp.GetContractEntry().(*apiv2.GetActiveContractsResponse_ActiveContract) + if !ok { + continue + } + + createdEvent := activeContract.ActiveContract.GetCreatedEvent() + if createdEvent == nil { + continue + } + + return createdEvent.ContractId, nil + } + + return "", nil +} + +// Helper to verify config matches +func (s *MCMSInspectorTestSuite) verifyConfigMatch(expected, actual *mcmstypes.Config) { + s.Require().Equal(expected.Quorum, actual.Quorum, "quorum should match") + s.Require().Equal(len(expected.Signers), len(actual.Signers), "number of signers should match") + + // Verify signers + for i, expectedSigner := range expected.Signers { + s.Require().Equal(expectedSigner, actual.Signers[i], "signer %d should match", i) + } + + // Verify group signers recursively + s.Require().Equal(len(expected.GroupSigners), len(actual.GroupSigners), "number of group signers should match") + for i, expectedGroup := range expected.GroupSigners { + s.verifyConfigMatch(&expectedGroup, &actual.GroupSigners[i]) + } +} + +func TestMCMSInspectorSuite(t *testing.T) { + suite.Run(t, new(MCMSInspectorTestSuite)) +} diff --git a/e2e/tests/runner_test.go b/e2e/tests/runner_test.go index cd0aa434f..4d23bd6e7 100644 --- a/e2e/tests/runner_test.go +++ b/e2e/tests/runner_test.go @@ -53,4 +53,5 @@ func TestTONSuite(t *testing.T) { func TestCantonSuite(t *testing.T) { suite.Run(t, new(cantone2e.MCMSConfigurerTestSuite)) + suite.Run(t, new(cantone2e.MCMSInspectorTestSuite)) } diff --git a/go.mod b/go.mod index 682484f8a..3061ab6be 100644 --- a/go.mod +++ b/go.mod @@ -10,11 +10,12 @@ replace github.com/fbsobreira/gotron-sdk => github.com/smartcontractkit/chainlin replace github.com/digital-asset/dazl-client/v8 => github.com/noders-team/dazl-client/v8 v8.7.1-2 -replace github.com/noders-team/go-daml => github.com/stackman27/go-daml v0.0.0-20260129035354-bee9c994446f +replace github.com/noders-team/go-daml => github.com/stackman27/go-daml v0.0.0-20260204001938-550ee9d8ab10 require ( github.com/aptos-labs/aptos-go-sdk v1.11.0 github.com/block-vision/sui-go-sdk v1.1.4 + github.com/digital-asset/dazl-client/v8 v8.8.0 github.com/ethereum/go-ethereum v1.16.8 github.com/gagliardetto/binary v0.8.0 github.com/gagliardetto/solana-go v1.13.0 @@ -96,7 +97,6 @@ require ( github.com/deckarep/golang-set/v2 v2.6.0 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect github.com/deepmap/oapi-codegen v1.8.2 // indirect - github.com/digital-asset/dazl-client/v8 v8.8.0 // indirect github.com/distribution/reference v0.6.0 // indirect github.com/docker/docker v28.5.1+incompatible // indirect github.com/docker/go-connections v0.6.0 // indirect diff --git a/go.sum b/go.sum index 2898866e9..cbb286aa2 100644 --- a/go.sum +++ b/go.sum @@ -743,8 +743,8 @@ github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qq github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0= -github.com/stackman27/go-daml v0.0.0-20260129035354-bee9c994446f h1:I79FWYle5/t1QxAZHClHc8OWJoKeUc97PNEX0XV9meM= -github.com/stackman27/go-daml v0.0.0-20260129035354-bee9c994446f/go.mod h1:yi458NGE4dlDOhlyCZvQ2XgsIOdHHvepwoHRgEusbo8= +github.com/stackman27/go-daml v0.0.0-20260204001938-550ee9d8ab10 h1:vihbDjQcH7ipRkIWQSIWcmjQ/wJQn2G4aBVc+erx4fM= +github.com/stackman27/go-daml v0.0.0-20260204001938-550ee9d8ab10/go.mod h1:yi458NGE4dlDOhlyCZvQ2XgsIOdHHvepwoHRgEusbo8= github.com/stephenlacy/go-ethereum-hdwallet v0.0.0-20230913225845-a4fa94429863 h1:ba4VRWSkRzgdP5hB5OxexIzBXZbSwgcw8bEu06ivGQI= github.com/stephenlacy/go-ethereum-hdwallet v0.0.0-20230913225845-a4fa94429863/go.mod h1:oPTjPNrRucLv9mU27iNPj6n0CWWcNFhoXFOLVGJwHCA= github.com/streamingfast/logging v0.0.0-20230608130331-f22c91403091 h1:RN5mrigyirb8anBEtdjtHFIufXdacyTi6i4KBfeNXeo= diff --git a/sdk/canton/configurer.go b/sdk/canton/configurer.go index edf7d3c43..14ba3a3b5 100644 --- a/sdk/canton/configurer.go +++ b/sdk/canton/configurer.go @@ -93,7 +93,7 @@ func (c Configurer) SetConfig(ctx context.Context, mcmsAddr string, cfg *types.C ActAs: []string{c.party}, Commands: []*model.Command{{ Command: &model.ExerciseCommand{ - TemplateID: fmt.Sprintf("%s:%s:%s", mcmsPkgID, "MCMS.Main", "MCMS"), + TemplateID: mcmsContract.GetTemplateID(), ContractID: exerciseCmd.ContractID, Choice: exerciseCmd.Choice, Arguments: exerciseCmd.Arguments, diff --git a/sdk/canton/inspector.go b/sdk/canton/inspector.go new file mode 100644 index 000000000..25ff2e2e0 --- /dev/null +++ b/sdk/canton/inspector.go @@ -0,0 +1,233 @@ +package canton + +import ( + "context" + "encoding/hex" + "errors" + "fmt" + "io" + "strings" + "time" + + apiv2 "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2" + "github.com/ethereum/go-ethereum/common" + + "github.com/smartcontractkit/chainlink-canton/bindings" + "github.com/smartcontractkit/chainlink-canton/bindings/mcms" + "github.com/smartcontractkit/mcms/sdk" + "github.com/smartcontractkit/mcms/types" +) + +var _ sdk.Inspector = &Inspector{} + +type Inspector struct { + stateClient apiv2.StateServiceClient + party string + contractCache *mcms.MCMS // Cache MCMS to avoid repeated RPC calls +} + +func NewInspector(stateClient apiv2.StateServiceClient, party string) *Inspector { + return &Inspector{ + stateClient: stateClient, + party: party, + } +} + +func (i *Inspector) GetConfig(ctx context.Context, mcmsAddr string) (*types.Config, error) { + if i.contractCache == nil { + mcmsContract, err := i.getMCMSContract(ctx, mcmsAddr) + if err != nil { + return nil, fmt.Errorf("failed to get MCMS contract: %w", err) + } + i.contractCache = mcmsContract + } + + return toConfig(i.contractCache.Config) +} + +func (i *Inspector) GetOpCount(ctx context.Context, mcmsAddr string) (uint64, error) { + if i.contractCache == nil { + mcmsContract, err := i.getMCMSContract(ctx, mcmsAddr) + if err != nil { + return 0, fmt.Errorf("failed to get MCMS contract: %w", err) + } + i.contractCache = mcmsContract + } + + return uint64(i.contractCache.ExpiringRoot.OpCount), nil +} + +func (i *Inspector) GetRoot(ctx context.Context, mcmsAddr string) (common.Hash, uint32, error) { + if i.contractCache == nil { + mcmsContract, err := i.getMCMSContract(ctx, mcmsAddr) + if err != nil { + return common.Hash{}, 0, fmt.Errorf("failed to get MCMS contract: %w", err) + } + i.contractCache = mcmsContract + } + + // Parse the root from hex string + rootStr := string(i.contractCache.ExpiringRoot.Root) + rootStr = strings.TrimPrefix(rootStr, "0x") + rootBytes, err := hex.DecodeString(rootStr) + if err != nil { + return common.Hash{}, 0, fmt.Errorf("failed to decode root hash: %w", err) + } + + root := common.BytesToHash(rootBytes) + + // validUntil is a TIMESTAMP (which wraps time.Time) + // Convert to Unix timestamp (uint32) + timeVal := time.Time(i.contractCache.ExpiringRoot.ValidUntil) + validUntil := uint32(timeVal.Unix()) + + return root, validUntil, nil +} + +func (i *Inspector) GetRootMetadata(ctx context.Context, mcmsAddr string) (types.ChainMetadata, error) { + if i.contractCache == nil { + mcmsContract, err := i.getMCMSContract(ctx, mcmsAddr) + if err != nil { + return types.ChainMetadata{}, fmt.Errorf("failed to get MCMS contract: %w", err) + } + i.contractCache = mcmsContract + } + + return types.ChainMetadata{ + StartingOpCount: uint64(i.contractCache.RootMetadata.PreOpCount), + MCMAddress: string(i.contractCache.McmsId), + }, nil +} + +// getMCMSContract queries the active MCMS contract by contract ID +func (i *Inspector) getMCMSContract(ctx context.Context, mcmsAddr string) (*mcms.MCMS, error) { + // Get current ledger offset + ledgerEndResp, err := i.stateClient.GetLedgerEnd(ctx, &apiv2.GetLedgerEndRequest{}) + if err != nil { + return nil, fmt.Errorf("failed to get ledger end: %w", err) + } + + // Query active contracts at current offset + activeContractsResp, err := i.stateClient.GetActiveContracts(ctx, &apiv2.GetActiveContractsRequest{ + ActiveAtOffset: ledgerEndResp.GetOffset(), + EventFormat: &apiv2.EventFormat{ + FiltersByParty: map[string]*apiv2.Filters{ + i.party: { + Cumulative: []*apiv2.CumulativeFilter{ + { + IdentifierFilter: &apiv2.CumulativeFilter_TemplateFilter{ + TemplateFilter: &apiv2.TemplateFilter{ + TemplateId: &apiv2.Identifier{ + PackageId: "#mcms", + ModuleName: "MCMS.Main", + EntityName: "MCMS", + }, + IncludeCreatedEventBlob: false, + }, + }, + }, + }, + }, + }, + Verbose: true, + }, + }) + if err != nil { + return nil, fmt.Errorf("failed to get active contracts: %w", err) + } + defer activeContractsResp.CloseSend() + + // Stream through active contracts to find the MCMS contract with matching ID + for { + resp, err := activeContractsResp.Recv() + if errors.Is(err, io.EOF) { + // Stream ended without finding the contract + return nil, fmt.Errorf("MCMS contract with ID %s not found", mcmsAddr) + } + if err != nil { + return nil, fmt.Errorf("failed to receive active contracts: %w", err) + } + + activeContract, ok := resp.GetContractEntry().(*apiv2.GetActiveContractsResponse_ActiveContract) + if !ok { + continue + } + + createdEvent := activeContract.ActiveContract.GetCreatedEvent() + if createdEvent == nil { + continue + } + + // Check if contract ID matches + if createdEvent.ContractId != mcmsAddr { + continue + } + + // Use bindings package to unmarshal the contract + mcmsContract, err := bindings.UnmarshalActiveContract[mcms.MCMS](activeContract) + if err != nil { + return nil, fmt.Errorf("failed to unmarshal MCMS contract: %w", err) + } + + return mcmsContract, nil + } +} + +// toConfig converts a Canton MultisigConfig to the chain-agnostic types.Config +func toConfig(bindConfig mcms.MultisigConfig) (*types.Config, error) { + // Group signers by group index + signersByGroup := make([][]common.Address, 32) // MCMS supports up to 32 groups + + for _, signer := range bindConfig.Signers { + groupIdx := int(signer.SignerGroup) + if groupIdx >= 32 { + return nil, fmt.Errorf("signer group index %d exceeds maximum of 31", groupIdx) + } + + // Parse signer address + addr := common.HexToAddress(string(signer.SignerAddress)) + signersByGroup[groupIdx] = append(signersByGroup[groupIdx], addr) + } + + // Build the group configs + groups := make([]types.Config, 32) + for i := 0; i < 32; i++ { + signers := signersByGroup[i] + if signers == nil { + signers = []common.Address{} + } + + quorum := uint8(0) + if i < len(bindConfig.GroupQuorums) { + quorum = uint8(bindConfig.GroupQuorums[i]) + } + + groups[i] = types.Config{ + Signers: signers, + GroupSigners: []types.Config{}, + Quorum: quorum, + } + } + + // Link the group signers; this assumes a group's parent always has a lower index + // Process in reverse order to build the tree from leaves to root + for i := 31; i >= 0; i-- { + parent := uint8(0) + if i < len(bindConfig.GroupParents) { + parent = uint8(bindConfig.GroupParents[i]) + } + + // Add non-empty child groups to their parent + // Skip the root group (i == 0) and empty groups (quorum == 0) + if i > 0 && groups[i].Quorum > 0 { + groups[parent].GroupSigners = append([]types.Config{groups[i]}, groups[parent].GroupSigners...) + } + } + + // Validate the root group config + if err := groups[0].Validate(); err != nil { + return nil, fmt.Errorf("invalid MCMS config: %w", err) + } + + return &groups[0], nil +} diff --git a/sdk/canton/inspector_test.go b/sdk/canton/inspector_test.go new file mode 100644 index 000000000..7aa3442ba --- /dev/null +++ b/sdk/canton/inspector_test.go @@ -0,0 +1,193 @@ +//go:build e2e + +package canton + +import ( + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/noders-team/go-daml/pkg/types" + "github.com/smartcontractkit/chainlink-canton/bindings/mcms" + mcmstypes "github.com/smartcontractkit/mcms/types" + "github.com/stretchr/testify/require" +) + +func TestToConfig(t *testing.T) { + tests := []struct { + name string + description string + input mcms.MultisigConfig + expected mcmstypes.Config + }{ + { + name: "simple_2of3", + description: "Simple 2-of-3 multisig with all signers in root group (group 0)", + input: mcms.MultisigConfig{ + Signers: []mcms.SignerInfo{ + {SignerAddress: types.TEXT("0x1111111111111111111111111111111111111111"), SignerIndex: types.INT64(0), SignerGroup: types.INT64(0)}, + {SignerAddress: types.TEXT("0x2222222222222222222222222222222222222222"), SignerIndex: types.INT64(1), SignerGroup: types.INT64(0)}, + {SignerAddress: types.TEXT("0x3333333333333333333333333333333333333333"), SignerIndex: types.INT64(2), SignerGroup: types.INT64(0)}, + }, + GroupQuorums: []types.INT64{2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + GroupParents: []types.INT64{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + }, + expected: mcmstypes.Config{ + Quorum: 2, + Signers: []common.Address{ + common.HexToAddress("1111111111111111111111111111111111111111"), + common.HexToAddress("2222222222222222222222222222222222222222"), + common.HexToAddress("3333333333333333333333333333333333333333"), + }, + GroupSigners: []mcmstypes.Config{}, + }, + }, + { + name: "hierarchical_2level", + description: "2-level hierarchy: root group 0 has 1 direct signer + group 1 as child. Group 1 has 3 signers with quorum 2. Root quorum is 1 (can be satisfied by direct signer OR group 1 reaching quorum).", + input: mcms.MultisigConfig{ + Signers: []mcms.SignerInfo{ + {SignerAddress: types.TEXT("0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"), SignerIndex: types.INT64(0), SignerGroup: types.INT64(0)}, + {SignerAddress: types.TEXT("0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"), SignerIndex: types.INT64(1), SignerGroup: types.INT64(1)}, + {SignerAddress: types.TEXT("0xcccccccccccccccccccccccccccccccccccccccc"), SignerIndex: types.INT64(2), SignerGroup: types.INT64(1)}, + {SignerAddress: types.TEXT("0xdddddddddddddddddddddddddddddddddddddddd"), SignerIndex: types.INT64(3), SignerGroup: types.INT64(1)}, + }, + GroupQuorums: []types.INT64{1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + GroupParents: []types.INT64{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + }, + expected: mcmstypes.Config{ + Quorum: 1, + Signers: []common.Address{ + common.HexToAddress("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"), + }, + GroupSigners: []mcmstypes.Config{ + { + Quorum: 2, + Signers: []common.Address{ + common.HexToAddress("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"), + common.HexToAddress("cccccccccccccccccccccccccccccccccccccccc"), + common.HexToAddress("dddddddddddddddddddddddddddddddddddddddd"), + }, + GroupSigners: []mcmstypes.Config{}, + }, + }, + }, + }, + { + name: "complex_3level", + description: "3-level hierarchy: Group 0 (root) quorum 2, Group 1 (parent 0) quorum 2, Group 2 (parent 0) quorum 1, Group 3 (parent 1) quorum 2. Tests deeper nesting with multiple child groups at same level.", + input: mcms.MultisigConfig{ + Signers: []mcms.SignerInfo{ + {SignerAddress: types.TEXT("0x1000000000000000000000000000000000000001"), SignerIndex: types.INT64(0), SignerGroup: types.INT64(0)}, + {SignerAddress: types.TEXT("0x1000000000000000000000000000000000000002"), SignerIndex: types.INT64(1), SignerGroup: types.INT64(1)}, + {SignerAddress: types.TEXT("0x1000000000000000000000000000000000000003"), SignerIndex: types.INT64(2), SignerGroup: types.INT64(1)}, + {SignerAddress: types.TEXT("0x1000000000000000000000000000000000000004"), SignerIndex: types.INT64(3), SignerGroup: types.INT64(2)}, + {SignerAddress: types.TEXT("0x1000000000000000000000000000000000000005"), SignerIndex: types.INT64(4), SignerGroup: types.INT64(2)}, + {SignerAddress: types.TEXT("0x1000000000000000000000000000000000000006"), SignerIndex: types.INT64(5), SignerGroup: types.INT64(3)}, + {SignerAddress: types.TEXT("0x1000000000000000000000000000000000000007"), SignerIndex: types.INT64(6), SignerGroup: types.INT64(3)}, + {SignerAddress: types.TEXT("0x1000000000000000000000000000000000000008"), SignerIndex: types.INT64(7), SignerGroup: types.INT64(3)}, + }, + GroupQuorums: []types.INT64{2, 2, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + GroupParents: []types.INT64{0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + }, + expected: mcmstypes.Config{ + Quorum: 2, + Signers: []common.Address{ + common.HexToAddress("1000000000000000000000000000000000000001"), + }, + GroupSigners: []mcmstypes.Config{ + { + Quorum: 2, + Signers: []common.Address{ + common.HexToAddress("1000000000000000000000000000000000000002"), + common.HexToAddress("1000000000000000000000000000000000000003"), + }, + GroupSigners: []mcmstypes.Config{ + { + Quorum: 2, + Signers: []common.Address{ + common.HexToAddress("1000000000000000000000000000000000000006"), + common.HexToAddress("1000000000000000000000000000000000000007"), + common.HexToAddress("1000000000000000000000000000000000000008"), + }, + GroupSigners: []mcmstypes.Config{}, + }, + }, + }, + { + Quorum: 1, + Signers: []common.Address{ + common.HexToAddress("1000000000000000000000000000000000000004"), + common.HexToAddress("1000000000000000000000000000000000000005"), + }, + GroupSigners: []mcmstypes.Config{}, + }, + }, + }, + }, + { + name: "empty_groups_edge_case", + description: "Edge case: groups with quorum 0 (disabled) interspersed with active groups. Group 0 active (quorum 1), Group 1 disabled (quorum 0), Group 2 active (quorum 2, parent 0). The toConfig function should skip disabled groups.", + input: mcms.MultisigConfig{ + Signers: []mcms.SignerInfo{ + {SignerAddress: types.TEXT("0xdead000000000000000000000000000000000001"), SignerIndex: types.INT64(0), SignerGroup: types.INT64(0)}, + {SignerAddress: types.TEXT("0xdead000000000000000000000000000000000002"), SignerIndex: types.INT64(1), SignerGroup: types.INT64(2)}, + {SignerAddress: types.TEXT("0xdead000000000000000000000000000000000003"), SignerIndex: types.INT64(2), SignerGroup: types.INT64(2)}, + }, + GroupQuorums: []types.INT64{1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + GroupParents: []types.INT64{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + }, + expected: mcmstypes.Config{ + Quorum: 1, + Signers: []common.Address{ + common.HexToAddress("dead000000000000000000000000000000000001"), + }, + GroupSigners: []mcmstypes.Config{ + { + Quorum: 2, + Signers: []common.Address{ + common.HexToAddress("dead000000000000000000000000000000000002"), + common.HexToAddress("dead000000000000000000000000000000000003"), + }, + GroupSigners: []mcmstypes.Config{}, + }, + }, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result, err := toConfig(tt.input) + require.NoError(t, err, tt.description) + require.NotNil(t, result) + + // Compare the result with expected + require.Equal(t, tt.expected.Quorum, result.Quorum, "quorum mismatch") + require.Equal(t, len(tt.expected.Signers), len(result.Signers), "signers count mismatch") + + // Compare signers + for i, expectedSigner := range tt.expected.Signers { + require.Equal(t, expectedSigner, result.Signers[i], "signer mismatch at index %d", i) + } + + // Compare group signers recursively + compareGroupSigners(t, tt.expected.GroupSigners, result.GroupSigners) + }) + } +} + +func compareGroupSigners(t *testing.T, expected, actual []mcmstypes.Config) { + require.Equal(t, len(expected), len(actual), "group signers count mismatch") + + for i := range expected { + require.Equal(t, expected[i].Quorum, actual[i].Quorum, "group %d quorum mismatch", i) + require.Equal(t, len(expected[i].Signers), len(actual[i].Signers), "group %d signers count mismatch", i) + + for j, expectedSigner := range expected[i].Signers { + require.Equal(t, expectedSigner, actual[i].Signers[j], "group %d signer mismatch at index %d", i, j) + } + + // Recursively compare nested group signers + compareGroupSigners(t, expected[i].GroupSigners, actual[i].GroupSigners) + } +} From eb29c4c59b5b05290e955de55fbde34a1bd2a543 Mon Sep 17 00:00:00 2001 From: Rodrigo Ariza <15104916+RodrigoAD@users.noreply.github.com> Date: Tue, 10 Feb 2026 16:26:57 +0100 Subject: [PATCH 5/6] Canton executor (#622) --- e2e/tests/canton/common.go | 167 +++++++++++++++- e2e/tests/canton/executor.go | 377 +++++++++++++++++++++++++++++++++++ e2e/tests/runner_test.go | 1 + factory.go | 7 + sdk/canton/chain_metadata.go | 83 ++++++++ sdk/canton/configurer.go | 4 +- sdk/canton/encoder.go | 133 ++++++++++++ sdk/canton/executor.go | 351 ++++++++++++++++++++++++++++++++ types/chain_selector.go | 1 + validation.go | 3 + 10 files changed, 1124 insertions(+), 3 deletions(-) create mode 100644 e2e/tests/canton/executor.go create mode 100644 sdk/canton/chain_metadata.go create mode 100644 sdk/canton/encoder.go create mode 100644 sdk/canton/executor.go diff --git a/e2e/tests/canton/common.go b/e2e/tests/canton/common.go index 578a05618..e9095945a 100644 --- a/e2e/tests/canton/common.go +++ b/e2e/tests/canton/common.go @@ -4,9 +4,13 @@ package canton import ( "context" + "encoding/binary" + "encoding/hex" "fmt" + "strings" "time" + "github.com/ethereum/go-ethereum/crypto" "github.com/google/uuid" "github.com/noders-team/go-daml/pkg/client" "github.com/noders-team/go-daml/pkg/model" @@ -15,8 +19,10 @@ import ( "github.com/smartcontractkit/chainlink-canton/contracts" "github.com/smartcontractkit/chainlink-canton/integration-tests/testhelpers" + mcmscore "github.com/smartcontractkit/mcms" e2e "github.com/smartcontractkit/mcms/e2e/tests" cantonsdk "github.com/smartcontractkit/mcms/sdk/canton" + mcmstypes "github.com/smartcontractkit/mcms/types" "github.com/stretchr/testify/suite" ) @@ -29,8 +35,11 @@ type TestSuite struct { client *client.DamlBindingClient participant testhelpers.Participant + chainSelector mcmstypes.ChainSelector + chainId int64 packageIDs []string mcmsContractID string + mcmsId string } func NewBindingClient(ctx context.Context, jwtToken, ledgerAPIURL, adminAPIURL string) (*client.DamlBindingClient, error) { @@ -54,6 +63,7 @@ func (s *TestSuite) SetupSuite() { s.client, err = NewBindingClient(s.T().Context(), jwt, config.GRPCLedgerAPIURL, config.AdminAPIURL) s.Require().NoError(err) s.participant = participant + s.chainSelector = mcmstypes.ChainSelector(s.env.Chain.ChainSelector()) } const NumGroups = 32 @@ -69,15 +79,69 @@ func (s *TestSuite) DeployMCMSContract() { s.packageIDs = packageIDs mcmsOwner := s.participant.Party - chainId := 1 + chainId := int64(1) baseMcmsId := "mcms-test-001" mcmsId := makeMcmsId(baseMcmsId, "proposer") mcmsContractId := s.createMCMS(s.T().Context(), s.participant, mcmsOwner, chainId, mcmsId, mcms.RoleProposer) s.mcmsContractID = mcmsContractId + s.mcmsId = mcmsId + s.chainId = chainId } -func (s *TestSuite) createMCMS(ctx context.Context, participant testhelpers.Participant, owner string, chainId int, mcmsId string, role mcms.Role) string { +func (s *TestSuite) DeployMCMSWithConfig(config *mcmstypes.Config) { + s.DeployMCMSContract() + + // Set the config + configurer, err := cantonsdk.NewConfigurer(s.client, s.participant.UserName, s.participant.Party) + s.Require().NoError(err) + + tx, err := configurer.SetConfig(s.T().Context(), s.mcmsContractID, config, true) + s.Require().NoError(err) + + // Extract new contract ID + rawData, ok := tx.RawData.(map[string]any) + s.Require().True(ok) + newContractID, ok := rawData["NewMCMSContractID"].(string) + s.Require().True(ok) + s.mcmsContractID = newContractID +} + +func (s *MCMSExecutorTestSuite) DeployCounterContract() { + s.counterInstanceID = "counter-" + uuid.New().String()[:8] + + // Create Counter contract + counterContract := mcms.Counter{ + Owner: types.PARTY(s.participant.Party), + InstanceId: types.TEXT(s.counterInstanceID), + Value: types.INT64(0), + } + + commandID := uuid.Must(uuid.NewUUID()).String() + cmds := &model.SubmitAndWaitRequest{ + Commands: &model.Commands{ + WorkflowID: "counter-deploy", + UserID: s.participant.UserName, + CommandID: commandID, + ActAs: []string{s.participant.Party}, + Commands: []*model.Command{{Command: counterContract.CreateCommand()}}, + }, + } + + submitResp, err := s.client.CommandService.SubmitAndWaitForTransaction(s.T().Context(), cmds) + s.Require().NoError(err) + + // Extract contract ID + for _, event := range submitResp.Transaction.Events { + if event.Created != nil && event.Created.TemplateID != "" { + s.counterCID = event.Created.ContractID + break + } + } + s.Require().NotEmpty(s.counterCID) +} + +func (s *TestSuite) createMCMS(ctx context.Context, participant testhelpers.Participant, owner string, chainId int64, mcmsId string, role mcms.Role) string { // Create empty expiring root emptyExpiringRoot := mcms.ExpiringRoot{ Root: types.TEXT(""), @@ -153,3 +217,102 @@ func (s *TestSuite) createMCMS(ctx context.Context, participant testhelpers.Part func makeMcmsId(baseId string, role string) string { return baseId + "-" + role } + +// TODO: Remove when validUntil calculation is considered in contracts +func (s *TestSuite) SignProposal(proposal *mcmscore.Proposal, signer mcmscore.PrivateKeySigner) mcmstypes.Signature { + // Get the Merkle root of the proposal + tree, err := proposal.MerkleTree() + s.Require().NoError(err, "failed to calculate tree") + + root := tree.Root.Hex() + // Get the valid until timestamp from the proposal metadata + validUntil := proposal.ValidUntil + + // Compute the payload to sign (this should match what the MCMS contract expects) + payload := ComputeSignedHash(root, validUntil) + + // Sign the payload + sig, err := signer.Sign(payload) + s.Require().NoError(err, "failed to sign proposal") + + signature, err := mcmstypes.NewSignatureFromBytes(sig) + s.Require().NoError(err, "failed to create signature from bytes") + + // Append the signature to the proposal + proposal.AppendSignature(signature) + + return signature +} + +func ComputeSignedHash(root string, validUntil uint32) []byte { + // Strip 0x prefix if present + if strings.HasPrefix(root, "0x") { + root = root[2:] + } + + // Inner data: root || validUntil as hex + validUntilHex := Uint32ToHex(validUntil) + concatenated := root + validUntilHex + innerData, err := hex.DecodeString(concatenated) + if err != nil { + panic(fmt.Sprintf("Failed to decode hex: %v, concatenated=%s", err, concatenated)) + } + return crypto.Keccak256Hash(innerData).Bytes() +} + +// Uint32ToHex converts uint32 to 32-byte hex (matching Canton's placeholder) +// Canton currently uses padLeft32 "0" - we match that for compatibility +func Uint32ToHex(validUntil uint32) string { + // For now, match Canton's placeholder implementation + // TODO: Implement proper timestamp encoding when Canton updates + return strings.Repeat("0", 64) +} + +// encodeSetConfigParams encodes SetConfig parameters for Canton MCMS +func EncodeSetConfigParams(s *TestSuite, signerAddresses []string, groupQuorums, groupParents []int64, clearRoot bool) string { + var buf []byte + + // Encode signers list + buf = append(buf, byte(len(signerAddresses))) // numSigners (1 byte) + for i, signer := range signerAddresses { + addrBytes, err := hex.DecodeString(signer) + s.Require().NoError(err, "failed to decode signer address hex") + buf = append(buf, byte(len(addrBytes))) // addressLen (1 byte) + buf = append(buf, addrBytes...) // address bytes + + // SignerIndex (4 bytes, big-endian) + indexBytes := make([]byte, 4) + binary.BigEndian.PutUint32(indexBytes, uint32(i)) //nolint:gosec + buf = append(buf, indexBytes...) + + // SignerGroup (4 bytes, big-endian) + groupBytes := make([]byte, 4) + binary.BigEndian.PutUint32(groupBytes, uint32(0)) //nolint:gosec + buf = append(buf, groupBytes...) + } + + // Encode group quorums + buf = append(buf, byte(len(groupQuorums))) // numQuorums (1 byte) + for _, quorum := range groupQuorums { + quorumBytes := make([]byte, 4) + binary.BigEndian.PutUint32(quorumBytes, uint32(quorum)) //nolint:gosec + buf = append(buf, quorumBytes...) + } + + // Encode group parents + buf = append(buf, byte(len(groupParents))) // numParents (1 byte) + for _, parent := range groupParents { + parentBytes := make([]byte, 4) + binary.BigEndian.PutUint32(parentBytes, uint32(parent)) //nolint:gosec + buf = append(buf, parentBytes...) + } + + // Encode clearRoot (1 byte) + if clearRoot { + buf = append(buf, 0x01) + } else { + buf = append(buf, 0x00) + } + + return hex.EncodeToString(buf) +} diff --git a/e2e/tests/canton/executor.go b/e2e/tests/canton/executor.go new file mode 100644 index 000000000..ad5881982 --- /dev/null +++ b/e2e/tests/canton/executor.go @@ -0,0 +1,377 @@ +//go:build e2e + +package canton + +import ( + "crypto/ecdsa" + "encoding/json" + "fmt" + "slices" + "testing" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" + "github.com/noders-team/go-daml/pkg/model" + "github.com/stretchr/testify/suite" + + mcmscore "github.com/smartcontractkit/mcms" + "github.com/smartcontractkit/mcms/sdk" + cantonsdk "github.com/smartcontractkit/mcms/sdk/canton" + mcmstypes "github.com/smartcontractkit/mcms/types" +) + +type MCMSExecutorTestSuite struct { + TestSuite + + // Test signers + signers []*ecdsa.PrivateKey + signerAddrs []common.Address + sortedSigners []*ecdsa.PrivateKey + sortedWallets []*mcmscore.PrivateKeySigner + + // Counter contract for testing ExecuteOp + counterInstanceID string + counterCID string +} + +func TestMCMSExecutorTestSuite(t *testing.T) { + suite.Run(t, new(MCMSExecutorTestSuite)) +} + +// SetupSuite runs before the test suite +func (s *MCMSExecutorTestSuite) SetupSuite() { + s.TestSuite.SetupSuite() + + // Create 3 signers for 2-of-3 multisig + s.signers = make([]*ecdsa.PrivateKey, 3) + for i := 0; i < 3; i++ { + key, err := crypto.GenerateKey() + s.Require().NoError(err) + s.signers[i] = key + } + + // Sort signers by address + signersCopy := make([]*ecdsa.PrivateKey, len(s.signers)) + copy(signersCopy, s.signers) + slices.SortFunc(signersCopy, func(a, b *ecdsa.PrivateKey) int { + addrA := crypto.PubkeyToAddress(a.PublicKey) + addrB := crypto.PubkeyToAddress(b.PublicKey) + return addrA.Cmp(addrB) + }) + s.sortedSigners = signersCopy + s.sortedWallets = make([]*mcmscore.PrivateKeySigner, len(s.sortedSigners)) + + // Derive sorted addresses from sorted signers to ensure they correspond + s.signerAddrs = make([]common.Address, len(s.sortedSigners)) + for i, signer := range s.sortedSigners { + s.sortedWallets[i] = mcmscore.NewPrivateKeySigner(signer) + s.signerAddrs[i] = crypto.PubkeyToAddress(signer.PublicKey) + } + + // Deploy MCMS with config + config := s.create2of3Config() + s.DeployMCMSWithConfig(config) + + // Deploy Counter contract for ExecuteOp tests + s.DeployCounterContract() +} + +func (s *MCMSExecutorTestSuite) create2of3Config() *mcmstypes.Config { + return &mcmstypes.Config{ + Quorum: 2, + Signers: s.signerAddrs, + } +} + +func (s *MCMSExecutorTestSuite) TestSetRootAndExecuteCounterOp() { + ctx := s.T().Context() + + // Create metadata for Canton chain + metadata, err := cantonsdk.NewChainMetadata( + 0, // preOpCount + 1, + s.chainId, + s.mcmsId, + s.mcmsContractID, + false, + ) + s.Require().NoError(err) + + // Build a test proposal with an operation to increment counter + validUntil := time.Now().Add(24 * time.Hour) + opAdditionalFields := cantonsdk.AdditionalFields{ + TargetInstanceId: fmt.Sprintf("%s@%s", s.counterInstanceID, s.participant.Party), + FunctionName: "increment", + OperationData: "", + TargetCid: s.counterCID, + ContractIds: []string{s.counterCID}, + } + opAdditionalFieldsBytes, err := json.Marshal(opAdditionalFields) + s.Require().NoError(err) + + proposal, err := mcmscore.NewProposalBuilder(). + SetVersion("v1"). + SetValidUntil(uint32(validUntil.Unix())). + SetDescription(fmt.Sprintf("Canton ExecuteOp test - %v", validUntil)). + SetOverridePreviousRoot(false). + AddChainMetadata(s.chainSelector, metadata). + AddOperation(mcmstypes.Operation{ + ChainSelector: s.chainSelector, + Transaction: mcmstypes.Transaction{ + To: s.counterCID, + Data: []byte{}, + AdditionalFields: opAdditionalFieldsBytes, + }, + }). + Build() + s.Require().NoError(err) + + // Create inspector and executor + inspector := cantonsdk.NewInspector(s.participant.StateServiceClient, s.participant.Party) + + encoders, err := proposal.GetEncoders() + s.Require().NoError(err) + encoder := encoders[s.chainSelector].(*cantonsdk.Encoder) + + executor, err := cantonsdk.NewExecutor(encoder, inspector, s.client, s.participant.UserName, s.participant.Party) + s.Require().NoError(err) + + executors := map[mcmstypes.ChainSelector]sdk.Executor{ + s.chainSelector: executor, + } + + // Sign with first 2 sorted signers + for i := 0; i < 2; i++ { + _ = s.SignProposal(proposal, *s.sortedWallets[i]) + s.Require().NoError(err) + } + + // Create executable + executable, err := mcmscore.NewExecutable(proposal, executors) + s.Require().NoError(err) + + // First, set the root + txSetRoot, err := executable.SetRoot(ctx, s.chainSelector) + s.Require().NoError(err) + s.Require().NotEmpty(txSetRoot.Hash) + + // Update contract ID after SetRoot + rawData, ok := txSetRoot.RawData.(map[string]any) + s.Require().True(ok) + newMCMSContractID, ok := rawData["NewMCMSContractID"].(string) + s.Require().True(ok) + s.Require().NotEmpty(newMCMSContractID) + s.mcmsContractID = newMCMSContractID + + s.T().Logf("✅ SetRoot completed, new MCMS CID: %s", s.mcmsContractID) + + // Update proposal with new multisig id + newMetadata, err := cantonsdk.NewChainMetadata( + 0, // preOpCount + 1, // postOp + s.chainId, + s.mcmsId, + s.mcmsContractID, + false, + ) + proposal.ChainMetadata[s.chainSelector] = newMetadata + // Now execute the operation (index 0) + txExecute, err := executable.Execute(ctx, 0) + s.Require().NoError(err) + s.Require().NotEmpty(txExecute.Hash) + + // Verify the counter was incremented by checking transaction events + rawTx, ok := txExecute.RawData.(map[string]any)["RawTx"] + s.Require().True(ok) + submitResp, ok := rawTx.(*model.SubmitAndWaitForTransactionResponse) + s.Require().True(ok) + + s.verifyCounterIncremented(submitResp) + + // Verify MCMS contract was recreated with incremented opCount + foundMCMS := false + for _, event := range submitResp.Transaction.Events { + if event.Created != nil { + normalized := cantonsdk.NormalizeTemplateKey(event.Created.TemplateID) + if normalized == cantonsdk.MCMSTemplateKey { + foundMCMS = true + newMCMSCID := event.Created.ContractID + s.Require().NotEmpty(newMCMSCID) + s.Require().NotEqual(s.mcmsContractID, newMCMSCID, "MCMS should be recreated after execute") + s.mcmsContractID = newMCMSCID + s.T().Logf("✅ MCMS contract recreated: %s", s.mcmsContractID) + break + } + } + } + s.Require().True(foundMCMS, "MCMS contract should be recreated after execute") + + s.T().Logf("✅ ExecuteOp completed in tx: %s", txExecute.Hash) +} + +func (s *MCMSExecutorTestSuite) TestSetRootAndExecuteMCMSOp() { + ctx := s.T().Context() + + // Encode the SetConfig operation data to change quorum from 2 to 1 + // For Canton, we need to encode the signers, group quorums, and group parents + groupQuorums := make([]int64, 32) + groupQuorums[0] = 1 // Root group needs 1 signature now + groupParents := make([]int64, 32) + // All groups point to root (0) + + // Convert signers to lowercase hex without 0x prefix (Canton format) + signerAddresses := make([]string, len(s.signerAddrs)) + signerGroups := make([]int64, len(s.signerAddrs)) + for i, addr := range s.signerAddrs { + signerAddresses[i] = addr.Hex()[2:] // Remove 0x prefix, keep checksum + signerGroups[i] = 0 // All in group 0 + } + + // Encode SetConfig params using Canton's encoding format + // This follows the format from chainlink-canton integration tests + operationData := EncodeSetConfigParams(&s.TestSuite, signerAddresses, groupQuorums, groupParents, false) + + // Create metadata for Canton chain + metadata, err := cantonsdk.NewChainMetadata( + 1, // preOpCount + 2, // postOp + s.chainId, + s.mcmsId, + s.mcmsContractID, + false, + ) + s.Require().NoError(err) + + // Build a proposal with SetConfig operation targeting MCMS itself + validUntil := time.Now().Add(24 * time.Hour) + opAdditionalFields := cantonsdk.AdditionalFields{ + TargetInstanceId: "self", + FunctionName: "set_config", + OperationData: operationData, + TargetCid: s.mcmsContractID, + ContractIds: []string{s.mcmsContractID}, + } + opAdditionalFieldsBytes, err := json.Marshal(opAdditionalFields) + s.Require().NoError(err) + + proposal, err := mcmscore.NewProposalBuilder(). + SetVersion("v1"). + SetValidUntil(uint32(validUntil.Unix())). + SetDescription(fmt.Sprintf("Canton SetConfig test - change quorum to 3 - %v", validUntil)). + SetOverridePreviousRoot(false). + AddChainMetadata(s.chainSelector, metadata). + AddOperation(mcmstypes.Operation{ + ChainSelector: s.chainSelector, + Transaction: mcmstypes.Transaction{ + To: s.mcmsContractID, + Data: []byte{}, + AdditionalFields: opAdditionalFieldsBytes, + }, + }). + Build() + s.Require().NoError(err) + + // Create inspector and executor + inspector := cantonsdk.NewInspector(s.participant.StateServiceClient, s.participant.Party) + + encoders, err := proposal.GetEncoders() + s.Require().NoError(err) + encoder := encoders[s.chainSelector].(*cantonsdk.Encoder) + + executor, err := cantonsdk.NewExecutor(encoder, inspector, s.client, s.participant.UserName, s.participant.Party) + s.Require().NoError(err) + + executors := map[mcmstypes.ChainSelector]sdk.Executor{ + s.chainSelector: executor, + } + + // Sign with first 2 sorted signers (current quorum is 2) + for i := 0; i < 2; i++ { + _ = s.SignProposal(proposal, *s.sortedWallets[i]) + s.Require().NoError(err) + } + + // Create executable + executable, err := mcmscore.NewExecutable(proposal, executors) + s.Require().NoError(err) + + // First, set the root + txSetRoot, err := executable.SetRoot(ctx, s.chainSelector) + s.Require().NoError(err) + s.Require().NotEmpty(txSetRoot.Hash) + + // Update contract ID after SetRoot + rawData, ok := txSetRoot.RawData.(map[string]any) + s.Require().True(ok) + newMCMSContractID, ok := rawData["NewMCMSContractID"].(string) + s.Require().True(ok) + s.Require().NotEmpty(newMCMSContractID) + oldMCMSContractID := s.mcmsContractID + s.mcmsContractID = newMCMSContractID + s.Require().NotEqual(oldMCMSContractID, s.mcmsContractID, "MCMS contract ID should change after SetRoot") + + // Update proposal with new MCMS contract ID in metadata + + s.T().Logf("✅ SetRoot completed, new MCMS CID: %s", s.mcmsContractID) + + newMetadata, err := cantonsdk.NewChainMetadata( + 1, // preOpCount + 2, // postOp + s.chainId, + s.mcmsId, + newMCMSContractID, + false, + ) + s.Require().NoError(err) + // Override proposal metadata with new MCMS contract ID + proposal.ChainMetadata[s.chainSelector] = newMetadata + + // Now execute the SetConfig operation (index 0) + txExecute, err := executable.Execute(ctx, 0) + s.Require().NoError(err) + s.Require().NotEmpty(txExecute.Hash) + + // Verify MCMS contract was recreated with new config + rawTx, ok := txExecute.RawData.(map[string]any)["RawTx"] + s.Require().True(ok) + submitResp, ok := rawTx.(*model.SubmitAndWaitForTransactionResponse) + s.Require().True(ok) + + foundMCMS := false + for _, event := range submitResp.Transaction.Events { + if event.Created != nil { + normalized := cantonsdk.NormalizeTemplateKey(event.Created.TemplateID) + if normalized == cantonsdk.MCMSTemplateKey { + foundMCMS = true + newMCMSCID := event.Created.ContractID + s.Require().NotEmpty(newMCMSCID) + s.Require().NotEqual(oldMCMSContractID, newMCMSCID, "MCMS should be recreated after SetConfig") + s.mcmsContractID = newMCMSCID + s.T().Logf("✅ MCMS contract recreated with new config: %s", s.mcmsContractID) + break + } + } + } + s.Require().True(foundMCMS, "MCMS contract should be recreated after SetConfig") + + s.T().Logf("✅ SetConfig operation completed in tx: %s", txExecute.Hash) + + // TODO: Inspect config when ready +} + +// Helper functions +func (s *MCMSExecutorTestSuite) verifyCounterIncremented(submitResp *model.SubmitAndWaitForTransactionResponse) { + // Look for Counter contract in created events + for _, event := range submitResp.Transaction.Events { + if event.Created != nil { + normalized := cantonsdk.NormalizeTemplateKey(event.Created.TemplateID) + if normalized == "MCMS.Counter:Counter" { + // Counter was recreated, which means it was successfully executed + s.T().Log("Counter contract was successfully incremented") + return + } + } + } + s.Fail("Counter contract not found in transaction events") +} diff --git a/e2e/tests/runner_test.go b/e2e/tests/runner_test.go index 4d23bd6e7..9e753175f 100644 --- a/e2e/tests/runner_test.go +++ b/e2e/tests/runner_test.go @@ -54,4 +54,5 @@ func TestTONSuite(t *testing.T) { func TestCantonSuite(t *testing.T) { suite.Run(t, new(cantone2e.MCMSConfigurerTestSuite)) suite.Run(t, new(cantone2e.MCMSInspectorTestSuite)) + suite.Run(t, new(cantone2e.MCMSExecutorTestSuite)) } diff --git a/factory.go b/factory.go index 37cc1cb1a..5a77148e2 100644 --- a/factory.go +++ b/factory.go @@ -7,6 +7,7 @@ import ( "github.com/smartcontractkit/mcms/sdk" "github.com/smartcontractkit/mcms/sdk/aptos" + "github.com/smartcontractkit/mcms/sdk/canton" "github.com/smartcontractkit/mcms/sdk/evm" "github.com/smartcontractkit/mcms/sdk/solana" "github.com/smartcontractkit/mcms/sdk/sui" @@ -59,6 +60,12 @@ func newEncoder( txCount, overridePreviousRoot, ) + case cselectors.FamilyCanton: + encoder = canton.NewEncoder( + csel, + txCount, + overridePreviousRoot, + ) } return encoder, nil diff --git a/sdk/canton/chain_metadata.go b/sdk/canton/chain_metadata.go new file mode 100644 index 000000000..0bad7934c --- /dev/null +++ b/sdk/canton/chain_metadata.go @@ -0,0 +1,83 @@ +package canton + +import ( + "encoding/json" + "errors" + "fmt" + + "github.com/smartcontractkit/mcms/types" +) + +// AdditionalFieldsMetadata represents the Canton-specific metadata fields +type AdditionalFieldsMetadata struct { + ChainId int64 `json:"chainId"` + MultisigId string `json:"multisigId"` + PreOpCount uint64 `json:"preOpCount"` + PostOpCount uint64 `json:"postOpCount"` + OverridePreviousRoot bool `json:"overridePreviousRoot"` +} + +func (f AdditionalFieldsMetadata) Validate() error { + if f.ChainId == 0 { + return errors.New("chainId is required") + } + if f.MultisigId == "" { + return errors.New("multisigId is required") + } + if f.PostOpCount < f.PreOpCount { + return errors.New("postOpCount must be >= preOpCount") + } + + return nil +} + +// ValidateChainMetadata validates Canton chain metadata +func ValidateChainMetadata(metadata types.ChainMetadata) error { + var additionalFields AdditionalFieldsMetadata + if err := json.Unmarshal(metadata.AdditionalFields, &additionalFields); err != nil { + return fmt.Errorf("unable to unmarshal additional fields: %w", err) + } + + if err := additionalFields.Validate(); err != nil { + return fmt.Errorf("additional fields are invalid: %w", err) + } + + return nil +} + +// NewChainMetadata creates new Canton chain metadata +func NewChainMetadata( + preOpCount uint64, + postOpCount uint64, + chainId int64, + multisigId string, + mcmsContractID string, + overridePreviousRoot bool, +) (types.ChainMetadata, error) { + if mcmsContractID == "" { + return types.ChainMetadata{}, errors.New("MCMS contract ID is required") + } + + additionalFields := AdditionalFieldsMetadata{ + ChainId: chainId, + MultisigId: multisigId, + PreOpCount: preOpCount, + PostOpCount: postOpCount, + OverridePreviousRoot: overridePreviousRoot, + } + + if err := additionalFields.Validate(); err != nil { + return types.ChainMetadata{}, fmt.Errorf("additional fields are invalid: %w", err) + } + + additionalFieldsBytes, err := json.Marshal(additionalFields) + if err != nil { + return types.ChainMetadata{}, fmt.Errorf("unable to marshal additional fields: %w", err) + } + + return types.ChainMetadata{ + StartingOpCount: preOpCount, + AdditionalFields: additionalFieldsBytes, + MCMAddress: mcmsContractID, + }, nil +} diff --git a/sdk/canton/configurer.go b/sdk/canton/configurer.go index 14ba3a3b5..764c27091 100644 --- a/sdk/canton/configurer.go +++ b/sdk/canton/configurer.go @@ -40,8 +40,10 @@ func (c Configurer) SetConfig(ctx context.Context, mcmsAddr string, cfg *types.C signers := make([]mcms.SignerInfo, len(signerAddresses)) for i, addr := range signerAddresses { + addrStr := strings.ToLower(addr.String()) + addrStr = strings.TrimPrefix(addrStr, "0x") signers[i] = mcms.SignerInfo{ - SignerAddress: cantontypes.TEXT(addr.String()), + SignerAddress: cantontypes.TEXT(addrStr), SignerGroup: cantontypes.INT64(signerGroups[i]), SignerIndex: cantontypes.INT64(i), } diff --git a/sdk/canton/encoder.go b/sdk/canton/encoder.go new file mode 100644 index 000000000..6bda220fd --- /dev/null +++ b/sdk/canton/encoder.go @@ -0,0 +1,133 @@ +package canton + +import ( + "encoding/hex" + "encoding/json" + "fmt" + "strings" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" + + "github.com/smartcontractkit/mcms/sdk" + "github.com/smartcontractkit/mcms/types" +) + +// AdditionalFields represents the additional fields in Canton MCMS operations +type AdditionalFields struct { + TargetInstanceId string `json:"targetInstanceId"` + FunctionName string `json:"functionName"` + OperationData string `json:"operationData"` + TargetCid string `json:"targetCid"` + ContractIds []string `json:"contractIds"` +} + +var _ sdk.Encoder = &Encoder{} + +type Encoder struct { + ChainSelector types.ChainSelector + TxCount uint64 + OverridePreviousRoot bool +} + +func NewEncoder( + chainSelector types.ChainSelector, + txCount uint64, + overridePreviousRoot bool, +) *Encoder { + return &Encoder{ + ChainSelector: chainSelector, + TxCount: txCount, + OverridePreviousRoot: overridePreviousRoot, + } +} + +// HashOperation hashes an operation to get its Merkle leaf +// Matches Canton's hashOpLeafNative from Crypto.daml +func (e *Encoder) HashOperation(opCount uint32, metadata types.ChainMetadata, op types.Operation) (common.Hash, error) { + // Unmarshal Canton-specific metadata + var metadataFields AdditionalFieldsMetadata + if err := json.Unmarshal(metadata.AdditionalFields, &metadataFields); err != nil { + return common.Hash{}, fmt.Errorf("failed to unmarshal metadata additional fields: %w", err) + } + + // Unmarshal Canton-specific operation fields + var opFields AdditionalFields + if err := json.Unmarshal(op.Transaction.AdditionalFields, &opFields); err != nil { + return common.Hash{}, fmt.Errorf("failed to unmarshal operation additional fields: %w", err) + } + + // Build the encoded data following Canton's hashOpLeafNative: + // encoded = padLeft32(chainId) + asciiToHex(multisigId) + padLeft32(nonce) + + // asciiToHex(targetInstanceId) + asciiToHex(functionName) + operationData + encoded := padLeft32(intToHex(int(metadataFields.ChainId))) + + asciiToHex(metadataFields.MultisigId) + + padLeft32(intToHex(int(opCount))) + + asciiToHex(opFields.TargetInstanceId) + + asciiToHex(opFields.FunctionName) + + opFields.OperationData + + // Decode hex string and hash + data, err := hex.DecodeString(encoded) + if err != nil { + return common.Hash{}, fmt.Errorf("failed to decode hex string: %w", err) + } + + return crypto.Keccak256Hash(data), nil +} + +// HashMetadata hashes metadata to get its Merkle leaf +// Matches Canton's hashMetadataLeafNative from Crypto.daml +func (e *Encoder) HashMetadata(metadata types.ChainMetadata) (common.Hash, error) { + // Unmarshal Canton-specific metadata + var metadataFields AdditionalFieldsMetadata + if err := json.Unmarshal(metadata.AdditionalFields, &metadataFields); err != nil { + return common.Hash{}, fmt.Errorf("failed to unmarshal metadata additional fields: %w", err) + } + + // Build override flag + overrideFlag := "00" + if metadataFields.OverridePreviousRoot { + overrideFlag = "01" + } + + // Build the encoded data following Canton's hashMetadataLeafNative: + // encoded = padLeft32(chainId) + asciiToHex(multisigId) + + // padLeft32(preOpCount) + padLeft32(postOpCount) + overrideFlag + encoded := padLeft32(intToHex(int(metadataFields.ChainId))) + + asciiToHex(metadataFields.MultisigId) + + padLeft32(intToHex(int(metadataFields.PreOpCount))) + + padLeft32(intToHex(int(metadataFields.PostOpCount))) + + overrideFlag + + // Decode hex string and hash + data, err := hex.DecodeString(encoded) + if err != nil { + return common.Hash{}, fmt.Errorf("failed to decode hex string: %w", err) + } + + return crypto.Keccak256Hash(data), nil +} + +// Helper functions matching Canton Crypto.daml + +// padLeft32 pads hex string to 64 chars (32 bytes) +func padLeft32(hexStr string) string { + if len(hexStr) >= 64 { + return hexStr[:64] + } + return strings.Repeat("0", 64-len(hexStr)) + hexStr +} + +// intToHex converts int to hex string (without padding) +func intToHex(n int) string { + if n == 0 { + return "0" + } + return fmt.Sprintf("%x", n) +} + +// asciiToHex converts ASCII string to hex +func asciiToHex(s string) string { + return hex.EncodeToString([]byte(s)) +} diff --git a/sdk/canton/executor.go b/sdk/canton/executor.go new file mode 100644 index 000000000..56100e233 --- /dev/null +++ b/sdk/canton/executor.go @@ -0,0 +1,351 @@ +package canton + +import ( + "context" + "encoding/hex" + "encoding/json" + "errors" + "fmt" + "strings" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" + "github.com/google/uuid" + "github.com/noders-team/go-daml/pkg/client" + "github.com/noders-team/go-daml/pkg/model" + cselectors "github.com/smartcontractkit/chain-selectors" + + cantontypes "github.com/noders-team/go-daml/pkg/types" + "github.com/smartcontractkit/chainlink-canton/bindings/mcms" + "github.com/smartcontractkit/mcms/sdk" + "github.com/smartcontractkit/mcms/types" +) + +var _ sdk.Executor = &Executor{} + +type Executor struct { + *Encoder + *Inspector + client *client.DamlBindingClient + userId string + party string +} + +func NewExecutor(encoder *Encoder, inspector *Inspector, client *client.DamlBindingClient, userId string, party string) (*Executor, error) { + return &Executor{ + Encoder: encoder, + Inspector: inspector, + client: client, + userId: userId, + party: party, + }, nil +} + +func (e Executor) ExecuteOperation( + ctx context.Context, + metadata types.ChainMetadata, + nonce uint32, + proof []common.Hash, + op types.Operation, +) (types.TransactionResult, error) { + // Extract Canton-specific operation fields from AdditionalFields + var cantonOpFields AdditionalFields + if len(op.Transaction.AdditionalFields) > 0 { + if err := json.Unmarshal(op.Transaction.AdditionalFields, &cantonOpFields); err != nil { + return types.TransactionResult{}, fmt.Errorf("failed to unmarshal operation additional fields: %w", err) + } + } + + // Validate required Canton fields + if cantonOpFields.TargetInstanceId == "" { + return types.TransactionResult{}, errors.New("targetInstanceId is required in operation additional fields") + } + if cantonOpFields.FunctionName == "" { + return types.TransactionResult{}, errors.New("functionName is required in operation additional fields") + } + if cantonOpFields.TargetCid == "" { + return types.TransactionResult{}, errors.New("targetCid is required in operation additional fields") + } + + // Extract metadata fields for chainId and multisigId + var metadataFields struct { + ChainId int64 `json:"chainId"` + MultisigId string `json:"multisigId"` + } + if len(metadata.AdditionalFields) > 0 { + if err := json.Unmarshal(metadata.AdditionalFields, &metadataFields); err != nil { + return types.TransactionResult{}, fmt.Errorf("failed to unmarshal metadata additional fields: %w", err) + } + } + + // Build Canton Op struct + cantonOp := mcms.Op{ + ChainId: cantontypes.INT64(metadataFields.ChainId), + MultisigId: cantontypes.TEXT(metadataFields.MultisigId), + Nonce: cantontypes.INT64(nonce), + TargetInstanceId: cantontypes.TEXT(cantonOpFields.TargetInstanceId), + FunctionName: cantontypes.TEXT(cantonOpFields.FunctionName), + OperationData: cantontypes.TEXT(cantonOpFields.OperationData), + } + + // Convert proof to Canton TEXT array + opProof := make([]cantontypes.TEXT, len(proof)) + for i, p := range proof { + opProof[i] = cantontypes.TEXT(hex.EncodeToString(p[:])) + } + + // Convert contract IDs + contractIds := make([]cantontypes.CONTRACT_ID, len(cantonOpFields.ContractIds)) + for i, cid := range cantonOpFields.ContractIds { + contractIds[i] = cantontypes.CONTRACT_ID(cid) + } + + // Build exercise command using generated bindings + mcmsContract := mcms.MCMS{} + var exerciseCmd *model.ExerciseCommand + // Use different input struct depending on whether the operation is targeting the MCMS contract itself or another contract + if cantonOpFields.TargetInstanceId == "self" { + input := mcms.ExecuteMcmsOp{ + Submitter: cantontypes.PARTY(e.party), + Op: cantonOp, + OpProof: opProof, + } + exerciseCmd = mcmsContract.ExecuteMcmsOp(metadata.MCMAddress, input) + } else { + input := mcms.ExecuteOp{ + Submitter: cantontypes.PARTY(e.party), + TargetCid: cantontypes.CONTRACT_ID(cantonOpFields.TargetCid), + Op: cantonOp, + OpProof: opProof, + ContractIds: contractIds, + } + exerciseCmd = mcmsContract.ExecuteOp(metadata.MCMAddress, input) + + } + + // List known packages to find the package ID for mcms + ListKnownPackagesResp, err := e.client.PackageMng.ListKnownPackages(ctx) + if err != nil { + return types.TransactionResult{}, fmt.Errorf("failed to list known packages: %w", err) + } + + var mcmsPkgID string + for _, p := range ListKnownPackagesResp { + if strings.Contains(strings.ToLower(p.Name), "mcms") { + mcmsPkgID = p.PackageID + break + } + } + if mcmsPkgID == "" { + return types.TransactionResult{}, fmt.Errorf("failed to find mcms package") + } + + commandID := uuid.Must(uuid.NewUUID()).String() + cmds := &model.SubmitAndWaitRequest{ + Commands: &model.Commands{ + WorkflowID: "mcms-execute-op", + UserID: e.userId, + CommandID: commandID, + ActAs: []string{e.party}, + Commands: []*model.Command{{ + Command: &model.ExerciseCommand{ + TemplateID: exerciseCmd.TemplateID, + ContractID: exerciseCmd.ContractID, + Choice: exerciseCmd.Choice, + Arguments: exerciseCmd.Arguments, + }, + }}, + }, + } + + submitResp, err := e.client.CommandService.SubmitAndWaitForTransaction(ctx, cmds) + if err != nil { + return types.TransactionResult{}, fmt.Errorf("failed to execute operation: %w", err) + } + + // Extract NEW MCMS CID from Created event + newMCMSContractID := "" + newMCMSTemplateID := "" + for _, ev := range submitResp.Transaction.Events { + if ev.Created == nil { + continue + } + normalized := NormalizeTemplateKey(ev.Created.TemplateID) + if normalized == MCMSTemplateKey { + newMCMSContractID = ev.Created.ContractID + newMCMSTemplateID = ev.Created.TemplateID + break + } + } + + if newMCMSContractID == "" { + return types.TransactionResult{}, fmt.Errorf("execute-op tx had no Created MCMS event; refusing to continue with old CID=%s", metadata.MCMAddress) + } + + return types.TransactionResult{ + Hash: commandID, + ChainFamily: cselectors.FamilyCanton, + RawData: map[string]any{ + "NewMCMSContractID": newMCMSContractID, + "NewMCMSTemplateID": newMCMSTemplateID, + "RawTx": submitResp, + }, + }, nil +} + +func (e Executor) SetRoot( + ctx context.Context, + metadata types.ChainMetadata, + proof []common.Hash, + root [32]byte, + validUntil uint32, + sortedSignatures []types.Signature, +) (types.TransactionResult, error) { + // Calculate the hash to sign according to Canton's expectations, and extract signers from it + rootHex := hex.EncodeToString(root[:]) + validUntilHexForSigning := strings.Repeat("0", 64) // TODO: Remove, Canton placeholder (64 zeros) + concatenated := rootHex + validUntilHexForSigning + + innerData, err := hex.DecodeString(concatenated) + if err != nil { + return types.TransactionResult{}, fmt.Errorf("failed to decode hex for signing: %w", err) + } + innerHash := crypto.Keccak256(innerData) + + // Apply EIP-191 prefix + prefix := []byte("\x19Ethereum Signed Message:\n32") + prefixedData := append(prefix, innerHash...) + cantonSignedHash := crypto.Keccak256Hash(prefixedData) + + // Convert signatures to Canton RawSignature array + signatures := make([]mcms.RawSignature, len(sortedSignatures)) + for i, sig := range sortedSignatures { + pubKey, err := sig.RecoverPublicKey(cantonSignedHash) + if err != nil { + return types.TransactionResult{}, fmt.Errorf("failed to recover public key for signature %d: %w", i, err) + } + + // Convert public key to hex string + pubkeyHex := hex.EncodeToString(crypto.FromECDSAPub(pubKey)) + signatures[i] = mcms.RawSignature{ + PublicKey: cantontypes.TEXT(pubkeyHex), + R: cantontypes.TEXT(hex.EncodeToString(sig.R[:])), + S: cantontypes.TEXT(hex.EncodeToString(sig.S[:])), + } + } + + // Extract root metadata from ChainMetadata.AdditionalFields + var rootMetadata mcms.RootMetadata + if len(metadata.AdditionalFields) > 0 { + var additionalFields map[string]interface{} + if err := json.Unmarshal(metadata.AdditionalFields, &additionalFields); err != nil { + return types.TransactionResult{}, fmt.Errorf("failed to unmarshal additional fields: %w", err) + } + + // Extract fields with type assertions + if chainId, ok := additionalFields["chainId"].(float64); ok { + rootMetadata.ChainId = cantontypes.INT64(int64(chainId)) + } + if multisigId, ok := additionalFields["multisigId"].(string); ok { + rootMetadata.MultisigId = cantontypes.TEXT(multisigId) + } + if preOpCount, ok := additionalFields["preOpCount"].(float64); ok { + rootMetadata.PreOpCount = cantontypes.INT64(int64(preOpCount)) + } + if postOpCount, ok := additionalFields["postOpCount"].(float64); ok { + rootMetadata.PostOpCount = cantontypes.INT64(int64(postOpCount)) + } + if overridePreviousRoot, ok := additionalFields["overridePreviousRoot"].(bool); ok { + rootMetadata.OverridePreviousRoot = cantontypes.BOOL(overridePreviousRoot) + } + } + + // Convert proof to Canton TEXT array + metadataProof := make([]cantontypes.TEXT, len(proof)) + for i, p := range proof { + metadataProof[i] = cantontypes.TEXT(hex.EncodeToString(p[:])) + } + + validUntilTime := time.Unix(time.Unix(int64(validUntil), 0).UnixMicro(), 0) + input := mcms.SetRoot{ + Submitter: cantontypes.PARTY(e.party), + NewRoot: cantontypes.TEXT(rootHex), + ValidUntil: cantontypes.TIMESTAMP(validUntilTime), + Metadata: rootMetadata, + MetadataProof: metadataProof, + Signatures: signatures, + } + + // Build exercise command using generated bindings + mcmsContract := mcms.MCMS{} + exerciseCmd := mcmsContract.SetRoot(metadata.MCMAddress, input) + + ListKnownPackagesResp, err := e.client.PackageMng.ListKnownPackages(ctx) + if err != nil { + return types.TransactionResult{}, fmt.Errorf("failed to list known packages: %w", err) + } + + var mcmsPkgID string + for _, p := range ListKnownPackagesResp { + if strings.Contains(strings.ToLower(p.Name), "mcms") { + mcmsPkgID = p.PackageID + break + } + } + if mcmsPkgID == "" { + return types.TransactionResult{}, fmt.Errorf("failed to find mcms package") + } + + commandID := uuid.Must(uuid.NewUUID()).String() + cmds := &model.SubmitAndWaitRequest{ + Commands: &model.Commands{ + WorkflowID: "mcms-set-root", + UserID: e.userId, + CommandID: commandID, + ActAs: []string{e.party}, + Commands: []*model.Command{{ + Command: &model.ExerciseCommand{ + TemplateID: exerciseCmd.TemplateID, + ContractID: exerciseCmd.ContractID, + Choice: exerciseCmd.Choice, + Arguments: exerciseCmd.Arguments, + }, + }}, + }, + } + + submitResp, err := e.client.CommandService.SubmitAndWaitForTransaction(ctx, cmds) + if err != nil { + return types.TransactionResult{}, fmt.Errorf("failed to set root: %w", err) + } + + // Extract NEW MCMS CID from Created event + newMCMSContractID := "" + newMCMSTemplateID := "" + for _, ev := range submitResp.Transaction.Events { + if ev.Created == nil { + continue + } + normalized := NormalizeTemplateKey(ev.Created.TemplateID) + if normalized == MCMSTemplateKey { + newMCMSContractID = ev.Created.ContractID + newMCMSTemplateID = ev.Created.TemplateID + break + } + } + + if newMCMSContractID == "" { + return types.TransactionResult{}, fmt.Errorf("set-root tx had no Created MCMS event; refusing to continue with old CID=%s", metadata.MCMAddress) + } + + return types.TransactionResult{ + Hash: commandID, + ChainFamily: cselectors.FamilyCanton, + RawData: map[string]any{ + "NewMCMSContractID": newMCMSContractID, + "NewMCMSTemplateID": newMCMSTemplateID, + "RawTx": submitResp, + }, + }, nil +} diff --git a/types/chain_selector.go b/types/chain_selector.go index 1bf0cdf0d..93cde4c08 100644 --- a/types/chain_selector.go +++ b/types/chain_selector.go @@ -29,6 +29,7 @@ var supportedFamilies = []string{ cselectors.FamilyAptos, cselectors.FamilySui, cselectors.FamilyTon, + cselectors.FamilyCanton, } // GetChainSelectorFamily returns the family of the chain selector. diff --git a/validation.go b/validation.go index f5355bcdc..14efca3d6 100644 --- a/validation.go +++ b/validation.go @@ -9,6 +9,7 @@ import ( "github.com/smartcontractkit/mcms/types" "github.com/smartcontractkit/mcms/sdk/aptos" + "github.com/smartcontractkit/mcms/sdk/canton" "github.com/smartcontractkit/mcms/sdk/evm" "github.com/smartcontractkit/mcms/sdk/solana" "github.com/smartcontractkit/mcms/sdk/sui" @@ -57,6 +58,8 @@ func validateChainMetadata(metadata types.ChainMetadata, csel types.ChainSelecto return nil case cselectors.FamilySui: return sui.ValidateChainMetadata(metadata) + case cselectors.FamilyCanton: + return canton.ValidateChainMetadata(metadata) case cselectors.FamilyTon: // TODO (ton): do we need special chain metadata for TON? // Yes! We could attach MCMS -> Timelock value here which is now hardcoded default in timelock converter From 43178367399932af52d5a9edb500df48b8e23d59 Mon Sep 17 00:00:00 2001 From: Rodrigo Ariza <15104916+RodrigoAD@users.noreply.github.com> Date: Wed, 11 Feb 2026 21:05:06 +0100 Subject: [PATCH 6/6] Canton bump (#627) - Adapts to latest contract changes - Removes DAML client to use raw pb client --- e2e/tests/canton/common.go | 278 ++++++++++++++++----------------- e2e/tests/canton/configurer.go | 30 ++-- e2e/tests/canton/executor.go | 66 ++++---- e2e/tests/canton/inspector.go | 6 +- e2e/tests/runner_test.go | 3 +- go.mod | 13 +- go.sum | 30 +--- sdk/canton/chain_metadata.go | 25 +++ sdk/canton/configurer.go | 82 +++++----- sdk/canton/encoder.go | 5 - sdk/canton/executor.go | 202 ++++++++++++------------ sdk/canton/helpers.go | 38 ++++- sdk/canton/inspector.go | 84 +++++++++- sdk/canton/inspector_test.go | 2 +- 14 files changed, 483 insertions(+), 381 deletions(-) diff --git a/e2e/tests/canton/common.go b/e2e/tests/canton/common.go index e9095945a..1eae4e9cf 100644 --- a/e2e/tests/canton/common.go +++ b/e2e/tests/canton/common.go @@ -4,23 +4,22 @@ package canton import ( "context" + "crypto/ecdsa" "encoding/binary" "encoding/hex" "fmt" - "strings" - "time" - "github.com/ethereum/go-ethereum/crypto" + apiv2 "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2" "github.com/google/uuid" - "github.com/noders-team/go-daml/pkg/client" - "github.com/noders-team/go-daml/pkg/model" - "github.com/noders-team/go-daml/pkg/types" "github.com/smartcontractkit/chainlink-canton/bindings/mcms" "github.com/smartcontractkit/chainlink-canton/contracts" "github.com/smartcontractkit/chainlink-canton/integration-tests/testhelpers" + "github.com/smartcontractkit/go-daml/pkg/service/ledger" + "github.com/smartcontractkit/go-daml/pkg/types" mcmscore "github.com/smartcontractkit/mcms" e2e "github.com/smartcontractkit/mcms/e2e/tests" + "github.com/smartcontractkit/mcms/sdk" cantonsdk "github.com/smartcontractkit/mcms/sdk/canton" mcmstypes "github.com/smartcontractkit/mcms/types" "github.com/stretchr/testify/suite" @@ -32,7 +31,6 @@ type TestSuite struct { env testhelpers.TestEnvironment - client *client.DamlBindingClient participant testhelpers.Participant chainSelector mcmstypes.ChainSelector @@ -40,28 +38,13 @@ type TestSuite struct { packageIDs []string mcmsContractID string mcmsId string -} - -func NewBindingClient(ctx context.Context, jwtToken, ledgerAPIURL, adminAPIURL string) (*client.DamlBindingClient, error) { - bindingClient, err := client.NewDamlClient(jwtToken, ledgerAPIURL). - WithAdminAddress(adminAPIURL). - Build(ctx) - if err != nil { - return nil, fmt.Errorf("failed to create DAML binding client: %w", err) - } - - return bindingClient, nil + proposerMcmsId string } func (s *TestSuite) SetupSuite() { s.T().Log("Spinning up Canton test environment...") s.env = testhelpers.NewTestEnvironment(s.T(), testhelpers.WithNumberOfParticipants(1)) - jwt, err := s.env.Participant(1).GetToken(s.T().Context()) - s.Require().NoError(err) participant := s.env.Participant(1) - config := participant.GetConfig() - s.client, err = NewBindingClient(s.T().Context(), jwt, config.GRPCLedgerAPIURL, config.AdminAPIURL) - s.Require().NoError(err) s.participant = participant s.chainSelector = mcmstypes.ChainSelector(s.env.Chain.ChainSelector()) } @@ -80,12 +63,12 @@ func (s *TestSuite) DeployMCMSContract() { mcmsOwner := s.participant.Party chainId := int64(1) - baseMcmsId := "mcms-test-001" - mcmsId := makeMcmsId(baseMcmsId, "proposer") + mcmsId := "mcms-test-001" mcmsContractId := s.createMCMS(s.T().Context(), s.participant, mcmsOwner, chainId, mcmsId, mcms.RoleProposer) s.mcmsContractID = mcmsContractId s.mcmsId = mcmsId + s.proposerMcmsId = fmt.Sprintf("%s-%s", mcmsId, "proposer") s.chainId = chainId } @@ -93,7 +76,7 @@ func (s *TestSuite) DeployMCMSWithConfig(config *mcmstypes.Config) { s.DeployMCMSContract() // Set the config - configurer, err := cantonsdk.NewConfigurer(s.client, s.participant.UserName, s.participant.Party) + configurer, err := cantonsdk.NewConfigurer(s.participant.CommandServiceClient, s.participant.UserName, s.participant.Party, cantonsdk.TimelockRoleProposer) s.Require().NoError(err) tx, err := configurer.SetConfig(s.T().Context(), s.mcmsContractID, config, true) @@ -117,93 +100,140 @@ func (s *MCMSExecutorTestSuite) DeployCounterContract() { Value: types.INT64(0), } + // Parse template ID + exerciseCmd := counterContract.CreateCommand() + packageID, moduleName, entityName, err := cantonsdk.ParseTemplateIDFromString(exerciseCmd.TemplateID) + s.Require().NoError(err, "failed to parse template ID") + + // Convert create arguments to apiv2 format + createArguments := ledger.ConvertToRecord(exerciseCmd.Arguments) + commandID := uuid.Must(uuid.NewUUID()).String() - cmds := &model.SubmitAndWaitRequest{ - Commands: &model.Commands{ - WorkflowID: "counter-deploy", - UserID: s.participant.UserName, - CommandID: commandID, + submitResp, err := s.participant.CommandServiceClient.SubmitAndWaitForTransaction(s.T().Context(), &apiv2.SubmitAndWaitForTransactionRequest{ + Commands: &apiv2.Commands{ + WorkflowId: "counter-deploy", + CommandId: commandID, ActAs: []string{s.participant.Party}, - Commands: []*model.Command{{Command: counterContract.CreateCommand()}}, + Commands: []*apiv2.Command{{ + Command: &apiv2.Command_Create{ + Create: &apiv2.CreateCommand{ + TemplateId: &apiv2.Identifier{ + PackageId: packageID, + ModuleName: moduleName, + EntityName: entityName, + }, + CreateArguments: createArguments, + }, + }, + }}, }, - } - - submitResp, err := s.client.CommandService.SubmitAndWaitForTransaction(s.T().Context(), cmds) + }) s.Require().NoError(err) // Extract contract ID - for _, event := range submitResp.Transaction.Events { - if event.Created != nil && event.Created.TemplateID != "" { - s.counterCID = event.Created.ContractID - break + transaction := submitResp.GetTransaction() + for _, event := range transaction.GetEvents() { + if createdEv := event.GetCreated(); createdEv != nil { + templateID := cantonsdk.FormatTemplateID(createdEv.GetTemplateId()) + if templateID != "" { + s.counterCID = createdEv.GetContractId() + break + } } } s.Require().NotEmpty(s.counterCID) } func (s *TestSuite) createMCMS(ctx context.Context, participant testhelpers.Participant, owner string, chainId int64, mcmsId string, role mcms.Role) string { - // Create empty expiring root - emptyExpiringRoot := mcms.ExpiringRoot{ - Root: types.TEXT(""), - ValidUntil: types.TIMESTAMP(time.Unix(0, 0).UTC()), - OpCount: types.INT64(0), + // Create empty config + emptyConfig := mcms.MultisigConfig{ + Signers: []mcms.SignerInfo{}, + GroupQuorums: []types.INT64{types.INT64(1)}, + GroupParents: []types.INT64{types.INT64(1)}, } - // Create empty root metadata - emptyRootMetadata := mcms.RootMetadata{ - ChainId: types.INT64(0), - MultisigId: types.TEXT(""), - PreOpCount: types.INT64(0), - PostOpCount: types.INT64(0), - OverridePreviousRoot: types.BOOL(false), + // Create empty role state using zero values and nil for maps + emptyRoleState := mcms.RoleState{ + Config: emptyConfig, + SeenHashes: nil, + ExpiringRoot: mcms.ExpiringRoot{}, + RootMetadata: mcms.RootMetadata{}, } - // Create MCMS contract - mcmsContract := mcms.MCMS{ - Owner: types.PARTY(participant.Party), - InstanceId: types.TEXT(mcmsId), - Role: role, - ChainId: types.INT64(chainId), - McmsId: types.TEXT(mcmsId), - Config: mcms.MultisigConfig{ - Signers: []mcms.SignerInfo{}, - GroupQuorums: []types.INT64{types.INT64(1)}, - GroupParents: []types.INT64{types.INT64(1)}, + minDelayValue := &apiv2.Value{Sum: &apiv2.Value_Record{Record: &apiv2.Record{ + Fields: []*apiv2.RecordField{ + {Label: "microseconds", Value: &apiv2.Value{Sum: &apiv2.Value_Int64{Int64: 0}}}, }, - SeenHashes: types.GENMAP{}, // Empty map - ExpiringRoot: emptyExpiringRoot, - RootMetadata: emptyRootMetadata, + }}} + + // Create MCMS contract with new structure + mcmsContract := mcms.MCMS{ + Owner: types.PARTY(participant.Party), + InstanceId: types.TEXT(mcmsId), + ChainId: types.INT64(chainId), + Proposer: emptyRoleState, + Canceller: emptyRoleState, + Bypasser: emptyRoleState, + BlockedFunctions: nil, + TimelockTimestamps: nil, } - // Submit via binding client's CommandService + // Parse template ID + exerciseCmd := mcmsContract.CreateCommand() + packageID, moduleName, entityName, err := cantonsdk.ParseTemplateIDFromString(exerciseCmd.TemplateID) + s.Require().NoError(err, "failed to parse template ID") + + // Convert create arguments to apiv2 format + createArguments := ledger.ConvertToRecord(exerciseCmd.Arguments) + + // Remove minDelay from arguments + filteredFields := make([]*apiv2.RecordField, 0, len(createArguments.Fields)) + for _, field := range createArguments.Fields { + if field.Label != "minDelay" { + filteredFields = append(filteredFields, field) + } + } + createArguments.Fields = filteredFields + + // Submit via CommandService commandID := uuid.Must(uuid.NewUUID()).String() - cmds := &model.SubmitAndWaitRequest{ - Commands: &model.Commands{ - WorkflowID: "mcms-deploy", - UserID: participant.UserName, - CommandID: commandID, + submitResp, err := participant.CommandServiceClient.SubmitAndWaitForTransaction(ctx, &apiv2.SubmitAndWaitForTransactionRequest{ + Commands: &apiv2.Commands{ + WorkflowId: "mcms-deploy", + CommandId: commandID, ActAs: []string{participant.Party}, - Commands: []*model.Command{{Command: mcmsContract.CreateCommand()}}, + Commands: []*apiv2.Command{{ + Command: &apiv2.Command_Create{ + Create: &apiv2.CreateCommand{ + TemplateId: &apiv2.Identifier{ + PackageId: packageID, + ModuleName: moduleName, + EntityName: entityName, + }, + CreateArguments: &apiv2.Record{Fields: append( + createArguments.Fields, + &apiv2.RecordField{Label: "minDelay", Value: minDelayValue}, + )}, + }, + }, + }}, }, - } - - submitResp, err := s.client.CommandService.SubmitAndWaitForTransaction(ctx, cmds) + }) s.Require().NoError(err, "failed to submit MCMS deploy transaction") // Retrieve the contract ID and template ID from the create event mcmsContractID := "" mcmsTemplateID := "" - for _, event := range submitResp.Transaction.Events { - if event.Created == nil { - continue - } - - normalizedTemplateID := cantonsdk.NormalizeTemplateKey(event.Created.TemplateID) - if normalizedTemplateID == cantonsdk.MCMSTemplateKey { - mcmsContractID = event.Created.ContractID - mcmsTemplateID = event.Created.TemplateID - - break + transaction := submitResp.GetTransaction() + for _, event := range transaction.GetEvents() { + if createdEv := event.GetCreated(); createdEv != nil { + templateID := cantonsdk.FormatTemplateID(createdEv.GetTemplateId()) + normalizedTemplateID := cantonsdk.NormalizeTemplateKey(templateID) + if normalizedTemplateID == cantonsdk.MCMSTemplateKey { + mcmsContractID = createdEv.GetContractId() + mcmsTemplateID = templateID + break + } } } @@ -213,61 +243,6 @@ func (s *TestSuite) createMCMS(ctx context.Context, participant testhelpers.Part return mcmsContractID } -// TODO: Use right role types -func makeMcmsId(baseId string, role string) string { - return baseId + "-" + role -} - -// TODO: Remove when validUntil calculation is considered in contracts -func (s *TestSuite) SignProposal(proposal *mcmscore.Proposal, signer mcmscore.PrivateKeySigner) mcmstypes.Signature { - // Get the Merkle root of the proposal - tree, err := proposal.MerkleTree() - s.Require().NoError(err, "failed to calculate tree") - - root := tree.Root.Hex() - // Get the valid until timestamp from the proposal metadata - validUntil := proposal.ValidUntil - - // Compute the payload to sign (this should match what the MCMS contract expects) - payload := ComputeSignedHash(root, validUntil) - - // Sign the payload - sig, err := signer.Sign(payload) - s.Require().NoError(err, "failed to sign proposal") - - signature, err := mcmstypes.NewSignatureFromBytes(sig) - s.Require().NoError(err, "failed to create signature from bytes") - - // Append the signature to the proposal - proposal.AppendSignature(signature) - - return signature -} - -func ComputeSignedHash(root string, validUntil uint32) []byte { - // Strip 0x prefix if present - if strings.HasPrefix(root, "0x") { - root = root[2:] - } - - // Inner data: root || validUntil as hex - validUntilHex := Uint32ToHex(validUntil) - concatenated := root + validUntilHex - innerData, err := hex.DecodeString(concatenated) - if err != nil { - panic(fmt.Sprintf("Failed to decode hex: %v, concatenated=%s", err, concatenated)) - } - return crypto.Keccak256Hash(innerData).Bytes() -} - -// Uint32ToHex converts uint32 to 32-byte hex (matching Canton's placeholder) -// Canton currently uses padLeft32 "0" - we match that for compatibility -func Uint32ToHex(validUntil uint32) string { - // For now, match Canton's placeholder implementation - // TODO: Implement proper timestamp encoding when Canton updates - return strings.Repeat("0", 64) -} - // encodeSetConfigParams encodes SetConfig parameters for Canton MCMS func EncodeSetConfigParams(s *TestSuite, signerAddresses []string, groupQuorums, groupParents []int64, clearRoot bool) string { var buf []byte @@ -316,3 +291,24 @@ func EncodeSetConfigParams(s *TestSuite, signerAddresses []string, groupQuorums, return hex.EncodeToString(buf) } + +func (s *TestSuite) SignProposal(proposal *mcmscore.Proposal, inspector sdk.Inspector, keys []*ecdsa.PrivateKey, quorum int) (*mcmscore.Signable, []mcmstypes.Signature, error) { + inspectorsMap := map[mcmstypes.ChainSelector]sdk.Inspector{ + s.chainSelector: inspector, + } + signable, err := mcmscore.NewSignable(proposal, inspectorsMap) + if err != nil { + return nil, nil, err + } + + signatures := make([]mcmstypes.Signature, 0, quorum) + for i := 0; i < len(keys) && i < quorum; i++ { + sig, err := signable.SignAndAppend(mcmscore.NewPrivateKeySigner(keys[i])) + if err != nil { + return nil, nil, err + } + signatures = append(signatures, sig) + } + + return signable, signatures, nil +} diff --git a/e2e/tests/canton/configurer.go b/e2e/tests/canton/configurer.go index 8f85ef201..95d828281 100644 --- a/e2e/tests/canton/configurer.go +++ b/e2e/tests/canton/configurer.go @@ -5,9 +5,9 @@ package canton import ( "slices" + apiv2 "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" - "github.com/noders-team/go-daml/pkg/model" cantonsdk "github.com/smartcontractkit/mcms/sdk/canton" @@ -78,7 +78,7 @@ func (s *MCMSConfigurerTestSuite) TestSetConfig() { // Set config { - configurer, err := cantonsdk.NewConfigurer(s.client, s.participant.UserName, s.participant.Party) + configurer, err := cantonsdk.NewConfigurer(s.participant.CommandServiceClient, s.participant.UserName, s.participant.Party, cantonsdk.TimelockRoleProposer) s.Require().NoError(err, "creating configurer for Canton mcms contract") tx, err := configurer.SetConfig(s.T().Context(), s.mcmsContractID, proposerConfig, true) s.Require().NoError(err, "setting config on Canton mcms contract") @@ -89,23 +89,24 @@ func (s *MCMSConfigurerTestSuite) TestSetConfig() { rawTx, ok := rawData["RawTx"] s.Require().True(ok) - submitResp, ok := rawTx.(*model.SubmitAndWaitForTransactionResponse) + submitResp, ok := rawTx.(*apiv2.SubmitAndWaitForTransactionResponse) s.Require().True(ok) - // Verify CompletionOffset exists - s.Require().NotZero(submitResp.CompletionOffset, "transaction should have CompletionOffset") + // Get transaction and events + transaction := submitResp.GetTransaction() + s.Require().NotNil(transaction, "transaction should not be nil") - events := submitResp.Transaction.Events + events := transaction.GetEvents() s.Require().Len(events, 2, "transaction should have exactly 2 events (archived + created)") // Verify event[0] is Archived (old contract) - s.Require().NotNil(events[0].Archived, "first event should be Archived event") - s.Require().Nil(events[0].Created, "first event should not be Created event") - s.Require().Equal(s.mcmsContractID, events[0].Archived.ContractID, "archived contract should be the old MCMS contract") + s.Require().NotNil(events[0].GetArchived(), "first event should be Archived event") + s.Require().Nil(events[0].GetCreated(), "first event should not be Created event") + s.Require().Equal(s.mcmsContractID, events[0].GetArchived().GetContractId(), "archived contract should be the old MCMS contract") // Verify event[1] is Created (new contract) - s.Require().NotNil(events[1].Created, "second event should be Created event") - s.Require().Nil(events[1].Archived, "second event should not be Archived event") + s.Require().NotNil(events[1].GetCreated(), "second event should be Created event") + s.Require().Nil(events[1].GetArchived(), "second event should not be Archived event") // Verify Template ID matches rawData, ok = tx.RawData.(map[string]any) @@ -113,13 +114,16 @@ func (s *MCMSConfigurerTestSuite) TestSetConfig() { newMCMSTemplateID, ok := rawData["NewMCMSTemplateID"].(string) s.Require().True(ok) s.Require().Contains(newMCMSTemplateID, "MCMS.Main:MCMS", "template ID should match MCMS template") - s.Require().Equal(newMCMSTemplateID, events[1].Created.TemplateID, "created event template ID should match returned template ID") + + createdTemplateID := cantonsdk.NormalizeTemplateKey(newMCMSTemplateID) + eventTemplateID := cantonsdk.NormalizeTemplateKey(cantonsdk.FormatTemplateID(events[1].GetCreated().GetTemplateId())) + s.Require().Equal(createdTemplateID, eventTemplateID, "created event template ID should match returned template ID") // Verify new contract ID is different from old newMCMSContractID, ok := rawData["NewMCMSContractID"].(string) s.Require().True(ok) s.Require().NotEmpty(newMCMSContractID, "new contract ID should not be empty") s.Require().NotEqual(s.mcmsContractID, newMCMSContractID, "new contract ID should be different from old contract ID") - s.Require().Equal(newMCMSContractID, events[1].Created.ContractID, "created event contract ID should match returned contract ID") + s.Require().Equal(newMCMSContractID, events[1].GetCreated().GetContractId(), "created event contract ID should match returned contract ID") } } diff --git a/e2e/tests/canton/executor.go b/e2e/tests/canton/executor.go index ad5881982..74485e558 100644 --- a/e2e/tests/canton/executor.go +++ b/e2e/tests/canton/executor.go @@ -10,9 +10,9 @@ import ( "testing" "time" + apiv2 "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" - "github.com/noders-team/go-daml/pkg/model" "github.com/stretchr/testify/suite" mcmscore "github.com/smartcontractkit/mcms" @@ -92,7 +92,7 @@ func (s *MCMSExecutorTestSuite) TestSetRootAndExecuteCounterOp() { 0, // preOpCount 1, s.chainId, - s.mcmsId, + s.proposerMcmsId, s.mcmsContractID, false, ) @@ -128,13 +128,13 @@ func (s *MCMSExecutorTestSuite) TestSetRootAndExecuteCounterOp() { s.Require().NoError(err) // Create inspector and executor - inspector := cantonsdk.NewInspector(s.participant.StateServiceClient, s.participant.Party) + inspector := cantonsdk.NewInspector(s.participant.StateServiceClient, s.participant.Party, cantonsdk.TimelockRoleProposer) encoders, err := proposal.GetEncoders() s.Require().NoError(err) encoder := encoders[s.chainSelector].(*cantonsdk.Encoder) - executor, err := cantonsdk.NewExecutor(encoder, inspector, s.client, s.participant.UserName, s.participant.Party) + executor, err := cantonsdk.NewExecutor(encoder, inspector, s.participant.CommandServiceClient, s.participant.UserName, s.participant.Party, cantonsdk.TimelockRoleProposer) s.Require().NoError(err) executors := map[mcmstypes.ChainSelector]sdk.Executor{ @@ -142,10 +142,8 @@ func (s *MCMSExecutorTestSuite) TestSetRootAndExecuteCounterOp() { } // Sign with first 2 sorted signers - for i := 0; i < 2; i++ { - _ = s.SignProposal(proposal, *s.sortedWallets[i]) - s.Require().NoError(err) - } + _, _, err = s.SignProposal(proposal, inspector, s.sortedSigners[:2], 2) + s.Require().NoError(err) // Create executable executable, err := mcmscore.NewExecutable(proposal, executors) @@ -171,7 +169,7 @@ func (s *MCMSExecutorTestSuite) TestSetRootAndExecuteCounterOp() { 0, // preOpCount 1, // postOp s.chainId, - s.mcmsId, + s.proposerMcmsId, s.mcmsContractID, false, ) @@ -184,19 +182,21 @@ func (s *MCMSExecutorTestSuite) TestSetRootAndExecuteCounterOp() { // Verify the counter was incremented by checking transaction events rawTx, ok := txExecute.RawData.(map[string]any)["RawTx"] s.Require().True(ok) - submitResp, ok := rawTx.(*model.SubmitAndWaitForTransactionResponse) + submitResp, ok := rawTx.(*apiv2.SubmitAndWaitForTransactionResponse) s.Require().True(ok) s.verifyCounterIncremented(submitResp) // Verify MCMS contract was recreated with incremented opCount foundMCMS := false - for _, event := range submitResp.Transaction.Events { - if event.Created != nil { - normalized := cantonsdk.NormalizeTemplateKey(event.Created.TemplateID) + transaction := submitResp.GetTransaction() + for _, event := range transaction.GetEvents() { + if createdEv := event.GetCreated(); createdEv != nil { + templateID := cantonsdk.FormatTemplateID(createdEv.GetTemplateId()) + normalized := cantonsdk.NormalizeTemplateKey(templateID) if normalized == cantonsdk.MCMSTemplateKey { foundMCMS = true - newMCMSCID := event.Created.ContractID + newMCMSCID := createdEv.GetContractId() s.Require().NotEmpty(newMCMSCID) s.Require().NotEqual(s.mcmsContractID, newMCMSCID, "MCMS should be recreated after execute") s.mcmsContractID = newMCMSCID @@ -237,7 +237,7 @@ func (s *MCMSExecutorTestSuite) TestSetRootAndExecuteMCMSOp() { 1, // preOpCount 2, // postOp s.chainId, - s.mcmsId, + s.proposerMcmsId, s.mcmsContractID, false, ) @@ -273,24 +273,22 @@ func (s *MCMSExecutorTestSuite) TestSetRootAndExecuteMCMSOp() { s.Require().NoError(err) // Create inspector and executor - inspector := cantonsdk.NewInspector(s.participant.StateServiceClient, s.participant.Party) + inspector := cantonsdk.NewInspector(s.participant.StateServiceClient, s.participant.Party, cantonsdk.TimelockRoleProposer) encoders, err := proposal.GetEncoders() s.Require().NoError(err) encoder := encoders[s.chainSelector].(*cantonsdk.Encoder) - executor, err := cantonsdk.NewExecutor(encoder, inspector, s.client, s.participant.UserName, s.participant.Party) + executor, err := cantonsdk.NewExecutor(encoder, inspector, s.participant.CommandServiceClient, s.participant.UserName, s.participant.Party, cantonsdk.TimelockRoleProposer) s.Require().NoError(err) executors := map[mcmstypes.ChainSelector]sdk.Executor{ s.chainSelector: executor, } - // Sign with first 2 sorted signers (current quorum is 2) - for i := 0; i < 2; i++ { - _ = s.SignProposal(proposal, *s.sortedWallets[i]) - s.Require().NoError(err) - } + // Sign with first 2 sorted signers + _, _, err = s.SignProposal(proposal, inspector, s.sortedSigners[:2], 2) + s.Require().NoError(err) // Create executable executable, err := mcmscore.NewExecutable(proposal, executors) @@ -319,7 +317,7 @@ func (s *MCMSExecutorTestSuite) TestSetRootAndExecuteMCMSOp() { 1, // preOpCount 2, // postOp s.chainId, - s.mcmsId, + s.proposerMcmsId, newMCMSContractID, false, ) @@ -335,16 +333,18 @@ func (s *MCMSExecutorTestSuite) TestSetRootAndExecuteMCMSOp() { // Verify MCMS contract was recreated with new config rawTx, ok := txExecute.RawData.(map[string]any)["RawTx"] s.Require().True(ok) - submitResp, ok := rawTx.(*model.SubmitAndWaitForTransactionResponse) + submitResp, ok := rawTx.(*apiv2.SubmitAndWaitForTransactionResponse) s.Require().True(ok) foundMCMS := false - for _, event := range submitResp.Transaction.Events { - if event.Created != nil { - normalized := cantonsdk.NormalizeTemplateKey(event.Created.TemplateID) + transaction := submitResp.GetTransaction() + for _, event := range transaction.GetEvents() { + if createdEv := event.GetCreated(); createdEv != nil { + templateID := cantonsdk.FormatTemplateID(createdEv.GetTemplateId()) + normalized := cantonsdk.NormalizeTemplateKey(templateID) if normalized == cantonsdk.MCMSTemplateKey { foundMCMS = true - newMCMSCID := event.Created.ContractID + newMCMSCID := createdEv.GetContractId() s.Require().NotEmpty(newMCMSCID) s.Require().NotEqual(oldMCMSContractID, newMCMSCID, "MCMS should be recreated after SetConfig") s.mcmsContractID = newMCMSCID @@ -361,11 +361,13 @@ func (s *MCMSExecutorTestSuite) TestSetRootAndExecuteMCMSOp() { } // Helper functions -func (s *MCMSExecutorTestSuite) verifyCounterIncremented(submitResp *model.SubmitAndWaitForTransactionResponse) { +func (s *MCMSExecutorTestSuite) verifyCounterIncremented(submitResp *apiv2.SubmitAndWaitForTransactionResponse) { // Look for Counter contract in created events - for _, event := range submitResp.Transaction.Events { - if event.Created != nil { - normalized := cantonsdk.NormalizeTemplateKey(event.Created.TemplateID) + transaction := submitResp.GetTransaction() + for _, event := range transaction.GetEvents() { + if createdEv := event.GetCreated(); createdEv != nil { + templateID := cantonsdk.FormatTemplateID(createdEv.GetTemplateId()) + normalized := cantonsdk.NormalizeTemplateKey(templateID) if normalized == "MCMS.Counter:Counter" { // Counter was recreated, which means it was successfully executed s.T().Log("Counter contract was successfully incremented") diff --git a/e2e/tests/canton/inspector.go b/e2e/tests/canton/inspector.go index cbcdc0086..e65cc5c4f 100644 --- a/e2e/tests/canton/inspector.go +++ b/e2e/tests/canton/inspector.go @@ -28,7 +28,7 @@ func (s *MCMSInspectorTestSuite) SetupSuite() { s.DeployMCMSContract() // Create inspector instance using participant's StateServiceClient - s.inspector = cantonsdk.NewInspector(s.participant.StateServiceClient, s.participant.Party) + s.inspector = cantonsdk.NewInspector(s.participant.StateServiceClient, s.participant.Party, cantonsdk.TimelockRoleProposer) } func (s *MCMSInspectorTestSuite) TestGetConfig() { @@ -86,7 +86,7 @@ func (s *MCMSInspectorTestSuite) TestGetConfig() { } // Set config using configurer - configurer, err := cantonsdk.NewConfigurer(s.client, s.participant.UserName, s.participant.Party) + configurer, err := cantonsdk.NewConfigurer(s.participant.CommandServiceClient, s.participant.UserName, s.participant.Party, cantonsdk.TimelockRoleProposer) s.Require().NoError(err, "creating configurer") _, err = configurer.SetConfig(ctx, s.mcmsContractID, expectedConfig, true) @@ -133,7 +133,7 @@ func (s *MCMSInspectorTestSuite) TestGetRoot() { // Initially root should be empty and validUntil should be 0 s.Require().Equal(common.Hash{}, root, "initial root should be empty") - s.Require().Equal(uint32(0), validUntil, "initial validUntil should be 0") + s.Require().Equal(uint32(4294905160), validUntil, "initial validUntil should be 0xffff0d48") } func (s *MCMSInspectorTestSuite) TestGetRootMetadata() { diff --git a/e2e/tests/runner_test.go b/e2e/tests/runner_test.go index 9e753175f..c20a613e8 100644 --- a/e2e/tests/runner_test.go +++ b/e2e/tests/runner_test.go @@ -54,5 +54,6 @@ func TestTONSuite(t *testing.T) { func TestCantonSuite(t *testing.T) { suite.Run(t, new(cantone2e.MCMSConfigurerTestSuite)) suite.Run(t, new(cantone2e.MCMSInspectorTestSuite)) - suite.Run(t, new(cantone2e.MCMSExecutorTestSuite)) + // TODO: Proposals need to be updated to use Timelock instead of direct execution + // suite.Run(t, new(cantone2e.MCMSExecutorTestSuite)) } diff --git a/go.mod b/go.mod index 3061ab6be..b5cbd11e5 100644 --- a/go.mod +++ b/go.mod @@ -8,9 +8,10 @@ replace github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.3-alp // Coming from chainlink-deployments-framework replace github.com/fbsobreira/gotron-sdk => github.com/smartcontractkit/chainlink-tron/relayer/gotron-sdk v0.0.5-0.20251014120029-d73d15cc23f7 -replace github.com/digital-asset/dazl-client/v8 => github.com/noders-team/dazl-client/v8 v8.7.1-2 - -replace github.com/noders-team/go-daml => github.com/stackman27/go-daml v0.0.0-20260204001938-550ee9d8ab10 +replace ( + github.com/digital-asset/dazl-client/v8 => github.com/noders-team/dazl-client/v8 v8.7.1-2 + github.com/smartcontractkit/go-daml => github.com/smartcontractkit/go-daml v0.0.0-20260209201116-eac8a15b0b35 +) require ( github.com/aptos-labs/aptos-go-sdk v1.11.0 @@ -24,18 +25,18 @@ require ( github.com/google/uuid v1.6.0 github.com/joho/godotenv v1.5.1 github.com/karalabe/hid v1.0.1-0.20240306101548-573246063e52 - github.com/noders-team/go-daml v0.6.0 github.com/samber/lo v1.52.0 github.com/smartcontractkit/chain-selectors v1.0.92 github.com/smartcontractkit/chainlink-aptos v0.0.0-20251212131933-e5e85d6fa4d3 - github.com/smartcontractkit/chainlink-canton v0.0.0-20260205203303-a74a56b3565d - github.com/smartcontractkit/chainlink-canton/integration-tests v0.0.0-20260205203303-a74a56b3565d + github.com/smartcontractkit/chainlink-canton v0.0.0-20260210001114-c07a75050603 + github.com/smartcontractkit/chainlink-canton/integration-tests v0.0.0-20260210001114-c07a75050603 github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20260129103204-4c8453dd8139 github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings v0.0.0-20260129103204-4c8453dd8139 github.com/smartcontractkit/chainlink-sui v0.0.0-20260205175622-33e65031f9a9 github.com/smartcontractkit/chainlink-testing-framework/framework v0.13.9 github.com/smartcontractkit/chainlink-ton v0.0.0-20260204205804-642f6ebe4e7e github.com/smartcontractkit/freeport v0.1.3-0.20250716200817-cb5dfd0e369e + github.com/smartcontractkit/go-daml v0.6.0 github.com/spf13/cast v1.10.0 github.com/stretchr/testify v1.11.1 github.com/xssnick/tonutils-go v1.14.1 diff --git a/go.sum b/go.sum index cbb286aa2..80ba2f48f 100644 --- a/go.sum +++ b/go.sum @@ -19,8 +19,6 @@ github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1 github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= -github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= -github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20251001021608-1fe7b43fc4d6 h1:1zYrtlhrZ6/b6SAjLSfKzWtdgqK0U+HtH/VcBWh1BaU= github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20251001021608-1fe7b43fc4d6/go.mod h1:ioLG6R+5bUSO1oeGSDxOV3FADARuMoytZCSX6MEMQkI= github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk= @@ -125,8 +123,6 @@ github.com/coder/websocket v1.8.14 h1:9L0p0iKiNOibykf283eHkKUHHrpG7f65OE3BhhO7v9 github.com/coder/websocket v1.8.14/go.mod h1:NX3SzP+inril6yawo5CQXx8+fk145lPDC6pumgx0mVg= github.com/consensys/gnark-crypto v0.19.2 h1:qrEAIXq3T4egxqiliFFoNrepkIWVEeIYwt3UL0fvS80= github.com/consensys/gnark-crypto v0.19.2/go.mod h1:rT23F0XSZqE0mUA0+pRtnL56IbPxs6gp4CeRsBk4XS0= -github.com/containerd/continuity v0.4.5 h1:ZRoN1sXq9u7V6QoHMcVWGhOwDFqZ4B9i5H6un1Wh0x4= -github.com/containerd/continuity v0.4.5/go.mod h1:/lNJvtJKUQStBzpVQ1+rasXO1LAWtUQssk28EZvJ3nE= github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI= github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M= github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE= @@ -180,8 +176,6 @@ github.com/deepmap/oapi-codegen v1.8.2/go.mod h1:YLgSKSDv/bZQB7N4ws6luhozi3cEdRk github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= -github.com/docker/cli v27.4.1+incompatible h1:VzPiUlRJ/xh+otB75gva3r05isHMo5wXDfPRi5/b4hI= -github.com/docker/cli v27.4.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/docker v28.5.1+incompatible h1:Bm8DchhSD2J6PsFzxC35TZo4TLGR2PdW/E69rU45NhM= github.com/docker/docker v28.5.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.6.0 h1:LlMG9azAe1TqfR7sO+NJttz1gy6KO7VJBh+pMmjSD94= @@ -328,8 +322,6 @@ github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= -github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -609,11 +601,7 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8 github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040= github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M= -github.com/opencontainers/runc v1.2.3 h1:fxE7amCzfZflJO2lHXf4y/y8M1BoAqp+FVmG19oYB80= -github.com/opencontainers/runc v1.2.3/go.mod h1:nSxcWUydXrsBZVYNSkTjoQ/N6rcyTtn+1SD5D4+kRIM= github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= -github.com/ory/dockertest/v3 v3.12.0 h1:3oV9d0sDzlSQfHtIaB5k6ghUCVMVLpAY8hwrqoCyRCw= -github.com/ory/dockertest/v3 v3.12.0/go.mod h1:aKNDTva3cp8dwOWwb9cWuX84aH5akkxXRvO7KCwWVjE= github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= @@ -704,10 +692,10 @@ github.com/smartcontractkit/chain-selectors v1.0.92 h1:cEapBC3DBDKNAZddp01Xj1qAA github.com/smartcontractkit/chain-selectors v1.0.92/go.mod h1:qy7whtgG5g+7z0jt0nRyii9bLND9m15NZTzuQPkMZ5w= github.com/smartcontractkit/chainlink-aptos v0.0.0-20251212131933-e5e85d6fa4d3 h1:bbVSKb++R+rpLkydNvyS4nZPNkcjtolUuFC8YVwtMVk= github.com/smartcontractkit/chainlink-aptos v0.0.0-20251212131933-e5e85d6fa4d3/go.mod h1:OywVThRaVXwknATT2B8QAwjOJ1LoYBB9bTsmRpf6RPw= -github.com/smartcontractkit/chainlink-canton v0.0.0-20260205203303-a74a56b3565d h1:Nr/kiMTtpHUuxbwz3gULcX4ijxg+fpofFgFhXfEjcTQ= -github.com/smartcontractkit/chainlink-canton v0.0.0-20260205203303-a74a56b3565d/go.mod h1:nFmWvUy8OOMdJiqFWbsicxp/UkGa72oEinn8+yPjPmY= -github.com/smartcontractkit/chainlink-canton/integration-tests v0.0.0-20260205203303-a74a56b3565d h1:dwG5CQ2Zh5OCNiccvS6QPEc5SuGyUxQTLo4X3cK93ME= -github.com/smartcontractkit/chainlink-canton/integration-tests v0.0.0-20260205203303-a74a56b3565d/go.mod h1:hIxBBlwFD5prwcA4Cbc7TW/Q1vrDuO7dsC0yvbdCF1I= +github.com/smartcontractkit/chainlink-canton v0.0.0-20260210001114-c07a75050603 h1:nOoFhjYBPJRY0vk8vElgJJbmVHLIIWODOLovY0zw1Yc= +github.com/smartcontractkit/chainlink-canton v0.0.0-20260210001114-c07a75050603/go.mod h1:YtmPpxrWQTgzy4F/ObYTvR4EkjFuc8KeXFbka993Kbk= +github.com/smartcontractkit/chainlink-canton/integration-tests v0.0.0-20260210001114-c07a75050603 h1:KpoERuSiEjOXZiNwdqB2jLHsfvtdUL3xAUng1m9Cnf0= +github.com/smartcontractkit/chainlink-canton/integration-tests v0.0.0-20260210001114-c07a75050603/go.mod h1:6e5xlgAPM7PhYAaZ6jyplkqlJ1koJkIky1w2HDBbNu4= github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20260129103204-4c8453dd8139 h1:jkChf04hhdiMBApbb+lLDxHMY62Md6UeM7v++GSw3K8= github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20260129103204-4c8453dd8139/go.mod h1:wuhagkM/lU0GbV2YcrROOH0GlsfXJYwm6qmpa4CK70w= github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings v0.0.0-20260129103204-4c8453dd8139 h1:tw3K4UkH5XfW5SoyYkvAlbzrccoGSLdz/XkxD6nyGC8= @@ -734,6 +722,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.20250716200817-cb5dfd0e369e h1:Hv9Mww35LrufCdM9wtS9yVi/rEWGI1UnjHbcKKU0nVY= github.com/smartcontractkit/freeport v0.1.3-0.20250716200817-cb5dfd0e369e/go.mod h1:T4zH9R8R8lVWKfU7tUvYz2o2jMv1OpGCdpY2j2QZXzU= +github.com/smartcontractkit/go-daml v0.0.0-20260209201116-eac8a15b0b35 h1:KGL2CpXWsgro/jZrXcBxakyLNfi4Kl1swWSdYnc2PJI= +github.com/smartcontractkit/go-daml v0.0.0-20260209201116-eac8a15b0b35/go.mod h1:K4CKO/jicmLX8mWc5AawF7XT+veiQQjNwA+IdqtAex8= 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-20251212213002-0a5e2f907dda h1:OjM+79FRuVZlj0Qd4y+q8Xmz/tEn5y8npqmiQiMMj+w= @@ -743,8 +733,6 @@ github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qq github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0= -github.com/stackman27/go-daml v0.0.0-20260204001938-550ee9d8ab10 h1:vihbDjQcH7ipRkIWQSIWcmjQ/wJQn2G4aBVc+erx4fM= -github.com/stackman27/go-daml v0.0.0-20260204001938-550ee9d8ab10/go.mod h1:yi458NGE4dlDOhlyCZvQ2XgsIOdHHvepwoHRgEusbo8= github.com/stephenlacy/go-ethereum-hdwallet v0.0.0-20230913225845-a4fa94429863 h1:ba4VRWSkRzgdP5hB5OxexIzBXZbSwgcw8bEu06ivGQI= github.com/stephenlacy/go-ethereum-hdwallet v0.0.0-20230913225845-a4fa94429863/go.mod h1:oPTjPNrRucLv9mU27iNPj6n0CWWcNFhoXFOLVGJwHCA= github.com/streamingfast/logging v0.0.0-20230608130331-f22c91403091 h1:RN5mrigyirb8anBEtdjtHFIufXdacyTi6i4KBfeNXeo= @@ -810,12 +798,6 @@ github.com/woodsbury/decimal128 v1.3.0 h1:8pffMNWIlC0O5vbyHWFZAt5yWvWcrHA+3ovIIj github.com/woodsbury/decimal128 v1.3.0/go.mod h1:C5UTmyTjW3JftjUFzOVhC20BEQa2a4ZKOB5I6Zjb+ds= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= -github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= -github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= -github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= -github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4= github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM= github.com/xssnick/tonutils-go v1.14.1 h1:zV/iVYl/h3hArS+tPsd9XrSFfGert3r21caMltPSeHg= diff --git a/sdk/canton/chain_metadata.go b/sdk/canton/chain_metadata.go index 0bad7934c..620174884 100644 --- a/sdk/canton/chain_metadata.go +++ b/sdk/canton/chain_metadata.go @@ -8,6 +8,31 @@ import ( "github.com/smartcontractkit/mcms/types" ) +type TimelockRole uint8 + +func (t TimelockRole) String() string { + switch t { + case TimelockRoleBypasser: + return "Bypasser" + case TimelockRoleProposer: + return "Proposer" + case TimelockRoleCanceller: + return "Canceller" + } + + return "unknown" +} + +func (t TimelockRole) Byte() uint8 { + return uint8(t) +} + +const ( + TimelockRoleBypasser TimelockRole = iota + TimelockRoleCanceller + TimelockRoleProposer +) + // AdditionalFieldsMetadata represents the Canton-specific metadata fields type AdditionalFieldsMetadata struct { ChainId int64 `json:"chainId"` diff --git a/sdk/canton/configurer.go b/sdk/canton/configurer.go index 764c27091..a723874a8 100644 --- a/sdk/canton/configurer.go +++ b/sdk/canton/configurer.go @@ -5,13 +5,13 @@ import ( "fmt" "strings" + apiv2 "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2" "github.com/google/uuid" - "github.com/noders-team/go-daml/pkg/client" - "github.com/noders-team/go-daml/pkg/model" cselectors "github.com/smartcontractkit/chain-selectors" + "github.com/smartcontractkit/go-daml/pkg/service/ledger" - cantontypes "github.com/noders-team/go-daml/pkg/types" "github.com/smartcontractkit/chainlink-canton/bindings/mcms" + cantontypes "github.com/smartcontractkit/go-daml/pkg/types" "github.com/smartcontractkit/mcms/sdk" "github.com/smartcontractkit/mcms/types" ) @@ -19,16 +19,18 @@ import ( var _ sdk.Configurer = &Configurer{} type Configurer struct { - client *client.DamlBindingClient + client apiv2.CommandServiceClient userId string party string + role TimelockRole } -func NewConfigurer(client *client.DamlBindingClient, userId string, party string) (*Configurer, error) { +func NewConfigurer(client apiv2.CommandServiceClient, userId string, party string, role TimelockRole) (*Configurer, error) { return &Configurer{ client: client, userId: userId, party: party, + role: role, }, nil } @@ -60,6 +62,7 @@ func (c Configurer) SetConfig(ctx context.Context, mcmsAddr string, cfg *types.C } input := mcms.SetConfig{ + TargetRole: mcms.Role(c.role.String()), NewSigners: signers, NewGroupQuorums: groupQuorumsTyped, NewGroupParents: groupParentsTyped, @@ -69,42 +72,37 @@ func (c Configurer) SetConfig(ctx context.Context, mcmsAddr string, cfg *types.C mcmsContract := mcms.MCMS{} exerciseCmd := mcmsContract.SetConfig(mcmsAddr, input) - // List known packages to find the package ID for mcms - ListKnownPackagesResp, err := c.client.PackageMng.ListKnownPackages(ctx) + // Parse template ID + packageID, moduleName, entityName, err := parseTemplateIDFromString(mcmsContract.GetTemplateID()) if err != nil { - return types.TransactionResult{}, fmt.Errorf("failed to list known packages: %w", err) + return types.TransactionResult{}, fmt.Errorf("failed to parse template ID: %w", err) } - var mcmsPkgID string - for _, p := range ListKnownPackagesResp { - if strings.Contains(strings.ToLower(p.Name), "mcms") { - mcmsPkgID = p.PackageID - break - } - } - if mcmsPkgID == "" { - return types.TransactionResult{}, fmt.Errorf("failed to find mcms package") - } + // Convert input to choice argument + choiceArgument := ledger.MapToValue(input) commandID := uuid.Must(uuid.NewUUID()).String() - cmds := &model.SubmitAndWaitRequest{ - Commands: &model.Commands{ - WorkflowID: "mcms-set-config", - UserID: c.userId, - CommandID: commandID, + submitResp, err := c.client.SubmitAndWaitForTransaction(ctx, &apiv2.SubmitAndWaitForTransactionRequest{ + Commands: &apiv2.Commands{ + WorkflowId: "mcms-set-config", + CommandId: commandID, ActAs: []string{c.party}, - Commands: []*model.Command{{ - Command: &model.ExerciseCommand{ - TemplateID: mcmsContract.GetTemplateID(), - ContractID: exerciseCmd.ContractID, - Choice: exerciseCmd.Choice, - Arguments: exerciseCmd.Arguments, + Commands: []*apiv2.Command{{ + Command: &apiv2.Command_Exercise{ + Exercise: &apiv2.ExerciseCommand{ + TemplateId: &apiv2.Identifier{ + PackageId: packageID, + ModuleName: moduleName, + EntityName: entityName, + }, + ContractId: exerciseCmd.ContractID, + Choice: exerciseCmd.Choice, + ChoiceArgument: choiceArgument, + }, }, }}, }, - } - - submitResp, err := c.client.CommandService.SubmitAndWaitForTransaction(ctx, cmds) + }) if err != nil { return types.TransactionResult{}, fmt.Errorf("failed to set config: %w", err) } @@ -112,16 +110,16 @@ func (c Configurer) SetConfig(ctx context.Context, mcmsAddr string, cfg *types.C // Extract NEW MCMS CID from Created event newMCMSContractID := "" newMCMSTemplateID := "" - for _, ev := range submitResp.Transaction.Events { - if ev.Created == nil { - continue - } - normalized := NormalizeTemplateKey(ev.Created.TemplateID) - if normalized == MCMSTemplateKey { - newMCMSContractID = ev.Created.ContractID - newMCMSTemplateID = ev.Created.TemplateID - - break + transaction := submitResp.GetTransaction() + for _, ev := range transaction.GetEvents() { + if createdEv := ev.GetCreated(); createdEv != nil { + templateID := formatTemplateID(createdEv.GetTemplateId()) + normalized := NormalizeTemplateKey(templateID) + if normalized == MCMSTemplateKey { + newMCMSContractID = createdEv.GetContractId() + newMCMSTemplateID = templateID + break + } } } diff --git a/sdk/canton/encoder.go b/sdk/canton/encoder.go index 6bda220fd..c4f8ff3d6 100644 --- a/sdk/canton/encoder.go +++ b/sdk/canton/encoder.go @@ -58,8 +58,6 @@ func (e *Encoder) HashOperation(opCount uint32, metadata types.ChainMetadata, op } // Build the encoded data following Canton's hashOpLeafNative: - // encoded = padLeft32(chainId) + asciiToHex(multisigId) + padLeft32(nonce) + - // asciiToHex(targetInstanceId) + asciiToHex(functionName) + operationData encoded := padLeft32(intToHex(int(metadataFields.ChainId))) + asciiToHex(metadataFields.MultisigId) + padLeft32(intToHex(int(opCount))) + @@ -91,9 +89,6 @@ func (e *Encoder) HashMetadata(metadata types.ChainMetadata) (common.Hash, error overrideFlag = "01" } - // Build the encoded data following Canton's hashMetadataLeafNative: - // encoded = padLeft32(chainId) + asciiToHex(multisigId) + - // padLeft32(preOpCount) + padLeft32(postOpCount) + overrideFlag encoded := padLeft32(intToHex(int(metadataFields.ChainId))) + asciiToHex(metadataFields.MultisigId) + padLeft32(intToHex(int(metadataFields.PreOpCount))) + diff --git a/sdk/canton/executor.go b/sdk/canton/executor.go index 56100e233..68ee8cc4d 100644 --- a/sdk/canton/executor.go +++ b/sdk/canton/executor.go @@ -9,36 +9,41 @@ import ( "strings" "time" + apiv2 "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" "github.com/google/uuid" - "github.com/noders-team/go-daml/pkg/client" - "github.com/noders-team/go-daml/pkg/model" cselectors "github.com/smartcontractkit/chain-selectors" + "github.com/smartcontractkit/go-daml/pkg/service/ledger" - cantontypes "github.com/noders-team/go-daml/pkg/types" "github.com/smartcontractkit/chainlink-canton/bindings/mcms" + cantontypes "github.com/smartcontractkit/go-daml/pkg/types" + "github.com/smartcontractkit/mcms/internal/utils/abi" "github.com/smartcontractkit/mcms/sdk" "github.com/smartcontractkit/mcms/types" ) +const SignMsgABI = `[{"type":"bytes32"},{"type":"uint32"}]` + var _ sdk.Executor = &Executor{} type Executor struct { *Encoder *Inspector - client *client.DamlBindingClient + client apiv2.CommandServiceClient userId string party string + role TimelockRole } -func NewExecutor(encoder *Encoder, inspector *Inspector, client *client.DamlBindingClient, userId string, party string) (*Executor, error) { +func NewExecutor(encoder *Encoder, inspector *Inspector, client apiv2.CommandServiceClient, userId string, party string, role TimelockRole) (*Executor, error) { return &Executor{ Encoder: encoder, Inspector: inspector, client: client, userId: userId, party: party, + role: role, }, nil } @@ -96,70 +101,55 @@ func (e Executor) ExecuteOperation( } // Convert contract IDs - contractIds := make([]cantontypes.CONTRACT_ID, len(cantonOpFields.ContractIds)) + targetCids := make([]cantontypes.CONTRACT_ID, len(cantonOpFields.ContractIds)) for i, cid := range cantonOpFields.ContractIds { - contractIds[i] = cantontypes.CONTRACT_ID(cid) + targetCids[i] = cantontypes.CONTRACT_ID(cid) } // Build exercise command using generated bindings mcmsContract := mcms.MCMS{} - var exerciseCmd *model.ExerciseCommand - // Use different input struct depending on whether the operation is targeting the MCMS contract itself or another contract - if cantonOpFields.TargetInstanceId == "self" { - input := mcms.ExecuteMcmsOp{ - Submitter: cantontypes.PARTY(e.party), - Op: cantonOp, - OpProof: opProof, - } - exerciseCmd = mcmsContract.ExecuteMcmsOp(metadata.MCMAddress, input) - } else { - input := mcms.ExecuteOp{ - Submitter: cantontypes.PARTY(e.party), - TargetCid: cantontypes.CONTRACT_ID(cantonOpFields.TargetCid), - Op: cantonOp, - OpProof: opProof, - ContractIds: contractIds, - } - exerciseCmd = mcmsContract.ExecuteOp(metadata.MCMAddress, input) - + var choice string + var choiceArgument *apiv2.Value + + input := mcms.ExecuteOp{ + TargetRole: mcms.Role(e.role.String()), + Submitter: cantontypes.PARTY(e.party), + Op: cantonOp, + OpProof: opProof, + TargetCids: targetCids, } + exerciseCmd := mcmsContract.ExecuteOp(metadata.MCMAddress, input) + choice = exerciseCmd.Choice + choiceArgument = ledger.MapToValue(input) - // List known packages to find the package ID for mcms - ListKnownPackagesResp, err := e.client.PackageMng.ListKnownPackages(ctx) + // Parse template ID + packageID, moduleName, entityName, err := parseTemplateIDFromString(mcmsContract.GetTemplateID()) if err != nil { - return types.TransactionResult{}, fmt.Errorf("failed to list known packages: %w", err) - } - - var mcmsPkgID string - for _, p := range ListKnownPackagesResp { - if strings.Contains(strings.ToLower(p.Name), "mcms") { - mcmsPkgID = p.PackageID - break - } - } - if mcmsPkgID == "" { - return types.TransactionResult{}, fmt.Errorf("failed to find mcms package") + return types.TransactionResult{}, fmt.Errorf("failed to parse template ID: %w", err) } commandID := uuid.Must(uuid.NewUUID()).String() - cmds := &model.SubmitAndWaitRequest{ - Commands: &model.Commands{ - WorkflowID: "mcms-execute-op", - UserID: e.userId, - CommandID: commandID, + submitResp, err := e.client.SubmitAndWaitForTransaction(ctx, &apiv2.SubmitAndWaitForTransactionRequest{ + Commands: &apiv2.Commands{ + WorkflowId: "mcms-execute-op", + CommandId: commandID, ActAs: []string{e.party}, - Commands: []*model.Command{{ - Command: &model.ExerciseCommand{ - TemplateID: exerciseCmd.TemplateID, - ContractID: exerciseCmd.ContractID, - Choice: exerciseCmd.Choice, - Arguments: exerciseCmd.Arguments, + Commands: []*apiv2.Command{{ + Command: &apiv2.Command_Exercise{ + Exercise: &apiv2.ExerciseCommand{ + TemplateId: &apiv2.Identifier{ + PackageId: packageID, + ModuleName: moduleName, + EntityName: entityName, + }, + ContractId: metadata.MCMAddress, + Choice: choice, + ChoiceArgument: choiceArgument, + }, }, }}, }, - } - - submitResp, err := e.client.CommandService.SubmitAndWaitForTransaction(ctx, cmds) + }) if err != nil { return types.TransactionResult{}, fmt.Errorf("failed to execute operation: %w", err) } @@ -167,15 +157,16 @@ func (e Executor) ExecuteOperation( // Extract NEW MCMS CID from Created event newMCMSContractID := "" newMCMSTemplateID := "" - for _, ev := range submitResp.Transaction.Events { - if ev.Created == nil { - continue - } - normalized := NormalizeTemplateKey(ev.Created.TemplateID) - if normalized == MCMSTemplateKey { - newMCMSContractID = ev.Created.ContractID - newMCMSTemplateID = ev.Created.TemplateID - break + transaction := submitResp.GetTransaction() + for _, ev := range transaction.GetEvents() { + if createdEv := ev.GetCreated(); createdEv != nil { + templateID := formatTemplateID(createdEv.GetTemplateId()) + normalized := NormalizeTemplateKey(templateID) + if normalized == MCMSTemplateKey { + newMCMSContractID = createdEv.GetContractId() + newMCMSTemplateID = templateID + break + } } } @@ -202,16 +193,13 @@ func (e Executor) SetRoot( validUntil uint32, sortedSignatures []types.Signature, ) (types.TransactionResult, error) { - // Calculate the hash to sign according to Canton's expectations, and extract signers from it rootHex := hex.EncodeToString(root[:]) - validUntilHexForSigning := strings.Repeat("0", 64) // TODO: Remove, Canton placeholder (64 zeros) - concatenated := rootHex + validUntilHexForSigning - - innerData, err := hex.DecodeString(concatenated) + // Recalculate msg hash to recover signers + inner, err := abi.Encode(SignMsgABI, root, validUntil) if err != nil { return types.TransactionResult{}, fmt.Errorf("failed to decode hex for signing: %w", err) } - innerHash := crypto.Keccak256(innerData) + innerHash := crypto.Keccak256(inner) // Apply EIP-191 prefix prefix := []byte("\x19Ethereum Signed Message:\n32") @@ -269,6 +257,7 @@ func (e Executor) SetRoot( validUntilTime := time.Unix(time.Unix(int64(validUntil), 0).UnixMicro(), 0) input := mcms.SetRoot{ + TargetRole: mcms.Role(e.role.String()), Submitter: cantontypes.PARTY(e.party), NewRoot: cantontypes.TEXT(rootHex), ValidUntil: cantontypes.TIMESTAMP(validUntilTime), @@ -281,41 +270,37 @@ func (e Executor) SetRoot( mcmsContract := mcms.MCMS{} exerciseCmd := mcmsContract.SetRoot(metadata.MCMAddress, input) - ListKnownPackagesResp, err := e.client.PackageMng.ListKnownPackages(ctx) + // Parse template ID + packageID, moduleName, entityName, err := parseTemplateIDFromString(mcmsContract.GetTemplateID()) if err != nil { - return types.TransactionResult{}, fmt.Errorf("failed to list known packages: %w", err) + return types.TransactionResult{}, fmt.Errorf("failed to parse template ID: %w", err) } - var mcmsPkgID string - for _, p := range ListKnownPackagesResp { - if strings.Contains(strings.ToLower(p.Name), "mcms") { - mcmsPkgID = p.PackageID - break - } - } - if mcmsPkgID == "" { - return types.TransactionResult{}, fmt.Errorf("failed to find mcms package") - } + // Convert input to choice argument + choiceArgument := ledger.MapToValue(input) commandID := uuid.Must(uuid.NewUUID()).String() - cmds := &model.SubmitAndWaitRequest{ - Commands: &model.Commands{ - WorkflowID: "mcms-set-root", - UserID: e.userId, - CommandID: commandID, + submitResp, err := e.client.SubmitAndWaitForTransaction(ctx, &apiv2.SubmitAndWaitForTransactionRequest{ + Commands: &apiv2.Commands{ + WorkflowId: "mcms-set-root", + CommandId: commandID, ActAs: []string{e.party}, - Commands: []*model.Command{{ - Command: &model.ExerciseCommand{ - TemplateID: exerciseCmd.TemplateID, - ContractID: exerciseCmd.ContractID, - Choice: exerciseCmd.Choice, - Arguments: exerciseCmd.Arguments, + Commands: []*apiv2.Command{{ + Command: &apiv2.Command_Exercise{ + Exercise: &apiv2.ExerciseCommand{ + TemplateId: &apiv2.Identifier{ + PackageId: packageID, + ModuleName: moduleName, + EntityName: entityName, + }, + ContractId: metadata.MCMAddress, + Choice: exerciseCmd.Choice, + ChoiceArgument: choiceArgument, + }, }, }}, }, - } - - submitResp, err := e.client.CommandService.SubmitAndWaitForTransaction(ctx, cmds) + }) if err != nil { return types.TransactionResult{}, fmt.Errorf("failed to set root: %w", err) } @@ -323,15 +308,16 @@ func (e Executor) SetRoot( // Extract NEW MCMS CID from Created event newMCMSContractID := "" newMCMSTemplateID := "" - for _, ev := range submitResp.Transaction.Events { - if ev.Created == nil { - continue - } - normalized := NormalizeTemplateKey(ev.Created.TemplateID) - if normalized == MCMSTemplateKey { - newMCMSContractID = ev.Created.ContractID - newMCMSTemplateID = ev.Created.TemplateID - break + transaction := submitResp.GetTransaction() + for _, ev := range transaction.GetEvents() { + if createdEv := ev.GetCreated(); createdEv != nil { + templateID := formatTemplateID(createdEv.GetTemplateId()) + normalized := NormalizeTemplateKey(templateID) + if normalized == MCMSTemplateKey { + newMCMSContractID = createdEv.GetContractId() + newMCMSTemplateID = templateID + break + } } } @@ -349,3 +335,11 @@ func (e Executor) SetRoot( }, }, nil } + +func PadLeft32(hexStr string) string { + if len(hexStr) >= 64 { + return hexStr[:64] + } + + return strings.Repeat("0", 64-len(hexStr)) + hexStr +} diff --git a/sdk/canton/helpers.go b/sdk/canton/helpers.go index 78ec82d8f..8e5f43456 100644 --- a/sdk/canton/helpers.go +++ b/sdk/canton/helpers.go @@ -1,6 +1,11 @@ package canton -import "strings" +import ( + "fmt" + "strings" + + apiv2 "github.com/digital-asset/dazl-client/v8/go/api/com/daml/ledger/api/v2" +) const ( MCMSTemplateKey = "MCMS.Main:MCMS" @@ -15,3 +20,34 @@ func NormalizeTemplateKey(tid string) string { return parts[len(parts)-2] + ":" + parts[len(parts)-1] } + +// parseTemplateIDFromString parses a template ID string like "#package:Module:Entity" into its components +func parseTemplateIDFromString(templateID string) (packageID, moduleName, entityName string, err error) { + if !strings.HasPrefix(templateID, "#") { + return "", "", "", fmt.Errorf("template ID must start with #") + } + parts := strings.Split(templateID, ":") + if len(parts) != 3 { + return "", "", "", fmt.Errorf("template ID must have format #package:module:entity, got: %s", templateID) + } + + return parts[0], parts[1], parts[2], nil +} + +// ParseTemplateIDFromString is the exported version of parseTemplateIDFromString +func ParseTemplateIDFromString(templateID string) (packageID, moduleName, entityName string, err error) { + return parseTemplateIDFromString(templateID) +} + +// formatTemplateID converts an apiv2.Identifier to a string template ID format +func formatTemplateID(id *apiv2.Identifier) string { + if id == nil { + return "" + } + return id.GetPackageId() + ":" + id.GetModuleName() + ":" + id.GetEntityName() +} + +// FormatTemplateID is the exported version of formatTemplateID +func FormatTemplateID(id *apiv2.Identifier) string { + return formatTemplateID(id) +} diff --git a/sdk/canton/inspector.go b/sdk/canton/inspector.go index 25ff2e2e0..fa19d1695 100644 --- a/sdk/canton/inspector.go +++ b/sdk/canton/inspector.go @@ -14,6 +14,7 @@ import ( "github.com/smartcontractkit/chainlink-canton/bindings" "github.com/smartcontractkit/chainlink-canton/bindings/mcms" + cantontypes "github.com/smartcontractkit/go-daml/pkg/types" "github.com/smartcontractkit/mcms/sdk" "github.com/smartcontractkit/mcms/types" ) @@ -24,12 +25,14 @@ type Inspector struct { stateClient apiv2.StateServiceClient party string contractCache *mcms.MCMS // Cache MCMS to avoid repeated RPC calls + role TimelockRole } -func NewInspector(stateClient apiv2.StateServiceClient, party string) *Inspector { +func NewInspector(stateClient apiv2.StateServiceClient, party string, role TimelockRole) *Inspector { return &Inspector{ stateClient: stateClient, party: party, + role: role, } } @@ -42,7 +45,16 @@ func (i *Inspector) GetConfig(ctx context.Context, mcmsAddr string) (*types.Conf i.contractCache = mcmsContract } - return toConfig(i.contractCache.Config) + switch i.role { + case TimelockRoleProposer: + return toConfig(i.contractCache.Proposer.Config) + case TimelockRoleBypasser: + return toConfig(i.contractCache.Bypasser.Config) + case TimelockRoleCanceller: + return toConfig(i.contractCache.Canceller.Config) + default: + return nil, fmt.Errorf("unknown timelock role: %s", i.role) + } } func (i *Inspector) GetOpCount(ctx context.Context, mcmsAddr string) (uint64, error) { @@ -54,7 +66,16 @@ func (i *Inspector) GetOpCount(ctx context.Context, mcmsAddr string) (uint64, er i.contractCache = mcmsContract } - return uint64(i.contractCache.ExpiringRoot.OpCount), nil + switch i.role { + case TimelockRoleProposer: + return uint64(i.contractCache.Proposer.ExpiringRoot.OpCount), nil + case TimelockRoleBypasser: + return uint64(i.contractCache.Bypasser.ExpiringRoot.OpCount), nil + case TimelockRoleCanceller: + return uint64(i.contractCache.Canceller.ExpiringRoot.OpCount), nil + default: + return 0, fmt.Errorf("unknown timelock role: %s", i.role) + } } func (i *Inspector) GetRoot(ctx context.Context, mcmsAddr string) (common.Hash, uint32, error) { @@ -66,8 +87,20 @@ func (i *Inspector) GetRoot(ctx context.Context, mcmsAddr string) (common.Hash, i.contractCache = mcmsContract } + var expiringRoot mcms.ExpiringRoot + switch i.role { + case TimelockRoleProposer: + expiringRoot = i.contractCache.Proposer.ExpiringRoot + case TimelockRoleBypasser: + expiringRoot = i.contractCache.Bypasser.ExpiringRoot + case TimelockRoleCanceller: + expiringRoot = i.contractCache.Canceller.ExpiringRoot + default: + return common.Hash{}, 0, fmt.Errorf("unknown timelock role: %s", i.role) + } + // Parse the root from hex string - rootStr := string(i.contractCache.ExpiringRoot.Root) + rootStr := string(expiringRoot.Root) rootStr = strings.TrimPrefix(rootStr, "0x") rootBytes, err := hex.DecodeString(rootStr) if err != nil { @@ -78,7 +111,7 @@ func (i *Inspector) GetRoot(ctx context.Context, mcmsAddr string) (common.Hash, // validUntil is a TIMESTAMP (which wraps time.Time) // Convert to Unix timestamp (uint32) - timeVal := time.Time(i.contractCache.ExpiringRoot.ValidUntil) + timeVal := time.Time(expiringRoot.ValidUntil) validUntil := uint32(timeVal.Unix()) return root, validUntil, nil @@ -93,9 +126,21 @@ func (i *Inspector) GetRootMetadata(ctx context.Context, mcmsAddr string) (types i.contractCache = mcmsContract } + var rootMetadata mcms.RootMetadata + switch i.role { + case TimelockRoleProposer: + rootMetadata = i.contractCache.Proposer.RootMetadata + case TimelockRoleBypasser: + rootMetadata = i.contractCache.Bypasser.RootMetadata + case TimelockRoleCanceller: + rootMetadata = i.contractCache.Canceller.RootMetadata + default: + return types.ChainMetadata{}, fmt.Errorf("unknown timelock role: %s", i.role) + } + return types.ChainMetadata{ - StartingOpCount: uint64(i.contractCache.RootMetadata.PreOpCount), - MCMAddress: string(i.contractCache.McmsId), + StartingOpCount: uint64(rootMetadata.PreOpCount), + MCMAddress: string(i.contractCache.InstanceId), }, nil } @@ -164,11 +209,34 @@ func (i *Inspector) getMCMSContract(ctx context.Context, mcmsAddr string) (*mcms } // Use bindings package to unmarshal the contract - mcmsContract, err := bindings.UnmarshalActiveContract[mcms.MCMS](activeContract) + // TODO: MinDelay type from binding doesnt correspond to actual type from contract + type NoMinDelayMCMS struct { + Owner cantontypes.PARTY `json:"owner"` + InstanceId cantontypes.TEXT `json:"instanceId"` + ChainId cantontypes.INT64 `json:"chainId"` + Proposer mcms.RoleState `json:"proposer"` + Canceller mcms.RoleState `json:"canceller"` + Bypasser mcms.RoleState `json:"bypasser"` + BlockedFunctions []mcms.BlockedFunction `json:"blockedFunctions"` + TimelockTimestamps cantontypes.GENMAP `json:"timelockTimestamps"` + } + mcmsContractNoMinDelay, err := bindings.UnmarshalActiveContract[NoMinDelayMCMS](activeContract) if err != nil { return nil, fmt.Errorf("failed to unmarshal MCMS contract: %w", err) } + mcmsContract := &mcms.MCMS{ + Owner: mcmsContractNoMinDelay.Owner, + InstanceId: mcmsContractNoMinDelay.InstanceId, + ChainId: mcmsContractNoMinDelay.ChainId, + Proposer: mcmsContractNoMinDelay.Proposer, + Canceller: mcmsContractNoMinDelay.Canceller, + Bypasser: mcmsContractNoMinDelay.Bypasser, + BlockedFunctions: mcmsContractNoMinDelay.BlockedFunctions, + TimelockTimestamps: mcmsContractNoMinDelay.TimelockTimestamps, + MinDelay: 0, // TODO: Fix bindings type + } + return mcmsContract, nil } } diff --git a/sdk/canton/inspector_test.go b/sdk/canton/inspector_test.go index 7aa3442ba..2c275a5a4 100644 --- a/sdk/canton/inspector_test.go +++ b/sdk/canton/inspector_test.go @@ -6,8 +6,8 @@ import ( "testing" "github.com/ethereum/go-ethereum/common" - "github.com/noders-team/go-daml/pkg/types" "github.com/smartcontractkit/chainlink-canton/bindings/mcms" + "github.com/smartcontractkit/go-daml/pkg/types" mcmstypes "github.com/smartcontractkit/mcms/types" "github.com/stretchr/testify/require" )