diff --git a/.tool-versions b/.tool-versions index 4e95e10..06ccce9 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1,4 +1,4 @@ -golang 1.25.7 +golang 1.26.2 golangci-lint 2.11.4 mockery 3.6.3 task 3.48.0 diff --git a/go.mod b/go.mod index 916a72a..537071a 100644 --- a/go.mod +++ b/go.mod @@ -1,28 +1,34 @@ module github.com/smartcontractkit/cld-changesets -go 1.25.7 +go 1.26.2 require ( github.com/Masterminds/semver/v3 v3.4.0 - github.com/aptos-labs/aptos-go-sdk v1.12.0 - github.com/deckarep/golang-set/v2 v2.6.0 - github.com/ethereum/go-ethereum v1.17.1 + github.com/aptos-labs/aptos-go-sdk v1.12.1 + github.com/deckarep/golang-set/v2 v2.8.0 + github.com/ethereum/go-ethereum v1.17.2 + github.com/gagliardetto/binary v0.8.0 github.com/gagliardetto/solana-go v1.13.0 github.com/google/go-cmp v0.7.0 github.com/samber/lo v1.52.0 github.com/smartcontractkit/ccip-owner-contracts v0.1.0 - github.com/smartcontractkit/chain-selectors v1.0.97 - github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20260121163256-85accaf3d28d - github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings v0.0.0-20250912190424-fd2e35d7deb5 - github.com/smartcontractkit/chainlink-common v0.10.1-0.20260217160002-b56cb5356cc7 - github.com/smartcontractkit/chainlink-deployments-framework v0.99.0 - github.com/smartcontractkit/chainlink-evm v0.3.3 + github.com/smartcontractkit/chain-selectors v1.0.98 + github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20260506144252-c100eabfda74 + github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings v0.0.0-20260506144252-c100eabfda74 + github.com/smartcontractkit/chainlink-common v0.11.2-0.20260429111145-3667714e0b37 + github.com/smartcontractkit/chainlink-deployments-framework v0.101.0 + github.com/smartcontractkit/chainlink-evm v0.3.4-0.20260429160308-91a892a60171 github.com/smartcontractkit/chainlink-evm/gethwrappers v0.0.0-20260421142741-9c7fbaf7c828 github.com/smartcontractkit/chainlink-protos/job-distributor v0.18.0 - github.com/smartcontractkit/mcms v0.40.1 + github.com/smartcontractkit/chainlink-ton/deployment v0.0.0-20260430134932-681b7a7fe426 + github.com/smartcontractkit/mcms v0.41.1 + github.com/smartcontractkit/quarantine v0.0.0-20251203215908-fd0551c6adf9 + github.com/smartcontractkit/wsrpc v0.8.5-0.20250502134807-c57d3d995945 + github.com/spf13/cast v1.10.0 github.com/stretchr/testify v1.11.1 - golang.org/x/mod v0.33.0 - golang.org/x/sync v0.19.0 + github.com/zksync-sdk/zksync2-go v1.1.1-0.20250620124214-2c742ee399c6 + golang.org/x/mod v0.34.0 + golang.org/x/sync v0.20.0 gopkg.in/yaml.v3 v3.0.1 ) @@ -59,20 +65,20 @@ require ( 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/block-vision/sui-go-sdk v1.1.4 // indirect + github.com/block-vision/sui-go-sdk v1.2.1 // indirect github.com/btcsuite/btcd v0.24.2 // 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/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce // indirect github.com/buger/jsonparser v1.1.2 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // 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 + github.com/cloudevents/sdk-go/binding/format/protobuf/v2 v2.16.2 // indirect + github.com/cloudevents/sdk-go/v2 v2.16.2 // indirect github.com/cockroachdb/errors v1.11.3 // indirect github.com/cockroachdb/fifo v0.0.0-20240816210425-c5d0cb0b6fc0 // indirect github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect @@ -88,20 +94,21 @@ require ( github.com/cosmos/go-bip39 v1.0.0 // indirect github.com/cpuguy83/dockercfg v0.3.2 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect - github.com/crate-crypto/go-eth-kzg v1.4.0 // indirect + github.com/crate-crypto/go-eth-kzg v1.5.0 // indirect github.com/creachadair/jrpc2 v1.2.0 // indirect github.com/creachadair/mds v0.13.4 // indirect + github.com/creack/pty v1.1.24 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/dchest/siphash v1.2.3 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect github.com/digital-asset/dazl-client/v8 v8.9.0 // indirect github.com/distribution/reference v0.6.0 // indirect - github.com/docker/docker v28.5.2+incompatible // indirect + github.com/docker/docker v28.5.3-0.20260325154711-31a1689cb0a1+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.10.0 // indirect github.com/emicklei/dot v1.6.2 // indirect - github.com/emicklei/go-restful/v3 v3.11.0 // indirect + github.com/emicklei/go-restful/v3 v3.12.1 // indirect github.com/ethereum/c-kzg-4844/v2 v2.1.6 // indirect github.com/ethereum/go-bigmodexpfix v0.0.0-20250911101455-f9e208c548ab // indirect github.com/fatih/color v1.18.0 // indirect @@ -109,9 +116,9 @@ require ( github.com/felixge/httpsnoop v1.0.4 // indirect github.com/ferranbt/fastssz v0.1.4 // indirect github.com/fsnotify/fsnotify v1.9.0 // indirect - github.com/fxamacker/cbor/v2 v2.7.0 // indirect + github.com/fxamacker/cbor/v2 v2.9.0 // indirect github.com/gabriel-vasile/mimetype v1.4.13 // indirect - github.com/gagliardetto/binary v0.8.0 // indirect + github.com/gagliardetto/metaplex-go v0.2.1 // indirect github.com/gagliardetto/treeout v0.1.4 // indirect github.com/getsentry/sentry-go v0.27.0 // indirect github.com/go-json-experiment/json v0.0.0-20250223041408-d3c622f1b874 // indirect @@ -125,18 +132,20 @@ require ( github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.30.1 // indirect github.com/go-resty/resty/v2 v2.17.2 // indirect + github.com/go-sql-driver/mysql v1.9.3 // indirect github.com/go-viper/mapstructure/v2 v2.5.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.0 // 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/gnostic-models v0.6.9 // indirect - github.com/google/gofuzz v1.2.0 // indirect + github.com/google/pprof v0.0.0-20260302011040-a15ffb7f9dcc // indirect github.com/google/uuid v1.6.0 // indirect - github.com/gorilla/websocket v1.5.3 // indirect - github.com/grafana/pyroscope-go v1.2.7 // indirect + github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // indirect + github.com/grafana/otel-profiling-go v0.5.1 // indirect + github.com/grafana/pyroscope-go v1.2.8 // indirect github.com/grafana/pyroscope-go/godeltaprof v0.1.9 // 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 @@ -152,14 +161,10 @@ require ( github.com/holiman/uint256 v1.3.2 // indirect github.com/huin/goupnp v1.3.0 // indirect github.com/invopop/jsonschema v0.13.0 // indirect - github.com/jackc/chunkreader/v2 v2.0.1 // indirect - github.com/jackc/pgconn v1.14.3 // indirect - github.com/jackc/pgio v1.0.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect - github.com/jackc/pgproto3/v2 v2.3.4-0.20250125160525-bc041643406d // indirect github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect - github.com/jackc/pgtype v1.14.4 // indirect - github.com/jackc/pgx/v4 v4.18.3 // indirect + github.com/jackc/pgx/v5 v5.9.2 // indirect + github.com/jackc/puddle/v2 v2.2.2 // indirect github.com/jackpal/go-nat-pmp v1.0.2 // indirect github.com/jinzhu/copier v0.4.0 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect @@ -167,13 +172,13 @@ require ( github.com/josharian/intern v1.0.0 // indirect github.com/jpillora/backoff v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/karalabe/hid v1.0.1-0.20240306101548-573246063e52 // indirect - github.com/klauspost/compress v1.18.4 // indirect + github.com/karalabe/hid v1.0.1-0.20260315100226-f5d04adeffeb // indirect + github.com/klauspost/compress v1.18.5 // 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/lib/pq v1.11.1 // indirect github.com/logrusorgru/aurora v2.0.3+incompatible // indirect github.com/lufia/plan9stats v0.0.0-20260216142805-b3301c5f2a88 // indirect github.com/magiconair/properties v1.8.10 // indirect @@ -193,7 +198,7 @@ require ( github.com/moby/sys/userns v0.1.0 // indirect github.com/moby/term v0.5.2 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect - github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect github.com/montanaflynn/stats v0.7.1 // indirect github.com/morikuni/aec v1.1.0 // indirect github.com/mostynb/zstdpool-freelist v0.0.0-20201229113212-927304c0c3b1 // indirect @@ -204,7 +209,7 @@ require ( 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 - github.com/pelletier/go-toml/v2 v2.2.4 // indirect + github.com/pelletier/go-toml/v2 v2.3.0 // indirect github.com/pion/dtls/v2 v2.2.12 // indirect github.com/pion/logging v0.2.2 // indirect github.com/pion/stun/v2 v2.0.0 // indirect @@ -215,7 +220,7 @@ require ( github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect github.com/prometheus/client_golang v1.23.2 // indirect github.com/prometheus/client_model v0.6.2 // indirect - github.com/prometheus/common v0.66.1 // indirect + github.com/prometheus/common v0.67.5 // indirect github.com/prometheus/procfs v0.16.1 // indirect github.com/rogpeppe/go-internal v1.14.1 // indirect github.com/rs/cors v1.11.1 // indirect @@ -230,23 +235,24 @@ 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.4 // indirect - github.com/smartcontractkit/chainlink-aptos v0.0.0-20260306142855-8d629e752265 // indirect + github.com/smartcontractkit/chainlink-aptos v0.0.0-20260430175646-295a7f9a1500 // indirect + github.com/smartcontractkit/chainlink-ccip/deployment v0.0.0-20260504204047-af9826978b72 // indirect + github.com/smartcontractkit/chainlink-common/keystore v1.1.0 // indirect github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.10 // indirect - github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260226130359-963f935e0396 // indirect + github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260420204255-a3f3bdd56877 // indirect github.com/smartcontractkit/chainlink-protos/linking-service/go v0.0.0-20251002192024-d2ad9222409b // indirect - github.com/smartcontractkit/chainlink-protos/node-platform v0.0.0-20260205130626-db2a2aab956b // indirect + github.com/smartcontractkit/chainlink-protos/node-platform v0.0.0-20260319180422-b5808c964785 // indirect github.com/smartcontractkit/chainlink-protos/op-catalog v0.0.4 // indirect - github.com/smartcontractkit/chainlink-sui v0.0.0-20260205175622-33e65031f9a9 // indirect - github.com/smartcontractkit/chainlink-testing-framework/framework v0.15.18 // indirect + github.com/smartcontractkit/chainlink-sui v0.0.0-20260428231901-a394dd724761 // indirect + github.com/smartcontractkit/chainlink-testing-framework/framework v0.15.19 // indirect github.com/smartcontractkit/chainlink-testing-framework/seth v1.51.5 // indirect - github.com/smartcontractkit/chainlink-ton v0.0.0-20260219201907-054376f21418 // indirect - github.com/smartcontractkit/chainlink-tron/relayer v0.0.11-0.20250815105909-75499abc4335 // indirect + github.com/smartcontractkit/chainlink-ton v1.0.5-0.20260430134932-681b7a7fe426 // indirect + github.com/smartcontractkit/chainlink-tron/relayer v0.0.11-0.20260408092456-3c6369888d4a // indirect github.com/smartcontractkit/freeport v0.1.3-0.20250828155247-add56fa28aad // indirect github.com/smartcontractkit/grpc-proxy v0.0.0-20240830132753-a7e17fec5ab7 // indirect - github.com/smartcontractkit/libocr v0.0.0-20250912173940-f3ab0246e23d // indirect + github.com/smartcontractkit/libocr v0.0.0-20260403184524-b6409238958d // indirect github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect github.com/spf13/afero v1.15.0 // indirect - github.com/spf13/cast v1.10.0 // indirect github.com/spf13/pflag v1.0.10 // indirect github.com/spf13/viper v1.21.0 // indirect github.com/stellar/go-stellar-sdk v0.1.0 // indirect @@ -273,60 +279,62 @@ require ( github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect github.com/xssnick/tonutils-go v1.14.1 // indirect github.com/yusufpapurcu/wmi v1.2.4 // indirect - github.com/zksync-sdk/zksync2-go v1.1.1-0.20250620124214-2c742ee399c6 // indirect + go.dedis.ch/fixbuf v1.0.3 // indirect + go.dedis.ch/kyber/v3 v3.1.0 // indirect 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.65.0 // indirect go.opentelemetry.io/otel v1.43.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/otlpmetrichttp v1.36.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.41.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.36.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.41.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.15.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.19.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.19.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.43.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.43.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.43.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0 // indirect + go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.19.0 // indirect + go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.43.0 // indirect + go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.43.0 // indirect + go.opentelemetry.io/otel/log v0.19.0 // indirect go.opentelemetry.io/otel/metric v1.43.0 // indirect go.opentelemetry.io/otel/sdk v1.43.0 // indirect - go.opentelemetry.io/otel/sdk/log v0.15.0 // indirect + go.opentelemetry.io/otel/sdk/log v0.19.0 // indirect go.opentelemetry.io/otel/sdk/metric v1.43.0 // indirect go.opentelemetry.io/otel/trace v1.43.0 // indirect - go.opentelemetry.io/proto/otlp v1.9.0 // indirect + go.opentelemetry.io/proto/otlp v1.10.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/ratelimit v0.3.1 // indirect - go.uber.org/zap v1.27.1 // indirect - go.yaml.in/yaml/v2 v2.4.2 // indirect + go.uber.org/zap v1.28.0 // indirect + go.yaml.in/yaml/v2 v2.4.4 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect - golang.org/x/crypto v0.48.0 // indirect + golang.org/x/crypto v0.50.0 // indirect golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa // indirect - golang.org/x/net v0.50.0 // indirect - golang.org/x/oauth2 v0.35.0 // indirect - golang.org/x/sys v0.42.0 // indirect - golang.org/x/term v0.40.0 // indirect - golang.org/x/text v0.34.0 // indirect - golang.org/x/time v0.14.0 // indirect - golang.org/x/tools v0.42.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20260209200024-4cfbd4190f57 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57 // indirect - google.golang.org/grpc v1.79.3 // indirect + golang.org/x/net v0.52.0 // indirect + golang.org/x/oauth2 v0.36.0 // indirect + golang.org/x/sys v0.43.0 // indirect + golang.org/x/term v0.42.0 // indirect + golang.org/x/text v0.36.0 // indirect + golang.org/x/time v0.15.0 // indirect + golang.org/x/tools v0.43.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20260401024825-9d38bb4040a9 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20260401024825-9d38bb4040a9 // indirect + google.golang.org/grpc v1.80.0 // indirect google.golang.org/protobuf v1.36.11 // indirect gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect k8s.io/api v0.32.3 // indirect - k8s.io/apimachinery v0.32.3 // indirect + k8s.io/apimachinery v0.33.2 // indirect k8s.io/client-go v0.32.3 // indirect k8s.io/klog/v2 v2.130.1 // indirect - k8s.io/kube-openapi v0.0.0-20241212222426-2c72e554b1e7 // indirect - k8s.io/utils v0.0.0-20241104163129-6fe5fd82f078 // indirect + k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff // indirect + k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 // indirect sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.4.2 // indirect - sigs.k8s.io/yaml v1.4.0 // indirect + sigs.k8s.io/randfill v1.0.0 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.6.0 // indirect + sigs.k8s.io/yaml v1.6.0 // indirect ) replace ( diff --git a/go.sum b/go.sum index 8be895f..7b2c1e6 100644 --- a/go.sum +++ b/go.sum @@ -1,6 +1,33 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.43.0/go.mod h1:BOSR3VbTLkk6FDC/TcffxP4NF/FFBGA5ku+jvKOP7pg= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +contrib.go.opencensus.io/exporter/stackdriver v0.12.6/go.mod h1:8x999/OcIPy5ivx/wDiV7Gx4D+VUPODf0mWRGRc5kSk= +contrib.go.opencensus.io/exporter/stackdriver v0.13.4/go.mod h1:aXENhDJ1Y4lIg4EUaVTwzvYETVNZk10Pu26tevFKLUc= dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8= dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +filippo.io/edwards25519 v1.0.0-rc.1/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= filippo.io/edwards25519 v1.1.1 h1:YpjwWWlNmGIDyXOn8zLzqiD+9TyIlPhGFG96P39uBpw= filippo.io/edwards25519 v1.1.1/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= @@ -13,13 +40,16 @@ github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg6 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/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= 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= +github.com/GeertJohan/go.incremental v1.0.0/go.mod h1:6fAjUhbVuX1KcMD3c8TEgVUqmo4seqhv0i0kdATSkM0= +github.com/GeertJohan/go.rice v1.0.0/go.mod h1:eH6gbSOAUv07dQuZVnBmoDP8mgsM1rtixis4Tib9if0= github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0= 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/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= 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/VictoriaMetrics/fastcache v1.13.0 h1:AW4mheMR5Vd9FkAPUv+NH6Nhw+fmbTMGMsNAoA/+4G0= @@ -27,12 +57,19 @@ github.com/VictoriaMetrics/fastcache v1.13.0/go.mod h1:hHXhl4DA2fTL2HTZDJFXWgW0L github.com/XSAM/otelsql v0.37.0 h1:ya5RNw028JW0eJW8Ma4AmoKxAYsJSGuNVbC7F1J457A= github.com/XSAM/otelsql v0.37.0/go.mod h1:LHbCu49iU8p255nCn1oi04oX2UjSoRcUMiKEHo2a5qM= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= +github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/allegro/bigcache v1.2.1 h1:hg1sY1raCwic3Vnsvje6TT7/pnZba83LeFck5NrFKSc= github.com/allegro/bigcache v1.2.1/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= +github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129/go.mod h1:rFgpPQZYZ8vdbc+48xibu8ALc3yeyd64IhHS+PU6Yyg= 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/aptos-labs/aptos-go-sdk v1.12.0 h1:deHZ7NJlFhHm2i+eaPHt6EPa3BuXXnIYx2X5J3/U0Es= -github.com/aptos-labs/aptos-go-sdk v1.12.0/go.mod h1:FTgKp0RLfEefllCdkCj0jPU14xWk11yA7SFVfCDLUj8= +github.com/aptos-labs/aptos-go-sdk v1.12.1 h1:EXtA9GF9fJndRcjWVZZ3Hf5hXxvGWNPu+1k3A6eGOfM= +github.com/aptos-labs/aptos-go-sdk v1.12.1/go.mod h1:FTgKp0RLfEefllCdkCj0jPU14xWk11yA7SFVfCDLUj8= +github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= +github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/avast/retry-go v3.0.0+incompatible h1:4SOWQ7Qs+oroOTQOYnAHqelpCO0biHSxpiH9JdtuBj0= @@ -41,6 +78,8 @@ github.com/avast/retry-go/v4 v4.7.0 h1:yjDs35SlGvKwRNSykujfjdMxMhMQQM0TnIjJaHB+Z github.com/avast/retry-go/v4 v4.7.0/go.mod h1:ZMPDa3sY2bKgpLtap9JRUgk2yTAba7cgiFhqxY2Sg6Q= github.com/awalterschulze/gographviz v2.0.3+incompatible h1:9sVEXJBJLwGX7EQVhLm2elIKCm7P2YHFC8v6096G09E= github.com/awalterschulze/gographviz v2.0.3+incompatible/go.mod h1:GEV5wmg4YquNw7v1kkyoX9etIk8yVmXj+AkDHuuETHs= +github.com/aws/aws-sdk-go v1.22.1/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.23.20/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.55.8 h1:JRmEUbU52aJQZ2AjX4q4Wu7t4uZjOu71uyNmaWlUkJQ= github.com/aws/aws-sdk-go v1.55.8/go.mod h1:ZkViS9AqA6otK+JBBNH2++sx1sgxrPKcSzPPvQkUtXk= github.com/aws/aws-sdk-go-v2 v1.41.4 h1:10f50G7WyU02T56ox1wWXq+zTX9I1zxG46HYuG1hH/k= @@ -75,6 +114,7 @@ github.com/aws/aws-sdk-go-v2/service/sts v1.41.9 h1:Cng+OOwCHmFljXIxpEVXAGMnBia8 github.com/aws/aws-sdk-go-v2/service/sts v1.41.9/go.mod h1:LrlIndBDdjA/EeXeyNBle+gyCwTlizzW5ycgWnvIxkk= github.com/aws/smithy-go v1.24.2 h1:FzA3bu/nt/vDvmnkg+R8Xl46gmzEDam6mZ1hzmwXFng= github.com/aws/smithy-go v1.24.2/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc= +github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I= github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk= github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg= github.com/barkimedes/go-deepcopy v0.0.0-20220514131651-17c30cfc62df h1:GSoSVRLoBaFpOOds6QyY1L8AX7uoY+Ln3BHc22W40X0= @@ -82,14 +122,18 @@ github.com/barkimedes/go-deepcopy v0.0.0-20220514131651-17c30cfc62df/go.mod h1:h github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o= github.com/benbjohnson/clock v1.3.5/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= 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/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +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/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= 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= -github.com/block-vision/sui-go-sdk v1.1.4/go.mod h1:t8mWASwfyv+EyqHGO9ZrcDiCJWGOFEXqq50TMJ8GQco= +github.com/block-vision/sui-go-sdk v1.2.1 h1:uwvGbzfcrS4SsIaakclYxy0qgEF1XWIUtTYWXB4PoAw= +github.com/block-vision/sui-go-sdk v1.2.1/go.mod h1:t8mWASwfyv+EyqHGO9ZrcDiCJWGOFEXqq50TMJ8GQco= 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= @@ -110,8 +154,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= @@ -121,6 +165,8 @@ github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtE github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= github.com/bufbuild/protocompile v0.14.1 h1:iA73zAf/fyljNjQKwYzUHD6AD4R8KMasmwa/FBatYVw= github.com/bufbuild/protocompile v0.14.1/go.mod h1:ppVdAIhbr2H8asPk6k4pY7t9zB1OU5DoEw9xY/FUi1c= +github.com/buger/goterm v0.0.0-20200322175922-2f3e71b85129/go.mod h1:u9UyCz2eTrSGy6fbupqJ54eY5c4IC8gREQ1053dK12U= +github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= github.com/buger/jsonparser v1.1.2 h1:frqHqw7otoVbk5M8LlE/L7HTnIq2v9RX6EJ48i9AxJk= github.com/buger/jsonparser v1.1.2/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= @@ -130,20 +176,19 @@ github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F9 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= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cloudevents/sdk-go/binding/format/protobuf/v2 v2.16.1 h1:nLaJZcVAnaqch3K83AyzHfY2DmQM18/L7jvkmKSfkpI= -github.com/cloudevents/sdk-go/binding/format/protobuf/v2 v2.16.1/go.mod h1:6Q+F2puKpJ6zWv+R02BVnizJICf7++oRT5zwpZQAsbk= -github.com/cloudevents/sdk-go/v2 v2.16.1 h1:G91iUdqvl88BZ1GYYr9vScTj5zzXSyEuqbfE63gbu9Q= -github.com/cloudevents/sdk-go/v2 v2.16.1/go.mod h1:v/kVOaWjNfbvc6tkhhlkhvLapj8Aa8kvXiH5GiOHCKI= +github.com/cloudevents/sdk-go/binding/format/protobuf/v2 v2.16.2 h1:ydUjnKn4RoCeN8rge3F/deT52w2WJMmIC5mHNUq+Ut8= +github.com/cloudevents/sdk-go/binding/format/protobuf/v2 v2.16.2/go.mod h1:Bny999RuVUtNjzTGa9HCHpXjrLGMipJVq5kqVpudBl0= +github.com/cloudevents/sdk-go/v2 v2.16.2 h1:ZYDFrYke4FD+jM8TZTJJO6JhKHzOQl2oqpFK1D+NnQM= +github.com/cloudevents/sdk-go/v2 v2.16.2/go.mod h1:laOcGImm4nVJEU+PHnUrKL56CKmRL65RlQF0kRmW/kg= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= -github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f h1:otljaYPt5hWxV3MUfO5dFPFiOXg9CyG5/kCfayTqsJ4= github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU= github.com/cockroachdb/errors v1.11.3 h1:5bA+k2Y6r+oz/6Z/RFlNeVCesGARKuC6YymtcDrbC/I= @@ -170,31 +215,35 @@ github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= github.com/containerd/platforms v1.0.0-rc.2 h1:0SPgaNZPVWGEi4grZdV8VRYQn78y+nm6acgLGv/QzE4= github.com/containerd/platforms v1.0.0-rc.2/go.mod h1:J71L7B+aiM5SdIEqmd9wp6THLVRzJGXfNuWCZCllLA4= +github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= +github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY= github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw= github.com/cpuguy83/dockercfg v0.3.2 h1:DlJTyZGBDlXqUZ2Dk2Q3xHs/FtnooJJVaad2S9GKorA= github.com/cpuguy83/dockercfg v0.3.2/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.7 h1:zbFlGlXEAKlwXpmvle3d8Oe3YnkKIK4xSRTd3sHPnBo= github.com/cpuguy83/go-md2man/v2 v2.0.7/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= -github.com/crate-crypto/go-eth-kzg v1.4.0 h1:WzDGjHk4gFg6YzV0rJOAsTK4z3Qkz5jd4RE3DAvPFkg= -github.com/crate-crypto/go-eth-kzg v1.4.0/go.mod h1:J9/u5sWfznSObptgfa92Jq8rTswn6ahQWEuiLHOjCUI= +github.com/crate-crypto/go-eth-kzg v1.5.0 h1:FYRiJMJG2iv+2Dy3fi14SVGjcPteZ5HAAUe4YWlJygc= +github.com/crate-crypto/go-eth-kzg v1.5.0/go.mod h1:J9/u5sWfznSObptgfa92Jq8rTswn6ahQWEuiLHOjCUI= github.com/creachadair/jrpc2 v1.2.0 h1:SXr0OgnwM0X18P+HccJP0uT3KGSDk/BCSRlJBvE2bMY= github.com/creachadair/jrpc2 v1.2.0/go.mod h1:66uKSdr6tR5ZeNvkIjDSbbVUtOv0UhjS/vcd8ECP7Iw= github.com/creachadair/mds v0.13.4 h1:RgU0MhiVqkzp6/xtNWhK6Pw7tDeaVuGFtA0UA2RBYvY= github.com/creachadair/mds v0.13.4/go.mod h1:4vrFYUzTXMJpMBU+OA292I6IUxKWCCfZkgXg+/kBZMo= -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= 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/daaku/go.zipexe v1.0.0/go.mod h1:z8IiR6TsVLEYKwXAoE/I+8ys/sDkgTzSL0CLnGVd57E= 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= @@ -202,8 +251,8 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dchest/siphash v1.2.3 h1:QXwFc8cFOR2dSa/gE6o/HokBMWtLUaNDVd+22aKHeEA= github.com/dchest/siphash v1.2.3/go.mod h1:0NvQU092bT0ipiFN++/rXm69QG9tVxLAlQHIXMPAkHc= -github.com/deckarep/golang-set/v2 v2.6.0 h1:XfcQbWM1LlMB8BsJ8N9vW5ehnnPVIw0je80NsVHagjM= -github.com/deckarep/golang-set/v2 v2.6.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= +github.com/deckarep/golang-set/v2 v2.8.0 h1:swm0rlPCmdWn9mESxKOjWk8hXSqoxOp+ZlfuyaAdFlQ= +github.com/deckarep/golang-set/v2 v2.8.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= github.com/decred/dcrd/crypto/blake256 v1.1.0 h1:zPMNGQCm0g4QTY27fOCorQW7EryeQ/U0x++OzVrdms8= github.com/decred/dcrd/crypto/blake256 v1.1.0/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= @@ -213,12 +262,16 @@ 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/dfuse-io/logging v0.0.0-20201110202154-26697de88c79/go.mod h1:V+ED4kT/t/lKtH99JQmKIb0v9WL3VaYkJ36CfHlVECI= +github.com/dfuse-io/logging v0.0.0-20210109005628-b97a57253f70/go.mod h1:EoK/8RFbMEteaCaz89uessDTnCWjbbcr+DXcBh4el5o= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/digital-asset/dazl-client/v8 v8.9.0 h1:F2qTUWtHAjhGyRGV+xTim+VAFwM99FpcOx4+wowvPnY= github.com/digital-asset/dazl-client/v8 v8.9.0/go.mod h1:q1KevCJ8FpH8je2MnnjN8/QUfhstB4fKpyKyqDtqFh0= 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.5.2+incompatible h1:DBX0Y0zAjZbSrm1uzOkdr1onVghKaftjlSWt4AFexzM= -github.com/docker/docker v28.5.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v28.5.3-0.20260325154711-31a1689cb0a1+incompatible h1:f51eIlZsZqGKXyNeCHs5oVo/xQiR9zh+pDYMfnu3VPQ= +github.com/docker/docker v28.5.3-0.20260325154711-31a1689cb0a1+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= @@ -227,8 +280,8 @@ github.com/ebitengine/purego v0.10.0 h1:QIw4xfpWT6GWTzaW5XEKy3HXoqrJGx1ijYHzTF0/ github.com/ebitengine/purego v0.10.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/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= -github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/emicklei/go-restful/v3 v3.12.1 h1:PJMDIM/ak7btuL8Ex0iYET9hxM3CI2sjZtzpL63nKAU= +github.com/emicklei/go-restful/v3 v3.12.1/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -238,8 +291,10 @@ github.com/ethereum/c-kzg-4844/v2 v2.1.6 h1:xQymkKCT5E2Jiaoqf3v4wsNgjZLY0lRSkZn2 github.com/ethereum/c-kzg-4844/v2 v2.1.6/go.mod h1:8HMkUZ5JRv4hpw/XUrYWSQNAUzhHMg2UDb/U+5m+XNw= github.com/ethereum/go-bigmodexpfix v0.0.0-20250911101455-f9e208c548ab h1:rvv6MJhy07IMfEKuARQ9TKojGqLVNxQajaXEp/BoqSk= github.com/ethereum/go-bigmodexpfix v0.0.0-20250911101455-f9e208c548ab/go.mod h1:IuLm4IsPipXKF7CW5Lzf68PIbZ5yl7FFd74l/E0o9A8= -github.com/ethereum/go-ethereum v1.17.1 h1:IjlQDjgxg2uL+GzPRkygGULPMLzcYWncEI7wbaizvho= -github.com/ethereum/go-ethereum v1.17.1/go.mod h1:7UWOVHL7K3b8RfVRea022btnzLCaanwHtBuH1jUCH/I= +github.com/ethereum/go-ethereum v1.17.2 h1:ag6geu0kn8Hv5FLKTpH+Hm2DHD+iuFtuqKxEuwUsDOI= +github.com/ethereum/go-ethereum v1.17.2/go.mod h1:KHcRXfGOUfUmKg51IhQ0IowiqZ6PqZf08CMtk0g5K1o= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= @@ -256,22 +311,29 @@ github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4 github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= -github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= -github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= +github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM= +github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= github.com/gabriel-vasile/mimetype v1.4.13 h1:46nXokslUBsAJE/wMsp5gtO500a4F3Nkz9Ufpk2AcUM= github.com/gabriel-vasile/mimetype v1.4.13/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s= +github.com/gagliardetto/binary v0.6.1/go.mod h1:aOfYkc20U0deHaHn/LVZXiqlkDbFAX0FpTlDhsXa0S0= github.com/gagliardetto/binary v0.8.0 h1:U9ahc45v9HW0d15LoN++vIXSJyqR/pWw8DDlhd7zvxg= github.com/gagliardetto/binary v0.8.0/go.mod h1:2tfj51g5o9dnvsc+fL3Jxr22MuWzYXwx9wEoN0XQ7/c= github.com/gagliardetto/gofuzz v1.2.2 h1:XL/8qDMzcgvR4+CyRQW9UGdwPRPMHVJfqQ/uMvSUuQw= github.com/gagliardetto/gofuzz v1.2.2/go.mod h1:bkH/3hYLZrMLbfYWA0pWzXmi5TTRZnu4pMGZBkqMKvY= +github.com/gagliardetto/hashsearch v0.0.0-20191005111333-09dd671e19f9/go.mod h1:513DXpQPzeRo7d4dsCP3xO3XI8hgvruMl9njxyQeraQ= +github.com/gagliardetto/metaplex-go v0.2.1 h1:NMBsgJe3I2avKZ39dfYQvXsGsr2BxUgARkA9LZ6szBg= +github.com/gagliardetto/metaplex-go v0.2.1/go.mod h1:6ZLYBvlWcXktXQ/QcBJYRzKgK7Q3WgiGD7BjE7Zxpw4= +github.com/gagliardetto/solana-go v1.4.0/go.mod h1:NFuoDwHPvw858ZMHUJr6bkhN8qHt4x6e+U3EYHxAwNY= github.com/gagliardetto/solana-go v1.13.0 h1:uNzhjwdAdbq9xMaX2DF0MwXNMw6f8zdZ7JPBtkJG7Ig= github.com/gagliardetto/solana-go v1.13.0/go.mod h1:l/qqqIN6qJJPtxW/G1PF4JtcE3Zg2vD2EliZrr9Gn5k= github.com/gagliardetto/treeout v0.1.4 h1:ozeYerrLCmCubo1TcIjFiOWTTGteOOHND1twdFpgwaw= github.com/gagliardetto/treeout v0.1.4/go.mod h1:loUefvXTrlRG5rYmJmExNryyBRh8f89VZhmMOyCyqok= +github.com/gagliardetto/utilz v0.1.1/go.mod h1:b+rGFkRHz3HWJD0RYMzat47JyvbTtpE0iEcYTRJTLLA= 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/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/gkampitakis/ciinfo v0.3.2 h1:JcuOPk8ZU7nZQjdUhctuhQofk7BGHuIy0c9Ez8BNhXs= github.com/gkampitakis/ciinfo v0.3.2/go.mod h1:1NIwaOcFChN4fa/B0hEBdAb6npDlFL8Bwx4dfRLRqAo= github.com/gkampitakis/go-snaps v0.5.19 h1:hUJlCQOpTt1M+kSisMwioDWZDWpDtdAvUhvWCx1YGW0= @@ -280,11 +342,16 @@ github.com/go-chi/chi v4.1.2+incompatible h1:fGFk2Gmi/YKXk0OmGfBh0WgmN3XB8lVnEyN github.com/go-chi/chi v4.1.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ= github.com/go-errors/errors v1.5.1 h1:ZwEMSLRCapFLflTpT7NKaAc7ukJ8ZPEjzlxt8rPN8bk= github.com/go-errors/errors v1.5.1/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-json-experiment/json v0.0.0-20250223041408-d3c622f1b874 h1:F8d1AJ6M9UQCavhwmO6ZsrYLfG8zVFWfEfMS2MXPkSY= github.com/go-json-experiment/json v0.0.0-20250223041408-d3c622f1b874/go.mod h1:TiCD2a1pcmjd7YnhGH0f/zKNcCD06B029pHhzV23c2M= -github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= -github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= @@ -308,8 +375,9 @@ github.com/go-playground/validator/v10 v10.30.1 h1:f3zDSN/zOma+w6+1Wswgd9fLkdwy0 github.com/go-playground/validator/v10 v10.30.1/go.mod h1:oSuBIQzuJxL//3MelwSLD5hc2Tu889bF0Idm9Dg26cM= github.com/go-resty/resty/v2 v2.17.2 h1:FQW5oHYcIlkCNrMD2lloGScxcHJ0gkjshV3qcQAyHQk= github.com/go-resty/resty/v2 v2.17.2/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 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= @@ -324,16 +392,24 @@ github.com/goccy/go-yaml v1.19.2/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7Lk github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/flock v0.12.1 h1:MTLVXXHf8ekldpJk3AKicLij9MdwOWkZ+a/jHHZby9E= github.com/gofrs/flock v0.12.1/go.mod h1:9zxTsyu5xtJ9DK+1tFZyibEV7y3uwDxPPfbxeeHCoD0= -github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA= 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.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo= -github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= +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/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= @@ -352,6 +428,8 @@ 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/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 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/gnostic-models v0.6.9 h1:MU/8wDLif2qCXZmzncUQ/BOfxWfthHi63KqpoNbWqVw= @@ -361,49 +439,89 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 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/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo= -github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= +github.com/google/pprof v0.0.0-20260302011040-a15ffb7f9dcc h1:VBbFa1lDYWEeV5FZKUiYKYT0VxCp9twUmmaq9eb8sXw= +github.com/google/pprof v0.0.0-20260302011040-a15ffb7f9dcc/go.mod h1:MxpfABSjhmINe3F1It9d+8exIHFvUqtLIRCdOGNXqiI= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= 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/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/rpc v1.2.0/go.mod h1:V4h9r+4sF5HnzqbwIez0fKSpANP0zlYd3qR7p36jkTQ= github.com/gorilla/schema v1.4.1 h1:jUg5hUjCSDZpNGLuXQOgIWGdlgrIdYvgQ0wZtdK1M3E= github.com/gorilla/schema v1.4.1/go.mod h1:Dg5SSm5PV60mhF2NFaTV1xuYYj8tV8NOPRo4FggUMnM= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= 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/pyroscope-go v1.2.7 h1:VWBBlqxjyR0Cwk2W6UrE8CdcdD80GOFNutj0Kb1T8ac= -github.com/grafana/pyroscope-go v1.2.7/go.mod h1:o/bpSLiJYYP6HQtvcoVKiE9s5RiNgjYTj1DhiddP2Pc= +github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 h1:JeSE6pjso5THxAzdVpqr6/geYxZytqFMBCOtn/ujyeo= +github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674/go.mod h1:r4w70xmWCQKmi1ONH4KIaBptdivuRPyosB9RmPlGEwA= +github.com/grafana/otel-profiling-go v0.5.1 h1:stVPKAFZSa7eGiqbYuG25VcqYksR6iWvF3YH66t4qL8= +github.com/grafana/otel-profiling-go v0.5.1/go.mod h1:ftN/t5A/4gQI19/8MoWurBEtC6gFw8Dns1sJZ9W4Tls= +github.com/grafana/pyroscope-go v1.2.8 h1:UvCwIhlx9DeV7F6TW/z8q1Mi4PIm3vuUJ2ZlCEvmA4M= +github.com/grafana/pyroscope-go v1.2.8/go.mod h1:SSi59eQ1/zmKoY/BKwa5rSFsJaq+242Bcrr4wPix1g8= github.com/grafana/pyroscope-go/godeltaprof v0.1.9 h1:c1Us8i6eSmkW+Ez05d3co8kasnuOY813tbMN8i/a3Og= github.com/grafana/pyroscope-go/godeltaprof v0.1.9/go.mod h1:2+l7K7twW49Ct4wFluZD3tZ6e0SjanjcUUBPVD/UuGU= 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 v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= 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/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 h1:HWRh5R2+9EifMyIHV7ZV+MIZqgz+PMpZ14Jynv3O2Zs= github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0/go.mod h1:JfhWUomR1baixubs02l85lZYYOm7LV6om4ceouMv45c= +github.com/hako/durafmt v0.0.0-20200710122514-c0fb7b4da026/go.mod h1:5Scbynm8dF1XAPwIwkGPqzkM/shndPm79Jd1003hTjE= +github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= +github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= 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-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k= github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-memdb v1.3.5 h1:b3taDMxCBCBVgyRrS1AZVHO14ubMYZB++QpNhBg+Nyo= github.com/hashicorp/go-memdb v1.3.5/go.mod h1:8IVKKBkVe+fxFgdFOYxzQQNjz+sWCyHCdIC/+5+Vy1Y= +github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-plugin v1.7.0 h1:YghfQH/0QmPNc/AZMTFE3ac8fipZyZECHdDPshfk+mA= github.com/hashicorp/go-plugin v1.7.0/go.mod h1:BExt6KEaIYx804z8k4gRzRLEvxKVb+kn0NMcihqOqb8= +github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c= github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= +github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= +github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/hashicorp/yamux v0.1.2 h1:XtB8kyFOyHXYVFnwT5C3+Bdo8gArse7j2AQ0DA0Uey8= github.com/hashicorp/yamux v0.1.2/go.mod h1:C+zze2n6e/7wshOZep2A70/aQU6QBRWJO/G6FT1wIns= github.com/hasura/go-graphql-client v0.15.1 h1:mCb5I+8Bk3FU3GKWvf/zDXkTh7FbGlqJmP3oisBdnN8= @@ -419,7 +537,9 @@ github.com/holiman/uint256 v1.3.2/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXei github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc= github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/influxdata/influxdb-client-go/v2 v2.4.0 h1:HGBfZYStlx3Kqvsv1h2pJixbCl/jhnFtxpKFAv9Tu5k= github.com/influxdata/influxdb-client-go/v2 v2.4.0/go.mod h1:vLNHdxTJkIf2mSLvGrpj8TCcISApPoXkaxP8g9uRlW8= github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c h1:qSHzRbhzK8RdXOsAdfDgO49TtqC1oZ+acxPrkfTxcCs= @@ -428,63 +548,14 @@ github.com/influxdata/line-protocol v0.0.0-20210311194329-9aa0e372d097 h1:vilfsD github.com/influxdata/line-protocol v0.0.0-20210311194329-9aa0e372d097/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo= github.com/invopop/jsonschema v0.13.0 h1:KvpoAJWEjR3uD9Kbm2HWJmqsEaHt8lBUpd0qHcIi21E= github.com/invopop/jsonschema v0.13.0/go.mod h1:ffZ5Km5SWWRAIN6wbDXItl95euhFz2uON45H2qjYt+0= -github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= -github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= -github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8= -github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= -github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA= -github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE= -github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s= -github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o= -github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY= -github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= -github.com/jackc/pgconn v1.14.3 h1:bVoTr12EGANZz66nZPkMInAV/KHD2TxH9npjXXgiB3w= -github.com/jackc/pgconn v1.14.3/go.mod h1:RZbme4uasqzybK2RK5c65VsHxoyaml09lx3tXOcO/VM= -github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= -github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= -github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE= -github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c= -github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65 h1:DadwsjnMwFjfWc9y5Wi/+Zz7xoE5ALHsRQlOctkOiHc= -github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= -github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78= -github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA= -github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg= -github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= -github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= -github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgproto3/v2 v2.3.3/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgproto3/v2 v2.3.4-0.20250125160525-bc041643406d h1:tfqquD0m2XihRYJ4SQ5dS3J0l4vIMXUT2dhvBib4d0Q= -github.com/jackc/pgproto3/v2 v2.3.4-0.20250125160525-bc041643406d/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= -github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= -github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg= -github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc= -github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw= -github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM= -github.com/jackc/pgtype v1.14.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= -github.com/jackc/pgtype v1.14.4 h1:fKuNiCumbKTAIxQwXfB/nsrnkEI6bPJrrSiMKgbJ2j8= -github.com/jackc/pgtype v1.14.4/go.mod h1:aKeozOde08iifGosdJpz9MBZonJOUJxqNpPBcMJTlVA= -github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= -github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= -github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= -github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs= -github.com/jackc/pgx/v4 v4.18.2/go.mod h1:Ey4Oru5tH5sB6tV7hDmfWFahwF15Eb7DNXlRKx2CkVw= -github.com/jackc/pgx/v4 v4.18.3 h1:dE2/TrEsGX3RBprb3qryqSV9Y60iZN1C6i8IrmW9/BA= -github.com/jackc/pgx/v4 v4.18.3/go.mod h1:Ey4Oru5tH5sB6tV7hDmfWFahwF15Eb7DNXlRKx2CkVw= -github.com/jackc/pgx/v5 v5.5.4 h1:Xp2aQS8uXButQdnCMWNmvx6UysWQQC+u1EoizjguY+8= -github.com/jackc/pgx/v5 v5.5.4/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A= -github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackc/puddle v1.3.0 h1:eHK/5clGOatcjX3oWGBO/MpxpbHzSwud5EWTSCI+MX0= -github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk= -github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= +github.com/jackc/pgx/v5 v5.9.2 h1:3ZhOzMWnR4yJ+RW1XImIPsD1aNSz4T4fyP7zlQb56hw= +github.com/jackc/pgx/v5 v5.9.2/go.mod h1:mal1tBGAFfLHvZzaYh77YS/eC6IX9OWbRV1QIIM0Jn4= +github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= +github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= github.com/jarcoal/httpmock v1.4.1 h1:0Ju+VCFuARfFlhVXFc2HxlcQkfB+Xq12/EotHko+x2A= @@ -495,37 +566,44 @@ github.com/jhump/protoreflect v1.17.0 h1:qOEr613fac2lOuTgWN4tPAtLL7fUSbuJL5X5Xum github.com/jhump/protoreflect v1.17.0/go.mod h1:h9+vUUL38jiBzck8ck+6G/aeMX8Z4QUY/NiJPwPNi+8= github.com/jinzhu/copier v0.4.0 h1:w3ciUoD19shMCRargcpm0cm91ytaBhDvuRpz1ODO/U8= github.com/jinzhu/copier v0.4.0/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o= github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= 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.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= 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/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/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/karalabe/hid v1.0.1-0.20260315100226-f5d04adeffeb h1:Ag83At00qa4FLkcdMgrwHVSakqky/eZczOlxd4q336E= +github.com/karalabe/hid v1.0.1-0.20260315100226-f5d04adeffeb/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.4 h1:RPhnKRAQ4Fh8zU2FY/6ZFDwTVTxgJ/EMydqSTzE9a2c= -github.com/klauspost/compress v1.18.4/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= +github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/klauspost/compress v1.18.5 h1:/h1gH5Ce+VWNLSWqPzOVn6XBO+vJbCNGvjoaGBFW2IE= +github.com/klauspost/compress v1.18.5/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ= 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= -github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= @@ -535,16 +613,14 @@ github.com/leanovate/gopter v0.2.11 h1:vRjThO1EKPb/1NsDXuDrzldR28RLkBflWYcU9CvzW 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= github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= -github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/lib/pq v1.11.1 h1:wuChtj2hfsGmmx3nf1m7xC2XpK6OtelS2shMY+bGMtI= +github.com/lib/pq v1.11.1/go.mod h1:/p+8NSbOcwzAEI7wiMXFlgydTwcgTr3OSKMsD2BitpA= 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-20260216142805-b3301c5f2a88 h1:PTw+yKnXcOFCR6+8hHTyWBeQ/P4Nb7dd4/0ohEcWQuM= github.com/lufia/plan9stats v0.0.0-20260216142805-b3301c5f2a88/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg= +github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= 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.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4= @@ -555,15 +631,16 @@ github.com/marcboeker/go-duckdb v1.8.5 h1:tkYp+TANippy0DaIOP5OEfBEwbUINqiFqgwMQ4 github.com/marcboeker/go-duckdb v1.8.5/go.mod h1:6mK7+WQE4P4u5AFLvVBmhFxY5fvhymFptghgJX6B+/8= github.com/maruel/natural v1.1.1 h1:Hja7XhhmvEFhcByqDoHz9QZbkWey+COd9xWfCfn1ioo= github.com/maruel/natural v1.1.1/go.mod h1:v+Rfd79xlw1AgVBjbO0BEQmptqb5HvL/k9GRHB7ZKEg= -github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= -github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= 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= github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= 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.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= 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= @@ -575,12 +652,23 @@ github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U= github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/mdelapenya/tlscert v0.2.0 h1:7H81W6Z/4weDvZBNOfQte5GpIMo0lGYEeWbkGp5LJHI= github.com/mdelapenya/tlscert v0.2.0/go.mod h1:O4njj3ELLnJjGdkN7M/vIVCpZ+Cf0L6muqOG4tLSl8o= +github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/miekg/dns v1.1.35/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM= github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= +github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= +github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= +github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.5.1-0.20220423185008-bf980b35cac4 h1:BpfhmLKZf+SjVanKKhCgf3bg+511DmU9eDQTen7LLbY= github.com/mitchellh/mapstructure v1.5.1-0.20220423185008-bf980b35cac4/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= @@ -607,8 +695,10 @@ github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFL github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= 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.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= +github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8eaE= github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= github.com/morikuni/aec v1.1.0 h1:vBBl0pUnvi/Je71dsRrhMBtreIqNMYErSAbEeb8jrXQ= @@ -619,13 +709,16 @@ 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/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= +github.com/nkovacs/streamquote v0.0.0-20170412213628-49af9bddb229/go.mod h1:0aYXnNPJ8l7uZxf45rWW1a/uME32OF0rhiYGNQ2oF2E= 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/oklog/run v1.2.0 h1:O8x3yXwah4A73hJdlrwo/2X6J62gE5qTMusH0dvz60E= github.com/oklog/run v1.2.0/go.mod h1:mgDbKRSwPhJfesJ4PntqFUbKQRZ50NgmZTSPlFA0YFk= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= @@ -634,8 +727,8 @@ github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vv github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= -github.com/onsi/ginkgo/v2 v2.21.0 h1:7rg/4f3rB88pb5obDgNZrNHrQ4e6WpjonchcpuBRnZM= -github.com/onsi/ginkgo/v2 v2.21.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo= +github.com/onsi/ginkgo/v2 v2.22.1 h1:QW7tbJAUDyVDVOM5dFa7qaybo+CRfR7bemlQUN6Z8aM= +github.com/onsi/ginkgo/v2 v2.22.1/go.mod h1:S6aTpoRsSq2cZOd+pssHAlKW/Q/jZt6cPrPlnj4a1xM= github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= @@ -648,10 +741,12 @@ 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/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= 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/pelletier/go-toml/v2 v2.3.0 h1:k59bC/lIZREW0/iVaQR8nDHxVq8OVlIzYCOJf421CaM= +github.com/pelletier/go-toml/v2 v2.3.0/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= 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= @@ -672,52 +767,64 @@ github.com/pion/transport/v2 v2.2.10/go.mod h1:sq1kSLWs+cHW9E+2fJP95QudkzbK7wscs github.com/pion/transport/v3 v3.0.1 h1:gDTlPJwROfSfz6QfSi0ZmeCSkFcnWWiiR9ES0ouANiM= github.com/pion/transport/v3 v3.0.1/go.mod h1:UY7kiITrlMv7/IKgd5eTUcaahZx5oUN3l9SzK5f5xE0= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU= github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o= github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 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.66.1 h1:h5E0h5/Y8niHc5DlaLlWLArTQI7tMrsfQjHV+d9ZoGs= -github.com/prometheus/common v0.66.1/go.mod h1:gcaUsgf3KfRSwHY4dIMXLPV0K/Wg1oZ8+SbZk/HH/dA= +github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.67.5 h1:pIgK94WWlQt1WLwAC5j2ynLaBRDiinoAb86HZHTUGI4= +github.com/prometheus/common v0.67.5/go.mod h1:SjE/0MzDEEAyrdr5Gqc6G+sXI67maCxzaT3A2+HqjUw= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= +github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/prysmaticlabs/gohashtree v0.0.4-beta h1:H/EbCuXPeTV3lpKeXGPpEV9gsUpkqOOVnWapUyeWro4= github.com/prysmaticlabs/gohashtree v0.0.4-beta/go.mod h1:BFdtALS+Ffhg3lGQIHv9HDWuHS8cTvHZzrHWxwOtGOs= github.com/regen-network/protobuf v1.3.3-alpha.regen.1 h1:OHEc+q5iIAXpqiqFKeLpu5NwTIkVXUs48vFMwzqpqY4= github.com/regen-network/protobuf v1.3.3-alpha.regen.1/go.mod h1:2DjTFR1HhMQhiWC5sZ4OhQ3+NtdbZ6oBDKQwq5Ou+FI= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= 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.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.34.0 h1:k43nTLIwcTVQAncfCw4KZ2VY6ukYoZaBPNOE8txlOeY= github.com/rs/zerolog v1.34.0/go.mod h1:bJsvje4Z08ROH4Nhs5iH600c3IkWhwp44iRc54W6wYQ= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= 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/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= github.com/sagikazarmark/locafero v0.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDcg+AAIFXc= github.com/sagikazarmark/locafero v0.11.0/go.mod h1:nVIGvgyzw595SUSUE6tvCp3YYTeHs15MvlmU87WwIik= github.com/samber/lo v1.52.0 h1:Rvi+3BFHES3A8meP33VPAxiBZX/Aws5RxrschYGjomw= github.com/samber/lo v1.52.0/go.mod h1:4+MXEGsJzbKGaUEQFKBq2xtfuznW9oz/WrgyzMzRoM0= github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 h1:lZUw3E0/J3roVtGQ+SCrUrg3ON6NgVqpn3+iol9aGu4= github.com/santhosh-tekuri/jsonschema/v5 v5.3.1/go.mod h1:uToXkOrWAZ6/Oc07xWQrPOhJotwFIyu2bBVN41fcDUY= -github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/scylladb/go-reflectx v1.0.1 h1:b917wZM7189pZdlND9PbIJ6NQxfDPfBvUaQ7cjj1iZQ= github.com/scylladb/go-reflectx v1.0.1/go.mod h1:rWnOfDIRWBGN0miMLIcoPt/Dhi2doCMZqwMCJ3KupFc= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/segmentio/go-loggly v0.5.1-0.20171222203950-eb91657e62b2 h1:S4OC0+OBKz6mJnzuHioeEat74PuQ4Sgvbf8eus695sc= github.com/segmentio/go-loggly v0.5.1-0.20171222203950-eb91657e62b2/go.mod h1:8zLRYR5npGjaOXgPSKat5+oOh+UHd8OdbS18iqX9F6Y= github.com/segmentio/ksuid v1.0.4 h1:sBo2BdShXjmcugAMwjugoGUdUV0pcxY5mW4xKRn3v4c= @@ -728,75 +835,95 @@ github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKl github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/shirou/gopsutil/v4 v4.26.2 h1:X8i6sicvUFih4BmYIGT1m2wwgw2VG9YgrDTi7cIRGUI= github.com/shirou/gopsutil/v4 v4.26.2/go.mod h1:LZ6ewCSkBqUpvSOf+LsTGnRinC6iaNUNMGBtDkJBaLQ= -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= github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sigurn/crc16 v0.0.0-20211026045750-20ab5afb07e3 h1:aQKxg3+2p+IFXXg97McgDGT5zcMrQoi0EICZs8Pgchs= github.com/sigurn/crc16 v0.0.0-20211026045750-20ab5afb07e3/go.mod h1:9/etS5gpQq9BJsJMWg1wpLbfuSnkm8dPF6FdW2JXVhA= -github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= -github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w= github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g= github.com/smartcontractkit/ccip-owner-contracts v0.1.0 h1:GiBDtlx7539o7AKlDV+9LsA7vTMPv+0n7ClhSFnZFAk= github.com/smartcontractkit/ccip-owner-contracts v0.1.0/go.mod h1:NnT6w4Kj42OFFXhSx99LvJZWPpMjmo4+CpDEWfw61xY= -github.com/smartcontractkit/chain-selectors v1.0.97 h1:ECOin+SkJv2MUrfqTUu28J0kub04Epds5NPMHERfGjo= -github.com/smartcontractkit/chain-selectors v1.0.97/go.mod h1:qy7whtgG5g+7z0jt0nRyii9bLND9m15NZTzuQPkMZ5w= -github.com/smartcontractkit/chainlink-aptos v0.0.0-20260306142855-8d629e752265 h1:Q/sYLdOefZUKc/Bxssq1mg8ptQE/AOot2WI+QcLoiVA= -github.com/smartcontractkit/chainlink-aptos v0.0.0-20260306142855-8d629e752265/go.mod h1:CQGkKp3YDsUuxixxmmngmRKfh6yIcftGEZsQrsSIIM8= -github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20260121163256-85accaf3d28d h1:xdFpzbApEMz4Rojg2Y2OjFlrh0wu7eB10V2tSZGW5y8= -github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20260121163256-85accaf3d28d/go.mod h1:bgmqE7x9xwmIVr8PqLbC0M5iPm4AV2DBl596lO6S5Sw= -github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings v0.0.0-20250912190424-fd2e35d7deb5 h1:Z4t2ZY+ZyGWxtcXvPr11y4o3CGqhg3frJB5jXkCSvWA= -github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings v0.0.0-20250912190424-fd2e35d7deb5/go.mod h1:xtZNi6pOKdC3sLvokDvXOhgHzT+cyBqH/gWwvxTxqrg= -github.com/smartcontractkit/chainlink-common v0.10.1-0.20260217160002-b56cb5356cc7 h1:h5cmgzKpKn5N5ItpEDFhRcrtqs36nu9r/dciJub1hos= -github.com/smartcontractkit/chainlink-common v0.10.1-0.20260217160002-b56cb5356cc7/go.mod h1:HXgSKzmZ/bhSx8nHU7hHW6dR+BHSXkdcpFv2T8qJcS8= +github.com/smartcontractkit/chain-selectors v1.0.98 h1:fuI7CQ1o5cX64eO4/LvwtfhdpGFH5vnsM/bFHRwEiww= +github.com/smartcontractkit/chain-selectors v1.0.98/go.mod h1:qy7whtgG5g+7z0jt0nRyii9bLND9m15NZTzuQPkMZ5w= +github.com/smartcontractkit/chainlink-aptos v0.0.0-20260430175646-295a7f9a1500 h1:045jrHCLI+MpeAyByJkyHbEjq0+aTPt04C7+sbsNNtw= +github.com/smartcontractkit/chainlink-aptos v0.0.0-20260430175646-295a7f9a1500/go.mod h1:zfE2R7887kiwXkGTHKPe5NBgwhFwIC3pnA2uAxrbvig= +github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20260506144252-c100eabfda74 h1:D03Y3PxaeMgK34N7zCOhc+86mw6FPalESR2Cl6x9728= +github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20260506144252-c100eabfda74/go.mod h1:xu0Jum/nGRkjBwT/Vq7WCElWOTBBkFRwG0ZIaw9tF2I= +github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings v0.0.0-20260506144252-c100eabfda74 h1:8etwBkRHwfWG54+1JldkPiYihu1bRwImvoqpGDrsXBU= +github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings v0.0.0-20260506144252-c100eabfda74/go.mod h1:67YbnoglYD61Pz/jTVCgav9wFq7S35OU8UyQSvPllRw= +github.com/smartcontractkit/chainlink-ccip/deployment v0.0.0-20260504204047-af9826978b72 h1:WJ+KO7/UgwoQoVVj1Hl+4MuzTW4/3I+wYxqgABLQyC0= +github.com/smartcontractkit/chainlink-ccip/deployment v0.0.0-20260504204047-af9826978b72/go.mod h1:Ls0oszLvhzV3/D0ivG85sh8qmmcsVhKplmepQdFq98E= +github.com/smartcontractkit/chainlink-common v0.11.2-0.20260429111145-3667714e0b37 h1:pEfHIsxPA6oeMDNeXSQCtbB+9GGiiHXygyh60mC69cA= +github.com/smartcontractkit/chainlink-common v0.11.2-0.20260429111145-3667714e0b37/go.mod h1:ohOxnxpzD382PS3nN4zhdJmWD+rsBh8zTLGGHhTdJCE= +github.com/smartcontractkit/chainlink-common/keystore v1.1.0 h1:2wzySccgk2fpWusPKO0bpeAZzfSU9eq6CS5U+JwYaVo= +github.com/smartcontractkit/chainlink-common/keystore v1.1.0/go.mod h1:6JexOOhPhknQ0QMuppFIlOpm6wCp54yZMxai+tWugwY= 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.99.0 h1:UmFIN63m3+qXB5sP3ZtNzoMS8iIPDxeDVzYnhFB/U2k= -github.com/smartcontractkit/chainlink-deployments-framework v0.99.0/go.mod h1:h2R69nbkSMGUSYHrf1lbrchml1CdR1jP4t9HsBb0xdY= -github.com/smartcontractkit/chainlink-evm v0.3.3 h1:JqwyJEtnNEUaoQQPoOBTT4sn2lpdIZHtf0Hr0M60YDw= -github.com/smartcontractkit/chainlink-evm v0.3.3/go.mod h1:q0ZBvaoisNaqC8NcMYWNPTjee88nQktDEeJMQHq3hVI= +github.com/smartcontractkit/chainlink-deployments-framework v0.101.0 h1:bTPDvJSLlMAibGuuewKK8hgVO3jBcyn/jaAiK2Agj98= +github.com/smartcontractkit/chainlink-deployments-framework v0.101.0/go.mod h1:d3twE7zrOtc0iuLs4EhBuaJAtAYOPZr+39nrXv4trw0= +github.com/smartcontractkit/chainlink-evm v0.3.4-0.20260429160308-91a892a60171 h1:HY+Ekr4+E3xokyNZ0oOj0gjO7B065uqTxa6wcXJfJto= +github.com/smartcontractkit/chainlink-evm v0.3.4-0.20260429160308-91a892a60171/go.mod h1:lhxIJe+Qy8duvf20q4D8ewfJzwHfvxK/s4s0exG1zEQ= github.com/smartcontractkit/chainlink-evm/gethwrappers v0.0.0-20260421142741-9c7fbaf7c828 h1:BmsFk/TSHL6dPPR86GTqgSrUXLSINNFC6cfpFRrQX+4= github.com/smartcontractkit/chainlink-evm/gethwrappers v0.0.0-20260421142741-9c7fbaf7c828/go.mod h1:a260YnLyWq2NHLUN5cSVyMGk9nhO6RguCaTI2rsVqyA= -github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260226130359-963f935e0396 h1:03tbcwjyIEjvHba1IWOj1sfThwebm2XNzyFHSuZtlWc= -github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260226130359-963f935e0396/go.mod h1:Jqt53s27Tr0jDl8mdBXg1xhu6F8Fci8JOuq43tgHOM8= +github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260420204255-a3f3bdd56877 h1:6UueUIbck1Ogarm9rm/9TS6b09mKgMmx+YE8XFg63AQ= +github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260420204255-a3f3bdd56877/go.mod h1:Jqt53s27Tr0jDl8mdBXg1xhu6F8Fci8JOuq43tgHOM8= github.com/smartcontractkit/chainlink-protos/job-distributor v0.18.0 h1:q+VDPcxWrj5k9QizSYfUOSMnDH3Sd5HvbPguZOgfXTY= github.com/smartcontractkit/chainlink-protos/job-distributor v0.18.0/go.mod h1:/dVVLXrsp+V0AbcYGJo3XMzKg3CkELsweA/TTopCsKE= github.com/smartcontractkit/chainlink-protos/linking-service/go v0.0.0-20251002192024-d2ad9222409b h1:QuI6SmQFK/zyUlVWEf0GMkiUYBPY4lssn26nKSd/bOM= github.com/smartcontractkit/chainlink-protos/linking-service/go v0.0.0-20251002192024-d2ad9222409b/go.mod h1:qSTSwX3cBP3FKQwQacdjArqv0g6QnukjV4XuzO6UyoY= -github.com/smartcontractkit/chainlink-protos/node-platform v0.0.0-20260205130626-db2a2aab956b h1:36knUpKHHAZ86K4FGWXtx8i/EQftGdk2bqCoEu/Cha8= -github.com/smartcontractkit/chainlink-protos/node-platform v0.0.0-20260205130626-db2a2aab956b/go.mod h1:dkR2uYg9XYJuT1JASkPzWE51jjFkVb86P7a/yXe5/GM= +github.com/smartcontractkit/chainlink-protos/node-platform v0.0.0-20260319180422-b5808c964785 h1:oli+2uLU6jcrJGCuYFqk3475hiwL17SWlITWLv+tx/w= +github.com/smartcontractkit/chainlink-protos/node-platform v0.0.0-20260319180422-b5808c964785/go.mod h1:dkR2uYg9XYJuT1JASkPzWE51jjFkVb86P7a/yXe5/GM= github.com/smartcontractkit/chainlink-protos/op-catalog v0.0.4 h1:AEnxv4HM3WD1RbQkRiFyb9cJ6YKAcqBp1CpIcFdZfuo= github.com/smartcontractkit/chainlink-protos/op-catalog v0.0.4/go.mod h1:PjZD54vr6rIKEKQj6HNA4hllvYI/QpT+Zefj3tqkFAs= -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.15.18 h1:ZPYXn3VvaZhWOyVHFBsKC543EJbL2d4PthQbdL3WgHs= -github.com/smartcontractkit/chainlink-testing-framework/framework v0.15.18/go.mod h1:BALK9cj8sk12e15UF6uDhifHgIApa+6N11TcQfInEro= +github.com/smartcontractkit/chainlink-sui v0.0.0-20260428231901-a394dd724761 h1:YwdUzW6/xCEa2Y5tGlLVlg+FICQPIKx1tIg1MHPFNOk= +github.com/smartcontractkit/chainlink-sui v0.0.0-20260428231901-a394dd724761/go.mod h1:xJ1UT4DKu1znbsm4ehkrfr92rgn8Hxgcp3Z9rgfXRjM= +github.com/smartcontractkit/chainlink-testing-framework/framework v0.15.19 h1:inTH0/PrEaVv4iLdGsdcrP/rX7KMrq/Roosr5nIA8io= +github.com/smartcontractkit/chainlink-testing-framework/framework v0.15.19/go.mod h1:BALK9cj8sk12e15UF6uDhifHgIApa+6N11TcQfInEro= github.com/smartcontractkit/chainlink-testing-framework/seth v1.51.5 h1:RwZXxdIAOyjp6cwc9Quxgr38k8r7ACz+Lxh9o/A6oH0= github.com/smartcontractkit/chainlink-testing-framework/seth v1.51.5/go.mod h1:kHYJnZUqiPF7/xN5273prV+srrLJkS77GbBXHLKQpx0= -github.com/smartcontractkit/chainlink-ton v0.0.0-20260219201907-054376f21418 h1:7f92q/Tz/Ns+gjChmWg5mEonrYutZV33k/1x+Xxsb4I= -github.com/smartcontractkit/chainlink-ton v0.0.0-20260219201907-054376f21418/go.mod h1:FDDjLuc4vrfclu3JHkMaREg0XZz7Lw1MK47Z4jJ4U5Q= -github.com/smartcontractkit/chainlink-tron/relayer v0.0.11-0.20250815105909-75499abc4335 h1:7bxYNrPpygn8PUSBiEKn8riMd7CXMi/4bjTy0fHhcrY= -github.com/smartcontractkit/chainlink-tron/relayer v0.0.11-0.20250815105909-75499abc4335/go.mod h1:ccjEgNeqOO+bjPddnL4lUrNLzyCvGCxgBjJdhFX3wa8= +github.com/smartcontractkit/chainlink-ton v1.0.5-0.20260430134932-681b7a7fe426 h1:DeQpkYzNYqAXfXnMwXmh5LfF86jDgvbvtB+zCgtovWA= +github.com/smartcontractkit/chainlink-ton v1.0.5-0.20260430134932-681b7a7fe426/go.mod h1:ueY5pFIW//gVJS8/rh8qIs2gdlntxfAiOZfBSvJRjXk= +github.com/smartcontractkit/chainlink-ton/deployment v0.0.0-20260430134932-681b7a7fe426 h1:X8MNLLrViwwhBRPwhSVywI1ym2/WBMdhnaBAIkTpwaU= +github.com/smartcontractkit/chainlink-ton/deployment v0.0.0-20260430134932-681b7a7fe426/go.mod h1:Y4xFqbrdQX+LjVzY5jHBnbTlP3erihUqYiH4h9XMWxU= +github.com/smartcontractkit/chainlink-tron/relayer v0.0.11-0.20260408092456-3c6369888d4a h1:Xu8iBnBQEibWIXTCwKYf8okXjFtzJ0KochjL03h+T40= +github.com/smartcontractkit/chainlink-tron/relayer v0.0.11-0.20260408092456-3c6369888d4a/go.mod h1:1eaXR+Fe6TlpP+CKXozfYlFM8QgN/N5C7OMvTRWNT8I= 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.20250828155247-add56fa28aad h1:lgHxTHuzJIF3Vj6LSMOnjhqKgRqYW+0MV2SExtCYL1Q= github.com/smartcontractkit/freeport v0.1.3-0.20250828155247-add56fa28aad/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/mcms v0.40.1 h1:r9bU/2GfIf6mHHM4PklSBkfi2Lq4+EGILC81e4IqKz0= -github.com/smartcontractkit/mcms v0.40.1/go.mod h1:7YqJPR8w9GiO1L/JjjTrwlSwAZ7i3J7cgOcu88PqtvU= +github.com/smartcontractkit/libocr v0.0.0-20260403184524-b6409238958d h1:PvXor5Fjer7FIONSqYXbpd1LkA14hWrlAyxXzOrC9t8= +github.com/smartcontractkit/libocr v0.0.0-20260403184524-b6409238958d/go.mod h1:PLdNK6GlqfxIWXzziPkU7dCAVlVFeYkyyW7AQY0R+4Q= +github.com/smartcontractkit/mcms v0.41.1 h1:rK5X7if29gRhL6yqpUwxwaLYV0CqgwSJivdDqEJGFv4= +github.com/smartcontractkit/mcms v0.41.1/go.mod h1:9AJhwHSVwV2mETizHBNfEF9CemL/Fmf0yPxNGdTtL/0= +github.com/smartcontractkit/quarantine v0.0.0-20251203215908-fd0551c6adf9 h1:MOEuXYogv+RStASb8dWsyescu/xkigSi/Sv45NEjV7A= +github.com/smartcontractkit/quarantine v0.0.0-20251203215908-fd0551c6adf9/go.mod h1:iwy4yWFuK+1JeoIRTaSOA9pl+8Kf//26zezxEXrAQEQ= +github.com/smartcontractkit/wsrpc v0.8.5-0.20250502134807-c57d3d995945 h1:zxcODLrFytOKmAd8ty8S/XK6WcIEJEgRBaL7sY/7l4Y= +github.com/smartcontractkit/wsrpc v0.8.5-0.20250502134807-c57d3d995945/go.mod h1:m3pdp17i4bD50XgktkzWetcV5yaLsi7Gunbv4ZgN6qg= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 h1:+jumHNA0Wrelhe64i8F6HNlS8pkoyMv5sreGx2Ry5Rw= github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8/go.mod h1:3n1Cwaq1E1/1lhQhtRK2ts/ZwZEhjcQeJQ1RuC6Q/8U= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I= github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= 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/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= +github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/spf13/viper v1.21.0 h1:x5S+0EU27Lbphp4UKm1C+1oQO+rKx36vfCoaVebLFSU= github.com/spf13/viper v1.21.0/go.mod h1:P0lhsswPGWD/1lZJ9ny3fYnVqxiegrlNrEmgLjbTCAY= github.com/stellar/go-stellar-sdk v0.1.0 h1:MfV7dv4k6xQQrWeKT7npWyKhjoayphLVGwXKtTLNeH8= @@ -809,7 +936,6 @@ github.com/streamingfast/logging v0.0.0-20230608130331-f22c91403091 h1:RN5mrigyi github.com/streamingfast/logging v0.0.0-20230608130331-f22c91403091/go.mod h1:VlduQ80JcGJSargkRU4Sg9Xo63wZD/l8A5NC/Uo1/uU= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= @@ -823,11 +949,11 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/supranational/blst v0.3.16 h1:bTDadT+3fK497EvLdWRQEjiGnUtzJ7jjIUMF0jqwYhE= @@ -837,12 +963,15 @@ github.com/suzuki-shunsuke/go-convmap v0.2.1/go.mod h1:3XfGRbtyNBMGfXAxhROSRki6/ github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d h1:vfofYNRScrDdvS342BElfbETmL1Aiz3i2t0zfRj16Hs= github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48= +github.com/teris-io/shortid v0.0.0-20171029131806-771a37caa5cf/go.mod h1:M8agBzgqHIhgj7wEn9/0hJUZcrvt9VY+Ln+S1I5Mha0= +github.com/teris-io/shortid v0.0.0-20201117134242-e59966efd125/go.mod h1:M8agBzgqHIhgj7wEn9/0hJUZcrvt9VY+Ln+S1I5Mha0= 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.41.0 h1:mfpsD0D36YgkxGj2LrIyxuwQ9i2wCKAD+ESsYM1wais= github.com/testcontainers/testcontainers-go v0.41.0/go.mod h1:pdFrEIfaPl24zmBjerWTTYaY0M6UHsqA1YSvsoU40MI= github.com/testcontainers/testcontainers-go/modules/postgres v0.41.0 h1:AOtFXssrDlLm84A2sTTR/AhvJiYbrIuCO59d+Ro9Tb0= github.com/testcontainers/testcontainers-go/modules/postgres v0.41.0/go.mod h1:k2a09UKhgSp6vNpliIY0QSgm4Hi7GXVTzWvWgUemu/8= +github.com/tidwall/gjson v1.9.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= 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= @@ -856,6 +985,7 @@ github.com/tklauser/go-sysconf v0.3.16 h1:frioLaCQSsF5Cy1jgRBrzr6t502KIIwQ0MArYI github.com/tklauser/go-sysconf v0.3.16/go.mod h1:/qNL9xxDhc7tx3HSRsLWNnuzbVfh3e7gh/BmM179nYI= github.com/tklauser/numcpus v0.11.0 h1:nSTwhKH5e1dMNsCdVBukSZrURJRoHbSEQjdEbY+9RXw= github.com/tklauser/numcpus v0.11.0/go.mod h1:z+LwcLq54uWZTX0u/bGobaV34u6V7KNlTZejzM6/3MQ= +github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8= github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U= github.com/urfave/cli/v2 v2.27.7 h1:bH59vdhbjLv3LAvIu6gd0usJHgoTTPhCFib8qqOwXYU= @@ -864,6 +994,7 @@ 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.10 h1:/yjJg8jaVQdYR3arGxPE2X5z89xrlhS0eGXdv+ADTh4= github.com/valyala/fastjson v1.6.10/go.mod h1:e6FubmQouUNP73jtMLmcbxS6ydWIpOfhz34TSfO3JaE= +github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= 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= @@ -871,10 +1002,12 @@ 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/xdrpp/goxdr v0.1.1 h1:E1B2c6E8eYhOVyd7yEpOyopzTPirUeF6mVOfXfGyJyc= github.com/xdrpp/goxdr v0.1.1/go.mod h1:dXo1scL/l6s7iME1gxHWo2XCppbHEKZS7m/KyYWkNzA= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= 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= github.com/xssnick/tonutils-go v1.14.1/go.mod h1:68xwWjpoGGqiTbLJ0gT63sKu1Z1moCnDLLzA+DKanIg= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= @@ -883,56 +1016,75 @@ github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= github.com/zeebo/xxh3 v1.0.2 h1:xZmwmqxHZA8AI603jOQ0tMqmBr9lPeFwGg6d+xy9DC0= github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA= -github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= github.com/zksync-sdk/zksync2-go v1.1.1-0.20250620124214-2c742ee399c6 h1:VRdX3Gn/I7ITbzUY4ZNfgn65tdQM9Zhf2b7KP0HZllk= github.com/zksync-sdk/zksync2-go v1.1.1-0.20250620124214-2c742ee399c6/go.mod h1:NWNlQS21isOsSsn+hLRAPpiuv+3P+LcdaZNuRt2T5Yo= +go.dedis.ch/fixbuf v1.0.3 h1:hGcV9Cd/znUxlusJ64eAlExS+5cJDIyTyEG+otu5wQs= +go.dedis.ch/fixbuf v1.0.3/go.mod h1:yzJMt34Wa5xD37V5RTdmp38cz3QhMagdGoem9anUalw= +go.dedis.ch/kyber/v3 v3.0.4/go.mod h1:OzvaEnPvKlyrWyp3kGXlFdp7ap1VC6RkZDTaPikqhsQ= +go.dedis.ch/kyber/v3 v3.0.9/go.mod h1:rhNjUUg6ahf8HEg5HUvVBYoWY4boAafX8tYxX+PS+qg= +go.dedis.ch/kyber/v3 v3.1.0 h1:ghu+kiRgM5JyD9TJ0hTIxTLQlJBR/ehjWvWwYW3XsC0= +go.dedis.ch/kyber/v3 v3.1.0/go.mod h1:kXy7p3STAurkADD+/aZcsznZGKVHEqbtmdIzvPfrs1U= +go.dedis.ch/protobuf v1.0.5/go.mod h1:eIV4wicvi6JK0q/QnfIEGeSFNG0ZeB24kzut5+HaRLo= +go.dedis.ch/protobuf v1.0.7/go.mod h1:pv5ysfkDX/EawiPqcW3ikOxsL5t+BqnV6xHSmE79KI4= +go.dedis.ch/protobuf v1.0.11/go.mod h1:97QR256dnkimeNdfmURz0wAMNVbd1VmLXhG1CrTYrJ4= +go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.mongodb.org/mongo-driver v1.17.2 h1:gvZyk8352qSfzyZ2UMWcpDpMSGEr1eqE4T793SqyhzM= go.mongodb.org/mongo-driver v1.17.2/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.1/go.mod h1:Ap50jQcDJrx6rB6VgeeFPtuPIf3wMRvRfrfYDO6+BmA= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= 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.65.0 h1:7iP2uCb7sGddAr30RRS6xjKy7AZ2JtTOPA3oolgVSw8= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.65.0/go.mod h1:c7hN3ddxs/z6q9xwvfLPk+UHlWRQyaeR1LdgfL/66l0= +go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo= go.opentelemetry.io/otel v1.43.0 h1:mYIM03dnh5zfN7HautFE4ieIig9amkNANT+xcVxAj9I= go.opentelemetry.io/otel v1.43.0/go.mod h1:JuG+u74mvjvcm8vj8pI5XiHy1zDeoCS2LB1spIq7Ay0= -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/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.41.0 h1:ao6Oe+wSebTlQ1OEht7jlYTzQKE+pnx/iNywFvTbuuI= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.41.0/go.mod h1:u3T6vz0gh/NVzgDgiwkgLxpsSF6PaPmo2il0apGJbls= -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/otlptracehttp v1.41.0 h1:inYW9ZhgqiDqh6BioM7DVHHzEGVq76Db5897WLGZ5Go= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.41.0/go.mod h1:Izur+Wt8gClgMJqO/cZ8wdeeMryJ/xxiOVgFSSfpDTY= -go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.13.0 h1:yEX3aC9KDgvYPhuKECHbOlr5GLwH6KTjLJ1sBSkkxkc= -go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.13.0/go.mod h1:/GXR0tBmmkxDaCUGahvksvp66mx4yh5+cFXgSlhg0vQ= -go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.36.0 h1:rixTyDGXFxRy1xzhKrotaHy3/KXdPhlWARrCgK+eqUY= -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.15.0 h1:0VqVnc3MgyYd7QqNVIldC3dsLFKgazR6P3P3+ypkyDY= -go.opentelemetry.io/otel/log v0.15.0/go.mod h1:9c/G1zbyZfgu1HmQD7Qj84QMmwTp2QCQsZH1aeoWDE4= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.19.0 h1:Dn8rkudDzY6KV9dr/D/bTUuWgqDf9xe0rr4G2elrn0Y= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.19.0/go.mod h1:gMk9F0xDgyN9M/3Ed5Y1wKcx/9mlU91NXY2SNq7RQuU= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.19.0 h1:HIBTQ3VO5aupLKjC90JgMqpezVXwFuq6Ryjn0/izoag= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.19.0/go.mod h1:ji9vId85hMxqfvICA0Jt8JqEdrXaAkcpkI9HPXya0ro= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.43.0 h1:8UQVDcZxOJLtX6gxtDt3vY2WTgvZqMQRzjsqiIHQdkc= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.43.0/go.mod h1:2lmweYCiHYpEjQ/lSJBYhj9jP1zvCvQW4BqL9dnT7FQ= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.43.0 h1:w1K+pCJoPpQifuVpsKamUdn9U0zM3xUziVOqsGksUrY= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.43.0/go.mod h1:HBy4BjzgVE8139ieRI75oXm3EcDN+6GhD88JT1Kjvxg= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0 h1:88Y4s2C8oTui1LGM6bTWkw0ICGcOLCAI5l6zsD1j20k= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0/go.mod h1:Vl1/iaggsuRlrHf/hfPJPvVag77kKyvrLeD10kpMl+A= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.43.0 h1:RAE+JPfvEmvy+0LzyUA25/SGawPwIUbZ6u0Wug54sLc= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.43.0/go.mod h1:AGmbycVGEsRx9mXMZ75CsOyhSP6MFIcj/6dnG+vhVjk= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0 h1:3iZJKlCZufyRzPzlQhUIWVmfltrXuGyfjREgGP3UUjc= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0/go.mod h1:/G+nUPfhq2e+qiXMGxMwumDrP5jtzU+mWN7/sjT2rak= +go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.19.0 h1:GJkybS+crDMdExT/BUNCEgfrmfboztcS6PhvSo88HKM= +go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.19.0/go.mod h1:NuAyxRYIG2lKX3YQkB+83StTxM7s52PUUkRRiC0wnYI= +go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.43.0 h1:TC+BewnDpeiAmcscXbGMfxkO+mwYUwE/VySwvw88PfA= +go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.43.0/go.mod h1:J/ZyF4vfPwsSr9xJSPyQ4LqtcTPULFR64KwTikGLe+A= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.43.0 h1:mS47AX77OtFfKG4vtp+84kuGSFZHTyxtXIN269vChY0= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.43.0/go.mod h1:PJnsC41lAGncJlPUniSwM81gc80GkgWJWr3cu2nKEtU= +go.opentelemetry.io/otel/log v0.19.0 h1:KUZs/GOsw79TBBMfDWsXS+KZ4g2Ckzksd1ymzsIEbo4= +go.opentelemetry.io/otel/log v0.19.0/go.mod h1:5DQYeGmxVIr4n0/BcJvF4upsraHjg6vudJJpnkL6Ipk= +go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM= go.opentelemetry.io/otel/metric v1.43.0 h1:d7638QeInOnuwOONPp4JAOGfbCEpYb+K6DVWvdxGzgM= go.opentelemetry.io/otel/metric v1.43.0/go.mod h1:RDnPtIxvqlgO8GRW18W6Z/4P462ldprJtfxHxyKd2PY= +go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E= go.opentelemetry.io/otel/sdk v1.43.0 h1:pi5mE86i5rTeLXqoF/hhiBtUNcrAGHLKQdhg4h4V9Dg= go.opentelemetry.io/otel/sdk v1.43.0/go.mod h1:P+IkVU3iWukmiit/Yf9AWvpyRDlUeBaRg6Y+C58QHzg= -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/log v0.19.0 h1:scYVLqT22D2gqXItnWiocLUKGH9yvkkeql5dBDiXyko= +go.opentelemetry.io/otel/sdk/log v0.19.0/go.mod h1:vFBowwXGLlW9AvpuF7bMgnNI95LiW10szrOdvzBHlAg= +go.opentelemetry.io/otel/sdk/log/logtest v0.19.0 h1:BEbF7ZBB6qQloV/Ub1+3NQoOUnVtcGkU3XX4Ws3GQfk= +go.opentelemetry.io/otel/sdk/log/logtest v0.19.0/go.mod h1:Lua81/3yM0wOmoHTokLj9y9ADeA02v1naRrVrkAZuKk= go.opentelemetry.io/otel/sdk/metric v1.43.0 h1:S88dyqXjJkuBNLeMcVPRFXpRw2fuwdvfCGLEo89fDkw= go.opentelemetry.io/otel/sdk/metric v1.43.0/go.mod h1:C/RJtwSEJ5hzTiUz5pXF1kILHStzb9zFlIEe85bhj6A= +go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ= go.opentelemetry.io/otel/trace v1.43.0 h1:BkNrHpup+4k4w+ZZ86CZoHHEkohws8AY+WTX09nk+3A= go.opentelemetry.io/otel/trace v1.43.0/go.mod h1:/QJhyVBUUswCphDVxq+8mld+AvhXZLhe+8WVFxiFff0= -go.opentelemetry.io/proto/otlp v1.9.0 h1:l706jCMITVouPOqEnii2fIAuO3IVGBRPV5ICjceRb/A= -go.opentelemetry.io/proto/otlp v1.9.0/go.mod h1:xE+Cx5E/eEHw+ISFkwPLwCZefwVjY+pqKg1qcK03+/4= -go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.opentelemetry.io/proto/otlp v1.10.0 h1:IQRWgT5srOCYfiWnpqUYz9CVmbO8bFmKcwYxpuCSL2g= +go.opentelemetry.io/proto/otlp v1.10.0/go.mod h1:/CV4QoCR/S9yaPj8utp3lvQPoqMtxXdzn7ozvvozVqk= 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= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= @@ -948,66 +1100,100 @@ go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKY go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/ratelimit v0.2.0/go.mod h1:YYBV4e4naJvhpitQrWJu1vCpgB7CboMe0qhltKt6mUg= go.uber.org/ratelimit v0.3.1 h1:K4qVE+byfv/B3tC+4nYWP7v/6SimcO7HzHekoMNBma0= go.uber.org/ratelimit v0.3.1/go.mod h1:6euWsTB6U/Nb3X++xEUXA8ciPJvr19Q/0h1+oDcJhRk= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= -go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= +go.uber.org/zap v1.14.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= +go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= -go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= -go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= -go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI= -go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU= +go.uber.org/zap v1.28.0 h1:IZzaP1Fv73/T/pBMLk4VutPl36uNC+OSUh3JLG3FIjo= +go.uber.org/zap v1.28.0/go.mod h1:rDLpOi171uODNm/mxFcuYWxDsqWSAVkFdX4XojSKg/Q= +go.yaml.in/yaml/v2 v2.4.4 h1:tuyd0P+2Ont/d6e2rl3be67goVK4R6deVxCUX5vyPaQ= +go.yaml.in/yaml/v2 v2.4.4/go.mod h1:gMZqIpDtDqOfM0uNfy0SkpRhvUryYH0Z6wdMYcacYXQ= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190123085648-057139ce5d2b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 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-20201203163018-be400aefbc4c/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-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE= golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= -golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= -golang.org/x/crypto v0.20.0/go.mod h1:Xwo95rrVNIoSMx9wa1JroENMToLWn3RNVrTBpLHgZPQ= -golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts= -golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos= +golang.org/x/crypto v0.50.0 h1:zO47/JPrL6vsNkINmLoo/PH1gcxpls50DNogFvB5ZGI= +golang.org/x/crypto v0.50.0/go.mod h1:3muZ7vA7PBCE6xgPX7nkzzjiUq87kRItoJQM1Yo8S+Q= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa h1:Zt3DZoOFFYkKhDT3v7Lm9FDMEV06GpzjG2jrqW+QTE0= golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa/go.mod h1:K79w1Vqn7PoiZn+TkNpx3BUWUQksGO3JcVX6qIjytmA= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= 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-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 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.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8= -golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w= +golang.org/x/mod v0.34.0 h1:xIHgNUUnW6sYkcM5Jleh05DvLOtwc6RitGHbDk4akRI= +golang.org/x/mod v0.34.0/go.mod h1:ykgH52iCZe79kzLLMhyCUzhMci+nQj+0XkbXpNYtVjY= 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= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 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= @@ -1018,6 +1204,7 @@ golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLd golang.org/x/net v0.0.0-20210331212208-0fccb6fa2b5c/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= +golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= @@ -1027,40 +1214,64 @@ golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= 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.50.0 h1:ucWh9eiCGyDR3vtzso0WMQinm2Dnt8cFMuQa9K33J60= -golang.org/x/net v0.50.0/go.mod h1:UgoSli3F/pBgdJBHCTc+tp3gmrU4XswgGRgtnwWTfyM= +golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0= +golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.35.0 h1:Mv2mzuHuZuY2+bkyWXIHMfhNdJAdwW3FuWeCPYN5GVQ= -golang.org/x/oauth2 v0.35.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs= +golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q= 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= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= -golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4= +golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190124100055-b90733256f2e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/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-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1074,6 +1285,7 @@ golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210331175145-43e1dd70ce54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1091,27 +1303,28 @@ golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 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.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo= -golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= -golang.org/x/telemetry v0.0.0-20260209163413-e7419c687ee4 h1:bTLqdHv7xrGlFbvf5/TXNxy/iUwwdkjhqQTJDjW7aj0= -golang.org/x/telemetry v0.0.0-20260209163413-e7419c687ee4/go.mod h1:g5NllXBEermZrmR51cJDQxmJUHUOfRAaNyWBM+R+548= +golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI= +golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/telemetry v0.0.0-20260311193753-579e4da9a98c h1:6a8FdnNk6bTXBjR4AGKFgUKuo+7GnR3FX5L7CbveeZc= +golang.org/x/telemetry v0.0.0-20260311193753-579e4da9a98c/go.mod h1:TpUTTEp9frx7rTdLpC9gFG9kdI7zVLFTFFlqaH2Cncw= 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-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= -golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= -golang.org/x/term v0.40.0 h1:36e4zGLqU4yhjlmxEaagx2KuYbJq3EwY8K943ZsHcvg= -golang.org/x/term v0.40.0/go.mod h1:w2P8uVp06p2iyKKuvXIm7N/y0UCRt3UfJTfZ7oOpglM= +golang.org/x/term v0.42.0 h1:UiKe+zDFmJobeJ5ggPwOshJIVt6/Ft0rcfrXZDLWAWY= +golang.org/x/term v0.42.0/go.mod h1:Dq/D+snpsbazcBG5+F9Q1n2rXV8Ma+71xEjTRufARgY= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= @@ -1119,23 +1332,50 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= 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.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk= -golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA= -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/text v0.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg= +golang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U= +golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno= 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= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191010075000-0337d82405ff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 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-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/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-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/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-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200601175630-2caf76543d99/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= @@ -1143,10 +1383,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.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k= -golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0= -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/tools v0.43.0 h1:12BdW9CeB3Z+J/I/wj34VMl8X+fEXBxVR90JeMX5E7s= +golang.org/x/tools v0.43.0/go.mod h1:uHkMso649BX2cZK6+RpuIPXS3ho2hZo4FVwfoy1vIk0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1156,25 +1394,64 @@ golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da h1:noIWHXmPHxILtqtCOPIhS golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4= gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.10.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= 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/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.2/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190716160619-c506a9f90610/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200324203455-a04cca1dde73/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20210401141331-865547bb08e2/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= -google.golang.org/genproto/googleapis/api v0.0.0-20260209200024-4cfbd4190f57 h1:JLQynH/LBHfCTSbDWl+py8C+Rg/k1OVH3xfcaiANuF0= -google.golang.org/genproto/googleapis/api v0.0.0-20260209200024-4cfbd4190f57/go.mod h1:kSJwQxqmFXeo79zOmbrALdflXQeAYcUbgS7PbpMknCY= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57 h1:mWPCjDEyshlQYzBpMNHaEof6UX1PmHcaUODUywQ0uac= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ= +google.golang.org/genproto/googleapis/api v0.0.0-20260401024825-9d38bb4040a9 h1:VPWxll4HlMw1Vs/qXtN7BvhZqsS9cdAittCNvVENElA= +google.golang.org/genproto/googleapis/api v0.0.0-20260401024825-9d38bb4040a9/go.mod h1:7QBABkRtR8z+TEnmXTqIqwJLlzrZKVfAUm7tY3yGv0M= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260401024825-9d38bb4040a9 h1:m8qni9SQFH0tJc1X0vmnpw/0t+AImlSvp30sEupozUg= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260401024825-9d38bb4040a9/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/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.79.3 h1:sybAEdRIEtvcD68Gx7dmnwjZKlyfuc61Dyo9pGXXkKE= -google.golang.org/grpc v1.79.3/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ= +google.golang.org/grpc v1.80.0 h1:Xr6m2WmWZLETvUNvIUmeD5OAagMw3FiKmMlTdViWsHM= +google.golang.org/grpc v1.80.0/go.mod h1:ho/dLnxwi3EDJA4Zghp7k2Ec1+c2jqup0bFkw07bwF4= 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= @@ -1188,6 +1465,7 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= @@ -1198,13 +1476,15 @@ gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWM gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/guregu/null.v4 v4.0.0 h1:1Wm3S1WEA2I26Kq+6vcW+w0gcDo44YKYD7YIEJNHDjg= gopkg.in/guregu/null.v4 v4.0.0/go.mod h1:YoQhUrADuG3i9WqesrCmpNRwm1ypAgSHYqoOcTu/JrI= -gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -1219,24 +1499,34 @@ gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q= gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= k8s.io/api v0.32.3 h1:Hw7KqxRusq+6QSplE3NYG4MBxZw1BZnq4aP4cJVINls= k8s.io/api v0.32.3/go.mod h1:2wEDTXADtm/HA7CCMD8D8bK4yuBUptzaRhYcYEEYA3k= -k8s.io/apimachinery v0.32.3 h1:JmDuDarhDmA/Li7j3aPrwhpNBA94Nvk5zLeOge9HH1U= -k8s.io/apimachinery v0.32.3/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE= +k8s.io/apimachinery v0.33.2 h1:IHFVhqg59mb8PJWTLi8m1mAoepkUNYmptHsV+Z1m5jY= +k8s.io/apimachinery v0.33.2/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM= k8s.io/client-go v0.32.3 h1:RKPVltzopkSgHS7aS98QdscAgtgah/+zmpAogooIqVU= k8s.io/client-go v0.32.3/go.mod h1:3v0+3k4IcT9bXTc4V2rt+d2ZPPG700Xy6Oi0Gdl2PaY= k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= -k8s.io/kube-openapi v0.0.0-20241212222426-2c72e554b1e7 h1:hcha5B1kVACrLujCKLbr8XWMxCxzQx42DY8QKYJrDLg= -k8s.io/kube-openapi v0.0.0-20241212222426-2c72e554b1e7/go.mod h1:GewRfANuJ70iYzvn+i4lezLDAFzvjxZYK1gn1lWcfas= -k8s.io/utils v0.0.0-20241104163129-6fe5fd82f078 h1:jGnCPejIetjiy2gqaJ5V0NLwTpF4wbQ6cZIItJCSHno= -k8s.io/utils v0.0.0-20241104163129-6fe5fd82f078/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff h1:/usPimJzUKKu+m+TE36gUyGcf03XZEP0ZIKgKj35LS4= +k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff/go.mod h1:5jIi+8yX4RIb8wk3XwBo5Pq2ccx4FP10ohkbSKCZoK8= +k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 h1:SjGebBtkBqHFOli+05xYbK8YF1Dzkbzn+gDM4X9T4Ck= +k8s.io/utils v0.0.0-20251002143259-bc988d571ff4/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 h1:/Rv+M11QRah1itp8VhT6HoVx1Ray9eB4DBr+K+/sCJ8= sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3/go.mod h1:18nIHnGi6636UCz6m8i4DhaJ65T6EruyzmoQqI2BVDo= -sigs.k8s.io/structured-merge-diff/v4 v4.4.2 h1:MdmvkGuXi/8io6ixD5wud3vOLwc1rj0aNqRlpuvjmwA= -sigs.k8s.io/structured-merge-diff/v4 v4.4.2/go.mod h1:N8f93tFZh9U6vpxwRArLiikrE5/2tiu1w1AGfACIGE4= -sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= +sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= +sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= +sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= +sigs.k8s.io/structured-merge-diff/v4 v4.6.0 h1:IUA9nvMmnKWcj5jl84xn+T5MnlZKThmUW1TdblaLVAc= +sigs.k8s.io/structured-merge-diff/v4 v4.6.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps= sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= +sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= +sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= diff --git a/link/changesets/deploy_link_token_test.go b/link/changesets/deploy_link_token_test.go index afbbf9b..1f1fb64 100644 --- a/link/changesets/deploy_link_token_test.go +++ b/link/changesets/deploy_link_token_test.go @@ -17,7 +17,7 @@ import ( "github.com/smartcontractkit/chainlink-deployments-framework/engine/test/runtime" cldchangesetscommon "github.com/smartcontractkit/cld-changesets/pkg/common" - evmstate "github.com/smartcontractkit/cld-changesets/pkg/family/evm" + evmstate "github.com/smartcontractkit/cld-changesets/pkg/family/evm/legacy" ) func TestDeployLinkToken(t *testing.T) { @@ -138,19 +138,6 @@ func TestDeployLinkTokenRejectsExistingStateBeforeDeploy(t *testing.T) { }, wantErr: "LinkToken contract already exists", }, - { - name: "link token exists in datastore with nil version", - env: cldf.Environment{ - BlockChains: cldf_chain.NewBlockChainsFromSlice([]cldf_chain.BlockChain{ - cldf_evm.Chain{Selector: evmSelector}, - }), - DataStore: datastoreWithNilVersion(t, evmSelector, evmAddress, linkcontracts.LinkToken, "migrated"), - }, - run: func(env cldf.Environment) (cldf.ChangesetOutput, error) { - return DeployLinkToken(env, []uint64{evmSelector}) - }, - wantErr: "LinkToken contract already exists", - }, { name: "static link token exists in datastore", env: cldf.Environment{ @@ -239,20 +226,6 @@ func datastoreWith(t *testing.T, selector uint64, address string, tv cldf.TypeAn return ds.Seal() } -func datastoreWithNilVersion(t *testing.T, selector uint64, address string, contractType cldf.ContractType, qualifier string) datastore.DataStore { - t.Helper() - - ds := datastore.NewMemoryDataStore() - require.NoError(t, ds.Addresses().Add(datastore.AddressRef{ - ChainSelector: selector, - Address: address, - Type: datastore.ContractType(contractType.String()), - Qualifier: qualifier, - })) - - return ds.Seal() -} - func typeAndVersionWithLabels(tv cldf.TypeAndVersion, labels ...string) cldf.TypeAndVersion { for _, label := range labels { tv.Labels.Add(label) diff --git a/mcms/changesets/legacy/deploy_mcms_with_timelock.go b/mcms/changesets/legacy/deploy_mcms_with_timelock.go new file mode 100644 index 0000000..62cec3e --- /dev/null +++ b/mcms/changesets/legacy/deploy_mcms_with_timelock.go @@ -0,0 +1,310 @@ +package legacy + +import ( + "context" + "fmt" + "slices" + "strings" + "sync" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + mcmscontracts "github.com/smartcontractkit/chainlink-deployments-framework/engine/cld/contracts/mcms" + xerrgroup "golang.org/x/sync/errgroup" + + evmchangesets "github.com/smartcontractkit/cld-changesets/pkg/family/evm/changesets" + evmstate "github.com/smartcontractkit/cld-changesets/pkg/family/evm/legacy" + + opsevm "github.com/smartcontractkit/cld-changesets/pkg/family/evm/operations" + solchangesets "github.com/smartcontractkit/cld-changesets/pkg/family/solana/changesets/legacy" + + cldfproposalutils "github.com/smartcontractkit/chainlink-deployments-framework/engine/cld/mcms/proposalutils" + + "github.com/ethereum/go-ethereum/common" + "github.com/gagliardetto/solana-go" + "github.com/smartcontractkit/ccip-owner-contracts/pkg/gethwrappers" + chainselectors "github.com/smartcontractkit/chain-selectors" + + "github.com/smartcontractkit/chainlink-deployments-framework/datastore" + cldf "github.com/smartcontractkit/chainlink-deployments-framework/deployment" + + "github.com/smartcontractkit/chainlink-deployments-framework/operations" +) + +// migrateAddressBookWithQualifiers migrates an address book to a data store, +// applying custom qualifiers from MCMS configs when available +func migrateAddressBookWithQualifiers(ab cldf.AddressBook, cfgByChain map[uint64]cldfproposalutils.MCMSWithTimelockConfig) (datastore.MutableDataStore, error) { + addrs, err := ab.Addresses() + if err != nil { + return nil, err + } + + ds := datastore.NewMemoryDataStore() + + for chainSelector, chainAddresses := range addrs { + // Get the qualifier for this chain from the config + qualifier := "" + if cfg, exists := cfgByChain[chainSelector]; exists && cfg.Qualifier != nil && *cfg.Qualifier != "" { + qualifier = *cfg.Qualifier + } + + for addr, typever := range chainAddresses { + ref := datastore.AddressRef{ + ChainSelector: chainSelector, + Address: addr, + Type: datastore.ContractType(typever.Type), + Version: &typever.Version, + } + + // If we have a custom qualifier for this chain, use it for MCMS contracts + if qualifier != "" && isMCMSContract(string(typever.Type)) { + ref.Qualifier = qualifier + } + + // If the address book has labels, we need to add them to the addressRef + if !typever.Labels.IsEmpty() { + ref.Labels = datastore.NewLabelSet(typever.Labels.List()...) + } + + if err = ds.Addresses().Add(ref); err != nil { + return nil, fmt.Errorf("failed to add address %s: %w", addr, err) + } + } + } + + return ds, nil +} + +// isMCMSContract checks if a contract type is part of the MCMS system +func isMCMSContract(contractType string) bool { + mcmsTypes := []string{ + string(mcmscontracts.RBACTimelock), + string(mcmscontracts.ManyChainMultisig), + string(mcmscontracts.ProposerManyChainMultisig), + string(mcmscontracts.BypasserManyChainMultisig), + string(mcmscontracts.CancellerManyChainMultisig), + string(mcmscontracts.CallProxy), + } + + return slices.Contains(mcmsTypes, contractType) +} + +var ( + _ cldf.ChangeSet[map[uint64]cldfproposalutils.MCMSWithTimelockConfig] = DeployMCMSWithTimelockV2 + + // GrantRoleInTimeLock grants proposer, canceller, bypasser, executor, admin roles to the timelock contract with corresponding addresses if the + // roles are not already set with the same addresses. + // It creates a proposal if deployer key is not admin of the timelock contract. + // otherwise it executes the transactions directly. + // If neither timelock, nor the deployer key is the admin of the timelock contract, it returns an error. + GrantRoleInTimeLock = cldf.CreateChangeSet(grantRoleLogic, grantRolePreconditions) +) + +// DeployMCMSWithTimelockV2 deploys and initializes the MCM and Timelock contracts +func DeployMCMSWithTimelockV2( + env cldf.Environment, cfgByChain map[uint64]cldfproposalutils.MCMSWithTimelockConfig, +) (cldf.ChangesetOutput, error) { + newAddresses := cldf.NewMemoryAddressBook() + + eg := xerrgroup.Group{} + mu := sync.Mutex{} + allReports := make([]operations.Report[any, any], 0) + for chainSel, cfg := range cfgByChain { + eg.Go(func() error { + family, err := chainselectors.GetSelectorFamily(chainSel) + if err != nil { + return err + } + + switch family { + case chainselectors.FamilyEVM: + // Extract qualifier from config for this chain + qualifier := "" + if cfg.Qualifier != nil { + qualifier = *cfg.Qualifier + } + + // load mcms state with qualifier awareness + // we load the state one by one to avoid early return from MaybeLoadMCMSWithTimelockStateWithQualifier + // due to one of the chain not found + var chainstate *evmstate.MCMSWithTimelockState + s, err := evmstate.MaybeLoadMCMSWithTimelockStateWithQualifier(env, []uint64{chainSel}, qualifier) + if err != nil { + // if the state is not found for chain, we assume it's a fresh deployment + // this includes "no addresses found" which is expected for new qualifiers + if !strings.Contains(err.Error(), cldf.ErrChainNotFound.Error()) && + !strings.Contains(err.Error(), "no addresses found") { + return err + } + } + if s != nil { + chainstate = s[chainSel] + } + reports, err := evmchangesets.DeployMCMSWithTimelockContractsEVM(env, env.BlockChains.EVMChains()[chainSel], newAddresses, cfg, chainstate) + mu.Lock() + allReports = append(allReports, reports...) + mu.Unlock() + + return err + + case chainselectors.FamilySolana: + // this is not used in CLD as we need to dynamically resolve the artifacts to deploy these contracts + // we did not want to add the artifact resolution logic here, so we instead deploy using ccip/changeset/solana/cs_deploy_chain.go + // for in memory tests, programs and state are pre-loaded, so we use this function via testhelpers.TransferOwnershipSolana + _, err := solchangesets.DeployMCMSWithTimelockProgramsSolana(env, env.BlockChains.SolanaChains()[chainSel], newAddresses, cfg) + return err + + default: + return fmt.Errorf("unsupported chain family: %s", family) + } + }) + } + err := eg.Wait() + if err != nil { + return cldf.ChangesetOutput{Reports: allReports, AddressBook: newAddresses}, err + } + ds, err := migrateAddressBookWithQualifiers(newAddresses, cfgByChain) + if err != nil { + return cldf.ChangesetOutput{Reports: allReports, AddressBook: newAddresses}, fmt.Errorf("failed to migrate address book to data store: %w", err) + } + + return cldf.ChangesetOutput{Reports: allReports, AddressBook: newAddresses, DataStore: ds}, nil +} + +type GrantRoleInput struct { + ExistingProposerByChain map[uint64]common.Address // if needed in the future, need to add bypasser and canceller here + MCMS *cldfproposalutils.TimelockConfig + GasBoostConfigPerChain map[uint64]cldfproposalutils.GasBoostConfig +} + +func grantRolePreconditions(e cldf.Environment, cfg GrantRoleInput) error { + mcmsState, err := loadMCMSStatePerChainWithQualifier(e, cfg) + if err != nil { + return err + } + for selector, proposer := range cfg.ExistingProposerByChain { + if proposer == (common.Address{}) { + return fmt.Errorf("proposer address not found for chain %d", selector) + } + chain, ok := e.BlockChains.EVMChains()[selector] + if !ok { + return fmt.Errorf("chain not found for chain %d", selector) + } + timelockContracts, ok := mcmsState[selector] + if !ok { + return fmt.Errorf("timelock state not found for chain %d", selector) + } + if timelockContracts.Timelock == nil { + return fmt.Errorf("timelock contract not found for chain %s", chain.String()) + } + if timelockContracts.ProposerMcm == nil { + return fmt.Errorf("proposerMcm contract not found for chain %s", chain.String()) + } + if timelockContracts.CancellerMcm == nil { + return fmt.Errorf("cancellerMcm contract not found for chain %s", chain.String()) + } + if timelockContracts.BypasserMcm == nil { + return fmt.Errorf("bypasserMcm contract not found for chain %s", chain.String()) + } + if timelockContracts.CallProxy == nil { + return fmt.Errorf("callProxy contract not found for chain %s", chain.String()) + } + } + + return nil +} + +// loads MCMS state for each chain using per-chain qualifiers from cfg.MCMS.TimelockQualifierPerChain when available +func loadMCMSStatePerChainWithQualifier(e cldf.Environment, cfg GrantRoleInput) (map[uint64]*evmstate.MCMSWithTimelockState, error) { + result := make(map[uint64]*evmstate.MCMSWithTimelockState) + for selector := range cfg.ExistingProposerByChain { + qualifier := "" + if cfg.MCMS != nil && cfg.MCMS.TimelockQualifierPerChain != nil { + qualifier = cfg.MCMS.TimelockQualifierPerChain[selector] + } + chainState, err := evmstate.MaybeLoadMCMSWithTimelockStateWithQualifier(e, []uint64{selector}, qualifier) + if err != nil { + return nil, err + } + result[selector] = chainState[selector] + } + + return result, nil +} + +func grantRoleLogic(e cldf.Environment, cfg GrantRoleInput) (cldf.ChangesetOutput, error) { + mcmsState, err := loadMCMSStatePerChainWithQualifier(e, cfg) + if err != nil { + return cldf.ChangesetOutput{}, err + } + mcmsStateForProposal := make(map[uint64]evmstate.MCMSWithTimelockState) + for k, v := range mcmsState { + if v != nil { + // Replace the proposer MCM in state with the existing proposer. + // This is to ensure that we are using an MCM contract that already has the proposer role. + existingProposerMcm, err := gethwrappers.NewManyChainMultiSig( + cfg.ExistingProposerByChain[k], + e.BlockChains.EVMChains()[k].Client, + ) + if err != nil { + return cldf.ChangesetOutput{}, fmt.Errorf("failed to create ManyChainMultiSig for existing proposer %s on chain %d: %w", + cfg.ExistingProposerByChain[k].Hex(), k, err) + } + mcmsStateForProposal[k] = evmstate.MCMSWithTimelockState{ + CancellerMcm: v.CancellerMcm, + BypasserMcm: v.BypasserMcm, + ProposerMcm: existingProposerMcm, + Timelock: v.Timelock, + CallProxy: v.CallProxy, + } + } + } + + out := cldf.ChangesetOutput{} + gasBoostConfigs := opsevm.GasBoostConfigsForChainMap(cfg.ExistingProposerByChain, cfg.GasBoostConfigPerChain) + for chain := range cfg.ExistingProposerByChain { + stateForChain := mcmsState[chain] + evmChains := e.BlockChains.EVMChains() + seqReport, err := evmchangesets.GrantRolesForTimelock( + e, evmChains[chain], &cldfproposalutils.MCMSWithTimelockContracts{ + CancellerMcm: stateForChain.CancellerMcm, + BypasserMcm: stateForChain.BypasserMcm, + ProposerMcm: stateForChain.ProposerMcm, + Timelock: stateForChain.Timelock, + CallProxy: stateForChain.CallProxy, + }, false, gasBoostConfigs[chain]) + out, err = opsevm.AddEVMCallSequenceToCSOutput(e, out, seqReport, err, mcmsStateForProposal, cfg.MCMS, fmt.Sprintf("GrantRolesForTimelock on %s", evmChains[chain])) + if err != nil { + return out, fmt.Errorf("failed to grant roles for timelock on chain %d: %w", chain, err) + } + } + + return out, nil +} + +func ValidateOwnership(ctx context.Context, mcms bool, deployerKey, timelock common.Address, contract evmstate.Ownable) error { + owner, err := contract.Owner(&bind.CallOpts{Context: ctx}) + if err != nil { + return fmt.Errorf("failed to get owner: %w", err) + } + if mcms && owner != timelock { + return fmt.Errorf("%s not owned by timelock, Owner: %s", contract.Address(), owner.Hex()) + } else if !mcms && owner != deployerKey { + return fmt.Errorf("%s not owned by deployer key, Owner: %s", contract.Address(), owner.Hex()) + } + + return nil +} + +func ValidateOwnershipSolanaCommon(mcms bool, deployerKey solana.PublicKey, timelockSignerPDA solana.PublicKey, programOwner solana.PublicKey) error { + if !mcms { + if deployerKey.String() != programOwner.String() { + return fmt.Errorf("deployer key %s does not match owner %s", deployerKey.String(), programOwner.String()) + } + } else { + if timelockSignerPDA.String() != programOwner.String() { + return fmt.Errorf("timelock signer PDA %s does not match owner %s", timelockSignerPDA.String(), programOwner.String()) + } + } + + return nil +} diff --git a/mcms/changesets/legacy/deploy_mcms_with_timelock_test.go b/mcms/changesets/legacy/deploy_mcms_with_timelock_test.go new file mode 100644 index 0000000..388a889 --- /dev/null +++ b/mcms/changesets/legacy/deploy_mcms_with_timelock_test.go @@ -0,0 +1,566 @@ +//nolint:testifylint // inverting want and got is more succinct +package legacy_test + +import ( + "context" + "math/big" + "testing" + + "github.com/ethereum/go-ethereum/common" + "github.com/gagliardetto/solana-go" + "github.com/google/go-cmp/cmp" + chain_selectors "github.com/smartcontractkit/chain-selectors" + mcmscontracts "github.com/smartcontractkit/chainlink-deployments-framework/engine/cld/contracts/mcms" + cldfproposalutils "github.com/smartcontractkit/chainlink-deployments-framework/engine/cld/mcms/proposalutils" + cldftesthelpers "github.com/smartcontractkit/chainlink-deployments-framework/engine/cld/mcms/proposalutils/testhelpers" + mcmsevmsdk "github.com/smartcontractkit/mcms/sdk/evm" + mcmssolanasdk "github.com/smartcontractkit/mcms/sdk/solana" + mcmstypes "github.com/smartcontractkit/mcms/types" + "github.com/smartcontractkit/quarantine" + "github.com/stretchr/testify/require" + + mcmschangesets "github.com/smartcontractkit/cld-changesets/mcms/changesets/legacy" + cldchangesetscommon "github.com/smartcontractkit/cld-changesets/pkg/common" + evmstate "github.com/smartcontractkit/cld-changesets/pkg/family/evm/legacy" + familysolana "github.com/smartcontractkit/cld-changesets/pkg/family/solana" + "github.com/smartcontractkit/cld-changesets/pkg/family/solana/legacy" + soltestutils2 "github.com/smartcontractkit/cld-changesets/pkg/family/solana/legacy/testutils" + + timelockBindings "github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings/v0_1_1/timelock" + "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" + "github.com/smartcontractkit/chainlink-deployments-framework/pkg/logger" + "github.com/smartcontractkit/chainlink-evm/pkg/utils" + + cldf_solana "github.com/smartcontractkit/chainlink-deployments-framework/chain/solana" + "github.com/smartcontractkit/chainlink-deployments-framework/datastore" + cldf "github.com/smartcontractkit/chainlink-deployments-framework/deployment" + "github.com/smartcontractkit/chainlink-deployments-framework/engine/test/environment" + "github.com/smartcontractkit/chainlink-deployments-framework/engine/test/onchain" + "github.com/smartcontractkit/chainlink-deployments-framework/engine/test/runtime" + + commonchangeset "github.com/smartcontractkit/cld-changesets/pkg/common/changeset" +) + +func TestGrantRoleInTimeLock(t *testing.T) { + t.Parallel() + + selector := chain_selectors.TEST_90000001.Selector + env, err := environment.New(t.Context(), + environment.WithEVMSimulatedWithConfig(t, []uint64{selector}, onchain.EVMSimLoaderConfig{ + NumAdditionalAccounts: 1, + }), + ) + require.NoError(t, err) + + // deploy the MCMS with timelock contracts + configuredChangeset := commonchangeset.Configure( + cldf.CreateLegacyChangeSet(mcmschangesets.DeployMCMSWithTimelockV2), + map[uint64]cldfproposalutils.MCMSWithTimelockConfig{ + selector: cldftesthelpers.SingleGroupTimelockConfig(t), + }, + ) + updatedEnv, err := commonchangeset.Apply(t, *env, configuredChangeset) + require.NoError(t, err) + mcmsState, err := evmstate.MaybeLoadMCMSWithTimelockState(updatedEnv, []uint64{selector}) + require.NoError(t, err) + + // change the environment to remove proposer from the timelock, so that we can deploy new proposer + // and then grant the role to the new proposer + existingProposer := mcmsState[selector].ProposerMcm + ab := cldf.NewMemoryAddressBook() + require.NoError(t, ab.Save(selector, existingProposer.Address().String(), + cldf.NewTypeAndVersion(mcmscontracts.ProposerManyChainMultisig, cldchangesetscommon.Version1_0_0))) + require.NoError(t, updatedEnv.ExistingAddresses.Remove(ab)) //nolint:staticcheck // test removes legacy AddressBook entry while verifying DataStore migration behavior + + // remove from DataStore since deployment now uses DataStore + // Since DataStore is immutable, create a new one without the proposer + newDataStore := datastore.NewMemoryDataStore() + refs, err := updatedEnv.DataStore.Addresses().Fetch() + require.NoError(t, err) + + // Copy all address refs except the proposer we want to remove + for _, ref := range refs { + // Skip the proposer we want to remove + if ref.ChainSelector == selector && + ref.Address == existingProposer.Address().String() && + ref.Type == datastore.ContractType(mcmscontracts.ProposerManyChainMultisig) { + continue + } + require.NoError(t, newDataStore.Addresses().Add(ref)) + } + + // Replace the DataStore in the environment + updatedEnv.DataStore = newDataStore.Seal() + + // change the deployer key, so that we can deploy proposer with a new key + // the new deployer key will not be admin of the timelock + // we can test granting roles through proposal + evmChains := updatedEnv.BlockChains.EVMChains() + chain := evmChains[selector] + chain.DeployerKey = evmChains[selector].Users[0] + + // now deploy MCMS again so that only the proposer is new + updatedEnv, err = commonchangeset.Apply(t, updatedEnv, configuredChangeset) + require.NoError(t, err) + mcmsState, err = evmstate.MaybeLoadMCMSWithTimelockState(updatedEnv, []uint64{selector}) + require.NoError(t, err) + + require.NotEqual(t, existingProposer.Address(), mcmsState[selector].ProposerMcm.Address()) + updatedEnv, err = commonchangeset.Apply(t, updatedEnv, commonchangeset.Configure( + mcmschangesets.GrantRoleInTimeLock, + mcmschangesets.GrantRoleInput{ + ExistingProposerByChain: map[uint64]common.Address{ + selector: existingProposer.Address(), + }, + MCMS: &cldfproposalutils.TimelockConfig{MinDelay: 0}, + }, + )) + require.NoError(t, err) + mcmsState, err = evmstate.MaybeLoadMCMSWithTimelockState(updatedEnv, []uint64{selector}) + require.NoError(t, err) + + evmTimelockInspector := mcmsevmsdk.NewTimelockInspector(updatedEnv.BlockChains.EVMChains()[selector].Client) + + proposers, err := evmTimelockInspector.GetProposers(t.Context(), mcmsState[selector].Timelock.Address().Hex()) + require.NoError(t, err) + require.Contains(t, proposers, mcmsState[selector].ProposerMcm.Address().Hex()) + require.Contains(t, proposers, existingProposer.Address().Hex()) +} + +func TestDeployMCMSWithTimelockV2WithFewExistingContracts(t *testing.T) { + t.Parallel() + + ctx := t.Context() + + selector1 := chain_selectors.TEST_90000001.Selector + selector2 := chain_selectors.TEST_90000002.Selector + selectors := []uint64{selector1, selector2} + + // Build a datastore with some dummy address for callproxy, canceller and bypasser + // to simulate the case where they already exist and so the changeset will not try to deploy + // them again + ds := datastore.NewMemoryDataStore() + + callProxyAddress := utils.RandomAddress() + mcmsAddress := utils.RandomAddress() + mcmsType := cldf.NewTypeAndVersion(mcmscontracts.ManyChainMultisig, cldchangesetscommon.Version1_0_0) + // we use same address for bypasser and canceller + mcmsType.AddLabel(mcmscontracts.BypasserRole.String()) + mcmsType.AddLabel(mcmscontracts.CancellerRole.String()) + + // Add CallProxy for first chain only + require.NoError(t, ds.AddressRefStore.Add(datastore.AddressRef{ + ChainSelector: selector1, + Address: callProxyAddress.String(), + Type: datastore.ContractType(mcmscontracts.CallProxy), + Version: &cldchangesetscommon.Version1_0_0, + })) + + // Add MCMS contract with both bypasser and canceller labels for first chain only + require.NoError(t, ds.AddressRefStore.Add(datastore.AddressRef{ + ChainSelector: selector1, + Address: mcmsAddress.String(), + Type: datastore.ContractType(mcmsType.Type), + Version: &mcmsType.Version, + Labels: datastore.NewLabelSet(mcmsType.Labels.List()...), + })) + + rt, err := runtime.New(t.Context(), runtime.WithEnvOpts( + environment.WithEVMSimulated(t, selectors), + environment.WithLogger(logger.Test(t)), + environment.WithDatastore(ds.Seal()), + )) + require.NoError(t, err) + + chain1 := rt.Environment().BlockChains.EVMChains()[selector1] + + changesetConfig := map[uint64]cldfproposalutils.MCMSWithTimelockConfig{ + selector1: { + Proposer: mcmstypes.Config{ + Quorum: 1, + Signers: []common.Address{common.HexToAddress("0x0000000000000000000000000000000000000001")}, + GroupSigners: []mcmstypes.Config{ + { + Quorum: 1, + Signers: []common.Address{common.HexToAddress("0x0000000000000000000000000000000000000002")}, + GroupSigners: []mcmstypes.Config{}, + }, + }, + }, + Canceller: mcmstypes.Config{ + Quorum: 1, + Signers: []common.Address{common.HexToAddress("0x0000000000000000000000000000000000000003")}, + GroupSigners: []mcmstypes.Config{}, + }, + Bypasser: mcmstypes.Config{ + Quorum: 1, + Signers: []common.Address{common.HexToAddress("0x0000000000000000000000000000000000000004")}, + GroupSigners: []mcmstypes.Config{}, + }, + TimelockMinDelay: big.NewInt(0), + }, + selector2: { + Proposer: mcmstypes.Config{ + Quorum: 1, + Signers: []common.Address{common.HexToAddress("0x0000000000000000000000000000000000000011")}, + GroupSigners: []mcmstypes.Config{}, + }, + Canceller: mcmstypes.Config{ + Quorum: 2, + Signers: []common.Address{ + common.HexToAddress("0x0000000000000000000000000000000000000012"), + common.HexToAddress("0x0000000000000000000000000000000000000013"), + common.HexToAddress("0x0000000000000000000000000000000000000014"), + }, + GroupSigners: []mcmstypes.Config{}, + }, + Bypasser: mcmstypes.Config{ + Quorum: 1, + Signers: []common.Address{common.HexToAddress("0x0000000000000000000000000000000000000005")}, + GroupSigners: []mcmstypes.Config{}, + }, + TimelockMinDelay: big.NewInt(1), + }, + } + + err = rt.Exec( + runtime.ChangesetTask(cldf.CreateLegacyChangeSet(mcmschangesets.DeployMCMSWithTimelockV2), changesetConfig), + ) + require.NoError(t, err) + + state, err := evmstate.MaybeLoadMCMSWithTimelockState(rt.Environment(), selectors) + require.NoError(t, err) + evmState1 := state[selector1] + + // --- assert --- + require.Equal(t, callProxyAddress, evmState1.CallProxy.Address()) + require.Equal(t, mcmsAddress, evmState1.BypasserMcm.Address()) + require.Equal(t, mcmsAddress, evmState1.CancellerMcm.Address()) + // proposer should be newly deployed + require.NotEqual(t, mcmsAddress, evmState1.ProposerMcm.Address()) + + evmTimelockInspector := mcmsevmsdk.NewTimelockInspector(chain1.Client) + + proposers, err := evmTimelockInspector.GetProposers(ctx, evmState1.Timelock.Address().Hex()) + require.NoError(t, err) + require.Equal(t, proposers, []string{evmState1.ProposerMcm.Address().Hex()}) + + executors, err := evmTimelockInspector.GetExecutors(ctx, evmState1.Timelock.Address().Hex()) + require.NoError(t, err) + require.Equal(t, executors, []string{evmState1.CallProxy.Address().Hex()}) + + cancellers, err := evmTimelockInspector.GetCancellers(ctx, evmState1.Timelock.Address().Hex()) + require.NoError(t, err) + require.ElementsMatch(t, cancellers, []string{ + evmState1.CancellerMcm.Address().Hex(), // bypasser and canceller are same + evmState1.ProposerMcm.Address().Hex(), + }) + + bypassers, err := evmTimelockInspector.GetBypassers(ctx, evmState1.Timelock.Address().Hex()) + require.NoError(t, err) + require.Equal(t, bypassers, []string{evmState1.BypasserMcm.Address().Hex()}) +} + +func TestDeployMCMSWithTimelockV2(t *testing.T) { + quarantine.Flaky(t, "DX-1719") + t.Parallel() + + evmSelector := chain_selectors.TEST_90000001.Selector + solSelector := chain_selectors.TEST_22222222222222222222222222222222222222222222.Selector + programsPath, programIDs, ab := soltestutils2.PreloadMCMS(t, solSelector) + + rt, err := runtime.New(t.Context(), runtime.WithEnvOpts( + environment.WithEVMSimulated(t, []uint64{evmSelector}), + environment.WithSolanaContainer(t, []uint64{solSelector}, programsPath, programIDs), + environment.WithAddressBook(ab), + environment.WithLogger(logger.Test(t)), + )) + require.NoError(t, err) + + evmChain := rt.Environment().BlockChains.EVMChains()[evmSelector] + solChain := rt.Environment().BlockChains.SolanaChains()[solSelector] + + changesetConfig := map[uint64]cldfproposalutils.MCMSWithTimelockConfig{ + evmSelector: { + Proposer: mcmstypes.Config{ + Quorum: 1, + Signers: []common.Address{common.HexToAddress("0x0000000000000000000000000000000000000001")}, + GroupSigners: []mcmstypes.Config{ + { + Quorum: 1, + Signers: []common.Address{common.HexToAddress("0x0000000000000000000000000000000000000002")}, + GroupSigners: []mcmstypes.Config{}, + }, + }, + }, + Canceller: mcmstypes.Config{ + Quorum: 1, + Signers: []common.Address{common.HexToAddress("0x0000000000000000000000000000000000000003")}, + GroupSigners: []mcmstypes.Config{}, + }, + Bypasser: mcmstypes.Config{ + Quorum: 1, + Signers: []common.Address{common.HexToAddress("0x0000000000000000000000000000000000000004")}, + GroupSigners: []mcmstypes.Config{}, + }, + TimelockMinDelay: big.NewInt(0), + }, + solSelector: { + Proposer: mcmstypes.Config{ + Quorum: 1, + Signers: []common.Address{ + common.HexToAddress("0x0000000000000000000000000000000000000021"), + common.HexToAddress("0x0000000000000000000000000000000000000022"), + }, + GroupSigners: []mcmstypes.Config{ + { + Quorum: 2, + Signers: []common.Address{ + common.HexToAddress("0x0000000000000000000000000000000000000023"), + common.HexToAddress("0x0000000000000000000000000000000000000024"), + common.HexToAddress("0x0000000000000000000000000000000000000025"), + }, + GroupSigners: []mcmstypes.Config{ + { + Quorum: 1, + Signers: []common.Address{ + common.HexToAddress("0x0000000000000000000000000000000000000026"), + }, + GroupSigners: []mcmstypes.Config{}, + }, + }, + }, + }, + }, + Canceller: mcmstypes.Config{ + Quorum: 1, + Signers: []common.Address{ + common.HexToAddress("0x0000000000000000000000000000000000000027"), + }, + GroupSigners: []mcmstypes.Config{}, + }, + Bypasser: mcmstypes.Config{ + Quorum: 1, + Signers: []common.Address{ + common.HexToAddress("0x0000000000000000000000000000000000000028"), + common.HexToAddress("0x0000000000000000000000000000000000000029"), + }, + GroupSigners: []mcmstypes.Config{}, + }, + TimelockMinDelay: big.NewInt(2), + }, + } + + err = rt.Exec( + runtime.ChangesetTask(cldf.CreateLegacyChangeSet(mcmschangesets.DeployMCMSWithTimelockV2), changesetConfig), + ) + require.NoError(t, err) + + // Load the MCMS contractsstate + evmMCMSState, err := evmstate.MaybeLoadMCMSWithTimelockState(rt.Environment(), []uint64{evmSelector}) + require.NoError(t, err) + require.Len(t, evmMCMSState, 1) + + solMCMSState := soltestutils2.GetMCMSStateFromAddressBook(t, rt.State().AddressBook, solChain) + + // --- assert --- + + ctx := t.Context() + + // evm chain + evmState := evmMCMSState[evmSelector] + evmInspector := mcmsevmsdk.NewInspector(evmChain.Client) + evmTimelockInspector := mcmsevmsdk.NewTimelockInspector(evmChain.Client) + + config, err := evmInspector.GetConfig(ctx, evmState.ProposerMcm.Address().Hex()) + require.NoError(t, err) + require.Empty(t, cmp.Diff(*config, changesetConfig[evmSelector].Proposer)) + + config, err = evmInspector.GetConfig(ctx, evmState.CancellerMcm.Address().Hex()) + require.NoError(t, err) + require.Empty(t, cmp.Diff(*config, changesetConfig[evmSelector].Canceller)) + + config, err = evmInspector.GetConfig(ctx, evmState.BypasserMcm.Address().Hex()) + require.NoError(t, err) + require.Empty(t, cmp.Diff(*config, changesetConfig[evmSelector].Bypasser)) + + proposers, err := evmTimelockInspector.GetProposers(ctx, evmState.Timelock.Address().Hex()) + require.NoError(t, err) + require.Equal(t, proposers, []string{evmState.ProposerMcm.Address().Hex()}) + + executors, err := evmTimelockInspector.GetExecutors(ctx, evmState.Timelock.Address().Hex()) + require.NoError(t, err) + require.Equal(t, executors, []string{evmState.CallProxy.Address().Hex()}) + + cancellers, err := evmTimelockInspector.GetCancellers(ctx, evmState.Timelock.Address().Hex()) + require.NoError(t, err) + require.ElementsMatch(t, cancellers, []string{ + evmState.CancellerMcm.Address().Hex(), + evmState.ProposerMcm.Address().Hex(), + evmState.BypasserMcm.Address().Hex(), + }) + + bypassers, err := evmTimelockInspector.GetBypassers(ctx, evmState.Timelock.Address().Hex()) + require.NoError(t, err) + require.Equal(t, bypassers, []string{evmState.BypasserMcm.Address().Hex()}) + + // solana chain + solanaInspector := mcmssolanasdk.NewInspector(solChain.Client) + solanaTimelockInspector := mcmssolanasdk.NewTimelockInspector(solChain.Client) + + addr := mcmssolanasdk.ContractAddress(solMCMSState.McmProgram, mcmssolanasdk.PDASeed(solMCMSState.ProposerMcmSeed)) + config, err = solanaInspector.GetConfig(ctx, addr) + require.NoError(t, err) + require.Empty(t, cmp.Diff(*config, changesetConfig[solSelector].Proposer)) + + addr = mcmssolanasdk.ContractAddress(solMCMSState.McmProgram, mcmssolanasdk.PDASeed(solMCMSState.CancellerMcmSeed)) + config, err = solanaInspector.GetConfig(ctx, addr) + require.NoError(t, err) + require.Empty(t, cmp.Diff(*config, changesetConfig[solSelector].Canceller)) + + addr = mcmssolanasdk.ContractAddress(solMCMSState.McmProgram, mcmssolanasdk.PDASeed(solMCMSState.BypasserMcmSeed)) + config, err = solanaInspector.GetConfig(ctx, addr) + require.NoError(t, err) + require.Empty(t, cmp.Diff(*config, changesetConfig[solSelector].Bypasser)) + + addr = mcmssolanasdk.ContractAddress(solMCMSState.TimelockProgram, mcmssolanasdk.PDASeed(solMCMSState.TimelockSeed)) + proposers, err = solanaTimelockInspector.GetProposers(ctx, addr) + require.NoError(t, err) + require.Equal(t, proposers, []string{mcmSignerPDA(solMCMSState.McmProgram, solMCMSState.ProposerMcmSeed)}) + + executors, err = solanaTimelockInspector.GetExecutors(ctx, addr) + require.NoError(t, err) + require.Equal(t, executors, []string{solChain.DeployerKey.PublicKey().String()}) + + cancellers, err = solanaTimelockInspector.GetCancellers(ctx, addr) + require.NoError(t, err) + require.ElementsMatch(t, cancellers, []string{ + mcmSignerPDA(solMCMSState.McmProgram, solMCMSState.CancellerMcmSeed), + mcmSignerPDA(solMCMSState.McmProgram, solMCMSState.ProposerMcmSeed), + mcmSignerPDA(solMCMSState.McmProgram, solMCMSState.BypasserMcmSeed), + }) + + bypassers, err = solanaTimelockInspector.GetBypassers(ctx, addr) + require.NoError(t, err) + require.Equal(t, bypassers, []string{mcmSignerPDA(solMCMSState.McmProgram, solMCMSState.BypasserMcmSeed)}) + + timelockConfig := solanaTimelockConfig(ctx, t, solChain, solMCMSState.TimelockProgram, solMCMSState.TimelockSeed) + require.NoError(t, err) + require.Equal(t, timelockConfig.ProposedOwner.String(), "11111111111111111111111111111111") +} + +// TestDeployMCMSWithTimelockV2SkipInit tests calling the deploy changeset when accounts have already been initialized +func TestDeployMCMSWithTimelockV2SkipInitSolana(t *testing.T) { + tests.SkipFlakey(t, "https://smartcontract-it.atlassian.net/browse/DX-438") + + t.Parallel() + + selector := chain_selectors.TEST_22222222222222222222222222222222222222222222.Selector + programsPath, programIDs, ab := soltestutils2.PreloadMCMS(t, selector) + + rt, err := runtime.New(t.Context(), runtime.WithEnvOpts( + environment.WithSolanaContainer(t, []uint64{selector}, programsPath, programIDs), + environment.WithAddressBook(ab), + environment.WithLogger(logger.Test(t)), + )) + require.NoError(t, err) + + changesetConfig := map[uint64]cldfproposalutils.MCMSWithTimelockConfig{ + selector: { + Proposer: mcmstypes.Config{ + Quorum: 1, + Signers: []common.Address{ + common.HexToAddress("0x0000000000000000000000000000000000000021"), + common.HexToAddress("0x0000000000000000000000000000000000000022"), + }, + GroupSigners: []mcmstypes.Config{ + { + Quorum: 2, + Signers: []common.Address{ + common.HexToAddress("0x0000000000000000000000000000000000000023"), + common.HexToAddress("0x0000000000000000000000000000000000000024"), + common.HexToAddress("0x0000000000000000000000000000000000000025"), + }, + GroupSigners: []mcmstypes.Config{ + { + Quorum: 1, + Signers: []common.Address{ + common.HexToAddress("0x0000000000000000000000000000000000000026"), + }, + GroupSigners: []mcmstypes.Config{}, + }, + }, + }, + }, + }, + Canceller: mcmstypes.Config{ + Quorum: 1, + Signers: []common.Address{ + common.HexToAddress("0x0000000000000000000000000000000000000027"), + }, + GroupSigners: []mcmstypes.Config{}, + }, + Bypasser: mcmstypes.Config{ + Quorum: 1, + Signers: []common.Address{ + common.HexToAddress("0x0000000000000000000000000000000000000028"), + common.HexToAddress("0x0000000000000000000000000000000000000029"), + }, + GroupSigners: []mcmstypes.Config{}, + }, + TimelockMinDelay: big.NewInt(2), + }, + } + + // --- act --- + err = rt.Exec( + runtime.ChangesetTask(cldf.CreateLegacyChangeSet(mcmschangesets.DeployMCMSWithTimelockV2), changesetConfig), + ) + require.NoError(t, err) + + solanaState, err := legacy.MaybeLoadMCMSWithTimelockState(rt.Environment(), []uint64{selector}) + require.NoError(t, err) + + // Call deploy again, seeds and addresses from original state should not change + err = rt.Exec( + runtime.ChangesetTask(cldf.CreateLegacyChangeSet(mcmschangesets.DeployMCMSWithTimelockV2), changesetConfig), + ) + require.NoError(t, err) + + solanaStateNew, err := legacy.MaybeLoadMCMSWithTimelockState(rt.Environment(), []uint64{selector}) + require.NoError(t, err) + + // --- assert --- + require.Len(t, solanaState, 1) + stateOld := solanaState[selector] + stateNew := solanaStateNew[selector] + require.Equal(t, stateOld.TimelockSeed, stateNew.TimelockSeed) + require.Equal(t, stateOld.TimelockProgram, stateNew.TimelockProgram) + require.Equal(t, stateOld.BypasserAccessControllerAccount, stateNew.BypasserAccessControllerAccount) + require.Equal(t, stateOld.CancellerAccessControllerAccount, stateNew.CancellerAccessControllerAccount) + require.Equal(t, stateOld.ExecutorAccessControllerAccount, stateNew.ExecutorAccessControllerAccount) + require.Equal(t, stateOld.ProposerAccessControllerAccount, stateNew.ProposerAccessControllerAccount) + require.Equal(t, stateOld.McmProgram, stateNew.McmProgram) + require.Equal(t, stateOld.BypasserMcmSeed, stateNew.BypasserMcmSeed) + require.Equal(t, stateOld.CancellerMcmSeed, stateNew.CancellerMcmSeed) + require.Equal(t, stateOld.ProposerMcmSeed, stateNew.ProposerMcmSeed) + require.Equal(t, stateOld.AccessControllerProgram, stateNew.AccessControllerProgram) +} + +// ----- helpers ----- + +func mcmSignerPDA(programID solana.PublicKey, seed legacy.PDASeed) string { + return familysolana.GetMCMSignerPDA(programID, seed).String() +} + +func solanaTimelockConfig( + ctx context.Context, t *testing.T, chain cldf_solana.Chain, programID solana.PublicKey, seed legacy.PDASeed, +) timelockBindings.Config { + t.Helper() + + var data timelockBindings.Config + err := chain.GetAccountDataBorshInto(ctx, familysolana.GetTimelockConfigPDA(programID, seed), &data) + require.NoError(t, err) + + return data +} diff --git a/mcms/changesets/firedrill.go b/mcms/changesets/legacy/firedrill.go similarity index 99% rename from mcms/changesets/firedrill.go rename to mcms/changesets/legacy/firedrill.go index df43592..f161b61 100644 --- a/mcms/changesets/firedrill.go +++ b/mcms/changesets/legacy/firedrill.go @@ -1,4 +1,4 @@ -package changesets +package legacy import ( "errors" @@ -14,7 +14,7 @@ import ( cldf_chain "github.com/smartcontractkit/chainlink-deployments-framework/chain" mcops "github.com/smartcontractkit/cld-changesets/mcms/operations" - evmstate "github.com/smartcontractkit/cld-changesets/pkg/family/evm" + evmstate "github.com/smartcontractkit/cld-changesets/pkg/family/evm/legacy" ) var _ cldf.ChangeSetV2[FireDrillConfig] = MCMSSignFireDrillChangeset{} diff --git a/mcms/changesets/firedrill_test.go b/mcms/changesets/legacy/firedrill_test.go similarity index 99% rename from mcms/changesets/firedrill_test.go rename to mcms/changesets/legacy/firedrill_test.go index d9e84bc..a28c5ba 100644 --- a/mcms/changesets/firedrill_test.go +++ b/mcms/changesets/legacy/firedrill_test.go @@ -1,4 +1,4 @@ -package changesets +package legacy import ( "testing" diff --git a/mcms/changesets/fund_mcm_pdas.go b/mcms/changesets/legacy/fund_mcm_pdas.go similarity index 92% rename from mcms/changesets/fund_mcm_pdas.go rename to mcms/changesets/legacy/fund_mcm_pdas.go index b04841b..0c6dcc7 100644 --- a/mcms/changesets/fund_mcm_pdas.go +++ b/mcms/changesets/legacy/fund_mcm_pdas.go @@ -1,5 +1,5 @@ // Package changesets provides reusable MCMS changesets. -package changesets +package legacy import ( "errors" @@ -11,6 +11,7 @@ import ( cldf "github.com/smartcontractkit/chainlink-deployments-framework/deployment" solanastate "github.com/smartcontractkit/cld-changesets/pkg/family/solana" + "github.com/smartcontractkit/cld-changesets/pkg/family/solana/legacy" ) var _ cldf.ChangeSetV2[FundMCMSignerConfig] = FundMCMSignersChangeset{} @@ -43,7 +44,7 @@ func (f FundMCMSignersChangeset) VerifyPreconditions(e cldf.Environment, config if err != nil { return fmt.Errorf("failed to get existing addresses: %w", err) } - mcmState, err := solanastate.MaybeLoadMCMSWithTimelockChainState(solChain, addreses) + mcmState, err := legacy.MaybeLoadMCMSWithTimelockChainState(solChain, addreses) if err != nil { return fmt.Errorf("failed to load MCMS state: %w", err) } @@ -77,33 +78,33 @@ func (f FundMCMSignersChangeset) Apply(e cldf.Environment, config FundMCMSignerC if err != nil { return cldf.ChangesetOutput{}, fmt.Errorf("failed to get existing addresses: %w", err) } - mcmState, err := solanastate.MaybeLoadMCMSWithTimelockChainState(solChain, addreses) + mcmState, err := legacy.MaybeLoadMCMSWithTimelockChainState(solChain, addreses) if err != nil { return cldf.ChangesetOutput{}, fmt.Errorf("failed to load MCMS state: %w", err) } - err = solanastate.FundFromDeployerKey( + err = legacy.FundFromDeployerKey( solChain, []solana.PublicKey{solanastate.GetTimelockSignerPDA(mcmState.TimelockProgram, mcmState.TimelockSeed)}, cfgAmounts.Timelock) if err != nil { return cldf.ChangesetOutput{}, fmt.Errorf("failed to fund timelock signer on chain %d: %w", chainSelector, err) } - err = solanastate.FundFromDeployerKey( + err = legacy.FundFromDeployerKey( solChain, []solana.PublicKey{solanastate.GetMCMSignerPDA(mcmState.McmProgram, mcmState.ProposerMcmSeed)}, cfgAmounts.ProposeMCM) if err != nil { return cldf.ChangesetOutput{}, fmt.Errorf("failed to fund MCMS proposer on chain %d: %w", chainSelector, err) } - err = solanastate.FundFromDeployerKey( + err = legacy.FundFromDeployerKey( solChain, []solana.PublicKey{solanastate.GetMCMSignerPDA(mcmState.McmProgram, mcmState.CancellerMcmSeed)}, cfgAmounts.CancellerMCM) if err != nil { return cldf.ChangesetOutput{}, fmt.Errorf("failed to fund MCMS canceller on chain %d: %w", chainSelector, err) } - err = solanastate.FundFromDeployerKey( + err = legacy.FundFromDeployerKey( solChain, []solana.PublicKey{solanastate.GetMCMSignerPDA(mcmState.McmProgram, mcmState.BypasserMcmSeed)}, cfgAmounts.BypasserMCM) diff --git a/mcms/changesets/fund_mcm_pdas_test.go b/mcms/changesets/legacy/fund_mcm_pdas_test.go similarity index 86% rename from mcms/changesets/fund_mcm_pdas_test.go rename to mcms/changesets/legacy/fund_mcm_pdas_test.go index c3a8ae2..32e17de 100644 --- a/mcms/changesets/fund_mcm_pdas_test.go +++ b/mcms/changesets/legacy/fund_mcm_pdas_test.go @@ -1,4 +1,4 @@ -package changesets +package legacy import ( "context" @@ -23,6 +23,7 @@ import ( cldchangesetscommon "github.com/smartcontractkit/cld-changesets/pkg/common" solanastate "github.com/smartcontractkit/cld-changesets/pkg/family/solana" + "github.com/smartcontractkit/cld-changesets/pkg/family/solana/legacy" ) func TestFundMCMSignersChangeset_VerifyPreconditions(t *testing.T) { @@ -227,29 +228,29 @@ func testFundMCMSignersEnv(t *testing.T, selector uint64, client *rpc.Client, co })) } -func saveMCMSAddresses(t *testing.T, addressBook cldf.AddressBook, selector uint64, completeState bool) *solanastate.MCMSWithTimelockState { +func saveMCMSAddresses(t *testing.T, addressBook cldf.AddressBook, selector uint64, completeState bool) *legacy.MCMSWithTimelockState { t.Helper() mcmDummyProgram := solana.NewWallet().PublicKey() timelockProgram := solana.NewWallet().PublicKey() - state := &solanastate.MCMSWithTimelockState{ - MCMSWithTimelockPrograms: &solanastate.MCMSWithTimelockPrograms{ + state := &legacy.MCMSWithTimelockState{ + MCMSWithTimelockPrograms: &legacy.MCMSWithTimelockPrograms{ McmProgram: mcmDummyProgram, TimelockProgram: timelockProgram, - ProposerMcmSeed: solanastate.PDASeed{'t', 'e', 's', 't', '1'}, - CancellerMcmSeed: solanastate.PDASeed{'t', 'e', 's', 't', '2'}, - BypasserMcmSeed: solanastate.PDASeed{'t', 'e', 's', 't', '3'}, - TimelockSeed: solanastate.PDASeed{'t', 'e', 's', 't'}, + ProposerMcmSeed: legacy.PDASeed{'t', 'e', 's', 't', '1'}, + CancellerMcmSeed: legacy.PDASeed{'t', 'e', 's', 't', '2'}, + BypasserMcmSeed: legacy.PDASeed{'t', 'e', 's', 't', '3'}, + TimelockSeed: legacy.PDASeed{'t', 'e', 's', 't'}, }, } if !completeState { - state.ProposerMcmSeed = solanastate.PDASeed{} - state.CancellerMcmSeed = solanastate.PDASeed{} - state.BypasserMcmSeed = solanastate.PDASeed{} - state.TimelockSeed = solanastate.PDASeed{} + state.ProposerMcmSeed = legacy.PDASeed{} + state.CancellerMcmSeed = legacy.PDASeed{} + state.BypasserMcmSeed = legacy.PDASeed{} + state.TimelockSeed = legacy.PDASeed{} - require.NoError(t, addressBook.Save(selector, solanastate.EncodeAddressWithSeed(state.McmProgram, state.BypasserMcmSeed), cldf.NewTypeAndVersion( + require.NoError(t, addressBook.Save(selector, legacy.EncodeAddressWithSeed(state.McmProgram, state.BypasserMcmSeed), cldf.NewTypeAndVersion( mcmscontracts.BypasserManyChainMultisig, cldchangesetscommon.Version1_0_0, ))) @@ -257,19 +258,19 @@ func saveMCMSAddresses(t *testing.T, addressBook cldf.AddressBook, selector uint return state } - require.NoError(t, addressBook.Save(selector, solanastate.EncodeAddressWithSeed(state.TimelockProgram, state.TimelockSeed), cldf.NewTypeAndVersion( + require.NoError(t, addressBook.Save(selector, legacy.EncodeAddressWithSeed(state.TimelockProgram, state.TimelockSeed), cldf.NewTypeAndVersion( mcmscontracts.RBACTimelock, cldchangesetscommon.Version1_0_0, ))) - require.NoError(t, addressBook.Save(selector, solanastate.EncodeAddressWithSeed(state.McmProgram, state.ProposerMcmSeed), cldf.NewTypeAndVersion( + require.NoError(t, addressBook.Save(selector, legacy.EncodeAddressWithSeed(state.McmProgram, state.ProposerMcmSeed), cldf.NewTypeAndVersion( mcmscontracts.ProposerManyChainMultisig, cldchangesetscommon.Version1_0_0, ))) - require.NoError(t, addressBook.Save(selector, solanastate.EncodeAddressWithSeed(state.McmProgram, state.CancellerMcmSeed), cldf.NewTypeAndVersion( + require.NoError(t, addressBook.Save(selector, legacy.EncodeAddressWithSeed(state.McmProgram, state.CancellerMcmSeed), cldf.NewTypeAndVersion( mcmscontracts.CancellerManyChainMultisig, cldchangesetscommon.Version1_0_0, ))) - require.NoError(t, addressBook.Save(selector, solanastate.EncodeAddressWithSeed(state.McmProgram, state.BypasserMcmSeed), cldf.NewTypeAndVersion( + require.NoError(t, addressBook.Save(selector, legacy.EncodeAddressWithSeed(state.McmProgram, state.BypasserMcmSeed), cldf.NewTypeAndVersion( mcmscontracts.BypasserManyChainMultisig, cldchangesetscommon.Version1_0_0, ))) diff --git a/mcms/changesets/grant_role_timelock.go b/mcms/changesets/legacy/grant_role_timelock.go similarity index 96% rename from mcms/changesets/grant_role_timelock.go rename to mcms/changesets/legacy/grant_role_timelock.go index ef86184..cbaee90 100644 --- a/mcms/changesets/grant_role_timelock.go +++ b/mcms/changesets/legacy/grant_role_timelock.go @@ -1,4 +1,4 @@ -package changesets +package legacy import ( "errors" @@ -16,9 +16,9 @@ import ( cldfproposalutils "github.com/smartcontractkit/chainlink-deployments-framework/engine/cld/mcms/proposalutils" fwops "github.com/smartcontractkit/chainlink-deployments-framework/operations" + mcmscontract "github.com/smartcontractkit/cld-changesets/mcms/legacy/proposeutils" mcops "github.com/smartcontractkit/cld-changesets/mcms/operations" - cldmcms "github.com/smartcontractkit/cld-changesets/pkg/contract/mcms" - solanastate "github.com/smartcontractkit/cld-changesets/pkg/family/solana" + solanastate "github.com/smartcontractkit/cld-changesets/pkg/family/solana/legacy" ) // GrantRoleTimelockSolana grants the given accounts access to the given role on the timelock @@ -155,7 +155,7 @@ func (t GrantRoleTimelockSolana) Apply( return cldf.ChangesetOutput{}, nil } - proposal, err := cldmcms.BuildProposalFromBatchesV2(env, timelocks, proposers, inspectors, + proposal, err := mcmscontract.BuildProposalFromBatchesV2(env, timelocks, proposers, inspectors, batchOps, "proposal to grant role in timelock", *cfg.MCMS) if err != nil { return cldf.ChangesetOutput{}, fmt.Errorf("failed to build proposal: %w", err) diff --git a/mcms/changesets/grant_role_timelock_test.go b/mcms/changesets/legacy/grant_role_timelock_test.go similarity index 99% rename from mcms/changesets/grant_role_timelock_test.go rename to mcms/changesets/legacy/grant_role_timelock_test.go index 7cf312e..9890b28 100644 --- a/mcms/changesets/grant_role_timelock_test.go +++ b/mcms/changesets/legacy/grant_role_timelock_test.go @@ -1,4 +1,4 @@ -package changesets +package legacy import ( "fmt" diff --git a/pkg/contract/mcms/propose.go b/mcms/legacy/proposeutils/propose.go similarity index 52% rename from pkg/contract/mcms/propose.go rename to mcms/legacy/proposeutils/propose.go index bcf8074..d1f7ab8 100644 --- a/pkg/contract/mcms/propose.go +++ b/mcms/legacy/proposeutils/propose.go @@ -1,11 +1,13 @@ -package mcms +package proposeutils import ( "encoding/json" "errors" "fmt" + "reflect" "time" + "github.com/aptos-labs/aptos-go-sdk" mapset "github.com/deckarep/golang-set/v2" chain_selectors "github.com/smartcontractkit/chain-selectors" mcmslib "github.com/smartcontractkit/mcms" @@ -14,17 +16,24 @@ import ( mcmssolanasdk "github.com/smartcontractkit/mcms/sdk/solana" "github.com/smartcontractkit/mcms/types" - "github.com/smartcontractkit/cld-changesets/pkg/family/solana" - cldf_adapters "github.com/smartcontractkit/chainlink-deployments-framework/chain/mcms/adapters" cldf "github.com/smartcontractkit/chainlink-deployments-framework/deployment" cldfproposalutils "github.com/smartcontractkit/chainlink-deployments-framework/engine/cld/mcms/proposalutils" + tonstate "github.com/smartcontractkit/chainlink-ton/deployment/state" + + evmstate "github.com/smartcontractkit/cld-changesets/pkg/family/evm/legacy" + solstate "github.com/smartcontractkit/cld-changesets/pkg/family/solana/legacy" ) const ( DefaultValidUntil = 72 * time.Hour ) +var ( + errNoMCMSConfig = errors.New("mcms config is required") + errNoProposalOperations = errors.New("no proposal operations") +) + type ChainMetadata map[uint64]map[string]any func (c *ChainMetadata) Set(chainSelector uint64, key string, value any) *ChainMetadata { @@ -144,7 +153,7 @@ func buildProposalMetadataV2( switch family { case chain_selectors.FamilySolana: - solanaState, err := solana.GetState(env, selector) + solanaState, err := solstate.GetState(env, selector) if err != nil { return nil, err } @@ -225,3 +234,176 @@ func buildProposalMetadataV2( return proposalChainMetadata, nil } + +// AggregateProposals aggregates multiple MCMS proposals into a single proposal by combining their operations, and +// setting up the proposers and inspectors for each chain. It returns a single MCMS proposal that can be executed +// and signed. +// +// Deprecated: Use extensible AggregateProposalsV2 instead. Which accepts multiple chain families. +func AggregateProposals( + env cldf.Environment, + mcmsEVMState map[uint64]evmstate.MCMSWithTimelockState, + mcmsSolanaState map[uint64]solstate.MCMSWithTimelockState, + proposals []mcmslib.TimelockProposal, + description string, + mcmsConfig *cldfproposalutils.TimelockConfig, +) (*mcmslib.TimelockProposal, error) { + return AggregateProposalsV2( + env, + MCMSStates{ + MCMSEVMState: mcmsEVMState, + MCMSSolanaState: mcmsSolanaState, + }, + proposals, + description, + mcmsConfig, + ) +} + +type MCMSStates struct { + MCMSEVMState map[uint64]evmstate.MCMSWithTimelockState + MCMSSolanaState map[uint64]solstate.MCMSWithTimelockState + MCMSAptosState map[uint64]aptos.AccountAddress + MCMSTONState map[uint64]tonstate.MCMSChainState +} + +// AggregateProposalsV2 aggregates multiple MCMS proposals into a single proposal by combining their operations, and +// setting up the proposers and inspectors for each chain. It returns a single MCMS proposal that can be executed +// and signed. +// It has an extensible signature to allow for future chain families implementations +func AggregateProposalsV2( + env cldf.Environment, + mcmsTimelockStates MCMSStates, + proposals []mcmslib.TimelockProposal, + description string, + mcmsConfig *cldfproposalutils.TimelockConfig, + opts ...BuildProposalOption, +) (*mcmslib.TimelockProposal, error) { + if mcmsConfig == nil { + return nil, errNoMCMSConfig + } + + var batches []types.BatchOperation + chainMetadata := make(map[types.ChainSelector]types.ChainMetadata) + + // Add proposals to the aggregate. + for _, proposal := range proposals { + batches = append(batches, proposal.Operations...) + + for selector, metadata := range proposal.ChainMetadata { + existingMetadata, exists := chainMetadata[selector] + if exists { + if !jsonEqual(existingMetadata.AdditionalFields, metadata.AdditionalFields) { + return nil, fmt.Errorf("conflicting metadata for chain selector %d: %#v vs %#v", selector, existingMetadata, metadata) + } + } else { + chainMetadata[selector] = metadata + } + } + } + + // Return early if there are no operations. + if len(batches) == 0 { + return nil, errNoProposalOperations + } + + // Store the timelock and mcm addresses for each chain. + timelocks := make(map[uint64]string) + mcmsPerChain := make(map[uint64]string) + for _, op := range batches { + chainSel := uint64(op.ChainSelector) + var err error + + family, err := chain_selectors.GetSelectorFamily(chainSel) + if err != nil { + return nil, fmt.Errorf("failed to get family for chain %d: %w", chainSel, err) + } + switch family { + case chain_selectors.FamilyEVM: + mcmsEVMState, exists := mcmsTimelockStates.MCMSEVMState[chainSel] + if !exists { + return nil, fmt.Errorf("missing MCMS state for chain with selector %d", chainSel) + } + mcmsContract, err := mcmsConfig.MCMBasedOnAction(mcmsEVMState) + if err != nil { + return &mcmslib.TimelockProposal{}, fmt.Errorf("failed to get MCMS contract for chain with selector %d: %w", chainSel, err) + } + timelocks[chainSel] = mcmsEVMState.Timelock.Address().Hex() + mcmsPerChain[chainSel] = mcmsContract.Address().Hex() + case chain_selectors.FamilySolana: + solanaState, existsInSolana := mcmsTimelockStates.MCMSSolanaState[chainSel] + if !existsInSolana { + return nil, fmt.Errorf("missing MCMS state for chain with selector %d", chainSel) + } + timelocks[chainSel] = mcmssolanasdk.ContractAddress( + solanaState.TimelockProgram, + mcmssolanasdk.PDASeed(solanaState.TimelockSeed), + ) + mcmsAddr, err := mcmsConfig.MCMBasedOnActionSolana(solanaState) + if err != nil { + return nil, err + } + mcmsPerChain[chainSel] = mcmsAddr + case chain_selectors.FamilyAptos: + // Set MCMS addresses. Aptos uses the same address for MCMS and Timelock + aptosMCMSAddress, existsInAptos := mcmsTimelockStates.MCMSAptosState[chainSel] + if !existsInAptos { + return nil, fmt.Errorf("missing MCMS state for chain with selector %d", chainSel) + } + timelocks[chainSel] = aptosMCMSAddress.StringLong() + mcmsPerChain[chainSel] = aptosMCMSAddress.StringLong() + case chain_selectors.FamilyTon: + tonMCMS, exists := mcmsTimelockStates.MCMSTONState[chainSel] + if !exists { + return nil, fmt.Errorf("missing MCMS state for TON chain %d", chainSel) + } + qualifier := mcmsConfig.TimelockQualifierPerChain[chainSel] + // Get the default qualifier suite (or iterate ByQualifier) + suite, ok := tonMCMS.ByQualifier[qualifier] // default qualifier? + if !ok || suite == nil { + return nil, fmt.Errorf("missing TON timelock for chain %d qualifier %q", chainSel, qualifier) + } + if suite.Timelock == nil { + return nil, fmt.Errorf("missing TON timelock address for chain %d", chainSel) + } + timelocks[chainSel] = suite.Timelock.String() + // Select MCMS address based on action + mcmsAddr, err := mcmsConfig.MCMBasedOnActionTon(suite) + if err != nil { + return nil, err + } + mcmsPerChain[chainSel] = mcmsAddr + } + } + + return BuildProposalFromBatchesV2( + env, + timelocks, + mcmsPerChain, + nil, // inspectors will be set automatically + batches, + description, + *mcmsConfig, + opts..., + ) +} + +func jsonEqual(messageA, messageB json.RawMessage) bool { + var unmarshalledA any + if len(messageA) > 0 { + err := json.Unmarshal(messageA, &unmarshalledA) + if err != nil { + return false + } + } + + var unmarshalledB any + if len(messageB) > 0 { + err := json.Unmarshal(messageB, &unmarshalledB) + if err != nil { + return false + } + } + + return reflect.DeepEqual(unmarshalledA, unmarshalledB) +} diff --git a/pkg/contract/mcms/propose_test.go b/mcms/legacy/proposeutils/propose_test.go similarity index 98% rename from pkg/contract/mcms/propose_test.go rename to mcms/legacy/proposeutils/propose_test.go index db16bce..426cdd7 100644 --- a/pkg/contract/mcms/propose_test.go +++ b/mcms/legacy/proposeutils/propose_test.go @@ -1,4 +1,4 @@ -package mcms +package proposeutils import ( "context" diff --git a/mcms/operations/firedrill.go b/mcms/operations/firedrill.go index f916a8f..2e38bc8 100644 --- a/mcms/operations/firedrill.go +++ b/mcms/operations/firedrill.go @@ -18,9 +18,9 @@ import ( cldfproposalutils "github.com/smartcontractkit/chainlink-deployments-framework/engine/cld/mcms/proposalutils" fwops "github.com/smartcontractkit/chainlink-deployments-framework/operations" - mcmscontract "github.com/smartcontractkit/cld-changesets/pkg/contract/mcms" - evmstate "github.com/smartcontractkit/cld-changesets/pkg/family/evm" - solanastate "github.com/smartcontractkit/cld-changesets/pkg/family/solana" + mcmscontract "github.com/smartcontractkit/cld-changesets/mcms/legacy/proposeutils" + evmstate "github.com/smartcontractkit/cld-changesets/pkg/family/evm/legacy" + solanastate "github.com/smartcontractkit/cld-changesets/pkg/family/solana/legacy" ) // FireDrillInput is JSON-serializable input for the MCMS signing fire-drill proposal operation. diff --git a/mcms/operations/firedrill_test.go b/mcms/operations/firedrill_test.go index 1b2e6a3..67b3d91 100644 --- a/mcms/operations/firedrill_test.go +++ b/mcms/operations/firedrill_test.go @@ -15,7 +15,7 @@ import ( mcmstypes "github.com/smartcontractkit/mcms/types" "github.com/stretchr/testify/require" - evmstate "github.com/smartcontractkit/cld-changesets/pkg/family/evm" + evmstate "github.com/smartcontractkit/cld-changesets/pkg/family/evm/legacy" ) func testFireDrillEnv(t *testing.T, chains cldf_chain.BlockChains) cldf.Environment { diff --git a/mcms/operations/grant_role_timelock.go b/mcms/operations/grant_role_timelock.go index 79a6936..6410eca 100644 --- a/mcms/operations/grant_role_timelock.go +++ b/mcms/operations/grant_role_timelock.go @@ -15,7 +15,8 @@ import ( cldfsolana "github.com/smartcontractkit/chainlink-deployments-framework/chain/solana" fwops "github.com/smartcontractkit/chainlink-deployments-framework/operations" - solanastate "github.com/smartcontractkit/cld-changesets/pkg/family/solana" + pdasol "github.com/smartcontractkit/cld-changesets/pkg/family/solana" + solanastate "github.com/smartcontractkit/cld-changesets/pkg/family/solana/legacy" ) type OpSolanaGrantRoleTimelockDeps struct { @@ -57,7 +58,7 @@ var OpSolanaGrantRoleTimelock = fwops.NewOperation( if in.IsDeployerKeyAdmin { signer = deps.Chain.DeployerKey.PublicKey() } else { - signer = solanastate.GetTimelockSignerPDA(in.ChainState.TimelockProgram, in.ChainState.TimelockSeed) + signer = pdasol.GetTimelockSignerPDA(in.ChainState.TimelockProgram, in.ChainState.TimelockSeed) } ix, err := accesscontrollerbindings.NewAddAccessInstruction(accessController, signer, in.Account).ValidateAndBuild() diff --git a/pkg/common/changeset/test_helpers.go b/pkg/common/changeset/test_helpers.go new file mode 100644 index 0000000..fd7ef41 --- /dev/null +++ b/pkg/common/changeset/test_helpers.go @@ -0,0 +1,237 @@ +package changeset + +import ( + "fmt" + "math/big" + "testing" + + mapset "github.com/deckarep/golang-set/v2" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/require" + + evmstate "github.com/smartcontractkit/cld-changesets/pkg/family/evm/legacy" + + cldftesthelpers "github.com/smartcontractkit/chainlink-deployments-framework/engine/cld/mcms/proposalutils/testhelpers" + + "github.com/smartcontractkit/chainlink-evm/pkg/utils" + + cldf_evm "github.com/smartcontractkit/chainlink-deployments-framework/chain/evm" + + "github.com/smartcontractkit/chainlink-deployments-framework/operations" + + mcmsTypes "github.com/smartcontractkit/mcms/types" + + "github.com/smartcontractkit/chainlink-deployments-framework/datastore" + + cldf "github.com/smartcontractkit/chainlink-deployments-framework/deployment" +) + +type ConfiguredChangeSet interface { + Apply(e cldf.Environment) (cldf.ChangesetOutput, error) +} + +func Configure[C any]( + changeset cldf.ChangeSetV2[C], + config C, +) ConfiguredChangeSet { + return configuredChangeSetImpl[C]{ + changeset: changeset, + config: config, + } +} + +type configuredChangeSetImpl[C any] struct { + changeset cldf.ChangeSetV2[C] + config C +} + +func (ca configuredChangeSetImpl[C]) Apply(e cldf.Environment) (cldf.ChangesetOutput, error) { + err := ca.changeset.VerifyPreconditions(e, ca.config) + if err != nil { + return cldf.ChangesetOutput{}, err + } + + return ca.changeset.Apply(e, ca.config) +} + +// Apply applies the changeset applications to the environment and returns the updated environment. This is the +// variadic function equivalent of ApplyChangesets, but allowing you to simply pass in one or more changesets as +// parameters at the end of the function. e.g. `changeset.Apply(t, e, nil, configuredCS1, configuredCS2)` etc. +func Apply(t *testing.T, e cldf.Environment, first ConfiguredChangeSet, rest ...ConfiguredChangeSet) (cldf.Environment, error) { + t.Helper() + + env, _, err := ApplyChangesets(t, e, append([]ConfiguredChangeSet{first}, rest...)) + + return env, err +} + +type applyChangesetOptions struct { + realBackend bool +} + +type ApplyChangesetsOptions func(*applyChangesetOptions) *applyChangesetOptions + +func WithRealBackend() ApplyChangesetsOptions { + return func(o *applyChangesetOptions) *applyChangesetOptions { + o.realBackend = true + return o + } +} + +// ApplyChangesets applies the changeset applications to the environment and returns the updated environment. +func ApplyChangesets(t *testing.T, e cldf.Environment, changesetApplications []ConfiguredChangeSet, opts ...ApplyChangesetsOptions) (cldf.Environment, []cldf.ChangesetOutput, error) { + t.Helper() + + opt := applyChangesetOptions{} + for _, o := range opts { + opt = *o(&opt) + } + + currentEnv := e + outputs := make([]cldf.ChangesetOutput, 0, len(changesetApplications)) + for i, csa := range changesetApplications { + out, err := csa.Apply(currentEnv) + if err != nil { + return e, nil, fmt.Errorf("failed to apply changeset at index %d: %w", i, err) + } + outputs = append(outputs, out) + var addresses cldf.AddressBook + if out.AddressBook != nil { //nolint:staticcheck // legacy AddressBook is still supported by test helper while changesets migrate to DataStore + addresses = out.AddressBook //nolint:staticcheck // legacy AddressBook is still supported by test helper while changesets migrate to DataStore + if err = addresses.Merge(currentEnv.ExistingAddresses); err != nil { //nolint:staticcheck // merge legacy addresses for compatibility + return e, nil, fmt.Errorf("failed to merge address book: %w", err) + } + } else { + addresses = currentEnv.ExistingAddresses //nolint:staticcheck // preserve legacy AddressBook state in test helper + } + + // Collect expected DataStore state after changeset is applied + var ds datastore.DataStore + if out.DataStore != nil { + ds1 := datastore.NewMemoryDataStore() + // New Addresses + if err = ds1.Merge(out.DataStore.Seal()); err != nil { + return e, nil, fmt.Errorf("failed to merge new addresses into datastore: %w", err) + } + // Existing Addresses + err = ds1.Merge(currentEnv.DataStore) + if err != nil { + return e, nil, fmt.Errorf("failed to merge current addresses into datastore: %w", err) + } + ds = ds1.Seal() + } else { + ds = currentEnv.DataStore + } + + if out.Jobs != nil { //nolint:revive,staticcheck // we want the empty block as documentation + // do nothing, as these jobs auto-accept. + } + + // Updated environment may be required before executing proposals when proposals involve new addresses + // Ex. changesets[0] deploys MCMS, changesets[1] generates a proposal with the new MCMS addresses + currentEnv = cldf.Environment{ + Name: e.Name, + Logger: e.Logger, + ExistingAddresses: addresses, //nolint:staticcheck // preserve legacy AddressBook state in test helper + DataStore: ds, + NodeIDs: e.NodeIDs, + Offchain: e.Offchain, + OCRSecrets: e.OCRSecrets, + GetContext: e.GetContext, + OperationsBundle: operations.NewBundle(e.GetContext, e.Logger, operations.NewMemoryReporter()), // to ensure that each migration is run in a clean environment + BlockChains: e.BlockChains, + } + + if out.MCMSTimelockProposals != nil { + for _, prop := range out.MCMSTimelockProposals { + chains := mapset.NewSet[uint64]() + for _, op := range prop.Operations { + chains.Add(uint64(op.ChainSelector)) + } + + // We need to supply a salt override, otherwise the validUntil timestamp will be used to generate the salt. + // In tests, validUntil is not always guaranteed to produce a unique operation ID because proposals often get generated within the same second. + // This has been a cause of flakiness in the past (caused an AlreadyScheduled error). + saltOverride := utils.RandomHash() + prop.SaltOverride = &saltOverride + + p := cldftesthelpers.SignMCMSTimelockProposal(t, currentEnv, &prop, opt.realBackend) + err = cldftesthelpers.ExecuteMCMSProposalV2(t, currentEnv, p) + if err != nil { + return cldf.Environment{}, nil, err + } + if prop.Action != mcmsTypes.TimelockActionSchedule { + // We don't need to execute the proposal if it's not a schedule action + // because the proposal is already executed in the previous step. + return currentEnv, outputs, nil + } + err = cldftesthelpers.ExecuteMCMSTimelockProposalV2(t, currentEnv, &prop) + if err != nil { + return cldf.Environment{}, nil, err + } + } + } + if out.MCMSProposals != nil { + for _, prop := range out.MCMSProposals { + chains := mapset.NewSet[uint64]() + for _, op := range prop.Operations { + chains.Add(uint64(op.ChainSelector)) + } + + p := cldftesthelpers.SignMCMSProposal(t, currentEnv, &prop) + err = cldftesthelpers.ExecuteMCMSProposalV2(t, currentEnv, p) + if err != nil { + return cldf.Environment{}, nil, err + } + } + } + } + + return currentEnv, outputs, nil +} + +func MustFundAddressWithLink(t *testing.T, e cldf.Environment, chain cldf_evm.Chain, to common.Address, amount int64) { + t.Helper() + + addresses, err := e.ExistingAddresses.AddressesForChain(chain.Selector) //nolint:staticcheck // legacy helper still loads LINK from AddressBook + require.NoError(t, err) + + linkState, err := evmstate.MaybeLoadLinkTokenChainState(chain, addresses) + require.NoError(t, err) + require.NotNil(t, linkState.LinkToken) + + // grant minter permissions - only owner can call this function + e.Logger.Info("granting minter permissions for chain", chain.DeployerKey) + tx, err := linkState.LinkToken.GrantMintRole(chain.DeployerKey, chain.DeployerKey.From) + require.NoError(t, err) + _, err = cldf.ConfirmIfNoError(chain, tx, err) + require.NoError(t, err) + + // Mint 'To' address some tokens + tx, err = linkState.LinkToken.Mint(chain.DeployerKey, to, big.NewInt(amount)) + require.NoError(t, err) + _, err = cldf.ConfirmIfNoError(chain, tx, err) + require.NoError(t, err) + + // 'To' address should have the tokens + ctx := e.GetContext() + endBalance, err := linkState.LinkToken.BalanceOf(&bind.CallOpts{Context: ctx}, to) + require.NoError(t, err) + expectedBalance := big.NewInt(amount) + require.Equal(t, expectedBalance, endBalance) +} + +// MaybeGetLinkBalance returns the LINK balance of the given address on the given chain. +func MaybeGetLinkBalance(t *testing.T, e cldf.Environment, chain cldf_evm.Chain, linkAddr common.Address) *big.Int { + t.Helper() + + addresses, err := e.ExistingAddresses.AddressesForChain(chain.Selector) //nolint:staticcheck // legacy helper still loads LINK from AddressBook + require.NoError(t, err) + linkState, err := evmstate.MaybeLoadLinkTokenChainState(chain, addresses) + require.NoError(t, err) + endBalance, err := linkState.LinkToken.BalanceOf(&bind.CallOpts{Context: chain.DeployerKey.Context}, linkAddr) + require.NoError(t, err) + + return endBalance +} diff --git a/pkg/common/version.go b/pkg/common/version.go index b53c72c..458135b 100644 --- a/pkg/common/version.go +++ b/pkg/common/version.go @@ -1,4 +1,4 @@ -package common +package common //nolint:revive // package name is part of the public repo layout import ( "github.com/Masterminds/semver/v3" diff --git a/pkg/contract/link/view/v1_0/link_token.go b/pkg/contract/link/view/v10/link_token.go similarity index 99% rename from pkg/contract/link/view/v1_0/link_token.go rename to pkg/contract/link/view/v10/link_token.go index 79412f6..2a8ccd7 100644 --- a/pkg/contract/link/view/v1_0/link_token.go +++ b/pkg/contract/link/view/v10/link_token.go @@ -1,4 +1,4 @@ -package v1_0 +package v10 import ( "fmt" diff --git a/pkg/contract/link/view/v1_0/link_token_test.go b/pkg/contract/link/view/v10/link_token_test.go similarity index 99% rename from pkg/contract/link/view/v1_0/link_token_test.go rename to pkg/contract/link/view/v10/link_token_test.go index cac8484..8a5efb2 100644 --- a/pkg/contract/link/view/v1_0/link_token_test.go +++ b/pkg/contract/link/view/v10/link_token_test.go @@ -1,4 +1,4 @@ -package v1_0 +package v10 import ( "math/big" diff --git a/pkg/contract/link/view/v1_0/static_link_token.go b/pkg/contract/link/view/v10/static_link_token.go similarity index 98% rename from pkg/contract/link/view/v1_0/static_link_token.go rename to pkg/contract/link/view/v10/static_link_token.go index 14ae1db..c53bd34 100644 --- a/pkg/contract/link/view/v1_0/static_link_token.go +++ b/pkg/contract/link/view/v10/static_link_token.go @@ -1,4 +1,4 @@ -package v1_0 +package v10 import ( "fmt" diff --git a/pkg/contract/link/view/v1_0/static_link_token_test.go b/pkg/contract/link/view/v10/static_link_token_test.go similarity index 93% rename from pkg/contract/link/view/v1_0/static_link_token_test.go rename to pkg/contract/link/view/v10/static_link_token_test.go index 92a99db..b8b08aa 100644 --- a/pkg/contract/link/view/v1_0/static_link_token_test.go +++ b/pkg/contract/link/view/v10/static_link_token_test.go @@ -1,4 +1,4 @@ -package v1_0 +package v10 //nolint:revive // package name mirrors versioned contract view path import ( "testing" diff --git a/pkg/contract/mcms/view/v1_0/mcms.go b/pkg/contract/mcms/view/v1_0/mcms.go index 12a30c1..8108a2f 100644 --- a/pkg/contract/mcms/view/v1_0/mcms.go +++ b/pkg/contract/mcms/view/v1_0/mcms.go @@ -1,4 +1,4 @@ -package v1_0 +package v1_0 //nolint:revive // package name mirrors versioned contract view path import ( "context" diff --git a/pkg/family/aptos/state.go b/pkg/family/aptos/legacy/state.go similarity index 99% rename from pkg/family/aptos/state.go rename to pkg/family/aptos/legacy/state.go index 2e4040e..857b240 100644 --- a/pkg/family/aptos/state.go +++ b/pkg/family/aptos/legacy/state.go @@ -1,4 +1,4 @@ -package aptos +package legacy import ( "fmt" diff --git a/pkg/family/aptos/state_test.go b/pkg/family/aptos/legacy/state_test.go similarity index 88% rename from pkg/family/aptos/state_test.go rename to pkg/family/aptos/legacy/state_test.go index 3ff4142..7dfaa84 100644 --- a/pkg/family/aptos/state_test.go +++ b/pkg/family/aptos/legacy/state_test.go @@ -1,4 +1,4 @@ -package aptos +package legacy import ( "context" @@ -15,7 +15,7 @@ import ( "github.com/smartcontractkit/chainlink-deployments-framework/offchain/ocr" "github.com/smartcontractkit/chainlink-deployments-framework/pkg/logger" - "github.com/smartcontractkit/cld-changesets/pkg/common" + cldchangesetscommon "github.com/smartcontractkit/cld-changesets/pkg/common" ) const testAptosMCMSAddr = "0x3" @@ -42,7 +42,7 @@ func TestLoadMCMSAddresses(t *testing.T) { t.Parallel() ab := cldf.NewMemoryAddressBook() - require.NoError(t, ab.Save(chainSel, testAptosMCMSAddr, cldf.NewTypeAndVersion(AptosMCMSType, common.Version1_6_0))) + require.NoError(t, ab.Save(chainSel, testAptosMCMSAddr, cldf.NewTypeAndVersion(AptosMCMSType, cldchangesetscommon.Version1_6_0))) ds := datastore.NewMemoryDataStore().Seal() env := testEnv(t, ab, ds) @@ -59,7 +59,7 @@ func TestLoadMCMSAddresses(t *testing.T) { t.Parallel() ab := cldf.NewMemoryAddressBook() - other := cldf.NewTypeAndVersion("SomeOtherContract", common.Version1_0_0) + other := cldf.NewTypeAndVersion("SomeOtherContract", cldchangesetscommon.Version1_0_0) require.NoError(t, ab.Save(chainSel, "0x1", other)) ds := datastore.NewMemoryDataStore().Seal() env := testEnv(t, ab, ds) @@ -86,7 +86,7 @@ func TestLoadMCMSAddresses(t *testing.T) { t.Parallel() ab := cldf.NewMemoryAddressBook() - require.NoError(t, ab.Save(chainSel, testAptosMCMSAddr, cldf.NewTypeAndVersion(AptosMCMSType, common.Version1_5_0))) + require.NoError(t, ab.Save(chainSel, testAptosMCMSAddr, cldf.NewTypeAndVersion(AptosMCMSType, cldchangesetscommon.Version1_5_0))) ds := datastore.NewMemoryDataStore().Seal() env := testEnv(t, ab, ds) @@ -99,7 +99,7 @@ func TestLoadMCMSAddresses(t *testing.T) { t.Parallel() ab := cldf.NewMemoryAddressBook() - require.NoError(t, ab.Save(chainSel, "NotHex", cldf.NewTypeAndVersion(AptosMCMSType, common.Version1_6_0))) + require.NoError(t, ab.Save(chainSel, "NotHex", cldf.NewTypeAndVersion(AptosMCMSType, cldchangesetscommon.Version1_6_0))) ds := datastore.NewMemoryDataStore().Seal() env := testEnv(t, ab, ds) @@ -107,7 +107,7 @@ func TestLoadMCMSAddresses(t *testing.T) { require.ErrorContains(t, err, fmt.Sprintf( "failed to parse Aptos MCMS address for chain %d (type=%s, version=%s, address=NotHex)", - chainSel, AptosMCMSType, common.Version1_6_0.String(), + chainSel, AptosMCMSType, cldchangesetscommon.Version1_6_0.String(), )) var scratch aptoschain.AccountAddress parseErr := scratch.ParseStringRelaxed("NotHex") diff --git a/pkg/family/evm/changesets/deploy_mcms_with_timelock.go b/pkg/family/evm/changesets/deploy_mcms_with_timelock.go new file mode 100644 index 0000000..79357d7 --- /dev/null +++ b/pkg/family/evm/changesets/deploy_mcms_with_timelock.go @@ -0,0 +1,419 @@ +package changesets + +import ( + "context" + "errors" + "fmt" + "math" + "math/big" + "slices" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + bindings "github.com/smartcontractkit/ccip-owner-contracts/pkg/gethwrappers" + cldf_evm "github.com/smartcontractkit/chainlink-deployments-framework/chain/evm" + cldf "github.com/smartcontractkit/chainlink-deployments-framework/deployment" + mcmscontracts "github.com/smartcontractkit/chainlink-deployments-framework/engine/cld/contracts/mcms" + cldfproposalutils "github.com/smartcontractkit/chainlink-deployments-framework/engine/cld/mcms/proposalutils" + "github.com/smartcontractkit/chainlink-deployments-framework/operations" + "github.com/spf13/cast" + + "github.com/smartcontractkit/cld-changesets/pkg/contract/mcms/view/v1_0" + evmstate "github.com/smartcontractkit/cld-changesets/pkg/family/evm/legacy" + opsevm "github.com/smartcontractkit/cld-changesets/pkg/family/evm/operations" + seqs "github.com/smartcontractkit/cld-changesets/pkg/family/evm/sequences" +) + +// DeployMCMSOption is a function that modifies a TypeAndVersion before or after deployment. +type DeployMCMSOption func(*cldf.TypeAndVersion) + +// WithLabel is a functional option that sets a label on the TypeAndVersion. +func WithLabel(label string) DeployMCMSOption { + return func(tv *cldf.TypeAndVersion) { + tv.AddLabel(label) + } +} + +// MCMSWithTimelockEVMDeploy holds a bundle of MCMS contract deploys. +type MCMSWithTimelockEVMDeploy struct { + Canceller *cldf.ContractDeploy[*bindings.ManyChainMultiSig] + Bypasser *cldf.ContractDeploy[*bindings.ManyChainMultiSig] + Proposer *cldf.ContractDeploy[*bindings.ManyChainMultiSig] + Timelock *cldf.ContractDeploy[*bindings.RBACTimelock] + CallProxy *cldf.ContractDeploy[*bindings.CallProxy] +} + +// DeployMCMSWithTimelockContractsEVM deploys an MCMS for +// each of the timelock roles Bypasser, ProposerMcm, Canceller on an EVM chain. +// MCMS contracts for the given configuration +// as well as the timelock. It's not necessarily the only way to use +// the timelock and MCMS, but its reasonable pattern. +func DeployMCMSWithTimelockContractsEVM( + env cldf.Environment, + chain cldf_evm.Chain, + ab cldf.AddressBook, + config cldfproposalutils.MCMSWithTimelockConfig, + state *evmstate.MCMSWithTimelockState, +) ([]operations.Report[any, any], error) { + execReports := make([]operations.Report[any, any], 0) + lggr := env.Logger + opts := []func(*cldf.TypeAndVersion){} + if config.Label != nil { + opts = append(opts, WithLabel(*config.Label)) + } + var bypasser, proposer, canceller *bindings.ManyChainMultiSig + var timelock *bindings.RBACTimelock + var callProxy *bindings.CallProxy + if state != nil { + bypasser = state.BypasserMcm + proposer = state.ProposerMcm + canceller = state.CancellerMcm + timelock = state.Timelock + callProxy = state.CallProxy + } + if bypasser == nil { + seqInput := seqs.SeqDeployMCMWithConfigInput{ + ContractType: mcmscontracts.BypasserManyChainMultisig, + MCMConfig: config.Bypasser, + ChainSelector: chain.Selector, + GasBoostConfig: config.GasBoostConfig, + } + + report, err := operations.ExecuteSequence( + env.OperationsBundle, + seqs.SeqEVMDeployMCMWithConfig, + chain, + seqInput, + ) + execReports = append(execReports, report.ExecutionReports...) + if err != nil { + lggr.Errorw("Failed to deploy bypasser MCMS", "chain", chain.String(), "err", err) + return execReports, err + } + typeAndVersion := cldf.MustTypeAndVersionFromString(report.Output.TypeAndVersion) + for _, option := range opts { + option(&typeAndVersion) + } + err = ab.Save(chain.Selector, report.Output.Address.Hex(), typeAndVersion) + if err != nil { + lggr.Errorw("Failed to save bypasser MCMS address in address book", "chain", chain.String(), "err", err) + return execReports, err + } + + bypasser, err = bindings.NewManyChainMultiSig(report.Output.Address, chain.Client) + if err != nil { + lggr.Errorw("Failed to create bypasser MCMS binding", "chain", chain.String(), "err", err) + return execReports, err + } + lggr.Infow("Bypasser MCMS deployed", "chain", chain.String(), "address", bypasser.Address().String()) + } else { + lggr.Infow("Bypasser MCMS already deployed", "chain", chain.String(), "address", bypasser.Address().String()) + } + + if canceller == nil { + seqInput := seqs.SeqDeployMCMWithConfigInput{ + ContractType: mcmscontracts.CancellerManyChainMultisig, + MCMConfig: config.Canceller, + ChainSelector: chain.Selector, + GasBoostConfig: config.GasBoostConfig, + } + + report, err := operations.ExecuteSequence( + env.OperationsBundle, + seqs.SeqEVMDeployMCMWithConfig, + chain, + seqInput, + ) + execReports = append(execReports, report.ExecutionReports...) + if err != nil { + lggr.Errorw("Failed to deploy Canceller MCMS", "chain", chain.String(), "err", err) + return execReports, err + } + typeAndVersion := cldf.MustTypeAndVersionFromString(report.Output.TypeAndVersion) + for _, option := range opts { + option(&typeAndVersion) + } + err = ab.Save(chain.Selector, report.Output.Address.Hex(), typeAndVersion) + if err != nil { + lggr.Errorw("Failed to save canceller MCMS address in address book", "chain", chain.String(), "err", err) + return execReports, err + } + + canceller, err = bindings.NewManyChainMultiSig(report.Output.Address, chain.Client) + if err != nil { + lggr.Errorw("Failed to create Canceller MCMS binding", "chain", chain.String(), "err", err) + return execReports, err + } + lggr.Infow("Canceller MCMS deployed", "chain", chain.String(), "address", canceller.Address().String()) + } else { + lggr.Infow("Canceller MCMS already deployed", "chain", chain.String(), "address", canceller.Address().String()) + } + + if proposer == nil { + seqInput := seqs.SeqDeployMCMWithConfigInput{ + ContractType: mcmscontracts.ProposerManyChainMultisig, + MCMConfig: config.Proposer, + ChainSelector: chain.Selector, + GasBoostConfig: config.GasBoostConfig, + } + + report, err := operations.ExecuteSequence( + env.OperationsBundle, + seqs.SeqEVMDeployMCMWithConfig, + chain, + seqInput, + ) + execReports = append(execReports, report.ExecutionReports...) + if err != nil { + lggr.Errorw("Failed to deploy Proposer MCMS", "chain", chain.String(), "err", err) + return execReports, err + } + typeAndVersion := cldf.MustTypeAndVersionFromString(report.Output.TypeAndVersion) + for _, option := range opts { + option(&typeAndVersion) + } + err = ab.Save(chain.Selector, report.Output.Address.Hex(), typeAndVersion) + if err != nil { + lggr.Errorw("Failed to save proposer MCMS address in address book", "chain", chain.String(), "err", err) + return execReports, err + } + + proposer, err = bindings.NewManyChainMultiSig(report.Output.Address, chain.Client) + if err != nil { + lggr.Errorw("Failed to create Proposer MCMS binding", "chain", chain.String(), "err", err) + return execReports, err + } + lggr.Infow("Proposer MCMS deployed", "chain", chain.String(), "address", proposer.Address().String()) + } else { + lggr.Infow("Proposer MCMS already deployed", "chain", chain.String(), "address", proposer.Address().String()) + } + + if timelock == nil { + opInput := opsevm.OpEVMDeployTimelockInput{ + // Deployer is the initial admin. + // TODO: Could expose this as config? + // Or keep this enforced to follow the same pattern? + Admin: chain.DeployerKey.From, + Proposers: []common.Address{proposer.Address()}, + // Executors field is empty here because we grant the executor role to the call proxy later + // and the call proxy cannot be deployed before the timelock. + Executors: []common.Address{}, + Cancellers: []common.Address{canceller.Address(), proposer.Address(), bypasser.Address()}, // cancellers + Bypassers: []common.Address{bypasser.Address()}, // bypassers + TimelockMinDelay: config.TimelockMinDelay, + } + + report, err := operations.ExecuteOperation( + env.OperationsBundle, + opsevm.OpEVMDeployTimelock, + chain, + opsevm.EVMDeployInput[opsevm.OpEVMDeployTimelockInput]{ + ChainSelector: chain.Selector, + DeployInput: opInput, + }, + opsevm.RetryDeploymentWithGasBoost[opsevm.OpEVMDeployTimelockInput](config.GasBoostConfig), + ) + execReports = append(execReports, report.ToGenericReport()) + if err != nil { + lggr.Errorw("Failed to deploy timelock", "chain", chain.String(), "err", err) + return execReports, err + } + typeAndVersion := cldf.MustTypeAndVersionFromString(report.Output.TypeAndVersion) + for _, option := range opts { + option(&typeAndVersion) + } + err = ab.Save(chain.Selector, report.Output.Address.Hex(), typeAndVersion) + if err != nil { + lggr.Errorw("Failed to save timelock address in address book", "chain", chain.String(), "err", err) + return execReports, err + } + + timelock, err = bindings.NewRBACTimelock(report.Output.Address, chain.Client) + if err != nil { + lggr.Errorw("Failed to create Timelock binding", "chain", chain.String(), "err", err) + return execReports, err + } + + lggr.Infow("Timelock deployed", "chain", chain.String(), "address", timelock.Address().String()) + } else { + lggr.Infow("Timelock already deployed", "chain", chain.String(), "address", timelock.Address().String()) + } + + if callProxy == nil { + opInput := opsevm.OpEVMDeployCallProxyInput{ + Timelock: timelock.Address(), + } + + report, err := operations.ExecuteOperation( + env.OperationsBundle, + opsevm.OpEVMDeployCallProxy, + chain, + opsevm.EVMDeployInput[opsevm.OpEVMDeployCallProxyInput]{ + ChainSelector: chain.Selector, + DeployInput: opInput, + }, + opsevm.RetryDeploymentWithGasBoost[opsevm.OpEVMDeployCallProxyInput](config.GasBoostConfig), + ) + execReports = append(execReports, report.ToGenericReport()) + if err != nil { + lggr.Errorw("Failed to deploy CallProxy", "chain", chain.String(), "err", err) + return execReports, err + } + typeAndVersion := cldf.MustTypeAndVersionFromString(report.Output.TypeAndVersion) + for _, option := range opts { + option(&typeAndVersion) + } + err = ab.Save(chain.Selector, report.Output.Address.Hex(), typeAndVersion) + if err != nil { + lggr.Errorw("Failed to save CallProxy address in address book", "chain", chain.String(), "err", err) + } + + callProxy, err = bindings.NewCallProxy(report.Output.Address, chain.Client) + if err != nil { + lggr.Errorw("Failed to create CallProxy binding", "chain", chain.String(), "err", err) + return execReports, err + } + lggr.Infow("CallProxy deployed", "chain", chain.String(), "address", callProxy.Address().String()) + } else { + lggr.Infow("CallProxy already deployed", "chain", chain.String(), "address", callProxy.Address().String()) + } + timelockContracts := &cldfproposalutils.MCMSWithTimelockContracts{ + BypasserMcm: bypasser, + ProposerMcm: proposer, + CancellerMcm: canceller, + Timelock: timelock, + CallProxy: callProxy, + } + // grant roles for timelock + // this is called only if deployer key is an admin in timelock + seqReport, err := GrantRolesForTimelock(env, chain, timelockContracts, true, config.GasBoostConfig) + execReports = append(execReports, seqReport.ExecutionReports...) + if err != nil { + return execReports, err + } + // After the proposer cycle is validated, + // we can remove the deployer as an admin. + return execReports, nil +} + +// TODO: delete this function after it is available in timelock Inspector +func getAdminAddresses(ctx context.Context, timelock *bindings.RBACTimelock) ([]string, error) { + numAddresses, err := timelock.GetRoleMemberCount(&bind.CallOpts{ + Context: ctx, + }, v1_0.ADMIN_ROLE.ID) + if err != nil { + return nil, err + } + adminAddresses := make([]string, 0, numAddresses.Uint64()) + for i := range numAddresses.Uint64() { + if i > math.MaxUint32 { + return nil, fmt.Errorf("value %d exceeds uint32 range", i) + } + idx, err := cast.ToInt64E(i) + if err != nil { + return nil, err + } + address, err := timelock.GetRoleMember(&bind.CallOpts{ + Context: ctx, + }, v1_0.ADMIN_ROLE.ID, big.NewInt(idx)) + if err != nil { + return nil, err + } + adminAddresses = append(adminAddresses, address.String()) + } + + return adminAddresses, nil +} + +func GrantRolesForTimelock( + env cldf.Environment, + chain cldf_evm.Chain, + timelockContracts *cldfproposalutils.MCMSWithTimelockContracts, + skipIfDeployerKeyNotAdmin bool, // If true, skip role grants if the deployer key is not an admin. + gasBoostConfig *cldfproposalutils.GasBoostConfig, +) (operations.SequenceReport[seqs.SeqGrantRolesTimelockInput, map[uint64][]opsevm.EVMCallOutput], error) { + lggr := env.Logger + ctx := env.GetContext() + + if timelockContracts == nil { + lggr.Errorw("Timelock contracts not found", "chain", chain.String()) + return operations.SequenceReport[seqs.SeqGrantRolesTimelockInput, map[uint64][]opsevm.EVMCallOutput]{}, fmt.Errorf("timelock contracts not found for chain %s", chain.String()) + } + + timelock := timelockContracts.Timelock + proposer := timelockContracts.ProposerMcm + canceller := timelockContracts.CancellerMcm + bypasser := timelockContracts.BypasserMcm + callProxy := timelockContracts.CallProxy + + // get admin addresses + adminAddresses, err := getAdminAddresses(ctx, timelock) + if err != nil { + return operations.SequenceReport[seqs.SeqGrantRolesTimelockInput, map[uint64][]opsevm.EVMCallOutput]{}, fmt.Errorf("failed to get admin addresses: %w", err) + } + isDeployerKeyAdmin := slices.Contains(adminAddresses, chain.DeployerKey.From.String()) + isTimelockAdmin := slices.Contains(adminAddresses, timelock.Address().String()) + if !isDeployerKeyAdmin && skipIfDeployerKeyNotAdmin { + lggr.Infow("Deployer key is not admin, skipping role grants", "chain", chain.String()) + return operations.SequenceReport[seqs.SeqGrantRolesTimelockInput, map[uint64][]opsevm.EVMCallOutput]{}, nil + } + if !isDeployerKeyAdmin && !isTimelockAdmin { + return operations.SequenceReport[seqs.SeqGrantRolesTimelockInput, map[uint64][]opsevm.EVMCallOutput]{}, errors.New("neither deployer key nor timelock is admin, cannot grant roles") + } + + seqDeps := seqs.SeqGrantRolesTimelockDeps{ + Chain: chain, + } + + seqInput := seqs.SeqGrantRolesTimelockInput{ + ContractType: mcmscontracts.RBACTimelock, + ChainSelector: chain.Selector, + Timelock: timelock.Address(), + IsDeployerKeyAdmin: isDeployerKeyAdmin, + RolesAndAddresses: []seqs.RolesAndAddresses{ + { + Role: v1_0.PROPOSER_ROLE.ID, + Name: v1_0.PROPOSER_ROLE.Name, + Addresses: []common.Address{proposer.Address()}, + }, + { + Role: v1_0.CANCELLER_ROLE.ID, + Name: v1_0.CANCELLER_ROLE.Name, + Addresses: []common.Address{proposer.Address(), canceller.Address(), bypasser.Address()}, + }, + { + Role: v1_0.BYPASSER_ROLE.ID, + Name: v1_0.BYPASSER_ROLE.Name, + Addresses: []common.Address{bypasser.Address()}, + }, + { + Role: v1_0.EXECUTOR_ROLE.ID, + Name: v1_0.EXECUTOR_ROLE.Name, + Addresses: []common.Address{callProxy.Address()}, + }, + }, + GasBoostConfig: gasBoostConfig, + } + + if !isTimelockAdmin { + // We grant the timelock the admin role on the MCMS contracts. + seqInput.RolesAndAddresses = append(seqInput.RolesAndAddresses, seqs.RolesAndAddresses{ + Role: v1_0.ADMIN_ROLE.ID, + Name: v1_0.ADMIN_ROLE.Name, + Addresses: []common.Address{timelock.Address()}, + }) + } + + report, err := operations.ExecuteSequence( + env.OperationsBundle, + seqs.SeqGrantRolesTimelock, + seqDeps, + seqInput, + ) + if err != nil { + lggr.Errorw("Failed to grant roles for timelock", "chain", chain.String(), "err", err) + return operations.SequenceReport[seqs.SeqGrantRolesTimelockInput, map[uint64][]opsevm.EVMCallOutput]{}, err + } + + return report, nil +} diff --git a/pkg/family/evm/legacy/ownable.go b/pkg/family/evm/legacy/ownable.go new file mode 100644 index 0000000..e709b1a --- /dev/null +++ b/pkg/family/evm/legacy/ownable.go @@ -0,0 +1,14 @@ +package legacy + +import ( + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + gethtypes "github.com/ethereum/go-ethereum/core/types" +) + +type Ownable interface { + Owner(opts *bind.CallOpts) (common.Address, error) + TransferOwnership(opts *bind.TransactOpts, newOwner common.Address) (*gethtypes.Transaction, error) + AcceptOwnership(opts *bind.TransactOpts) (*gethtypes.Transaction, error) + Address() common.Address +} diff --git a/pkg/family/evm/proposal_adapter.go b/pkg/family/evm/legacy/proposal_adapter.go similarity index 70% rename from pkg/family/evm/proposal_adapter.go rename to pkg/family/evm/legacy/proposal_adapter.go index d3baab9..a40712a 100644 --- a/pkg/family/evm/proposal_adapter.go +++ b/pkg/family/evm/legacy/proposal_adapter.go @@ -1,15 +1,11 @@ -package evm +package legacy import ( cldfproposalutils "github.com/smartcontractkit/chainlink-deployments-framework/engine/cld/mcms/proposalutils" ) // TimelockContracts implements [cldfproposalutils.EVMMCMSWithTimelock] for MCMS timelock proposal helpers. -func (s *MCMSWithTimelockState) TimelockContracts() cldfproposalutils.MCMSWithTimelockContracts { - if s == nil { - return cldfproposalutils.MCMSWithTimelockContracts{} - } - +func (s MCMSWithTimelockState) TimelockContracts() cldfproposalutils.MCMSWithTimelockContracts { return cldfproposalutils.MCMSWithTimelockContracts{ CancellerMcm: s.CancellerMcm, BypasserMcm: s.BypasserMcm, diff --git a/pkg/family/evm/state.go b/pkg/family/evm/legacy/state.go similarity index 99% rename from pkg/family/evm/state.go rename to pkg/family/evm/legacy/state.go index 7c03448..d78af5c 100644 --- a/pkg/family/evm/state.go +++ b/pkg/family/evm/legacy/state.go @@ -1,4 +1,4 @@ -package evm +package legacy import ( "errors" @@ -16,7 +16,7 @@ import ( "github.com/smartcontractkit/chainlink-evm/gethwrappers/shared/generated/initial/link_token" cldchangesetscommon "github.com/smartcontractkit/cld-changesets/pkg/common" - linkv10 "github.com/smartcontractkit/cld-changesets/pkg/contract/link/view/v1_0" + linkv10 "github.com/smartcontractkit/cld-changesets/pkg/contract/link/view/v10" "github.com/smartcontractkit/cld-changesets/pkg/contract/mcms/view/v1_0" ) diff --git a/pkg/family/evm/state_test.go b/pkg/family/evm/legacy/state_test.go similarity index 96% rename from pkg/family/evm/state_test.go rename to pkg/family/evm/legacy/state_test.go index 614a324..fcc11d4 100644 --- a/pkg/family/evm/state_test.go +++ b/pkg/family/evm/legacy/state_test.go @@ -1,4 +1,4 @@ -package evm +package legacy import ( "context" @@ -133,35 +133,33 @@ func TestGetAddressTypeVersionByQualifier(t *testing.T) { require.True(t, tv.Labels.Contains(mcmscontracts.ProposerRole.String())) }) - t.Run("nil version only returns error without panic", func(t *testing.T) { + t.Run("memory datastore rejects nil version refs", func(t *testing.T) { t.Parallel() ds := datastore.NewMemoryDataStore() - require.NoError(t, ds.Addresses().Add(datastore.AddressRef{ + err := ds.Addresses().Add(datastore.AddressRef{ Address: "0x0000000000000000000000000000000000000001", ChainSelector: chainSel, Type: datastore.ContractType(linkcontracts.LinkToken), - })) - var err error - require.NotPanics(t, func() { - _, err = GetAddressTypeVersionByQualifier(ds.Seal().Addresses(), chainSel, "") }) - require.ErrorContains(t, err, "no address refs with a non-nil contract version") + require.ErrorContains(t, err, "version is required") }) - t.Run("nil version skipped when another ref has version", func(t *testing.T) { + t.Run("memory datastore rejects nil version before mixed refs can be queried", func(t *testing.T) { t.Parallel() ds := datastore.NewMemoryDataStore() - require.NoError(t, ds.Addresses().Add(datastore.AddressRef{ - Address: "0x0000000000000000000000000000000000000001", - ChainSelector: chainSel, - Type: datastore.ContractType(linkcontracts.LinkToken), - })) require.NoError(t, ds.Addresses().Add(datastore.AddressRef{ Address: "0x0000000000000000000000000000000000000002", ChainSelector: chainSel, Type: datastore.ContractType(mcmscontracts.CallProxy), Version: &v, })) + err := ds.Addresses().Add(datastore.AddressRef{ + Address: "0x0000000000000000000000000000000000000001", + ChainSelector: chainSel, + Type: datastore.ContractType(linkcontracts.LinkToken), + }) + require.ErrorContains(t, err, "version is required") + got, err := GetAddressTypeVersionByQualifier(ds.Seal().Addresses(), chainSel, "") require.NoError(t, err) require.Len(t, got, 1) @@ -286,24 +284,15 @@ func TestMaybeLoadMCMSWithTimelockStateWithQualifier(t *testing.T) { require.Nil(t, st.Timelock) }) - t.Run("datastore only nil version refs merge falls back to empty address map", func(t *testing.T) { + t.Run("memory datastore rejects nil version refs before state loading", func(t *testing.T) { t.Parallel() ds := datastore.NewMemoryDataStore() - require.NoError(t, ds.Addresses().Add(datastore.AddressRef{ + err := ds.Addresses().Add(datastore.AddressRef{ Address: "0x0000000000000000000000000000000000000001", ChainSelector: chainSel, Type: datastore.ContractType(linkcontracts.LinkToken), - })) - evmCh := cldf_evm.Chain{Selector: chainSel, Client: nil} - env := testEVMEnv(t, ds.Seal(), chain.NewBlockChains(map[uint64]chain.BlockChain{ - chainSel: evmCh, - })) - got, err := MaybeLoadMCMSWithTimelockStateWithQualifier(env, []uint64{chainSel}, "") - require.NoError(t, err) - require.Len(t, got, 1) - st := got[chainSel] - require.NotNil(t, st) - require.Nil(t, st.Timelock) + }) + require.ErrorContains(t, err, "version is required") }) } diff --git a/pkg/family/evm/operations/callproxy_deploy.go b/pkg/family/evm/operations/callproxy_deploy.go new file mode 100644 index 0000000..e2906a1 --- /dev/null +++ b/pkg/family/evm/operations/callproxy_deploy.go @@ -0,0 +1,35 @@ +package operations + +import ( + "github.com/Masterminds/semver/v3" + "github.com/ethereum/go-ethereum/common" + mcmscontracts "github.com/smartcontractkit/chainlink-deployments-framework/engine/cld/contracts/mcms" + + bindings "github.com/smartcontractkit/ccip-owner-contracts/pkg/gethwrappers" + + zkbindings "github.com/smartcontractkit/mcms/sdk/zksync/bindings" + + cldchangesetscommon "github.com/smartcontractkit/cld-changesets/pkg/common" +) + +type OpEVMDeployCallProxyInput struct { + Timelock common.Address `json:"timelock"` +} + +var OpEVMDeployCallProxy = NewEVMDeployOperation( + "evm-call-proxy-deploy", + semver.MustParse("1.0.0"), + "Deploys CallProxy contract on the specified EVM chains", + mcmscontracts.CallProxy, + bindings.CallProxyMetaData, + &ContractOpts{ + Version: &cldchangesetscommon.Version1_0_0, + EVMBytecode: common.FromHex(bindings.CallProxyBin), + ZkSyncVMBytecode: zkbindings.CallProxyZkBytecode, + }, + func(input OpEVMDeployCallProxyInput) []any { + return []any{ + input.Timelock, + } + }, +) diff --git a/pkg/family/evm/operations/grant_role.go b/pkg/family/evm/operations/grant_role.go new file mode 100644 index 0000000..ac82599 --- /dev/null +++ b/pkg/family/evm/operations/grant_role.go @@ -0,0 +1,27 @@ +package operations + +import ( + "github.com/Masterminds/semver/v3" + "github.com/ethereum/go-ethereum/accounts/abi/bind/v2" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + mcmscontracts "github.com/smartcontractkit/chainlink-deployments-framework/engine/cld/contracts/mcms" + "github.com/smartcontractkit/mcms/sdk/evm/bindings" +) + +type OpEVMGrantRoleInput struct { + Account common.Address `json:"account"` + RoleID [32]byte `json:"roleID"` +} + +var OpEVMGrantRole = NewEVMCallOperation( + "evm-timelock-grant-role", + semver.MustParse("1.0.0"), + "Grants specified role to the ManyChainMultiSig contract on the EVM Timelock contract", + bindings.RBACTimelockABI, + mcmscontracts.RBACTimelock, + bindings.NewRBACTimelock, + func(timelock *bindings.RBACTimelock, opts *bind.TransactOpts, input OpEVMGrantRoleInput) (*types.Transaction, error) { + return timelock.GrantRole(opts, input.RoleID, input.Account) + }, +) diff --git a/pkg/family/evm/operations/mcm_deploy.go b/pkg/family/evm/operations/mcm_deploy.go new file mode 100644 index 0000000..3f676c3 --- /dev/null +++ b/pkg/family/evm/operations/mcm_deploy.go @@ -0,0 +1,65 @@ +package operations + +import ( + "github.com/Masterminds/semver/v3" + "github.com/ethereum/go-ethereum/common" + mcmscontracts "github.com/smartcontractkit/chainlink-deployments-framework/engine/cld/contracts/mcms" + + bindings "github.com/smartcontractkit/ccip-owner-contracts/pkg/gethwrappers" + + zkbindings "github.com/smartcontractkit/mcms/sdk/zksync/bindings" + + cldchangesetscommon "github.com/smartcontractkit/cld-changesets/pkg/common" +) + +type OpEVMDeployMCMOutput struct { + Address common.Address `json:"address"` +} + +var OpEVMDeployProposerMCM = NewEVMDeployOperation( + "evm-proposer-mcm-deploy", + semver.MustParse("1.0.0"), + "Deploys Proposer MCM contract", + mcmscontracts.ProposerManyChainMultisig, + bindings.ManyChainMultiSigMetaData, + &ContractOpts{ + Version: &cldchangesetscommon.Version1_0_0, + EVMBytecode: common.FromHex(bindings.ManyChainMultiSigBin), + ZkSyncVMBytecode: zkbindings.ManyChainMultiSigZkBytecode, + }, + func(input any) []any { + return []any{} + }, +) + +var OpEVMDeployBypasserMCM = NewEVMDeployOperation( + "evm-bypasser-mcm-deploy", + semver.MustParse("1.0.0"), + "Deploys Bypasser MCM contract", + mcmscontracts.BypasserManyChainMultisig, + bindings.ManyChainMultiSigMetaData, + &ContractOpts{ + Version: &cldchangesetscommon.Version1_0_0, + EVMBytecode: common.FromHex(bindings.ManyChainMultiSigBin), + ZkSyncVMBytecode: zkbindings.ManyChainMultiSigZkBytecode, + }, + func(input any) []any { + return []any{} + }, +) + +var OpEVMDeployCancellerMCM = NewEVMDeployOperation( + "evm-canceller-mcm-deploy", + semver.MustParse("1.0.0"), + "Deploys Canceller MCM contract", + mcmscontracts.CancellerManyChainMultisig, + bindings.ManyChainMultiSigMetaData, + &ContractOpts{ + Version: &cldchangesetscommon.Version1_0_0, + EVMBytecode: common.FromHex(bindings.ManyChainMultiSigBin), + ZkSyncVMBytecode: zkbindings.ManyChainMultiSigZkBytecode, + }, + func(input any) []any { + return []any{} + }, +) diff --git a/pkg/family/evm/operations/mcm_set_config.go b/pkg/family/evm/operations/mcm_set_config.go new file mode 100644 index 0000000..f7fb669 --- /dev/null +++ b/pkg/family/evm/operations/mcm_set_config.go @@ -0,0 +1,36 @@ +package operations + +import ( + "github.com/Masterminds/semver/v3" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + mcmscontracts "github.com/smartcontractkit/chainlink-deployments-framework/engine/cld/contracts/mcms" + + bindings "github.com/smartcontractkit/ccip-owner-contracts/pkg/gethwrappers" +) + +type OpEVMSetConfigMCMInput struct { + SignerAddresses []common.Address `json:"signerAddresses"` + SignerGroups []uint8 `json:"signerGroups"` // Signer 1 is int group 0 (root group) with quorum 1. + GroupQuorums [32]uint8 `json:"groupQuorums"` + GroupParents [32]uint8 `json:"groupParents"` +} + +var OpEVMSetConfigMCM = NewEVMCallOperation( + "evm-mcm-set-config", + semver.MustParse("1.0.0"), + "Sets Config on the deployed MCM contract", + bindings.ManyChainMultiSigABI, + mcmscontracts.ManyChainMultisig, + bindings.NewManyChainMultiSig, + func(mcm *bindings.ManyChainMultiSig, opts *bind.TransactOpts, input OpEVMSetConfigMCMInput) (*types.Transaction, error) { + return mcm.SetConfig( + opts, + input.SignerAddresses, + input.SignerGroups, + input.GroupQuorums, + input.GroupParents, + false, + ) + }) diff --git a/pkg/family/evm/operations/timelock_deploy.go b/pkg/family/evm/operations/timelock_deploy.go new file mode 100644 index 0000000..7d8ee36 --- /dev/null +++ b/pkg/family/evm/operations/timelock_deploy.go @@ -0,0 +1,47 @@ +package operations + +import ( + "math/big" + + "github.com/Masterminds/semver/v3" + "github.com/ethereum/go-ethereum/common" + mcmscontracts "github.com/smartcontractkit/chainlink-deployments-framework/engine/cld/contracts/mcms" + + bindings "github.com/smartcontractkit/ccip-owner-contracts/pkg/gethwrappers" + + zkbindings "github.com/smartcontractkit/mcms/sdk/zksync/bindings" + + cldchangesetscommon "github.com/smartcontractkit/cld-changesets/pkg/common" +) + +type OpEVMDeployTimelockInput struct { + TimelockMinDelay *big.Int `json:"timelockMinDelay"` + Admin common.Address `json:"admin"` // Admin of the timelock contract, usually the deployer key + Proposers []common.Address `json:"proposers"` // Proposer of the timelock contract, usually the deployer key + Executors []common.Address `json:"executors"` // Executor of the timelock contract, usually the call proxy + Cancellers []common.Address `json:"cancellers"` // Canceller of the timelock contract, usually the deployer key + Bypassers []common.Address `json:"bypassers"` // Bypasser of the timelock contract, usually the deployer key +} + +var OpEVMDeployTimelock = NewEVMDeployOperation( + "evm-timelock-deploy", + semver.MustParse("1.0.0"), + "Deploys Timelock contract on the specified EVM chains", + mcmscontracts.RBACTimelock, + bindings.RBACTimelockMetaData, + &ContractOpts{ + Version: &cldchangesetscommon.Version1_0_0, + EVMBytecode: common.FromHex(bindings.RBACTimelockBin), + ZkSyncVMBytecode: zkbindings.RBACTimelockZkBytecode, + }, + func(input OpEVMDeployTimelockInput) []any { + return []any{ + input.TimelockMinDelay, + input.Admin, + input.Proposers, + input.Executors, + input.Cancellers, + input.Bypassers, + } + }, +) diff --git a/pkg/family/evm/operations/utils.go b/pkg/family/evm/operations/utils.go new file mode 100644 index 0000000..7c1fd0f --- /dev/null +++ b/pkg/family/evm/operations/utils.go @@ -0,0 +1,501 @@ +package operations + +import ( + "context" + "crypto/rand" + "errors" + "fmt" + "math/big" + "strings" + + "github.com/Masterminds/semver/v3" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/zksync-sdk/zksync2-go/accounts" + "github.com/zksync-sdk/zksync2-go/clients" + + mcmspropose "github.com/smartcontractkit/cld-changesets/mcms/legacy/proposeutils" + evmstate "github.com/smartcontractkit/cld-changesets/pkg/family/evm/legacy" + + mcmslib "github.com/smartcontractkit/mcms" + mcmssdk "github.com/smartcontractkit/mcms/sdk" + mcmstypes "github.com/smartcontractkit/mcms/types" + + cldf_evm "github.com/smartcontractkit/chainlink-deployments-framework/chain/evm" + cldf "github.com/smartcontractkit/chainlink-deployments-framework/deployment" + cldfproposalutils "github.com/smartcontractkit/chainlink-deployments-framework/engine/cld/mcms/proposalutils" + "github.com/smartcontractkit/chainlink-deployments-framework/operations" +) + +// EVMCallInput is the input structure for an EVM call operation. +// Why not pull the chain selector from the chain dependency? Because addresses might be the same across chains and we need to differentiate them. +// This ensures no false report matches between operation runs that have the same call input and address but a different target chain. +type EVMCallInput[IN any] struct { + // Address is the address of the contract to call. + Address common.Address `json:"address"` + // ChainSelector is the selector for the chain on which the contract resides. + ChainSelector uint64 `json:"chainSelector"` + // CallInput is the input data for the call. + CallInput IN `json:"callInput"` + // NoSend indicates whether or not the transaction should be sent. + // If true, the transaction data be prepared and returned but not sent. + NoSend bool `json:"noSend"` + // GasPrice is a custom gas price to set for the transaction. + GasPrice uint64 `json:"gasPrice"` + // GasLimit is a custom gas limit to set for the transaction. + GasLimit uint64 `json:"gasLimit"` +} + +// EVMCallOutput is the output structure for an EVM call operation. +// It contains the transaction and the type of contract that is being called. +type EVMCallOutput struct { + // To is the address that initiated the transaction. + To common.Address `json:"to"` + // Data is the transaction data + Data []byte `json:"data"` + // ContractType is the type of contract that is being called. + ContractType cldf.ContractType `json:"contractType"` + // Confirmed indicates whether or not the transaction was confirmed. + Confirmed bool `json:"confirmed"` +} + +// NewEVMCallOperation creates a new operation that performs an EVM call. +// Any interfacing with gethwrappers should happen in the call function. +func NewEVMCallOperation[IN any, C any]( + name string, + version *semver.Version, + description string, + abi string, + contractType cldf.ContractType, + constructor func(address common.Address, backend bind.ContractBackend) (C, error), + call func(contract C, opts *bind.TransactOpts, input IN) (*types.Transaction, error), +) *operations.Operation[EVMCallInput[IN], EVMCallOutput, cldf_evm.Chain] { + return operations.NewOperation( + name, + version, + description, + func(b operations.Bundle, chain cldf_evm.Chain, input EVMCallInput[IN]) (EVMCallOutput, error) { + if input.ChainSelector != chain.Selector { + return EVMCallOutput{}, fmt.Errorf("mismatch between inputted chain selector and selector defined within dependencies: %d != %d", input.ChainSelector, chain.Selector) + } + opts := CloneTransactOptsWithGas(chain.DeployerKey, input.GasLimit, input.GasPrice) + if input.NoSend { + opts = cldf.SimTransactOpts() + } + contract, err := constructor(input.Address, chain.Client) + if err != nil { + return EVMCallOutput{}, fmt.Errorf("failed to create contract instance for %s at %s on %s: %w", name, input.Address, chain, err) + } + tx, err := call(contract, opts, input.CallInput) + confirmed := false + if !input.NoSend { + // If the call has actually been sent, we need check the call error and confirm the transaction. + if _, err = cldf.ConfirmIfNoErrorWithABI(chain, tx, abi, err); err != nil { + return EVMCallOutput{}, fmt.Errorf("failed to confirm %s tx against %s on %s: %w", name, input.Address, chain, err) + } + b.Logger.Debugw(fmt.Sprintf("Confirmed %s tx against %s on %s", name, input.Address, chain), "hash", tx.Hash().Hex(), "input", input.CallInput) + confirmed = true + } else { + b.Logger.Debugw(fmt.Sprintf("Prepared %s tx against %s on %s", name, input.Address, chain), "input", input.CallInput) + } + + return EVMCallOutput{ + To: input.Address, + Data: tx.Data(), + ContractType: contractType, + Confirmed: confirmed, + }, err + }, + ) +} + +// AddEVMCallSequenceToCSOutput updates the ChangesetOutput with the results of an EVM call sequence. +// It appends the execution reports from the sequence report to the ChangesetOutput's reports. +// If the sequence execution was successful and MCMS configuration is provided, it adds a proposal to the output. +func AddEVMCallSequenceToCSOutput[IN any]( + e cldf.Environment, + csOutput cldf.ChangesetOutput, + seqReport operations.SequenceReport[IN, map[uint64][]EVMCallOutput], + seqErr error, + mcmsStateByChain map[uint64]evmstate.MCMSWithTimelockState, + mcmsCfg *cldfproposalutils.TimelockConfig, + mcmsDescription string, +) (cldf.ChangesetOutput, error) { + defer func() { csOutput.Reports = append(csOutput.Reports, seqReport.ExecutionReports...) }() + if seqErr != nil { + return csOutput, fmt.Errorf("failed to execute %s: %w", seqReport.Def, seqErr) + } + + // Return early if MCMS is not being used + if mcmsCfg == nil { + return csOutput, nil + } + + batches := []mcmstypes.BatchOperation{} + timelocks := make(map[uint64]string) + inspectors := make(map[uint64]mcmssdk.Inspector) + mcmContractByChain := make(map[uint64]string) + for chainSel, outs := range seqReport.Output { + for _, out := range outs { + // If a transaction has already been confirmed, we do not need an operation for it. + // TODO: Instead of creating 1 batch operation per call, can we batch calls together based on some strategy? + if out.Confirmed { + continue + } + batchOperation, err := cldfproposalutils.BatchOperationForChain(chainSel, out.To.Hex(), out.Data, + big.NewInt(0), string(out.ContractType), []string{}) + if err != nil { + return csOutput, fmt.Errorf("failed to create batch operation for chain with selector %d: %w", chainSel, err) + } + batches = append(batches, batchOperation) + + mcmsState, ok := mcmsStateByChain[chainSel] + if !ok { + return csOutput, fmt.Errorf("mcms state not found for chain with selector %d", chainSel) + } + timelocks[chainSel] = mcmsState.Timelock.Address().Hex() + inspectors[chainSel], err = cldfproposalutils.McmsInspectorForChain(e, chainSel) + if err != nil { + return csOutput, fmt.Errorf("failed to get inspector for chain with selector %d: %w", chainSel, err) + } + mcm, err := mcmsCfg.MCMBasedOnAction(mcmsState) + if err != nil { + return csOutput, fmt.Errorf("failed to get MCM contract for chain with selector %d: %w", chainSel, err) + } + mcmContractByChain[chainSel] = mcm.Address().Hex() + } + } + if len(batches) == 0 { + return csOutput, nil + } + + // Build new proposal from the batches and MCMS configuration. + proposal, err := mcmspropose.BuildProposalFromBatchesV2( + e, + timelocks, + mcmContractByChain, + inspectors, + batches, + mcmsDescription, + *mcmsCfg, + ) + if err != nil { + return csOutput, fmt.Errorf("failed to build mcms proposal: %w", err) + } + + // Add the new proposal to the ChangesetOutput. + if csOutput.MCMSTimelockProposals == nil { + csOutput.MCMSTimelockProposals = make([]mcmslib.TimelockProposal, 1) + } + csOutput.MCMSTimelockProposals = append(csOutput.MCMSTimelockProposals, *proposal) + // Aggregate the proposals into a single proposal. + // Aggregate the descriptions of all proposals into a single string. + var builder strings.Builder + for i, prop := range csOutput.MCMSTimelockProposals { + builder.WriteString(prop.Description) + if i < len(csOutput.MCMSTimelockProposals)-1 { + builder.WriteString(", ") + } + } + aggProposal, err := mcmspropose.AggregateProposals( //nolint:staticcheck // existing EVM path still uses legacy aggregate helper + e, + mcmsStateByChain, + nil, + csOutput.MCMSTimelockProposals, + builder.String(), + mcmsCfg, + ) + if err != nil { + return csOutput, fmt.Errorf("failed to aggregate proposals: %w", err) + } + + csOutput.MCMSTimelockProposals = []mcmslib.TimelockProposal{*aggProposal} + + return csOutput, nil +} + +// EVMDeployInput is the input structure for an EVM deploy operation. +type EVMDeployInput[IN any] struct { + // ChainSelector is the selector for the chain on which the contract will be deployed. + ChainSelector uint64 `json:"chainSelector"` + // DeployInput is the input data for the call. + DeployInput IN `json:"deployInput"` + // GasPrice is a custom gas price to set for the transaction. + GasPrice uint64 `json:"gasPrice"` + // GasLimit is a custom gas limit to set for the transaction. + GasLimit uint64 `json:"gasLimit"` + // Qualifier is an optional qualifier for the deployment. + Qualifier *string `json:"qualifier"` + // ContractOpts (optional) further configure the deployment with a specific bytecode and version. + ContractOpts *ContractOpts `json:"contractOpts"` +} + +// EVMDeployOutput is the output structure for an EVM deploy operation. +// It contains the new address, the deployment transaction, and the type and version of the contract that was deployed. +type EVMDeployOutput struct { + // Address is the address of the deployed contract. + Address common.Address `json:"address"` + // TypeAndVersion is the type and version of the contract that was deployed. + TypeAndVersion string `json:"typeAndVersion"` + // Qualifier is an optional qualifier for the deployment. + Qualifier *string `json:"qualifier"` +} + +// ContractOpts specify the exact bytecode and version of the contract to deploy. +// Deployment operations must define defaults for these options in case users do not provide them. +// These options allow operators to deploy new bytecodes for the same ABI. +type ContractOpts struct { + Version *semver.Version + EVMBytecode []byte + ZkSyncVMBytecode []byte +} + +func (c *ContractOpts) Validate(isZkSyncVM bool) error { + if c.Version == nil { + return errors.New("version must be defined") + } + if isZkSyncVM && len(c.ZkSyncVMBytecode) == 0 { + return errors.New("zkSyncVM bytecode must be defined") + } + if !isZkSyncVM && len(c.EVMBytecode) == 0 { + return errors.New("evm bytecode must be defined") + } + + return nil +} + +// NewEVMDeployOperation creates a new operation that deploys an EVM contract. +// Any interfacing with gethwrappers should happen in the deploy function. +func NewEVMDeployOperation[IN any]( + name string, + version *semver.Version, + description string, + contractType cldf.ContractType, + contractMetadata *bind.MetaData, + defaultContractOpts *ContractOpts, + makeArgs func(IN) []any, +) *operations.Operation[EVMDeployInput[IN], EVMDeployOutput, cldf_evm.Chain] { + return operations.NewOperation( + name, + version, + description, + func(b operations.Bundle, chain cldf_evm.Chain, input EVMDeployInput[IN]) (EVMDeployOutput, error) { + if input.ChainSelector != chain.Selector { + return EVMDeployOutput{}, fmt.Errorf("mismatch between inputted chain selector and selector defined within dependencies: %d != %d", input.ChainSelector, chain.Selector) + } + if contractMetadata == nil { + return EVMDeployOutput{}, errors.New("contract metadata must be provided for deployment") + } + contractOpts := defaultContractOpts + if input.ContractOpts != nil { + contractOpts = input.ContractOpts + } + if contractOpts == nil { + return EVMDeployOutput{}, errors.New("must define ContractOpts for deployment, no defaults provided") + } + if err := contractOpts.Validate(chain.IsZkSyncVM); err != nil { + return EVMDeployOutput{}, fmt.Errorf("invalid ContractOpts: %w", err) + } + typeAndVersion := cldf.NewTypeAndVersion(contractType, *contractOpts.Version) + parsedABI, err := contractMetadata.GetAbi() + if err != nil { + return EVMDeployOutput{}, fmt.Errorf("failed to parse ABI for %s: %w", typeAndVersion, err) + } + if parsedABI == nil { + return EVMDeployOutput{}, fmt.Errorf("ABI is nil for %s", typeAndVersion) + } + + var ( + addr common.Address + tx *types.Transaction + ) + if chain.IsZkSyncVM { + addr, err = deployZkContract( + nil, + contractOpts.ZkSyncVMBytecode, + chain.ClientZkSyncVM, + chain.DeployerKeyZkSyncVM, + parsedABI, + makeArgs(input.DeployInput)..., + ) + } else { + addr, tx, _, err = bind.DeployContract( + CloneTransactOptsWithGas(chain.DeployerKey, input.GasLimit, input.GasPrice), + *parsedABI, + contractOpts.EVMBytecode, + chain.Client, + makeArgs(input.DeployInput)..., + ) + } + if err != nil { + b.Logger.Errorw("Failed to deploy contract", "typeAndVersion", typeAndVersion, "chain", chain.String(), "err", err.Error()) + return EVMDeployOutput{}, fmt.Errorf("failed to deploy %s on %s: %w", typeAndVersion, chain, err) + } + // ZkSync transactions are confirmed in deployZkContract + if !chain.IsZkSyncVM { + if _, err = chain.Confirm(tx); err != nil { + b.Logger.Errorw("Failed to confirm deployment", "typeAndVersion", typeAndVersion, "chain", chain.String(), "err", err.Error()) + return EVMDeployOutput{}, fmt.Errorf("failed to confirm deployment of %s on %s: %w", typeAndVersion, chain, err) + } + } + + return EVMDeployOutput{ + Address: addr, + TypeAndVersion: typeAndVersion.String(), + Qualifier: input.Qualifier, + }, err + }, + ) +} + +// cloneTransactOptsWithGas ensures that we don't impact the transact opts used by other operations. +func CloneTransactOptsWithGas(opts *bind.TransactOpts, gasLimit uint64, gasPrice uint64) *bind.TransactOpts { + if opts == nil { + return nil + } + newOpts := *opts + if gasLimit > 0 { + newOpts.GasLimit = gasLimit + } + if gasPrice > 0 { + newOpts.GasPrice = new(big.Int).SetUint64(gasPrice) + } + + return &newOpts +} + +// GasBoostConfigsForChainMap creates a map of GasBoostConfig pointers for each chain in the provided chainMap. +// If a chain selector exists in gasBoostConfigs, it uses that config; otherwise, it sets nil. +func GasBoostConfigsForChainMap[T any](chainMap map[uint64]T, gasBoostConfigs map[uint64]cldfproposalutils.GasBoostConfig) map[uint64]*cldfproposalutils.GasBoostConfig { + cfgs := make(map[uint64]*cldfproposalutils.GasBoostConfig, len(chainMap)) + if gasBoostConfigs == nil || chainMap == nil { // in either case, gas boosting should be empty + return cfgs + } + + for chainSelector := range chainMap { + if _, ok := gasBoostConfigs[chainSelector]; ok { + cfgs[chainSelector] = new(gasBoostConfigs[chainSelector]) + } else { + cfgs[chainSelector] = nil + } + } + + return cfgs +} + +// RetryDeploymentWithGasBoost is an ExecuteOption that retries EVM deployments with gas boosting. +// It uses the provided GasBoostConfig to adjust the gas limit and gas price on each retry attempt. +func RetryDeploymentWithGasBoost[IN any](cfg *cldfproposalutils.GasBoostConfig) operations.ExecuteOption[EVMDeployInput[IN], cldf_evm.Chain] { + if cfg == nil { + return withoutRetry[EVMDeployInput[IN], cldf_evm.Chain]() + } + c := *cfg + + return operations.WithRetryInput(func(attempt uint, err error, in EVMDeployInput[IN], deps cldf_evm.Chain) EVMDeployInput[IN] { + gasLimit, gasPrice := GetBoostedGasForAttempt(c, attempt) + in.GasLimit = gasLimit + in.GasPrice = gasPrice + + return in + }) +} + +// withoutRetry enables us to return an ExecuteOption that does nothing. +func withoutRetry[IN, DEP any]() operations.ExecuteOption[IN, DEP] { + return func(c *operations.ExecuteConfig[IN, DEP]) {} +} + +// RetryCallWithGasBoost is an ExecuteOption that retries EVM calls with gas boosting. +// It uses the provided GasBoostConfig to adjust the gas limit and gas price on each retry attempt. +// If NoSend is true, it will not apply gas boosting since the transaction is never sent. +func RetryCallWithGasBoost[IN any](cfg *cldfproposalutils.GasBoostConfig) operations.ExecuteOption[EVMCallInput[IN], cldf_evm.Chain] { + // Use default retry option if no gas boost config is provided + if cfg == nil { + return operations.WithRetry[EVMCallInput[IN], cldf_evm.Chain]() + } + c := *cfg + + return operations.WithRetryInput(func(attempt uint, err error, in EVMCallInput[IN], deps cldf_evm.Chain) EVMCallInput[IN] { + if in.NoSend { + return in // No gas boost for calls that do not send transactions + } + + gasLimit, gasPrice := GetBoostedGasForAttempt(c, attempt) + in.GasLimit = gasLimit + in.GasPrice = gasPrice + + return in + }) +} + +func GetBoostedGasForAttempt(cfg cldfproposalutils.GasBoostConfig, attempt uint) (gasLimit uint64, gasPrice uint64) { + initialGasLimit := uint64(200_000) // 200k + gasLimitIncrement := uint64(50_000) // 50k + initialGasPrice := uint64(20_000_000_000) // 20 Gwei + gasPriceIncrement := uint64(10_000_000_000) // 10 Gwei + + // Override defaults with config values if provided + if cfg.InitialGasLimit > 0 { + initialGasLimit = cfg.InitialGasLimit + } + if cfg.GasLimitIncrement > 0 { + gasLimitIncrement = cfg.GasLimitIncrement + } + if cfg.InitialGasPrice > 0 { + initialGasPrice = cfg.InitialGasPrice + } + if cfg.GasPriceIncrement > 0 { + gasPriceIncrement = cfg.GasPriceIncrement + } + + // initial + attempt * increment + gasLimit = initialGasLimit + uint64(attempt)*gasLimitIncrement + gasPrice = initialGasPrice + uint64(attempt)*gasPriceIncrement + + return +} + +func deployZkContract( + deployOpts *accounts.TransactOpts, + bytecode []byte, + client *clients.Client, + wallet *accounts.Wallet, + parsedABI *abi.ABI, + args ...any, +) (common.Address, error) { + var calldata []byte + var err error + if len(args) > 0 { + calldata, err = parsedABI.Pack("", args...) + if err != nil { + return common.Address{}, fmt.Errorf("failed to pack constructor args: %w", err) + } + } + + salt := make([]byte, 32) + n, err := rand.Read(salt) + if err != nil { + return common.Address{}, fmt.Errorf("failed to read random bytes: %w", err) + } + if n != len(salt) { + return common.Address{}, fmt.Errorf("failed to read random bytes: expected %d, got %d", len(salt), n) + } + + txHash, err := wallet.Deploy(deployOpts, accounts.Create2Transaction{ + Bytecode: bytecode, + Calldata: calldata, + Salt: salt, + }) + if err != nil { + return common.Address{}, fmt.Errorf("failed to deploy zk contract: %w", err) + } + + receipt, err := client.WaitMined(context.Background(), txHash) + if err != nil { + return common.Address{}, fmt.Errorf("failed to confirm zk contract deployment: %w", err) + } + + return receipt.ContractAddress, nil +} diff --git a/pkg/family/evm/operations/utils_test.go b/pkg/family/evm/operations/utils_test.go new file mode 100644 index 0000000..149612f --- /dev/null +++ b/pkg/family/evm/operations/utils_test.go @@ -0,0 +1,831 @@ +package operations_test + +import ( + "encoding/json" + "errors" + "math/big" + "testing" + "time" + + "github.com/Masterminds/semver/v3" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + cldfproposalutils "github.com/smartcontractkit/chainlink-deployments-framework/engine/cld/mcms/proposalutils" + "github.com/smartcontractkit/chainlink-deployments-framework/engine/test/runtime" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + mcmschangesets "github.com/smartcontractkit/cld-changesets/mcms/changesets/legacy" + evmstate "github.com/smartcontractkit/cld-changesets/pkg/family/evm/legacy" + opsevm "github.com/smartcontractkit/cld-changesets/pkg/family/evm/operations" + + chain_selectors "github.com/smartcontractkit/chain-selectors" + mcmslib "github.com/smartcontractkit/mcms" + mcmstypes "github.com/smartcontractkit/mcms/types" + + cldf_chain "github.com/smartcontractkit/chainlink-deployments-framework/chain" + cldf_evm "github.com/smartcontractkit/chainlink-deployments-framework/chain/evm" + cldf_evm_provider "github.com/smartcontractkit/chainlink-deployments-framework/chain/evm/provider" + cldf "github.com/smartcontractkit/chainlink-deployments-framework/deployment" + cldftesthelpers "github.com/smartcontractkit/chainlink-deployments-framework/engine/cld/mcms/proposalutils/testhelpers" + "github.com/smartcontractkit/chainlink-deployments-framework/engine/test/environment" + "github.com/smartcontractkit/chainlink-deployments-framework/operations" + "github.com/smartcontractkit/chainlink-deployments-framework/operations/optest" + + commonchangeset "github.com/smartcontractkit/cld-changesets/pkg/common/changeset" +) + +func TestCloneTransactOptsWithGas(t *testing.T) { + t.Parallel() + orig := &bind.TransactOpts{ + GasLimit: 100, + GasPrice: big.NewInt(123), + } + // Should clone and override both + cloned := opsevm.CloneTransactOptsWithGas(orig, 200, 456) + assert.NotSame(t, orig, cloned) + assert.Equal(t, uint64(200), cloned.GasLimit) + assert.Equal(t, big.NewInt(456), cloned.GasPrice) + // Should not override if zero + cloned2 := opsevm.CloneTransactOptsWithGas(orig, 0, 0) + assert.Equal(t, orig.GasLimit, cloned2.GasLimit) + assert.Equal(t, orig.GasPrice, cloned2.GasPrice) + // Nil input + assert.Nil(t, opsevm.CloneTransactOptsWithGas(nil, 1, 1)) +} + +func TestGasBoostConfigsForChainMap(t *testing.T) { + t.Parallel() + chainMap := map[uint64]string{1: "a", 2: "b"} + gasBoostConfigs := map[uint64]cldfproposalutils.GasBoostConfig{ + 1: {InitialGasLimit: 10}, + } + cfgs := opsevm.GasBoostConfigsForChainMap(chainMap, gasBoostConfigs) + assert.Len(t, cfgs, 2) + assert.NotNil(t, cfgs[1]) + assert.Nil(t, cfgs[2]) + // Nil configs + assert.Empty(t, opsevm.GasBoostConfigsForChainMap[string](chainMap, nil)) + assert.Empty(t, opsevm.GasBoostConfigsForChainMap[string](nil, gasBoostConfigs)) +} + +func TestGetBoostedGasForAttempt_DefaultsAndOverrides(t *testing.T) { + t.Parallel() + cfg := cldfproposalutils.GasBoostConfig{} + limit, price := opsevm.GetBoostedGasForAttempt(cfg, 0) + assert.Equal(t, uint64(200_000), limit) + assert.Equal(t, uint64(20_000_000_000), price) + limit, price = opsevm.GetBoostedGasForAttempt(cfg, 2) + assert.Equal(t, uint64(200_000+2*50_000), limit) + assert.Equal(t, uint64(20_000_000_000+2*10_000_000_000), price) + + cfg = cldfproposalutils.GasBoostConfig{ + InitialGasLimit: 1000, + GasLimitIncrement: 100, + InitialGasPrice: 2000, + GasPriceIncrement: 100, + } + limit, price = opsevm.GetBoostedGasForAttempt(cfg, 3) + assert.Equal(t, uint64(1000+3*100), limit) + assert.Equal(t, uint64(2000+3*100), price) +} + +func TestRetryDeploymentWithGasBoost(t *testing.T) { + t.Parallel() + cfg := &cldfproposalutils.GasBoostConfig{ + InitialGasLimit: 1000, + GasLimitIncrement: 100, + InitialGasPrice: 2000, + GasPriceIncrement: 100, + } + opt := opsevm.RetryDeploymentWithGasBoost[any](cfg) + // Should not panic and should be non-nil + assert.NotNil(t, opt) + // Should fallback to default if nil + assert.NotNil(t, opsevm.RetryDeploymentWithGasBoost[string](nil)) +} + +func TestAddEVMCallSequenceToCSOutput_SequenceError(t *testing.T) { + t.Parallel() + + env, err := environment.New(t.Context(), + environment.WithEVMSimulatedN(t, 1), + ) + require.NoError(t, err) + + csOutput := cldf.ChangesetOutput{} + seqReport := operations.SequenceReport[string, map[uint64][]opsevm.EVMCallOutput]{} + seqErr := errors.New("sequence failed") + + result, err := opsevm.AddEVMCallSequenceToCSOutput( + *env, + csOutput, + seqReport, + seqErr, + nil, + nil, + "test", + ) + + require.Error(t, err) + assert.Contains(t, err.Error(), "failed to execute") + assert.Contains(t, err.Error(), "sequence failed") + assert.Equal(t, seqReport.ExecutionReports, result.Reports) +} + +func TestAddEVMCallSequenceToCSOutput_NoMCMS(t *testing.T) { + t.Parallel() + + env, err := environment.New(t.Context(), + environment.WithEVMSimulatedN(t, 1), + ) + require.NoError(t, err) + + csOutput := cldf.ChangesetOutput{} + seqReport := operations.SequenceReport[string, map[uint64][]opsevm.EVMCallOutput]{} + + result, err := opsevm.AddEVMCallSequenceToCSOutput( + *env, + csOutput, + seqReport, + nil, + nil, + nil, // No MCMS config + "test", + ) + + require.NoError(t, err) + assert.Equal(t, seqReport.ExecutionReports, result.Reports) +} + +func TestAddEVMCallSequenceToCSOutput_AllConfirmed(t *testing.T) { + t.Parallel() + + env, err := environment.New(t.Context(), + environment.WithEVMSimulatedN(t, 1), + ) + require.NoError(t, err) + + csOutput := cldf.ChangesetOutput{} + seqReport := operations.SequenceReport[string, map[uint64][]opsevm.EVMCallOutput]{} + mcmsCfg := &cldfproposalutils.TimelockConfig{} + + result, err := opsevm.AddEVMCallSequenceToCSOutput( + *env, + csOutput, + seqReport, + nil, + map[uint64]evmstate.MCMSWithTimelockState{}, + mcmsCfg, + "test", + ) + + require.NoError(t, err) + assert.Equal(t, seqReport.ExecutionReports, result.Reports) + assert.Nil(t, result.MCMSTimelockProposals) +} + +func TestAddEVMCallSequenceToCSOutput_ProposalCombination(t *testing.T) { + t.Parallel() + + // Use two simulated EVM chains so we can exercise cross-chain proposal + selector1 := chain_selectors.TEST_90000001.Selector + selector2 := chain_selectors.TEST_90000002.Selector + selectors := []uint64{selector1, selector2} + + rt, err := runtime.New(t.Context(), runtime.WithEnvOpts( + environment.WithEVMSimulated(t, selectors), + )) + require.NoError(t, err) + + // Deploy MCMS+Timelock to both chains. Real deployments are required because + // AddEVMCallSequenceToCSOutput → BuildProposalFromBatchesV2 reads OpCount from + env, err := commonchangeset.Apply(t, rt.Environment(), commonchangeset.Configure( + cldf.CreateLegacyChangeSet(mcmschangesets.DeployMCMSWithTimelockV2), + map[uint64]cldfproposalutils.MCMSWithTimelockConfig{ + selector1: cldftesthelpers.SingleGroupTimelockConfig(t), + selector2: cldftesthelpers.SingleGroupTimelockConfig(t), + }, + )) + require.NoError(t, err) + + // Build the MCMS state map directly from the EVM state package — this is the + // product-agnostic, MCMS-only equivalent of CCIP's stateview.LoadOnchainState + // + chainState.EVMMCMSStateByChain(). + mcmsStateByChain := loadEVMMCMSStateByChain(t, env, selectors) + + // Two pre-existing proposals (one per chain) to exercise the aggregation path. + existingProposal1 := mcmslib.TimelockProposal{ + BaseProposal: mcmslib.BaseProposal{ + Description: "First proposal", + }, + Operations: []mcmstypes.BatchOperation{ + { + ChainSelector: mcmstypes.ChainSelector(selector1), + Transactions: []mcmstypes.Transaction{ + { + To: common.HexToAddress("0x1111111111111111111111111111111111111111").String(), + Data: []byte("data1"), + AdditionalFields: json.RawMessage(`{"value": 0}`), + }, + }, + }, + }, + } + + existingProposal2 := mcmslib.TimelockProposal{ + BaseProposal: mcmslib.BaseProposal{ + Description: "Second proposal", + }, + Operations: []mcmstypes.BatchOperation{ + { + ChainSelector: mcmstypes.ChainSelector(selector2), + Transactions: []mcmstypes.Transaction{ + { + To: common.HexToAddress("0x1111112222222222222222222222222222222222").String(), + Data: []byte("data2"), + AdditionalFields: json.RawMessage(`{"value": 0}`), + }, + }, + }, + }, + } + + csOutput := cldf.ChangesetOutput{ + MCMSTimelockProposals: []mcmslib.TimelockProposal{ + existingProposal1, + existingProposal2, + }, + } + + // Sequence report with one unconfirmed call against selector2 — this forces + // a third proposal to be built and combined with the two existing ones. + seqReport := operations.SequenceReport[string, map[uint64][]opsevm.EVMCallOutput]{ + Report: operations.Report[string, map[uint64][]opsevm.EVMCallOutput]{ + Output: map[uint64][]opsevm.EVMCallOutput{ + selector2: { + { + To: common.HexToAddress("0x3333333333333333333333333333333333333333"), + Data: []byte("new_call_data"), + ContractType: "TestContract", + Confirmed: false, + }, + }, + }, + }, + } + + mcmsCfg := &cldfproposalutils.TimelockConfig{ + MinDelay: 0 * time.Second, + MCMSAction: mcmstypes.TimelockActionSchedule, + } + + result, err := opsevm.AddEVMCallSequenceToCSOutput( + env, + csOutput, + seqReport, + nil, + mcmsStateByChain, + mcmsCfg, + "Third proposal", + ) + require.NoError(t, err) + assert.Equal(t, seqReport.ExecutionReports, result.Reports) + + // 1. Three input proposals should aggregate to a single output proposal. + require.Len(t, result.MCMSTimelockProposals, 1, "expected exactly 1 aggregated proposal") + + // 2. The aggregated description is the comma-joined originals. + aggregatedProposal := result.MCMSTimelockProposals[0] + assert.Equal(t, + "First proposal, Second proposal, Third proposal", + aggregatedProposal.Description, + "aggregated proposal should have comma-separated descriptions", + ) + + // 3. Operations from all source proposals are present. + assert.NotEmpty(t, aggregatedProposal.Operations, "aggregated proposal should contain operations") +} + +// loadEVMMCMSStateByChain loads the MCMS+Timelock state for the given chains and +// dereferences it into the map[uint64]MCMSWithTimelockState (value, not pointer) +// shape that AddEVMCallSequenceToCSOutput expects. It deliberately avoids any +// CCIP-specific state loaders so the test stays product-agnostic. +func loadEVMMCMSStateByChain(t *testing.T, env cldf.Environment, selectors []uint64) map[uint64]evmstate.MCMSWithTimelockState { + t.Helper() + + statePtrs, err := evmstate.MaybeLoadMCMSWithTimelockState(env, selectors) + require.NoError(t, err) + + out := make(map[uint64]evmstate.MCMSWithTimelockState, len(statePtrs)) + for sel, st := range statePtrs { + require.NotNilf(t, st, "expected non-nil MCMS state for chain %d", sel) + require.NoErrorf(t, st.Validate(), "MCMS state for chain %d failed validation", sel) + out[sel] = *st + } + + return out +} + +func TestNewEVMCallOperation(t *testing.T) { + t.Parallel() + version, _ := semver.NewVersion("1.0.0") + + t.Run("ChainSelectorMismatch", func(t *testing.T) { + t.Parallel() + + op := opsevm.NewEVMCallOperation( + "test", + version, + "description", + "abi", + cldf.ContractType("TestContract"), + func(address common.Address, backend bind.ContractBackend) (any, error) { + return struct{}{}, nil + }, + func(contract any, opts *bind.TransactOpts, input string) (*types.Transaction, error) { + return types.NewTransaction(0, common.Address{}, big.NewInt(0), 0, big.NewInt(0), nil), nil + }, + ) + + input := opsevm.EVMCallInput[string]{ + ChainSelector: 123, + Address: common.HexToAddress("0x1234"), + } + chain := cldf_evm.Chain{Selector: 456} + + _, err := operations.ExecuteOperation(optest.NewBundle(t), op, chain, input) + require.Error(t, err) + assert.Contains(t, err.Error(), "mismatch between inputted chain selector") + }) + + t.Run("ConstructorError", func(t *testing.T) { + t.Parallel() + + op := opsevm.NewEVMCallOperation[string, any]( + "test", + version, + "description", + "abi", + cldf.ContractType("TestContract"), + func(address common.Address, backend bind.ContractBackend) (any, error) { + return nil, errors.New("constructor failed") + }, + func(contract any, opts *bind.TransactOpts, input string) (*types.Transaction, error) { + return types.NewTransaction(0, common.Address{}, big.NewInt(0), 0, big.NewInt(0), nil), nil + }, + ) + + input := opsevm.EVMCallInput[string]{ + ChainSelector: 123, + Address: common.HexToAddress("0x1234"), + } + chain := cldf_evm.Chain{Selector: 123} + + _, err := operations.ExecuteOperation(optest.NewBundle(t), op, chain, input) + require.Error(t, err) + assert.Contains(t, err.Error(), "failed to create contract instance") + assert.Contains(t, err.Error(), "constructor failed") + }) + + t.Run("NoSendMode", func(t *testing.T) { + t.Parallel() + + mockTx := types.NewTransaction( + 0, // nonce + common.HexToAddress("0x1234"), // to address + big.NewInt(0), // value + 21000, // gas limit + big.NewInt(0), // gas price + nil, // data + ) + op := opsevm.NewEVMCallOperation[string, any]( + "test", + version, + "description", + "abi", + cldf.ContractType("TestContract"), + func(address common.Address, backend bind.ContractBackend) (any, error) { + return struct{}{}, nil + }, + func(contract any, opts *bind.TransactOpts, input string) (*types.Transaction, error) { + return mockTx, nil + }, + ) + + input := opsevm.EVMCallInput[string]{ + ChainSelector: 123, + Address: common.HexToAddress("0x1234"), + NoSend: true, + CallInput: "test input", + } + chain := cldf_evm.Chain{Selector: 123} + + output, err := operations.ExecuteOperation(optest.NewBundle(t), op, chain, input) + require.NoError(t, err) + assert.Equal(t, input.Address, output.Output.To) + assert.Equal(t, cldf.ContractType("TestContract"), output.Output.ContractType) + assert.False(t, output.Output.Confirmed) + }) + + t.Run("CustomGasSettings", func(t *testing.T) { + t.Parallel() + + var capturedOpts *bind.TransactOpts + mockTx := types.NewTransaction( + 0, // nonce + common.HexToAddress("0x1234"), // to address + big.NewInt(0), // value + 21000, // gas limit + big.NewInt(0), // gas price + nil, // data + ) + + op := opsevm.NewEVMCallOperation[string, any]( + "test", + version, + "description", + "abi", + cldf.ContractType("TestContract"), + func(address common.Address, backend bind.ContractBackend) (any, error) { + return struct{}{}, nil + }, + func(contract any, opts *bind.TransactOpts, input string) (*types.Transaction, error) { + capturedOpts = opts + return mockTx, nil + }, + ) + + input := opsevm.EVMCallInput[string]{ + ChainSelector: 123, + Address: common.HexToAddress("0x1234"), + GasLimit: 100000, + GasPrice: 50000000000, + NoSend: true, // Use NoSend to avoid confirmation + } + + deployerKey := &bind.TransactOpts{ + GasLimit: 50000, + GasPrice: big.NewInt(25000000000), + } + chain := cldf_evm.Chain{ + Selector: 123, + DeployerKey: deployerKey, + } + + _, err := operations.ExecuteOperation(optest.NewBundle(t), op, chain, input) + require.NoError(t, err) + + // In NoSend mode, SimTransactOpts are used instead of custom gas + assert.NotNil(t, capturedOpts.Signer) + }) +} + +func TestContractOpts_Validate(t *testing.T) { + t.Parallel() + + tests := []struct { + desc string + opts *opsevm.ContractOpts + isZkSyncVM bool + err string + }{ + { + desc: "valid evm opts", + opts: &opsevm.ContractOpts{ + Version: semver.MustParse("1.0.0"), + EVMBytecode: []byte{0x01, 0x02, 0x03}, + }, + isZkSyncVM: false, + }, + { + desc: "valid zksyncvm opts", + opts: &opsevm.ContractOpts{ + Version: semver.MustParse("1.0.0"), + ZkSyncVMBytecode: []byte{0x05, 0x06, 0x07, 0x08}, + }, + isZkSyncVM: true, + }, + { + desc: "nil version", + opts: &opsevm.ContractOpts{}, + err: "version must be defined", + }, + { + desc: "missing evm bytecode", + opts: &opsevm.ContractOpts{ + Version: semver.MustParse("1.0.0"), + }, + isZkSyncVM: false, + err: "evm bytecode must be defined", + }, + { + desc: "missing zkSyncVM bytecode", + opts: &opsevm.ContractOpts{ + Version: semver.MustParse("1.0.0"), + }, + isZkSyncVM: true, + err: "zkSyncVM bytecode must be defined", + }, + } + + for _, test := range tests { + t.Run(test.desc, func(t *testing.T) { + t.Parallel() + + err := test.opts.Validate(test.isZkSyncVM) + if test.err == "" { + require.NoError(t, err) + } else { + require.ErrorContains(t, err, test.err) + } + }) + } +} + +func TestNewEVMDeployOperation(t *testing.T) { + t.Parallel() + contractType := cldf.ContractType("TestContract") + version, _ := semver.NewVersion("1.0.0") + + t.Run("ChainSelectorMismatch", func(t *testing.T) { + t.Parallel() + + op := opsevm.NewEVMDeployOperation( + "test", + version, + "description", + contractType, + nil, + nil, + func(string) []any { return nil }, + ) + + input := opsevm.EVMDeployInput[string]{ + ChainSelector: 123, + DeployInput: "test", + } + chain := cldf_evm.Chain{Selector: 456} + + _, err := operations.ExecuteOperation(optest.NewBundle(t), op, chain, input) + require.Error(t, err) + assert.Contains(t, err.Error(), "mismatch between inputted chain selector") + }) + + t.Run("ContractMetadata undefined", func(t *testing.T) { + t.Parallel() + + op := opsevm.NewEVMDeployOperation( + "test", + version, + "description", + contractType, + nil, + nil, + func(string) []any { return nil }, + ) + + input := opsevm.EVMDeployInput[string]{ + ChainSelector: 123, + DeployInput: "test", + } + chain := cldf_evm.Chain{Selector: 123} + + _, err := operations.ExecuteOperation(optest.NewBundle(t), op, chain, input) + require.Error(t, err) + assert.Contains(t, err.Error(), "contract metadata must be provided for deployment") + }) + + t.Run("ContractOpts not defined", func(t *testing.T) { + t.Parallel() + + op := opsevm.NewEVMDeployOperation( + "test", + version, + "description", + contractType, + &bind.MetaData{}, + nil, + func(string) []any { return nil }, + ) + + input := opsevm.EVMDeployInput[string]{ + ChainSelector: 123, + DeployInput: "test", + } + chain := cldf_evm.Chain{Selector: 123} + + _, err := operations.ExecuteOperation(optest.NewBundle(t), op, chain, input) + require.Error(t, err) + assert.Contains(t, err.Error(), "must define ContractOpts for deployment, no defaults provided") + }) + + t.Run("Default ContractOpts not valid", func(t *testing.T) { + t.Parallel() + + op := opsevm.NewEVMDeployOperation( + "test", + version, + "description", + contractType, + &bind.MetaData{}, + &opsevm.ContractOpts{ + Version: semver.MustParse("0.1.0"), + EVMBytecode: nil, + ZkSyncVMBytecode: []byte{0x05, 0x06, 0x07, 0x08}, + }, + func(string) []any { return nil }, + ) + + input := opsevm.EVMDeployInput[string]{ + ChainSelector: 123, + DeployInput: "test", + } + chain := cldf_evm.Chain{Selector: 123} + + _, err := operations.ExecuteOperation(optest.NewBundle(t), op, chain, input) + require.Error(t, err) + assert.Contains(t, err.Error(), "invalid ContractOpts: evm bytecode must be defined") + }) + + t.Run("Inputted ContractOpts not valid", func(t *testing.T) { + t.Parallel() + + op := opsevm.NewEVMDeployOperation( + "test", + version, + "description", + contractType, + &bind.MetaData{}, + nil, + func(string) []any { return nil }, + ) + + input := opsevm.EVMDeployInput[string]{ + ChainSelector: 123, + ContractOpts: &opsevm.ContractOpts{ + Version: semver.MustParse("0.1.0"), + EVMBytecode: nil, + ZkSyncVMBytecode: []byte{0x05, 0x06, 0x07, 0x08}, + }, + DeployInput: "test", + } + chain := cldf_evm.Chain{Selector: 123} + + _, err := operations.ExecuteOperation(optest.NewBundle(t), op, chain, input) + require.Error(t, err) + assert.Contains(t, err.Error(), "invalid ContractOpts: evm bytecode must be defined") + }) + + t.Run("ABI parsing failure", func(t *testing.T) { + t.Parallel() + + op := opsevm.NewEVMDeployOperation( + "test", + version, + "description", + contractType, + &bind.MetaData{}, + nil, + func(string) []any { return nil }, + ) + + input := opsevm.EVMDeployInput[string]{ + ChainSelector: 123, + ContractOpts: &opsevm.ContractOpts{ + Version: semver.MustParse("0.1.0"), + EVMBytecode: []byte{0x01, 0x02, 0x03, 0x04}, + ZkSyncVMBytecode: []byte{0x05, 0x06, 0x07, 0x08}, + }, + DeployInput: "test", + } + chain := cldf_evm.Chain{Selector: 123} + + _, err := operations.ExecuteOperation(optest.NewBundle(t), op, chain, input) + require.Error(t, err) + assert.Contains(t, err.Error(), "failed to parse ABI") + }) + + t.Run("EVM deployment failure", func(t *testing.T) { + t.Parallel() + + op := opsevm.NewEVMDeployOperation( + "test", + version, + "description", + contractType, + &bind.MetaData{ABI: "[]"}, + nil, + func(string) []any { return nil }, + ) + + chain, err := cldf_evm_provider.NewSimChainProvider(t, 5009297550715157269, + cldf_evm_provider.SimChainProviderConfig{ + NumAdditionalAccounts: 1, + }, + ).Initialize(t.Context()) + require.NoError(t, err, "Failed to create SimChainProvider") + + chains := cldf_chain.NewBlockChainsFromSlice( + []cldf_chain.BlockChain{chain}, + ) + evmChain := chains.EVMChains()[5009297550715157269] + + input := opsevm.EVMDeployInput[string]{ + ChainSelector: 5009297550715157269, + ContractOpts: &opsevm.ContractOpts{ + Version: semver.MustParse("0.1.0"), + EVMBytecode: []byte{0x01, 0x02, 0x03, 0x04}, + ZkSyncVMBytecode: []byte{0x05, 0x06, 0x07, 0x08}, + }, + DeployInput: "test", + } + + _, err = operations.ExecuteOperation(optest.NewBundle(t), op, evmChain, input) + require.Error(t, err) + assert.Contains(t, err.Error(), "failed to deploy") + }) + + t.Run("EVM confirmation failure", func(t *testing.T) { + t.Parallel() + + op := opsevm.NewEVMDeployOperation( + "test", + version, + "description", + contractType, + &bind.MetaData{ABI: "[]"}, + nil, + func(string) []any { return nil }, + ) + + chain, err := cldf_evm_provider.NewSimChainProvider(t, 5009297550715157269, + cldf_evm_provider.SimChainProviderConfig{ + NumAdditionalAccounts: 1, + }, + ).Initialize(t.Context()) + require.NoError(t, err, "Failed to create SimChainProvider") + + chains := cldf_chain.NewBlockChainsFromSlice( + []cldf_chain.BlockChain{chain}, + ) + evmChain := chains.EVMChains()[5009297550715157269] + evmChain.Confirm = func(tx *types.Transaction) (uint64, error) { + return 0, errors.New("confirmation failed") + } + + input := opsevm.EVMDeployInput[string]{ + ChainSelector: 5009297550715157269, + ContractOpts: &opsevm.ContractOpts{ + Version: semver.MustParse("0.1.0"), + EVMBytecode: []byte{0x00}, + ZkSyncVMBytecode: []byte{0x00}, + }, + DeployInput: "test", + } + + _, err = operations.ExecuteOperation(optest.NewBundle(t), op, evmChain, input) + require.Error(t, err) + assert.Contains(t, err.Error(), "confirmation failed") + }) + + t.Run("EVM deployment success", func(t *testing.T) { + t.Parallel() + + op := opsevm.NewEVMDeployOperation( + "test", + version, + "description", + contractType, + &bind.MetaData{ABI: "[]"}, + nil, + func(string) []any { return nil }, + ) + + chain, err := cldf_evm_provider.NewSimChainProvider(t, 5009297550715157269, + cldf_evm_provider.SimChainProviderConfig{ + NumAdditionalAccounts: 1, + }, + ).Initialize(t.Context()) + require.NoError(t, err, "Failed to create SimChainProvider") + + chains := cldf_chain.NewBlockChainsFromSlice( + []cldf_chain.BlockChain{chain}, + ) + evmChain := chains.EVMChains()[5009297550715157269] + + input := opsevm.EVMDeployInput[string]{ + ChainSelector: 5009297550715157269, + ContractOpts: &opsevm.ContractOpts{ + Version: semver.MustParse("0.1.0"), + EVMBytecode: []byte{0x00}, + ZkSyncVMBytecode: []byte{0x00}, + }, + DeployInput: "test", + } + + _, err = operations.ExecuteOperation(optest.NewBundle(t), op, evmChain, input) + require.NoError(t, err) + }) +} diff --git a/pkg/family/evm/sequences/grant_roles_for_timelock.go b/pkg/family/evm/sequences/grant_roles_for_timelock.go new file mode 100644 index 0000000..882987f --- /dev/null +++ b/pkg/family/evm/sequences/grant_roles_for_timelock.go @@ -0,0 +1,126 @@ +package seqs + +import ( + "slices" + + "github.com/Masterminds/semver/v3" + "github.com/ethereum/go-ethereum/common" + cldfproposalutils "github.com/smartcontractkit/chainlink-deployments-framework/engine/cld/mcms/proposalutils" + evmMcms "github.com/smartcontractkit/mcms/sdk/evm" + mcmsTypes "github.com/smartcontractkit/mcms/types" + + cldfevm "github.com/smartcontractkit/chainlink-deployments-framework/chain/evm" + cldf "github.com/smartcontractkit/chainlink-deployments-framework/deployment" + "github.com/smartcontractkit/chainlink-deployments-framework/operations" + + "github.com/smartcontractkit/cld-changesets/pkg/contract/mcms/view/v1_0" + + opsevm "github.com/smartcontractkit/cld-changesets/pkg/family/evm/operations" +) + +type SeqGrantRolesTimelockDeps struct { + Chain cldfevm.Chain +} + +type RolesAndAddresses struct { + Role common.Hash + Name string + Addresses []common.Address +} + +type SeqGrantRolesTimelockInput struct { + ContractType cldf.ContractType `json:"contractType"` + ChainSelector uint64 `json:"chainSelector"` + Timelock common.Address `json:"timelock"` + RolesAndAddresses []RolesAndAddresses `json:"rolesAndAddresses"` + IsDeployerKeyAdmin bool `json:"isDeployerKeyAdmin"` + GasBoostConfig *cldfproposalutils.GasBoostConfig `json:"gasBoostConfig"` +} + +type SeqGrantRolesTimelockOutput struct { + McmsTxs []mcmsTypes.Transaction `json:"mcmsTxs"` +} + +var SeqGrantRolesTimelock = operations.NewSequence( + "seq-grant-role-with-config", + semver.MustParse("1.0.0"), + "Grants appropriate roles to MCMS contracts in the EVM Timelock contract", + func(b operations.Bundle, deps SeqGrantRolesTimelockDeps, in SeqGrantRolesTimelockInput) (map[uint64][]opsevm.EVMCallOutput, error) { + var ( + addressesInInspector []string + err2 error + ) + out := make([]opsevm.EVMCallOutput, 0) + + timelockInspector := evmMcms.NewTimelockInspector(deps.Chain.Client) + + for _, roleAndAddress := range in.RolesAndAddresses { + switch roleAndAddress.Role { + case v1_0.PROPOSER_ROLE.ID: + addressesInInspector, err2 = timelockInspector.GetProposers(b.GetContext(), in.Timelock.Hex()) + case v1_0.CANCELLER_ROLE.ID: + addressesInInspector, err2 = timelockInspector.GetCancellers(b.GetContext(), in.Timelock.Hex()) + case v1_0.BYPASSER_ROLE.ID: + addressesInInspector, err2 = timelockInspector.GetBypassers(b.GetContext(), in.Timelock.Hex()) + case v1_0.EXECUTOR_ROLE.ID: + addressesInInspector, err2 = timelockInspector.GetExecutors(b.GetContext(), in.Timelock.Hex()) + case v1_0.ADMIN_ROLE.ID: + addressesInInspector = []string{} + } + if err2 != nil { + b.Logger.Errorw("Failed to get addresses from Timelock Inspector", + "chainSelector", deps.Chain.ChainSelector(), + "chainName", deps.Chain.Name(), + "Timelock Address", in.Timelock.Hex(), + "Role", roleAndAddress.Name, + "Error", err2, + ) + + return nil, err2 + } + for _, addressToGrantRole := range roleAndAddress.Addresses { + if !slices.Contains(addressesInInspector, addressToGrantRole.Hex()) { + opReport, err := operations.ExecuteOperation(b, opsevm.OpEVMGrantRole, + deps.Chain, + opsevm.EVMCallInput[opsevm.OpEVMGrantRoleInput]{ + ChainSelector: in.ChainSelector, + CallInput: opsevm.OpEVMGrantRoleInput{ + Account: addressToGrantRole, + RoleID: roleAndAddress.Role, + }, + NoSend: !in.IsDeployerKeyAdmin, + Address: in.Timelock, + }, + opsevm.RetryCallWithGasBoost[opsevm.OpEVMGrantRoleInput](in.GasBoostConfig), + ) + if err != nil { + b.Logger.Errorw("Failed to grant role", + "chainSelector", deps.Chain.ChainSelector(), + "chainName", deps.Chain.Name(), + "Timelock Address", in.Timelock.Hex(), + "Role Name", roleAndAddress.Name, + "Address", addressToGrantRole.Hex(), + ) + + return nil, err + } + out = append(out, opReport.Output) + + if in.IsDeployerKeyAdmin { + b.Logger.Infow("Role granted", + "Role Name", roleAndAddress.Name, + "chainSelector", deps.Chain.ChainSelector(), + "chainName", deps.Chain.Name(), + "Timelock Address", in.Timelock.Hex(), + "Address", addressToGrantRole.Hex(), + ) + } + } + } + } + + return map[uint64][]opsevm.EVMCallOutput{ + in.ChainSelector: out, + }, nil + }, +) diff --git a/pkg/family/evm/sequences/mcm_with_config.go b/pkg/family/evm/sequences/mcm_with_config.go new file mode 100644 index 0000000..8bb1e0e --- /dev/null +++ b/pkg/family/evm/sequences/mcm_with_config.go @@ -0,0 +1,90 @@ +package seqs + +import ( + "fmt" + + "github.com/Masterminds/semver/v3" + "github.com/ethereum/go-ethereum/common" + mcmscontracts "github.com/smartcontractkit/chainlink-deployments-framework/engine/cld/contracts/mcms" + cldfproposalutils "github.com/smartcontractkit/chainlink-deployments-framework/engine/cld/mcms/proposalutils" + + "github.com/smartcontractkit/mcms/sdk" + mcmsTypes "github.com/smartcontractkit/mcms/types" + + cldf_evm "github.com/smartcontractkit/chainlink-deployments-framework/chain/evm" + cldf "github.com/smartcontractkit/chainlink-deployments-framework/deployment" + "github.com/smartcontractkit/chainlink-deployments-framework/operations" + + opsevm "github.com/smartcontractkit/cld-changesets/pkg/family/evm/operations" +) + +type SeqDeployMCMWithConfigInput struct { + ContractType cldf.ContractType `json:"contractType"` + MCMConfig mcmsTypes.Config `json:"mcmConfig"` + ChainSelector uint64 `json:"chainSelector"` + GasBoostConfig *cldfproposalutils.GasBoostConfig `json:"gasBoostConfig"` + Qualifier *string `json:"qualifier"` +} + +type SeqDeployMCMWithConfigOutput struct { + Address common.Address `json:"address"` +} + +var SeqEVMDeployMCMWithConfig = operations.NewSequence( + "seq-deploy-mcm-with-config", + semver.MustParse("1.0.0"), + "Deploys MCM contract & sets config", + func(b operations.Bundle, deps cldf_evm.Chain, in SeqDeployMCMWithConfigInput) (opsevm.EVMDeployOutput, error) { + // Deploy MCM contract + var deployReport operations.Report[opsevm.EVMDeployInput[any], opsevm.EVMDeployOutput] + var deployErr error + switch in.ContractType { + case mcmscontracts.BypasserManyChainMultisig: + deployReport, deployErr = operations.ExecuteOperation(b, opsevm.OpEVMDeployBypasserMCM, deps, opsevm.EVMDeployInput[any]{ + ChainSelector: in.ChainSelector, + Qualifier: in.Qualifier, + }, opsevm.RetryDeploymentWithGasBoost[any](in.GasBoostConfig)) + case mcmscontracts.ProposerManyChainMultisig: + deployReport, deployErr = operations.ExecuteOperation(b, opsevm.OpEVMDeployProposerMCM, deps, opsevm.EVMDeployInput[any]{ + ChainSelector: in.ChainSelector, + Qualifier: in.Qualifier, + }, opsevm.RetryDeploymentWithGasBoost[any](in.GasBoostConfig)) + case mcmscontracts.CancellerManyChainMultisig: + deployReport, deployErr = operations.ExecuteOperation(b, opsevm.OpEVMDeployCancellerMCM, deps, opsevm.EVMDeployInput[any]{ + ChainSelector: in.ChainSelector, + Qualifier: in.Qualifier, + }, opsevm.RetryDeploymentWithGasBoost[any](in.GasBoostConfig)) + default: + return opsevm.EVMDeployOutput{}, fmt.Errorf("unsupported contract type for seq-deploy-mcm-with-config: %s", in.ContractType) + } + if deployErr != nil { + return opsevm.EVMDeployOutput{}, fmt.Errorf("failed to deploy %s: %w", in.ContractType, deployErr) + } + + // Set config + groupQuorums, groupParents, signerAddresses, signerGroups, err := sdk.ExtractSetConfigInputs(&in.MCMConfig) + if err != nil { + return opsevm.EVMDeployOutput{}, err + } + _, err = operations.ExecuteOperation(b, opsevm.OpEVMSetConfigMCM, + deps, + opsevm.EVMCallInput[opsevm.OpEVMSetConfigMCMInput]{ + ChainSelector: in.ChainSelector, + Address: deployReport.Output.Address, + NoSend: false, + CallInput: opsevm.OpEVMSetConfigMCMInput{ + SignerAddresses: signerAddresses, + SignerGroups: signerGroups, + GroupQuorums: groupQuorums, + GroupParents: groupParents, + }, + }, + opsevm.RetryCallWithGasBoost[opsevm.OpEVMSetConfigMCMInput](in.GasBoostConfig), + ) + if err != nil { + return opsevm.EVMDeployOutput{}, err + } + + return deployReport.Output, nil + }, +) diff --git a/pkg/family/solana/changesets/legacy/access_controller.go b/pkg/family/solana/changesets/legacy/access_controller.go new file mode 100644 index 0000000..5ab34e2 --- /dev/null +++ b/pkg/family/solana/changesets/legacy/access_controller.go @@ -0,0 +1,219 @@ +package legacy + +import ( + "errors" + "fmt" + + "github.com/gagliardetto/solana-go" + "github.com/gagliardetto/solana-go/programs/system" + "github.com/gagliardetto/solana-go/rpc" + mcmscontracts "github.com/smartcontractkit/chainlink-deployments-framework/engine/cld/contracts/mcms" + + cldf_solana "github.com/smartcontractkit/chainlink-deployments-framework/chain/solana" + + accessControllerBindings "github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings/v0_1_1/access_controller" + timelockBindings "github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings/v0_1_1/timelock" + solanaUtils "github.com/smartcontractkit/chainlink-ccip/chains/solana/utils/common" + + cldf "github.com/smartcontractkit/chainlink-deployments-framework/deployment" + + cldchangesetscommon "github.com/smartcontractkit/cld-changesets/pkg/common" + familysolana "github.com/smartcontractkit/cld-changesets/pkg/family/solana" + legacy2 "github.com/smartcontractkit/cld-changesets/pkg/family/solana/legacy" + "github.com/smartcontractkit/cld-changesets/pkg/family/solana/legacy/solutils" +) + +func deployAccessControllerProgram( + e cldf.Environment, chainState *legacy2.MCMSWithTimelockState, + chain cldf_solana.Chain, addressBook cldf.AddressBook, +) error { + typeAndVersion := cldf.NewTypeAndVersion(mcmscontracts.AccessControllerProgram, cldchangesetscommon.Version1_0_0) + + programID, _, err := chainState.GetStateFromType(mcmscontracts.AccessControllerProgram) + if err != nil { + return fmt.Errorf("failed to get access controller program state: %w", err) + } + + if programID.IsZero() { + deployedProgramID, err := chain.DeployProgram(e.Logger, cldf_solana.ProgramInfo{ + Name: solutils.ProgAccessController, + Bytes: solutils.GetProgramBufferBytes(solutils.ProgAccessController), + }, false, true) + if err != nil { + return fmt.Errorf("failed to deploy access controller program: %w", err) + } + + programID, err = solana.PublicKeyFromBase58(deployedProgramID) + if err != nil { + return fmt.Errorf("failed to convert mcm program id to public key: %w", err) + } + + err = addressBook.Save(chain.Selector, programID.String(), typeAndVersion) + if err != nil { + return fmt.Errorf("failed to save address: %w", err) + } + + err = chainState.SetState(mcmscontracts.AccessControllerProgram, programID, legacy2.PDASeed{}) + if err != nil { + return fmt.Errorf("failed to save onchain state: %w", err) + } + + e.Logger.Infow("deployed access controller contract", + "chain", chain.String(), "contract", typeAndVersion.String(), "programId", programID) + } else { + e.Logger.Infow("using existing AccessController program", + "chain", chain.String(), "contract", typeAndVersion.String(), "programId", programID) + } + + return nil +} + +func initAccessController( + e cldf.Environment, chainState *legacy2.MCMSWithTimelockState, contractType cldf.ContractType, + chain cldf_solana.Chain, addressBook cldf.AddressBook, +) error { + if chainState.AccessControllerProgram.IsZero() { + return errors.New("access controller program is not deployed") + } + typeAndVersion := cldf.NewTypeAndVersion(contractType, cldchangesetscommon.Version1_0_0) + _, accessControllerAccountSeed, err := chainState.GetStateFromType(contractType) + if err != nil { + return fmt.Errorf("failed to get account controller state: %w", err) + } + + accessControllerAccount := solana.PublicKeyFromBytes(accessControllerAccountSeed[:]) + if !accessControllerAccount.IsZero() { + var data accessControllerBindings.AccessController + err = solanaUtils.GetAccountDataBorshInto(e.GetContext(), chain.Client, accessControllerAccount, rpc.CommitmentConfirmed, &data) + if err == nil { + e.Logger.Infow("access controller already initialized, skipping initialization", "chain", chain.String()) + return nil + } + + return fmt.Errorf("unable to read access controller account config %s", accessControllerAccount.String()) + } + + e.Logger.Infow("access controller not initialized, initializing", "chain", chain.String()) + + programID := chainState.AccessControllerProgram + accessControllerBindings.SetProgramID(programID) + + account, err := solana.NewRandomPrivateKey() // FIXME: what should we do with the account private key? + if err != nil { + return fmt.Errorf("failed to generate new random private key for access controller account: %w", err) + } + + err = initializeAccessController(e, chain, programID, account) + if err != nil { + return fmt.Errorf("failed to initialize access controller: %w", err) + } + e.Logger.Infow("initialized access controller", + "chain", chain.String(), "contract", typeAndVersion.String(), + "programID", programID, "account", account.PublicKey()) + + err = addressBook.Save(chain.Selector, account.PublicKey().String(), typeAndVersion) + if err != nil { + return fmt.Errorf("failed to save address: %w", err) + } + + err = chainState.SetState(contractType, account.PublicKey(), legacy2.PDASeed{}) + if err != nil { + return fmt.Errorf("failed to save onchain state: %w", err) + } + + return nil +} + +// discriminator + owner + proposed owner + access_list (64 max addresses + length) +const accessControllerAccountSize = uint64(8 + 32 + 32 + ((32 * 64) + 8)) + +func initializeAccessController( + e cldf.Environment, chain cldf_solana.Chain, programID solana.PublicKey, roleAccount solana.PrivateKey, +) error { + rentExemption, err := chain.Client.GetMinimumBalanceForRentExemption(e.GetContext(), + accessControllerAccountSize, rpc.CommitmentConfirmed) + if err != nil { + return fmt.Errorf("failed to get minimum balance for rent exemption: %w", err) + } + + createAccountInstruction, err := system.NewCreateAccountInstruction(rentExemption, accessControllerAccountSize, + programID, chain.DeployerKey.PublicKey(), roleAccount.PublicKey()).ValidateAndBuild() + if err != nil { + return fmt.Errorf("failed to create CreateAccount instruction: %w", err) + } + + initializeInstruction, err := accessControllerBindings.NewInitializeInstruction( + roleAccount.PublicKey(), + chain.DeployerKey.PublicKey(), + ).ValidateAndBuild() + if err != nil { + return fmt.Errorf("failed to build instruction: %w", err) + } + + instructions := []solana.Instruction{createAccountInstruction, initializeInstruction} + err = chain.Confirm(instructions, solanaUtils.AddSigners(roleAccount)) + if err != nil { + return fmt.Errorf("failed to confirm CreateAccount and InitializeAccessController instructions: %w", err) + } + + var data accessControllerBindings.AccessController + err = solanaUtils.GetAccountDataBorshInto(e.GetContext(), chain.Client, roleAccount.PublicKey(), rpc.CommitmentConfirmed, &data) + if err != nil { + return fmt.Errorf("failed to read access controller roleAccount: %w", err) + } + + return nil +} + +func setupRoles(chainState *legacy2.MCMSWithTimelockState, chain cldf_solana.Chain) error { + proposerPDA := familysolana.GetMCMSignerPDA(chainState.McmProgram, chainState.ProposerMcmSeed) + cancellerPDA := familysolana.GetMCMSignerPDA(chainState.McmProgram, chainState.CancellerMcmSeed) + bypasserPDA := familysolana.GetMCMSignerPDA(chainState.McmProgram, chainState.BypasserMcmSeed) + + err := addAccess(chain, chainState, timelockBindings.Proposer_Role, proposerPDA) + if err != nil { + return fmt.Errorf("failed to add access for proposer role: %w", err) + } + + err = addAccess(chain, chainState, timelockBindings.Executor_Role, chain.DeployerKey.PublicKey()) + if err != nil { + return fmt.Errorf("failed to add access for executor role: %w", err) + } + + err = addAccess(chain, chainState, timelockBindings.Canceller_Role, cancellerPDA, proposerPDA, bypasserPDA) + if err != nil { + return fmt.Errorf("failed to add access for canceller role: %w", err) + } + + err = addAccess(chain, chainState, timelockBindings.Bypasser_Role, bypasserPDA) + if err != nil { + return fmt.Errorf("failed to add access for bypasser role: %w", err) + } + + return nil +} + +func addAccess( + chain cldf_solana.Chain, chainState *legacy2.MCMSWithTimelockState, + role timelockBindings.Role, accounts ...solana.PublicKey, +) error { + timelockConfigPDA := familysolana.GetTimelockConfigPDA(chainState.TimelockProgram, chainState.TimelockSeed) + + instructionBuilder := timelockBindings.NewBatchAddAccessInstruction([32]uint8(chainState.TimelockSeed), role, + timelockConfigPDA, chainState.AccessControllerProgram, chainState.RoleAccount(role), chain.DeployerKey.PublicKey()) + for _, account := range accounts { + instructionBuilder.Append(solana.Meta(account)) + } + + instruction, err := instructionBuilder.ValidateAndBuild() + if err != nil { + return fmt.Errorf("failed to build BatchAddAccess instruction: %w", err) + } + + err = chain.Confirm([]solana.Instruction{instruction}) + if err != nil { + return fmt.Errorf("failed to confirm BatchAddAccess instruction: %w", err) + } + + return nil +} diff --git a/pkg/family/solana/changesets/legacy/deploy_mcm.go b/pkg/family/solana/changesets/legacy/deploy_mcm.go new file mode 100644 index 0000000..7c89d1a --- /dev/null +++ b/pkg/family/solana/changesets/legacy/deploy_mcm.go @@ -0,0 +1,199 @@ +package legacy + +import ( + "crypto/rand" + "errors" + "fmt" + "math/big" + + binary "github.com/gagliardetto/binary" + "github.com/gagliardetto/solana-go" + "github.com/gagliardetto/solana-go/rpc" + cldf_solana "github.com/smartcontractkit/chainlink-deployments-framework/chain/solana" + cldf "github.com/smartcontractkit/chainlink-deployments-framework/deployment" + mcmscontracts "github.com/smartcontractkit/chainlink-deployments-framework/engine/cld/contracts/mcms" + mcmsSolanaSdk "github.com/smartcontractkit/mcms/sdk/solana" + mcmsTypes "github.com/smartcontractkit/mcms/types" + + mcmBindings "github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings/v0_1_1/mcm" + solanaUtils "github.com/smartcontractkit/chainlink-ccip/chains/solana/utils/common" + + cldchangesetscommon "github.com/smartcontractkit/cld-changesets/pkg/common" + familysolana "github.com/smartcontractkit/cld-changesets/pkg/family/solana" + legacy2 "github.com/smartcontractkit/cld-changesets/pkg/family/solana/legacy" + "github.com/smartcontractkit/cld-changesets/pkg/family/solana/legacy/solutils" +) + +func deployMCMProgram( + env cldf.Environment, chainState *legacy2.MCMSWithTimelockState, + chain cldf_solana.Chain, addressBook cldf.AddressBook, +) error { + typeAndVersion := cldf.NewTypeAndVersion(mcmscontracts.ManyChainMultisigProgram, cldchangesetscommon.Version1_0_0) + + programID, _, err := chainState.GetStateFromType(mcmscontracts.ManyChainMultisigProgram) + if err != nil { + return fmt.Errorf("failed to get mcm state: %w", err) + } + + if programID.IsZero() { + deployedProgramID, err := chain.DeployProgram(env.Logger, cldf_solana.ProgramInfo{ + Name: solutils.ProgMCM, + Bytes: solutils.GetProgramBufferBytes(solutils.ProgMCM), + }, false, true) + if err != nil { + return fmt.Errorf("failed to deploy mcm program: %w", err) + } + + programID, err = solana.PublicKeyFromBase58(deployedProgramID) + if err != nil { + return fmt.Errorf("failed to convert mcm program id to public key: %w", err) + } + + err = addressBook.Save(chain.Selector, programID.String(), typeAndVersion) + if err != nil { + return fmt.Errorf("failed to save mcm address: %w", err) + } + + err = chainState.SetState(mcmscontracts.ManyChainMultisigProgram, programID, legacy2.PDASeed{}) + if err != nil { + return fmt.Errorf("failed to save onchain state: %w", err) + } + + env.Logger.Infow("deployed mcm contract", + "chain", chain.String(), "contract", typeAndVersion.String(), "programId", deployedProgramID) + } else { + env.Logger.Infow("using existing MCM program", + "chain", chain.String(), "contract", typeAndVersion.String(), "programId", programID.String()) + } + + return nil +} + +func initMCM( + env cldf.Environment, chainState *legacy2.MCMSWithTimelockState, contractType cldf.ContractType, + chain cldf_solana.Chain, addressBook cldf.AddressBook, mcmConfig *mcmsTypes.Config, +) error { + if chainState.McmProgram.IsZero() { + return errors.New("mcm program is not deployed") + } + programID := chainState.McmProgram + + typeAndVersion := cldf.NewTypeAndVersion(contractType, cldchangesetscommon.Version1_0_0) + mcmProgram, mcmSeed, err := chainState.GetStateFromType(contractType) + if err != nil { + return fmt.Errorf("failed to get mcm state: %w", err) + } + + if mcmSeed != (legacy2.PDASeed{}) { + mcmConfigPDA := familysolana.GetMCMConfigPDA(mcmProgram, mcmSeed) + var data mcmBindings.MultisigConfig + err = solanaUtils.GetAccountDataBorshInto(env.GetContext(), chain.Client, mcmConfigPDA, rpc.CommitmentConfirmed, &data) + if err == nil { + env.Logger.Infow("mcm config already initialized, skipping initialization", "chain", chain.String()) + return nil + } + + return fmt.Errorf("unable to read mcm ConfigPDA account config %s", mcmConfigPDA.String()) + } + + env.Logger.Infow("mcm config not initialized, initializing", "chain", chain.String()) + + seed, err := randomSeed() + if err != nil { + return fmt.Errorf("failed to generate MCM seed: %w", err) + } + env.Logger.Infow("generated MCM seed", + "chain", chain.String(), "contract", typeAndVersion.String(), "seed", string(seed[:])) + + err = initializeMCM(env, chain, programID, seed) + if err != nil { + return fmt.Errorf("failed to initialize mcm: %w", err) + } + + mcmAddress := legacy2.EncodeAddressWithSeed(programID, seed) + + configurer := mcmsSolanaSdk.NewConfigurer(chain.Client, *chain.DeployerKey, mcmsTypes.ChainSelector(chain.Selector)) + tx, err := configurer.SetConfig(env.GetContext(), mcmAddress, mcmConfig, false) + if err != nil { + return fmt.Errorf("failed to set config on mcm: %w", err) + } + env.Logger.Infow("called SetConfig on MCM", + "chain", chain.String(), "contract", typeAndVersion.String(), "transaction", tx.Hash) + + err = addressBook.Save(chain.Selector, mcmAddress, typeAndVersion) + if err != nil { + return fmt.Errorf("failed to save address: %w", err) + } + + err = chainState.SetState(contractType, programID, seed) + if err != nil { + return fmt.Errorf("failed to save onchain state: %w", err) + } + + return nil +} + +func initializeMCM(e cldf.Environment, chain cldf_solana.Chain, mcmProgram solana.PublicKey, multisigID legacy2.PDASeed) error { + var mcmConfig mcmBindings.MultisigConfig + err := chain.GetAccountDataBorshInto(e.GetContext(), familysolana.GetMCMConfigPDA(mcmProgram, multisigID), &mcmConfig) + if err == nil { + e.Logger.Infow("MCM already initialized, skipping initialization", "chain", chain.String()) + return nil + } + + var programData struct { + DataType uint32 + Address solana.PublicKey + } + opts := &rpc.GetAccountInfoOpts{Commitment: rpc.CommitmentConfirmed} + + data, err := chain.Client.GetAccountInfoWithOpts(e.GetContext(), mcmProgram, opts) + if err != nil { + return fmt.Errorf("failed to get mcm program account info: %w", err) + } + err = binary.UnmarshalBorsh(&programData, data.Bytes()) + if err != nil { + return fmt.Errorf("failed to unmarshal program data: %w", err) + } + + ix, err := mcmBindings.NewInitializeInstruction( + chain.Selector, + multisigID, + familysolana.GetMCMConfigPDA(mcmProgram, multisigID), + chain.DeployerKey.PublicKey(), + solana.SystemProgramID, + mcmProgram, + programData.Address, + familysolana.GetMCMRootMetadataPDA(mcmProgram, multisigID), + familysolana.GetMCMExpiringRootAndOpCountPDA(mcmProgram, multisigID), + ).ValidateAndBuild() + if err != nil { + return fmt.Errorf("failed to build instruction: %w", err) + } + ixData, err := ix.Data() + if err != nil { + return fmt.Errorf("failed to extract data payload from mcm initialize instruction: %w", err) + } + initIx := solana.NewInstruction(mcmProgram, ix.Accounts(), ixData) + err = chain.Confirm([]solana.Instruction{initIx}) + if err != nil { + return fmt.Errorf("failed to confirm instructions: %w", err) + } + + return nil +} + +func randomSeed() (legacy2.PDASeed, error) { + const alphabet = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + + seed := legacy2.PDASeed{} + for i := range seed { + n, err := rand.Int(rand.Reader, big.NewInt(int64(len(alphabet)))) + if err != nil { + return legacy2.PDASeed{}, fmt.Errorf("failed to generate random seed byte: %w", err) + } + seed[i] = alphabet[n.Int64()] + } + + return seed, nil +} diff --git a/pkg/family/solana/changesets/legacy/deploy_mcms_with_timelock.go b/pkg/family/solana/changesets/legacy/deploy_mcms_with_timelock.go new file mode 100644 index 0000000..5f221e6 --- /dev/null +++ b/pkg/family/solana/changesets/legacy/deploy_mcms_with_timelock.go @@ -0,0 +1,163 @@ +package legacy + +import ( + "context" + "errors" + "fmt" + "time" + + "github.com/gagliardetto/solana-go" + "github.com/gagliardetto/solana-go/rpc" + mcmscontracts "github.com/smartcontractkit/chainlink-deployments-framework/engine/cld/contracts/mcms" + cldfproposalutils "github.com/smartcontractkit/chainlink-deployments-framework/engine/cld/mcms/proposalutils" + + familysolana "github.com/smartcontractkit/cld-changesets/pkg/family/solana/legacy" + solseqs "github.com/smartcontractkit/cld-changesets/pkg/family/solana/sequences" + + cldf_solana "github.com/smartcontractkit/chainlink-deployments-framework/chain/solana" + "github.com/smartcontractkit/chainlink-deployments-framework/datastore" + cldf "github.com/smartcontractkit/chainlink-deployments-framework/deployment" + "github.com/smartcontractkit/chainlink-deployments-framework/operations" + + solops "github.com/smartcontractkit/cld-changesets/pkg/family/solana/operations" +) + +// DeployMCMSWithTimelockProgramsSolana deploys an MCMS program +// and initializes 3 instances for each of the timelock roles: Bypasser, ProposerMcm, Canceller on an Solana chain. +// as well as the timelock program. It's not necessarily the only way to use +// the timelock and MCMS, but its reasonable pattern. +func DeployMCMSWithTimelockProgramsSolana( + e cldf.Environment, + chain cldf_solana.Chain, + addressBook cldf.AddressBook, + config cldfproposalutils.MCMSWithTimelockConfig, +) (*familysolana.MCMSWithTimelockState, error) { + addresses, err := e.ExistingAddresses.AddressesForChain(chain.Selector) //nolint:staticcheck // legacy deployment path still accepts AddressBook input + if err != nil && !errors.Is(err, cldf.ErrChainNotFound) { + return nil, fmt.Errorf("failed to get addresses for chain %v from environment: %w", chain.Selector, err) + } + + chainState, err := familysolana.MaybeLoadMCMSWithTimelockChainState(chain, addresses) + if err != nil { + return nil, fmt.Errorf("failed to load mcms with timelock solana chain state: %w", err) + } + + // access controller + err = deployAccessControllerProgram(e, chainState, chain, addressBook) + if err != nil { + return nil, fmt.Errorf("failed to deploy access controller program: %w", err) + } + err = waitForProgramDeployment(e.GetContext(), chain.Client, chainState.AccessControllerProgram, 30*time.Second) + if err != nil { + return nil, fmt.Errorf("access controller program not ready: %w", err) + } + err = initAccessController(e, chainState, mcmscontracts.ProposerAccessControllerAccount, chain, addressBook) + if err != nil { + return nil, fmt.Errorf("failed to init proposer access controller: %w", err) + } + err = initAccessController(e, chainState, mcmscontracts.ExecutorAccessControllerAccount, chain, addressBook) + if err != nil { + return nil, fmt.Errorf("failed to init access controller: %w", err) + } + err = initAccessController(e, chainState, mcmscontracts.CancellerAccessControllerAccount, chain, addressBook) + if err != nil { + return nil, fmt.Errorf("failed to init access controller: %w", err) + } + err = initAccessController(e, chainState, mcmscontracts.BypasserAccessControllerAccount, chain, addressBook) + if err != nil { + return nil, fmt.Errorf("failed to init access controller: %w", err) + } + + // mcm + err = deployMCMProgram(e, chainState, chain, addressBook) + if err != nil { + return nil, fmt.Errorf("failed to deploy mcm program: %w", err) + } + err = waitForProgramDeployment(e.GetContext(), chain.Client, chainState.McmProgram, 30*time.Second) + if err != nil { + return nil, fmt.Errorf("mcm program not ready: %w", err) + } + err = initMCM(e, chainState, mcmscontracts.BypasserManyChainMultisig, chain, addressBook, &config.Bypasser) + if err != nil { + return nil, fmt.Errorf("failed to init bypasser mcm: %w", err) + } + err = initMCM(e, chainState, mcmscontracts.CancellerManyChainMultisig, chain, addressBook, &config.Canceller) + if err != nil { + return nil, fmt.Errorf("failed to init canceller mcm: %w", err) + } + err = initMCM(e, chainState, mcmscontracts.ProposerManyChainMultisig, chain, addressBook, &config.Proposer) + if err != nil { + return nil, fmt.Errorf("failed to init proposer mcm: %w", err) + } + + // timelock + err = deployTimelockProgram(e, chainState, chain, addressBook) + if err != nil { + return nil, fmt.Errorf("failed to deploy timelock program: %w", err) + } + err = waitForProgramDeployment(e.GetContext(), chain.Client, chainState.TimelockProgram, 30*time.Second) + if err != nil { + return nil, fmt.Errorf("timelock program not ready: %w", err) + } + err = initTimelock(e, chainState, chain, addressBook, config.TimelockMinDelay) + if err != nil { + return nil, fmt.Errorf("failed to init timelock: %w", err) + } + + err = setupRoles(chainState, chain) + if err != nil { + return nil, fmt.Errorf("failed to setup roles and ownership: %w", err) + } + + return chainState, nil +} + +// DeployMCMSWithTimelockProgramsSolanaV2 deploys an MCMS program using Operations API +// saves addresses to datastore +func DeployMCMSWithTimelockProgramsSolanaV2( + e cldf.Environment, + ds datastore.MutableDataStore, + chain cldf_solana.Chain, + config cldfproposalutils.MCMSWithTimelockConfig) (*familysolana.MCMSWithTimelockState, error) { + chainstate, err := familysolana.MaybeLoadMCMSWithTimelockChainStateV2(e.DataStore.Addresses().Filter(datastore.AddressRefByChainSelector(chain.Selector))) + if err != nil { + return nil, err + } + + deps := solops.Deps{ + State: chainstate, + Chain: chain, + Datastore: ds, + } + + _, err = operations.ExecuteSequence(e.OperationsBundle, solseqs.DeployMCMSWithTimelockSeq, deps, solseqs.DeployMCMSWithTimelockInput{ + MCMConfig: config, + TimelockMinDelay: config.TimelockMinDelay, + }) + if err != nil { + return nil, err + } + + return chainstate, nil +} + +func waitForProgramDeployment(ctx context.Context, client *rpc.Client, programID solana.PublicKey, maxWait time.Duration) error { + timeout := time.After(maxWait) + ticker := time.NewTicker(500 * time.Millisecond) + defer ticker.Stop() + + for { + select { + case <-timeout: + return fmt.Errorf("timed out waiting for program %s to be deployed", programID.String()) + case <-ticker.C: + resp, err := client.GetAccountInfo(ctx, programID) + if err != nil { + continue // Retry on RPC errors + } + if resp != nil && resp.Value != nil && resp.Value.Executable { + return nil // Ready + } + } + } +} diff --git a/pkg/family/solana/changesets/legacy/deploy_timelock.go b/pkg/family/solana/changesets/legacy/deploy_timelock.go new file mode 100644 index 0000000..5b8fd9a --- /dev/null +++ b/pkg/family/solana/changesets/legacy/deploy_timelock.go @@ -0,0 +1,182 @@ +package legacy + +import ( + "errors" + "fmt" + "math/big" + + binary "github.com/gagliardetto/binary" + "github.com/gagliardetto/solana-go" + "github.com/gagliardetto/solana-go/rpc" + mcmscontracts "github.com/smartcontractkit/chainlink-deployments-framework/engine/cld/contracts/mcms" + + cldf_solana "github.com/smartcontractkit/chainlink-deployments-framework/chain/solana" + + timelockBindings "github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings/v0_1_1/timelock" + + cldf "github.com/smartcontractkit/chainlink-deployments-framework/deployment" + + cldchangesetscommon "github.com/smartcontractkit/cld-changesets/pkg/common" + familysolana "github.com/smartcontractkit/cld-changesets/pkg/family/solana" + legacy2 "github.com/smartcontractkit/cld-changesets/pkg/family/solana/legacy" + "github.com/smartcontractkit/cld-changesets/pkg/family/solana/legacy/solutils" +) + +func deployTimelockProgram( + e cldf.Environment, chainState *legacy2.MCMSWithTimelockState, chain cldf_solana.Chain, + addressBook cldf.AddressBook, +) error { + typeAndVersion := cldf.NewTypeAndVersion(mcmscontracts.RBACTimelockProgram, cldchangesetscommon.Version1_0_0) + + programID, _, err := chainState.GetStateFromType(mcmscontracts.RBACTimelock) + if err != nil { + return fmt.Errorf("failed to get timelock state: %w", err) + } + + if programID.IsZero() { + deployedProgramID, err := chain.DeployProgram(e.Logger, cldf_solana.ProgramInfo{ + Name: solutils.ProgTimelock, + Bytes: solutils.GetProgramBufferBytes(solutils.ProgTimelock), + }, false, true) + if err != nil { + return fmt.Errorf("failed to deploy timelock program: %w", err) + } + + programID, err = solana.PublicKeyFromBase58(deployedProgramID) + if err != nil { + return fmt.Errorf("failed to convert timelock program id to public key: %w", err) + } + + err = addressBook.Save(chain.Selector, programID.String(), typeAndVersion) + if err != nil { + return fmt.Errorf("failed to save mcm address: %w", err) + } + + err = chainState.SetState(mcmscontracts.RBACTimelockProgram, programID, legacy2.PDASeed{}) + if err != nil { + return fmt.Errorf("failed to save onchain state: %w", err) + } + + e.Logger.Infow("deployed timelock contract", + "chain", chain.String(), "contract", typeAndVersion.String(), "programId", programID) + } else { + e.Logger.Infow("using existing Timelock program", + "chain", chain.String(), "contract", typeAndVersion.String(), "programId", programID.String()) + } + + return nil +} + +func initTimelock( + e cldf.Environment, chainState *legacy2.MCMSWithTimelockState, chain cldf_solana.Chain, + addressBook cldf.AddressBook, minDelay *big.Int, +) error { + if chainState.TimelockProgram.IsZero() { + return errors.New("mcm program is not deployed") + } + programID := chainState.TimelockProgram + timelockBindings.SetProgramID(programID) + + typeAndVersion := cldf.NewTypeAndVersion(mcmscontracts.RBACTimelock, cldchangesetscommon.Version1_0_0) + timelockProgram, timelockSeed, err := chainState.GetStateFromType(mcmscontracts.RBACTimelock) + if err != nil { + return fmt.Errorf("failed to get timelock state: %w", err) + } + + if (timelockSeed != legacy2.PDASeed{}) { + timelockConfigPDA := familysolana.GetTimelockConfigPDA(timelockProgram, timelockSeed) + var timelockConfig timelockBindings.Config + err = chain.GetAccountDataBorshInto(e.GetContext(), timelockConfigPDA, &timelockConfig) + if err == nil { + e.Logger.Infow("timelock config already initialized, skipping initialization", "chain", chain.String()) + return nil + } + + return fmt.Errorf("unable to read timelock ConfigPDA account config %s", timelockConfigPDA.String()) + } + + e.Logger.Infow("timelock config not initialized, initializing", "chain", chain.String()) + + seed, err := randomSeed() + if err != nil { + return fmt.Errorf("failed to generate timelock seed: %w", err) + } + e.Logger.Infow("generated Timelock seed", + "chain", chain.String(), "contract", typeAndVersion.String(), "seed", string(seed[:])) + + err = initializeTimelock(e, chain, programID, seed, chainState, minDelay) + if err != nil { + return fmt.Errorf("failed to initialize timelock: %w", err) + } + + timelockAddress := legacy2.EncodeAddressWithSeed(programID, seed) + + err = addressBook.Save(chain.Selector, timelockAddress, typeAndVersion) + if err != nil { + return fmt.Errorf("failed to save address: %w", err) + } + + err = chainState.SetState(mcmscontracts.RBACTimelock, programID, seed) + if err != nil { + return fmt.Errorf("failed to save onchain state: %w", err) + } + + return nil +} + +func initializeTimelock( + e cldf.Environment, chain cldf_solana.Chain, timelockProgram solana.PublicKey, timelockID legacy2.PDASeed, + chainState *legacy2.MCMSWithTimelockState, minDelay *big.Int, +) error { + if minDelay == nil { + minDelay = big.NewInt(0) + } + + var timelockConfig timelockBindings.Config + err := chain.GetAccountDataBorshInto(e.GetContext(), familysolana.GetTimelockConfigPDA(timelockProgram, timelockID), + &timelockConfig) + if err == nil { + e.Logger.Infow("Timelock already initialized, skipping initialization", "chain", chain.String()) + return nil + } + + var programData struct { + DataType uint32 + Address solana.PublicKey + } + opts := &rpc.GetAccountInfoOpts{Commitment: rpc.CommitmentConfirmed} + + data, err := chain.Client.GetAccountInfoWithOpts(e.GetContext(), timelockProgram, opts) + if err != nil { + return fmt.Errorf("failed to get timelock program account info: %w", err) + } + err = binary.UnmarshalBorsh(&programData, data.Bytes()) + if err != nil { + return fmt.Errorf("failed to unmarshal program data: %w", err) + } + + instruction, err := timelockBindings.NewInitializeInstruction( + timelockID, + minDelay.Uint64(), + familysolana.GetTimelockConfigPDA(timelockProgram, timelockID), + chain.DeployerKey.PublicKey(), + solana.SystemProgramID, + timelockProgram, + programData.Address, + chainState.AccessControllerProgram, + chainState.ProposerAccessControllerAccount, + chainState.ExecutorAccessControllerAccount, + chainState.CancellerAccessControllerAccount, + chainState.BypasserAccessControllerAccount, + ).ValidateAndBuild() + if err != nil { + return fmt.Errorf("failed to build instruction: %w", err) + } + + err = chain.Confirm([]solana.Instruction{instruction}) + if err != nil { + return fmt.Errorf("failed to confirm instructions: %w", err) + } + + return nil +} diff --git a/pkg/family/solana/fund.go b/pkg/family/solana/legacy/fund.go similarity index 98% rename from pkg/family/solana/fund.go rename to pkg/family/solana/legacy/fund.go index fcd703c..c2d684b 100644 --- a/pkg/family/solana/fund.go +++ b/pkg/family/solana/legacy/fund.go @@ -1,4 +1,4 @@ -package solana +package legacy import ( "fmt" diff --git a/pkg/family/solana/fund_test.go b/pkg/family/solana/legacy/fund_test.go similarity index 99% rename from pkg/family/solana/fund_test.go rename to pkg/family/solana/legacy/fund_test.go index ec5e80b..2b6ebf5 100644 --- a/pkg/family/solana/fund_test.go +++ b/pkg/family/solana/legacy/fund_test.go @@ -1,4 +1,4 @@ -package solana +package legacy import ( "testing" diff --git a/pkg/family/solana/proposal_adapter.go b/pkg/family/solana/legacy/proposal_adapter.go similarity index 73% rename from pkg/family/solana/proposal_adapter.go rename to pkg/family/solana/legacy/proposal_adapter.go index a5f27df..a0b83b1 100644 --- a/pkg/family/solana/proposal_adapter.go +++ b/pkg/family/solana/legacy/proposal_adapter.go @@ -1,4 +1,4 @@ -package solana +package legacy import ( mcmssolanasdk "github.com/smartcontractkit/mcms/sdk/solana" @@ -7,11 +7,7 @@ import ( ) // TimelockPrograms implements [cldfproposalutils.SolanaMCMSWithTimelock] for MCMS timelock proposal helpers. -func (s *MCMSWithTimelockState) TimelockPrograms() cldfproposalutils.MCMSWithTimelockPrograms { - if s == nil || s.MCMSWithTimelockPrograms == nil { - return cldfproposalutils.MCMSWithTimelockPrograms{} - } - +func (s MCMSWithTimelockState) TimelockPrograms() cldfproposalutils.MCMSWithTimelockPrograms { p := s.MCMSWithTimelockPrograms return cldfproposalutils.MCMSWithTimelockPrograms{ diff --git a/pkg/family/solana/utils/artifacts.go b/pkg/family/solana/legacy/solutils/artifacts.go similarity index 100% rename from pkg/family/solana/utils/artifacts.go rename to pkg/family/solana/legacy/solutils/artifacts.go diff --git a/pkg/family/solana/utils/artifacts_test.go b/pkg/family/solana/legacy/solutils/artifacts_test.go similarity index 100% rename from pkg/family/solana/utils/artifacts_test.go rename to pkg/family/solana/legacy/solutils/artifacts_test.go diff --git a/pkg/family/solana/utils/directory.go b/pkg/family/solana/legacy/solutils/directory.go similarity index 96% rename from pkg/family/solana/utils/directory.go rename to pkg/family/solana/legacy/solutils/directory.go index 231a17e..1475739 100644 --- a/pkg/family/solana/utils/directory.go +++ b/pkg/family/solana/legacy/solutils/directory.go @@ -1,4 +1,4 @@ -package solutils +package solutils //nolint:revive // legacy package name is part of the existing public layout // Program names const ( diff --git a/pkg/family/solana/utils/fund.go b/pkg/family/solana/legacy/solutils/fund.go similarity index 100% rename from pkg/family/solana/utils/fund.go rename to pkg/family/solana/legacy/solutils/fund.go diff --git a/pkg/family/solana/state.go b/pkg/family/solana/legacy/state.go similarity index 92% rename from pkg/family/solana/state.go rename to pkg/family/solana/legacy/state.go index 6542490..b1bb465 100644 --- a/pkg/family/solana/state.go +++ b/pkg/family/solana/legacy/state.go @@ -1,6 +1,7 @@ -package solana +package legacy import ( + "context" "errors" "fmt" @@ -13,6 +14,7 @@ import ( mcmssolanasdk "github.com/smartcontractkit/mcms/sdk/solana" cldchangesetscommon "github.com/smartcontractkit/cld-changesets/pkg/common" + "github.com/smartcontractkit/cld-changesets/pkg/contract/mcms/view/v1_0" ) type PDASeed [32]byte @@ -34,6 +36,48 @@ type MCMSWithTimelockPrograms struct { BypasserAccessControllerAccount solana.PublicKey } +// Validate checks that all fields are non-nil, ensuring it's ready +// for use generating views or interactions. +func (s *MCMSWithTimelockPrograms) Validate() error { + if s.McmProgram.IsZero() { + return errors.New("mcm program not found") + } + if s.TimelockProgram.IsZero() { + return errors.New("timelock program not found") + } + if s.AccessControllerProgram.IsZero() { + return errors.New("access controller program not found") + } + if s.ProposerAccessControllerAccount.IsZero() { + return errors.New("proposer access controller account not found") + } + if s.ExecutorAccessControllerAccount.IsZero() { + return errors.New("executor access controller account not found") + } + if s.CancellerAccessControllerAccount.IsZero() { + return errors.New("canceller access controller account not found") + } + if s.BypasserAccessControllerAccount.IsZero() { + return errors.New("bypasser access controller account not found") + } + + return nil +} + +func (s *MCMSWithTimelockPrograms) GenerateView( + ctx context.Context, chain cldf_solana.Chain, +) (v1_0.MCMSWithTimelockViewSolana, error) { + if err := s.Validate(); err != nil { + return v1_0.MCMSWithTimelockViewSolana{}, fmt.Errorf("unable to validate state: %w", err) + } + + inspector := mcmssolanasdk.NewInspector(chain.Client) + timelockInspector := mcmssolanasdk.NewTimelockInspector(chain.Client) + + return v1_0.GenerateMCMSWithTimelockViewSolana(ctx, inspector, timelockInspector, s.McmProgram, + s.ProposerMcmSeed, s.CancellerMcmSeed, s.BypasserMcmSeed, s.TimelockProgram, s.TimelockSeed) +} + func (s *MCMSWithTimelockPrograms) GetStateFromType(programType cldf.ContractType) (solana.PublicKey, PDASeed, error) { switch programType { case mcmscontracts.ManyChainMultisigProgram: diff --git a/pkg/family/solana/state_test.go b/pkg/family/solana/legacy/state_test.go similarity index 99% rename from pkg/family/solana/state_test.go rename to pkg/family/solana/legacy/state_test.go index 6c902d9..4485ec5 100644 --- a/pkg/family/solana/state_test.go +++ b/pkg/family/solana/legacy/state_test.go @@ -1,4 +1,4 @@ -package solana +package legacy import ( "context" diff --git a/pkg/family/solana/testutils/artifacts.go b/pkg/family/solana/legacy/testutils/artifacts.go similarity index 94% rename from pkg/family/solana/testutils/artifacts.go rename to pkg/family/solana/legacy/testutils/artifacts.go index 54af34d..051ab20 100644 --- a/pkg/family/solana/testutils/artifacts.go +++ b/pkg/family/solana/legacy/testutils/artifacts.go @@ -8,7 +8,7 @@ import ( "github.com/stretchr/testify/require" - solutils "github.com/smartcontractkit/cld-changesets/pkg/family/solana/utils" + "github.com/smartcontractkit/cld-changesets/pkg/family/solana/legacy/solutils" ) var ( diff --git a/pkg/family/solana/testutils/datastore.go b/pkg/family/solana/legacy/testutils/datastore.go similarity index 77% rename from pkg/family/solana/testutils/datastore.go rename to pkg/family/solana/legacy/testutils/datastore.go index 33115ca..afc4e9a 100644 --- a/pkg/family/solana/testutils/datastore.go +++ b/pkg/family/solana/legacy/testutils/datastore.go @@ -3,15 +3,15 @@ package soltestutils import ( "testing" - cldfsolana "github.com/smartcontractkit/chainlink-deployments-framework/chain/solana" + "github.com/smartcontractkit/chainlink-deployments-framework/chain/solana" mcmscontracts "github.com/smartcontractkit/chainlink-deployments-framework/engine/cld/contracts/mcms" "github.com/stretchr/testify/require" cldf "github.com/smartcontractkit/chainlink-deployments-framework/deployment" "github.com/smartcontractkit/cld-changesets/pkg/common" - solstate "github.com/smartcontractkit/cld-changesets/pkg/family/solana" - solutils "github.com/smartcontractkit/cld-changesets/pkg/family/solana/utils" + familysolana "github.com/smartcontractkit/cld-changesets/pkg/family/solana/legacy" + "github.com/smartcontractkit/cld-changesets/pkg/family/solana/legacy/solutils" ) // PreloadAddressBookWithMCMSPrograms creates and returns an address book containing preloaded MCMS @@ -38,14 +38,14 @@ func PreloadAddressBookWithMCMSPrograms(t *testing.T, selector uint64) *cldf.Add // GetMCMSStateFromAddressBook retrieves the state of the Solana MCMS contracts on the given chain. func GetMCMSStateFromAddressBook( - t *testing.T, ab cldf.AddressBook, chain cldfsolana.Chain, -) *solstate.MCMSWithTimelockState { + t *testing.T, ab cldf.AddressBook, chain solana.Chain, +) *familysolana.MCMSWithTimelockState { t.Helper() addresses, err := ab.AddressesForChain(chain.Selector) require.NoError(t, err) - mcmState, err := solstate.MaybeLoadMCMSWithTimelockChainState(chain, addresses) + mcmState, err := familysolana.MaybeLoadMCMSWithTimelockChainState(chain, addresses) require.NoError(t, err) return mcmState diff --git a/pkg/family/solana/testutils/fund.go b/pkg/family/solana/legacy/testutils/fund.go similarity index 64% rename from pkg/family/solana/testutils/fund.go rename to pkg/family/solana/legacy/testutils/fund.go index 1e309df..a0c7705 100644 --- a/pkg/family/solana/testutils/fund.go +++ b/pkg/family/solana/legacy/testutils/fund.go @@ -8,9 +8,10 @@ import ( cldfsolana "github.com/smartcontractkit/chainlink-deployments-framework/chain/solana" - solutils "github.com/smartcontractkit/cld-changesets/pkg/family/solana/utils" + "github.com/smartcontractkit/cld-changesets/pkg/family/solana/legacy/solutils" - solstate "github.com/smartcontractkit/cld-changesets/pkg/family/solana" + pdasol "github.com/smartcontractkit/cld-changesets/pkg/family/solana" + solstate "github.com/smartcontractkit/cld-changesets/pkg/family/solana/legacy" ) // FundSignerPDAs funds the timelock signer and MCMS signer PDAs with 1 SOL for testing @@ -19,8 +20,8 @@ func FundSignerPDAs( ) { t.Helper() - timelockSignerPDA := solstate.GetTimelockSignerPDA(mcmsState.TimelockProgram, mcmsState.TimelockSeed) - mcmSignerPDA := solstate.GetMCMSignerPDA(mcmsState.McmProgram, mcmsState.ProposerMcmSeed) + timelockSignerPDA := pdasol.GetTimelockSignerPDA(mcmsState.TimelockProgram, mcmsState.TimelockSeed) + mcmSignerPDA := pdasol.GetMCMSignerPDA(mcmsState.McmProgram, mcmsState.ProposerMcmSeed) signerPDAs := []solana.PublicKey{timelockSignerPDA, mcmSignerPDA} err := solutils.FundAccounts(t.Context(), chain.Client, signerPDAs, 1) require.NoError(t, err) diff --git a/pkg/family/solana/testutils/preload.go b/pkg/family/solana/legacy/testutils/preload.go similarity index 96% rename from pkg/family/solana/testutils/preload.go rename to pkg/family/solana/legacy/testutils/preload.go index e8a68b3..1cede87 100644 --- a/pkg/family/solana/testutils/preload.go +++ b/pkg/family/solana/legacy/testutils/preload.go @@ -10,7 +10,7 @@ import ( cldf "github.com/smartcontractkit/chainlink-deployments-framework/deployment" - solutils "github.com/smartcontractkit/cld-changesets/pkg/family/solana/utils" + "github.com/smartcontractkit/cld-changesets/pkg/family/solana/legacy/solutils" ) // LoadMCMSPrograms loads the MCMS program artifacts into the given directory. diff --git a/pkg/family/solana/mcms_pda.go b/pkg/family/solana/mcms_pda.go index c90c64d..ec04ad1 100644 --- a/pkg/family/solana/mcms_pda.go +++ b/pkg/family/solana/mcms_pda.go @@ -2,6 +2,8 @@ package solana import ( "github.com/gagliardetto/solana-go" + + "github.com/smartcontractkit/cld-changesets/pkg/family/solana/legacy" ) const ( @@ -14,37 +16,37 @@ const ( ) // GetMCMSignerPDA returns the PDA for the MCMS signer -func GetMCMSignerPDA(programID solana.PublicKey, seed PDASeed) solana.PublicKey { +func GetMCMSignerPDA(programID solana.PublicKey, seed legacy.PDASeed) solana.PublicKey { seeds := [][]byte{[]byte(pdaPrefixMultisigSigner), seed[:]} return getPDA(programID, seeds) } // GetMCMConfigPDA returns the PDA for the MCMS config -func GetMCMConfigPDA(programID solana.PublicKey, seed PDASeed) solana.PublicKey { +func GetMCMConfigPDA(programID solana.PublicKey, seed legacy.PDASeed) solana.PublicKey { seeds := [][]byte{[]byte(pdaPrefixMultisigConfig), seed[:]} return getPDA(programID, seeds) } // GetMCMRootMetadataPDA returns the PDA for the MCMS root metadata -func GetMCMRootMetadataPDA(programID solana.PublicKey, seed PDASeed) solana.PublicKey { +func GetMCMRootMetadataPDA(programID solana.PublicKey, seed legacy.PDASeed) solana.PublicKey { seeds := [][]byte{[]byte(pdaPrefixRootMetadata), seed[:]} return getPDA(programID, seeds) } // GetMCMExpiringRootAndOpCountPDA returns the PDA for the MCMS expiring root and op count -func GetMCMExpiringRootAndOpCountPDA(programID solana.PublicKey, seed PDASeed) solana.PublicKey { +func GetMCMExpiringRootAndOpCountPDA(programID solana.PublicKey, seed legacy.PDASeed) solana.PublicKey { seeds := [][]byte{[]byte(pdaPrefixExpiringRootAndOpCount), seed[:]} return getPDA(programID, seeds) } // GetTimelockConfigPDA returns the PDA for the Timelock config -func GetTimelockConfigPDA(programID solana.PublicKey, seed PDASeed) solana.PublicKey { +func GetTimelockConfigPDA(programID solana.PublicKey, seed legacy.PDASeed) solana.PublicKey { seeds := [][]byte{[]byte(pdaPrefixTimelockConfig), seed[:]} return getPDA(programID, seeds) } // GetTimelockSignerPDA returns the PDA for the Timelock signer -func GetTimelockSignerPDA(programID solana.PublicKey, seed PDASeed) solana.PublicKey { +func GetTimelockSignerPDA(programID solana.PublicKey, seed legacy.PDASeed) solana.PublicKey { seeds := [][]byte{[]byte(pdaPrefixTimelockSigner), seed[:]} return getPDA(programID, seeds) } diff --git a/pkg/family/solana/mcms_pda_test.go b/pkg/family/solana/mcms_pda_test.go index 6959b92..0166ed0 100644 --- a/pkg/family/solana/mcms_pda_test.go +++ b/pkg/family/solana/mcms_pda_test.go @@ -5,6 +5,8 @@ import ( "github.com/gagliardetto/solana-go" "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/cld-changesets/pkg/family/solana/legacy" ) func TestMCMSPDA(t *testing.T) { @@ -15,7 +17,7 @@ func TestMCMSPDA(t *testing.T) { tests := []struct { name string prefix string - fn func(programID solana.PublicKey, seed PDASeed) solana.PublicKey + fn func(programID solana.PublicKey, seed legacy.PDASeed) solana.PublicKey }{ {name: "GetMCMSignerPDA", prefix: pdaPrefixMultisigSigner, fn: GetMCMSignerPDA}, {name: "GetMCMConfigPDA", prefix: pdaPrefixMultisigConfig, fn: GetMCMConfigPDA}, @@ -65,9 +67,9 @@ func mustFindPDA(t *testing.T, seeds [][]byte, programID solana.PublicKey) solan return pda } -func testPDASeed(t *testing.T) PDASeed { +func testPDASeed(t *testing.T) legacy.PDASeed { t.Helper() - var s PDASeed + var s legacy.PDASeed for i := range s { s[i] = byte(i + 1) } diff --git a/pkg/family/solana/operations/common.go b/pkg/family/solana/operations/common.go new file mode 100644 index 0000000..72172a2 --- /dev/null +++ b/pkg/family/solana/operations/common.go @@ -0,0 +1,41 @@ +package operation + +import ( + "github.com/gagliardetto/solana-go" + cldfsol "github.com/smartcontractkit/chainlink-deployments-framework/chain/solana" + "github.com/smartcontractkit/chainlink-deployments-framework/operations" +) + +type ( + CommonDeps struct { + Chain cldfsol.Chain + } + + DeployInput struct { + ChainSel uint64 + ProgramName string + Size int + Overallocate bool + } + + DeployOutput struct { + ProgramID solana.PublicKey + } +) + +func Deploy(b operations.Bundle, deps CommonDeps, in DeployInput) (DeployOutput, error) { + var out DeployOutput + + b.Logger.Infof("deploying program %q, size %d, chain sel %d", in.ProgramName, in.Size, in.ChainSel) + programID, err := deps.Chain.DeployProgram(b.Logger, cldfsol.ProgramInfo{ + Name: in.ProgramName, + Bytes: in.Size, + }, false, in.Overallocate) + if err != nil { + return out, err + } + + out.ProgramID = solana.MustPublicKeyFromBase58(programID) + + return out, nil +} diff --git a/pkg/family/solana/operations/operation.go b/pkg/family/solana/operations/operation.go new file mode 100644 index 0000000..6298ab8 --- /dev/null +++ b/pkg/family/solana/operations/operation.go @@ -0,0 +1,504 @@ +package operation + +import ( + "crypto/rand" + "errors" + "fmt" + "math/big" + + binary "github.com/gagliardetto/binary" + "github.com/gagliardetto/solana-go" + "github.com/gagliardetto/solana-go/programs/system" + "github.com/gagliardetto/solana-go/rpc" + mcmsSolanaSdk "github.com/smartcontractkit/mcms/sdk/solana" + mcmsTypes "github.com/smartcontractkit/mcms/types" + + accessControllerBindings "github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings/v0_1_1/access_controller" + mcmBindings "github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings/v0_1_1/mcm" + timelockBindings "github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings/v0_1_1/timelock" + solanaUtils "github.com/smartcontractkit/chainlink-ccip/chains/solana/utils/common" + cldfsol "github.com/smartcontractkit/chainlink-deployments-framework/chain/solana" + "github.com/smartcontractkit/chainlink-deployments-framework/datastore" + cldf "github.com/smartcontractkit/chainlink-deployments-framework/deployment" + "github.com/smartcontractkit/chainlink-deployments-framework/operations" + + cldchangesetscommon "github.com/smartcontractkit/cld-changesets/pkg/common" + familysolana "github.com/smartcontractkit/cld-changesets/pkg/family/solana" + "github.com/smartcontractkit/cld-changesets/pkg/family/solana/legacy" +) + +type Deps struct { + Env cldf.Environment + State *legacy.MCMSWithTimelockState + Datastore datastore.MutableDataStore + Chain cldfsol.Chain +} + +var ( + DeployAccessControllerOp = operations.NewOperation( + "deploy-access-controller", + &cldchangesetscommon.Version1_0_0, + "Deploys access controller for solana", + Deploy, + ) + + DeployMCMProgramOp = operations.NewOperation( + "deploy-mcm-program", + &cldchangesetscommon.Version1_0_0, + "Deploys mcm for solana", + Deploy, + ) + + DeployTimelockOp = operations.NewOperation( + "deploy-timelock-program", + &cldchangesetscommon.Version1_0_0, + "Deploys timelock for solana", + Deploy, + ) + + InitAccessControllerOp = operations.NewOperation( + "init-access-controller", + &cldchangesetscommon.Version1_0_0, + "Initializes access controller for solana", + initAccessController, + ) + + InitMCMOp = operations.NewOperation( + "init-mcm-program", + &cldchangesetscommon.Version1_0_0, + "Initializes MCMProgram for solana", + initMCM, + ) + + InitTimelockOp = operations.NewOperation( + "init-timelock-program", + &cldchangesetscommon.Version1_0_0, + "Initializes timelock for solana", + initTimelock, + ) + AddAccessOp = operations.NewOperation( + "add-access-op", + &cldchangesetscommon.Version1_0_0, + "Adds access to provided role for timelock", + addAccess, + ) +) + +type ( + InitAccessControllerInput struct { + ContractType cldf.ContractType + ChainSel uint64 + } + + InitAccessControllerOutput struct{} + + InitMCMInput struct { + ContractType cldf.ContractType + MCMConfig mcmsTypes.Config + ChainSel uint64 + } + + InitMCMOutput struct{} + + InitTimelockInput struct { + ContractType cldf.ContractType + ChainSel uint64 + MinDelay *big.Int + } + InitTimelockOutput struct{} + + AddAccessInput struct { + Role timelockBindings.Role + Accounts []solana.PublicKey + ChainSel uint64 + } + + AddAccessOutput struct{} +) + +func initAccessController(b operations.Bundle, deps Deps, in InitAccessControllerInput) (InitAccessControllerOutput, error) { + var out InitAccessControllerOutput + + if deps.State.AccessControllerProgram.IsZero() { + return out, fmt.Errorf("access controller program is not deployed for chain sel %d", deps.Chain.ChainSelector()) + } + + typeAndVersion := cldf.NewTypeAndVersion(in.ContractType, cldchangesetscommon.Version1_0_0) + _, accessControllerAccountSeed, err := deps.State.GetStateFromType(in.ContractType) + if err != nil { + return out, fmt.Errorf("failed to get account controller state: %w", err) + } + + accessControllerAccount := solana.PublicKeyFromBytes(accessControllerAccountSeed[:]) + if !accessControllerAccount.IsZero() { + var data accessControllerBindings.AccessController + err = solanaUtils.GetAccountDataBorshInto(b.GetContext(), deps.Chain.Client, accessControllerAccount, rpc.CommitmentConfirmed, &data) + if err == nil { + b.Logger.Infow("access controller already initialized, skipping initialization", "chain", deps.Chain.String()) + return out, nil + } + + return out, fmt.Errorf("unable to read access controller account config %s", accessControllerAccount.String()) + } + + b.Logger.Infow("access controller not initialized, initializing", "chain", deps.Chain.String()) + + programID := deps.State.AccessControllerProgram + if accessControllerBindings.ProgramID.IsZero() { + accessControllerBindings.SetProgramID(programID) + } + + account, err := solana.NewRandomPrivateKey() + if err != nil { + return out, fmt.Errorf("failed to generate new random private key for access controller account: %w", err) + } + + err = initializeAccessController(b, deps.Chain, programID, account) + if err != nil { + return out, fmt.Errorf("failed to initialize access controller: %w", err) + } + + b.Logger.Infow( + "initialized access controller", + "chain", deps.Chain.String(), + "contract", typeAndVersion.String(), + "programID", programID, + "account", account.PublicKey(), + ) + + err = deps.State.SetState(in.ContractType, account.PublicKey(), legacy.PDASeed{}) + if err != nil { + return out, fmt.Errorf("failed to save onchain state: %w", err) + } + + err = deps.Datastore.Addresses().Add(datastore.AddressRef{ + Address: account.PublicKey().String(), + ChainSelector: deps.Chain.Selector, + Type: datastore.ContractType(in.ContractType), + }) + if err != nil { + return out, fmt.Errorf("failed to save address to datastore: %w", err) + } + + return out, nil +} + +// discriminator + owner + proposed owner + access_list (64 max addresses + length) +const accessControllerAccountSize = uint64(8 + 32 + 32 + ((32 * 64) + 8)) + +func initializeAccessController( + b operations.Bundle, chain cldfsol.Chain, programID solana.PublicKey, roleAccount solana.PrivateKey, +) error { + rentExemption, err := chain.Client.GetMinimumBalanceForRentExemption(b.GetContext(), + accessControllerAccountSize, rpc.CommitmentConfirmed) + if err != nil { + return fmt.Errorf("failed to get minimum balance for rent exemption: %w", err) + } + + createAccountInstruction, err := system.NewCreateAccountInstruction(rentExemption, accessControllerAccountSize, + programID, chain.DeployerKey.PublicKey(), roleAccount.PublicKey()).ValidateAndBuild() + if err != nil { + return fmt.Errorf("failed to create CreateAccount instruction: %w", err) + } + + initializeInstruction, err := accessControllerBindings.NewInitializeInstruction( + roleAccount.PublicKey(), + chain.DeployerKey.PublicKey(), + ).ValidateAndBuild() + if err != nil { + return fmt.Errorf("failed to build instruction: %w", err) + } + + instructions := []solana.Instruction{createAccountInstruction, initializeInstruction} + err = chain.Confirm(instructions, solanaUtils.AddSigners(roleAccount)) + if err != nil { + return fmt.Errorf("failed to confirm CreateAccount and InitializeAccessController instructions: %w", err) + } + + var data accessControllerBindings.AccessController + err = solanaUtils.GetAccountDataBorshInto(b.GetContext(), chain.Client, roleAccount.PublicKey(), rpc.CommitmentConfirmed, &data) + if err != nil { + return fmt.Errorf("failed to read access controller roleAccount: %w", err) + } + + return nil +} + +func initMCM(b operations.Bundle, deps Deps, in InitMCMInput) (InitMCMOutput, error) { + var out InitMCMOutput + + if deps.State.McmProgram.IsZero() { + return out, fmt.Errorf("mcm program is not deployed for chain sel %d", deps.Chain.ChainSelector()) + } + + programID := deps.State.McmProgram + mcmBindings.SetProgramID(programID) + + typeAndVersion := cldf.NewTypeAndVersion(in.ContractType, cldchangesetscommon.Version1_0_0) + mcmProgram, mcmSeed, err := deps.State.GetStateFromType(in.ContractType) + if err != nil { + return out, fmt.Errorf("failed to get mcm state: %w", err) + } + + if mcmSeed != (legacy.PDASeed{}) { + mcmConfigPDA := familysolana.GetMCMConfigPDA(mcmProgram, mcmSeed) + var data mcmBindings.MultisigConfig + err = solanaUtils.GetAccountDataBorshInto(b.GetContext(), deps.Chain.Client, mcmConfigPDA, rpc.CommitmentConfirmed, &data) + if err == nil { + b.Logger.Infow("mcm config already initialized, skipping initialization", "chain", deps.Chain.String()) + return out, nil + } + + return out, fmt.Errorf("unable to read mcm ConfigPDA account config %q", mcmConfigPDA.String()) + } + + b.Logger.Infow("mcm config not initialized, initializing", "chain", deps.Chain.String()) + seed, err := randomSeed() + if err != nil { + return out, fmt.Errorf("failed to generate MCM seed: %w", err) + } + b.Logger.Infow( + "generated MCM seed", + "chain", deps.Chain.String(), + "contract", typeAndVersion.String(), + "seed", string(seed[:]), + ) + err = initializeMCM(b, deps, programID, seed) + if err != nil { + return out, fmt.Errorf("failed to initialize mcm: %w", err) + } + + mcmAddress := legacy.EncodeAddressWithSeed(programID, seed) + + configurer := mcmsSolanaSdk.NewConfigurer(deps.Chain.Client, *deps.Chain.DeployerKey, mcmsTypes.ChainSelector(deps.Chain.ChainSelector())) + tx, err := configurer.SetConfig(b.GetContext(), mcmAddress, &in.MCMConfig, false) + if err != nil { + return out, fmt.Errorf("failed to set config on mcm: %w", err) + } + b.Logger.Infow( + "called SetConfig on MCM", + "chain", deps.Chain.String(), + "contract", typeAndVersion.String(), + "transaction", tx.Hash, + ) + + err = deps.Datastore.Addresses().Add(datastore.AddressRef{ + Address: mcmAddress, + ChainSelector: deps.Chain.Selector, + Type: datastore.ContractType(in.ContractType), + }) + if err != nil { + return out, fmt.Errorf("failed to save address to datastore: %w", err) + } + + err = deps.State.SetState(in.ContractType, programID, seed) + if err != nil { + return out, fmt.Errorf("failed to save onchain state: %w", err) + } + + return out, nil +} + +func initializeMCM(b operations.Bundle, deps Deps, mcmProgram solana.PublicKey, multisigID legacy.PDASeed) error { + var mcmConfig mcmBindings.MultisigConfig + err := deps.Chain.GetAccountDataBorshInto(b.GetContext(), familysolana.GetMCMConfigPDA(mcmProgram, multisigID), &mcmConfig) + if err == nil { + b.Logger.Infow("MCM already initialized, skipping initialization", "chain", deps.Chain.String()) + return nil + } + + var programData struct { + DataType uint32 + Address solana.PublicKey + } + opts := &rpc.GetAccountInfoOpts{Commitment: rpc.CommitmentConfirmed} + + data, err := deps.Chain.Client.GetAccountInfoWithOpts(b.GetContext(), mcmProgram, opts) + if err != nil { + return fmt.Errorf("failed to get mcm program account info: %w", err) + } + err = binary.UnmarshalBorsh(&programData, data.Bytes()) + if err != nil { + return fmt.Errorf("failed to unmarshal program data: %w", err) + } + + instruction, err := mcmBindings.NewInitializeInstruction( + deps.Chain.Selector, + multisigID, + familysolana.GetMCMConfigPDA(mcmProgram, multisigID), + deps.Chain.DeployerKey.PublicKey(), + solana.SystemProgramID, + mcmProgram, + programData.Address, + familysolana.GetMCMRootMetadataPDA(mcmProgram, multisigID), + familysolana.GetMCMExpiringRootAndOpCountPDA(mcmProgram, multisigID), + ).ValidateAndBuild() + if err != nil { + return fmt.Errorf("failed to build instruction: %w", err) + } + + err = deps.Chain.Confirm([]solana.Instruction{instruction}) + if err != nil { + return fmt.Errorf("failed to confirm instructions: %w", err) + } + + return nil +} + +func initTimelock(b operations.Bundle, deps Deps, in InitTimelockInput) (InitTimelockOutput, error) { + var out InitTimelockOutput + + if deps.State.TimelockProgram.IsZero() { + return out, errors.New("mcm program is not deployed") + } + programID := deps.State.TimelockProgram + timelockBindings.SetProgramID(programID) + + typeAndVersion := cldf.NewTypeAndVersion(in.ContractType, cldchangesetscommon.Version1_0_0) + timelockProgram, timelockSeed, err := deps.State.GetStateFromType(in.ContractType) + if err != nil { + return out, fmt.Errorf("failed to get timelock state: %w", err) + } + + if (timelockSeed != legacy.PDASeed{}) { + timelockConfigPDA := familysolana.GetTimelockConfigPDA(timelockProgram, timelockSeed) + var timelockConfig timelockBindings.Config + err = deps.Chain.GetAccountDataBorshInto(b.GetContext(), timelockConfigPDA, &timelockConfig) + if err == nil { + b.Logger.Infow("timelock config already initialized, skipping initialization", "chain", deps.Chain.String()) + return out, nil + } + + return out, fmt.Errorf("unable to read timelock ConfigPDA account config %s", timelockConfigPDA.String()) + } + + b.Logger.Infow("timelock config not initialized, initializing", "chain", deps.Chain.String()) + seed, err := randomSeed() + if err != nil { + return out, fmt.Errorf("failed to generate timelock seed: %w", err) + } + b.Logger.Infow( + "generated Timelock seed", + "chain", deps.Chain.String(), + "contract", typeAndVersion.String(), + "seed", string(seed[:]), + ) + + err = initializeTimelock(b, deps, programID, seed, in.MinDelay) + if err != nil { + return out, fmt.Errorf("failed to initialize timelock: %w", err) + } + + timelockAddress := legacy.EncodeAddressWithSeed(programID, seed) + + err = deps.Datastore.Addresses().Add(datastore.AddressRef{ + Address: timelockAddress, + ChainSelector: deps.Chain.Selector, + Type: datastore.ContractType(in.ContractType), + }) + if err != nil { + return out, fmt.Errorf("failed to save address to datastore: %w", err) + } + + err = deps.State.SetState(in.ContractType, programID, seed) + if err != nil { + return out, fmt.Errorf("failed to save onchain state: %w", err) + } + + return out, nil +} + +func initializeTimelock(b operations.Bundle, deps Deps, timelockProgram solana.PublicKey, + timelockID legacy.PDASeed, minDelay *big.Int) error { + if minDelay == nil { + minDelay = big.NewInt(0) + } + + var timelockConfig timelockBindings.Config + err := deps.Chain.GetAccountDataBorshInto(b.GetContext(), familysolana.GetTimelockConfigPDA(timelockProgram, timelockID), + &timelockConfig) + if err == nil { + b.Logger.Infow("Timelock already initialized, skipping initialization", "chain", deps.Chain.String()) + return nil + } + + var programData struct { + DataType uint32 + Address solana.PublicKey + } + opts := &rpc.GetAccountInfoOpts{Commitment: rpc.CommitmentConfirmed} + + data, err := deps.Chain.Client.GetAccountInfoWithOpts(b.GetContext(), timelockProgram, opts) + if err != nil { + return fmt.Errorf("failed to get timelock program account info: %w", err) + } + err = binary.UnmarshalBorsh(&programData, data.Bytes()) + if err != nil { + return fmt.Errorf("failed to unmarshal program data: %w", err) + } + + instruction, err := timelockBindings.NewInitializeInstruction( + timelockID, + minDelay.Uint64(), + familysolana.GetTimelockConfigPDA(timelockProgram, timelockID), + deps.Chain.DeployerKey.PublicKey(), + solana.SystemProgramID, + timelockProgram, + programData.Address, + deps.State.AccessControllerProgram, + deps.State.ProposerAccessControllerAccount, + deps.State.ExecutorAccessControllerAccount, + deps.State.CancellerAccessControllerAccount, + deps.State.BypasserAccessControllerAccount, + ).ValidateAndBuild() + if err != nil { + return fmt.Errorf("failed to build instruction: %w", err) + } + + err = deps.Chain.Confirm([]solana.Instruction{instruction}) + if err != nil { + return fmt.Errorf("failed to confirm instructions: %w", err) + } + + return nil +} + +func addAccess(b operations.Bundle, deps Deps, in AddAccessInput) (AddAccessOutput, error) { + var out AddAccessOutput + + timelockConfigPDA := familysolana.GetTimelockConfigPDA(deps.State.TimelockProgram, deps.State.TimelockSeed) + + instructionBuilder := timelockBindings.NewBatchAddAccessInstruction([32]uint8(deps.State.TimelockSeed), in.Role, + timelockConfigPDA, deps.State.AccessControllerProgram, deps.State.RoleAccount(in.Role), deps.Chain.DeployerKey.PublicKey()) + + for _, account := range in.Accounts { + instructionBuilder.Append(solana.Meta(account)) + } + + instruction, err := instructionBuilder.ValidateAndBuild() + if err != nil { + return out, fmt.Errorf("failed to build BatchAddAccess instruction: %w", err) + } + + err = deps.Chain.Confirm([]solana.Instruction{instruction}) + if err != nil { + return out, fmt.Errorf("failed to confirm BatchAddAccess instruction: %w", err) + } + + return out, nil +} + +func randomSeed() (legacy.PDASeed, error) { + const alphabet = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + + seed := legacy.PDASeed{} + for i := range seed { + n, err := rand.Int(rand.Reader, big.NewInt(int64(len(alphabet)))) + if err != nil { + return legacy.PDASeed{}, fmt.Errorf("failed to generate random seed byte: %w", err) + } + seed[i] = alphabet[n.Int64()] + } + + return seed, nil +} diff --git a/pkg/family/solana/sequences/sequence.go b/pkg/family/solana/sequences/sequence.go new file mode 100644 index 0000000..b5008f6 --- /dev/null +++ b/pkg/family/solana/sequences/sequence.go @@ -0,0 +1,325 @@ +package sequences + +import ( + "errors" + "fmt" + "math/big" + + "github.com/gagliardetto/solana-go" + mcmscontracts "github.com/smartcontractkit/chainlink-deployments-framework/engine/cld/contracts/mcms" + cldfproposalutils "github.com/smartcontractkit/chainlink-deployments-framework/engine/cld/mcms/proposalutils" + mcmsTypes "github.com/smartcontractkit/mcms/types" + "github.com/smartcontractkit/wsrpc/logger" + + timelockBindings "github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings/v0_1_1/timelock" + "github.com/smartcontractkit/chainlink-deployments-framework/datastore" + cldf "github.com/smartcontractkit/chainlink-deployments-framework/deployment" + "github.com/smartcontractkit/chainlink-deployments-framework/operations" + + cldchangesetscommon "github.com/smartcontractkit/cld-changesets/pkg/common" + familysolana "github.com/smartcontractkit/cld-changesets/pkg/family/solana" + "github.com/smartcontractkit/cld-changesets/pkg/family/solana/legacy" + "github.com/smartcontractkit/cld-changesets/pkg/family/solana/legacy/solutils" + solops "github.com/smartcontractkit/cld-changesets/pkg/family/solana/operations" +) + +var ( + DeployMCMSWithTimelockSeq = operations.NewSequence( + "deploy-access-controller-seq", + &cldchangesetscommon.Version1_0_0, + "Deploy AccessController,MCM and Timelock programs, Initialize them, set up role", + deployMCMSWithTimelock, + ) +) + +type ( + DeployMCMSWithTimelockInput struct { + MCMConfig cldfproposalutils.MCMSWithTimelockConfig + TimelockMinDelay *big.Int + } + + DeployMCMSWithTimelockOutput struct{} +) + +func deployMCMSWithTimelock(b operations.Bundle, deps solops.Deps, in DeployMCMSWithTimelockInput) (DeployMCMSWithTimelockOutput, error) { + var out DeployMCMSWithTimelockOutput + + // access controller + err := deployAccessController(b, deps) + if err != nil { + return out, err + } + + err = initAccessController(b, deps) + if err != nil { + return out, err + } + + // mcm + err = deployMCM(b, deps) + if err != nil { + return out, err + } + + err = initMCM(b, deps, in.MCMConfig) + if err != nil { + return out, err + } + + // timelock + err = deployTimelock(b, deps) + if err != nil { + return out, err + } + + err = initTimelock(b, deps, in.TimelockMinDelay) + if err != nil { + return out, err + } + + // roles + err = setupRoles(b, deps) + + return out, err +} + +func deployAccessController(b operations.Bundle, deps solops.Deps) error { + typeAndVersion := cldf.NewTypeAndVersion(mcmscontracts.AccessControllerProgram, cldchangesetscommon.Version1_0_0) + log := logger.With(b.Logger, "chain", deps.Chain.String(), "contract", typeAndVersion.String()) + + programID, _, err := deps.State.GetStateFromType(mcmscontracts.AccessControllerProgram) + if err != nil { + return fmt.Errorf("failed to get access controller program state: %w", err) + } + + if !programID.IsZero() { + log.Infow("using existing AccessController program", "programId", programID) + return nil + } + + opOut, err := operations.ExecuteOperation(b, solops.DeployAccessControllerOp, solops.CommonDeps{Chain: deps.Chain}, + solops.DeployInput{ + ProgramName: solutils.ProgAccessController, + Overallocate: true, + Size: solutils.GetProgramBufferBytes(solutils.ProgAccessController), + ChainSel: deps.Chain.ChainSelector(), + }, + ) + if err != nil { + return fmt.Errorf("failed to deploy access controller: %w", err) + } + programID = opOut.Output.ProgramID + + log.Infow("deployed access controller contract", "programId", programID) + + err = deps.Datastore.Addresses().Add(datastore.AddressRef{ + ChainSelector: deps.Chain.ChainSelector(), + Address: programID.String(), + Version: &cldchangesetscommon.Version1_0_0, + Type: datastore.ContractType(mcmscontracts.AccessControllerProgram), + }) + if err != nil { + return fmt.Errorf("failed to add access controller to datastore: %w", err) + } + + err = deps.State.SetState(mcmscontracts.AccessControllerProgram, programID, legacy.PDASeed{}) + if err != nil { + return fmt.Errorf("failed to save onchain state: %w", err) + } + + return nil +} + +func initAccessController(b operations.Bundle, deps solops.Deps) error { + roles := []cldf.ContractType{mcmscontracts.ProposerAccessControllerAccount, mcmscontracts.ExecutorAccessControllerAccount, + mcmscontracts.CancellerAccessControllerAccount, mcmscontracts.BypasserAccessControllerAccount} + for _, role := range roles { + _, err := operations.ExecuteOperation(b, solops.InitAccessControllerOp, deps, + solops.InitAccessControllerInput{ + ContractType: role, + ChainSel: deps.Chain.ChainSelector(), + }) + if err != nil { + return fmt.Errorf("failed to init access controller account role %q: %w", role, err) + } + } + + return nil +} + +func deployMCM(b operations.Bundle, deps solops.Deps) error { + typeAndVersion := cldf.NewTypeAndVersion(mcmscontracts.ManyChainMultisigProgram, cldchangesetscommon.Version1_0_0) + log := logger.With(b.Logger, "chain", deps.Chain.String(), "contract", typeAndVersion.String()) + + programID, _, err := deps.State.GetStateFromType(mcmscontracts.ManyChainMultisigProgram) + if err != nil { + return fmt.Errorf("failed to get mcm state: %w", err) + } + if !programID.IsZero() { + log.Infow("using existing MCM program", "programId", programID.String()) + return nil + } + + opOut, err := operations.ExecuteOperation(b, solops.DeployMCMProgramOp, solops.CommonDeps{Chain: deps.Chain}, + solops.DeployInput{ + ProgramName: solutils.ProgMCM, + Overallocate: true, + Size: solutils.GetProgramBufferBytes(solutils.ProgMCM), + ChainSel: deps.Chain.ChainSelector(), + }, + ) + if err != nil { + return fmt.Errorf("failed to deploy mcm program : %w", err) + } + programID = opOut.Output.ProgramID + + log.Infow("deployed mcm contract", "programId", programID) + + err = deps.Datastore.Addresses().Add(datastore.AddressRef{ + ChainSelector: deps.Chain.ChainSelector(), + Address: programID.String(), + Version: &cldchangesetscommon.Version1_0_0, + Type: datastore.ContractType(mcmscontracts.ManyChainMultisig), + }) + if err != nil { + return fmt.Errorf("failed to add mcm to datastore: %w", err) + } + + err = deps.State.SetState(mcmscontracts.ManyChainMultisigProgram, programID, legacy.PDASeed{}) + if err != nil { + return fmt.Errorf("failed to save onchain state: %w", err) + } + + return nil +} + +func initMCM(b operations.Bundle, deps solops.Deps, cfg cldfproposalutils.MCMSWithTimelockConfig) error { + configs := []struct { + ctype cldf.ContractType + cfg mcmsTypes.Config + }{ + { + mcmscontracts.BypasserManyChainMultisig, + cfg.Bypasser, + }, + { + mcmscontracts.CancellerManyChainMultisig, + cfg.Canceller, + }, + { + mcmscontracts.ProposerManyChainMultisig, + cfg.Proposer, + }, + } + + for _, cfg := range configs { + _, err := operations.ExecuteOperation(b, solops.InitMCMOp, deps, + solops.InitMCMInput{ContractType: cfg.ctype, MCMConfig: cfg.cfg, ChainSel: deps.Chain.ChainSelector()}) + if err != nil { + return fmt.Errorf("failed to init config type:%q, err:%w", cfg.ctype, err) + } + } + + return nil +} + +func deployTimelock(b operations.Bundle, deps solops.Deps) error { + typeAndVersion := cldf.NewTypeAndVersion(mcmscontracts.RBACTimelockProgram, cldchangesetscommon.Version1_0_0) + log := logger.With(b.Logger, "chain", deps.Chain.String(), "contract", typeAndVersion.String()) + + programID, _, err := deps.State.GetStateFromType(mcmscontracts.RBACTimelock) + if err != nil { + return fmt.Errorf("failed to get timelock state: %w", err) + } + + if !programID.IsZero() { + log.Infow("using existing Timelock program", "programId", programID.String()) + return nil + } + + opOut, err := operations.ExecuteOperation(b, solops.DeployTimelockOp, solops.CommonDeps{Chain: deps.Chain}, + solops.DeployInput{ + ProgramName: solutils.ProgTimelock, + Overallocate: true, + Size: solutils.GetProgramBufferBytes(solutils.ProgTimelock), + ChainSel: deps.Chain.ChainSelector(), + }, + ) + + if err != nil { + return fmt.Errorf("failed to deploy timelock program: %w", err) + } + + programID = opOut.Output.ProgramID + + log.Infow("deployed timelock program", "programId", programID) + + err = deps.Datastore.Addresses().Add(datastore.AddressRef{ + ChainSelector: deps.Chain.ChainSelector(), + Address: programID.String(), + Version: &cldchangesetscommon.Version1_0_0, + Type: datastore.ContractType(mcmscontracts.RBACTimelockProgram), + }) + if err != nil { + return fmt.Errorf("failed to add timelock to datastore: %w", err) + } + + err = deps.State.SetState(mcmscontracts.RBACTimelockProgram, programID, legacy.PDASeed{}) + if err != nil { + return fmt.Errorf("failed to save onchain state: %w", err) + } + + return nil +} + +func initTimelock(b operations.Bundle, deps solops.Deps, minDelay *big.Int) error { + if deps.State.TimelockProgram.IsZero() { + return errors.New("mcm program is not deployed") + } + + _, err := operations.ExecuteOperation(b, solops.InitTimelockOp, deps, solops.InitTimelockInput{ + ContractType: mcmscontracts.RBACTimelock, + ChainSel: deps.Chain.ChainSelector(), + MinDelay: minDelay, + }) + + return err +} + +func setupRoles(b operations.Bundle, deps solops.Deps) error { + proposerPDA := familysolana.GetMCMSignerPDA(deps.State.McmProgram, deps.State.ProposerMcmSeed) + cancellerPDA := familysolana.GetMCMSignerPDA(deps.State.McmProgram, deps.State.CancellerMcmSeed) + bypasserPDA := familysolana.GetMCMSignerPDA(deps.State.McmProgram, deps.State.BypasserMcmSeed) + roles := []struct { + pdas []solana.PublicKey + role timelockBindings.Role + }{ + { + role: timelockBindings.Proposer_Role, + pdas: []solana.PublicKey{proposerPDA}, + }, + { + role: timelockBindings.Executor_Role, + pdas: []solana.PublicKey{deps.Chain.DeployerKey.PublicKey()}, + }, + { + role: timelockBindings.Canceller_Role, + pdas: []solana.PublicKey{cancellerPDA, proposerPDA, bypasserPDA}, + }, + { + role: timelockBindings.Bypasser_Role, + pdas: []solana.PublicKey{bypasserPDA}, + }, + } + for _, role := range roles { + _, err := operations.ExecuteOperation(b, solops.AddAccessOp, deps, solops.AddAccessInput{ + Role: role.role, + Accounts: role.pdas, + }) + if err != nil { + return fmt.Errorf("failed to add access for role %d: %w", role.role, err) + } + } + + return nil +}