From 5f3b9328e0d48306e7a9224bb631d204097e819f Mon Sep 17 00:00:00 2001 From: Mateusz Sekara Date: Fri, 16 Jan 2026 13:09:10 +0100 Subject: [PATCH 1/6] Fixing configuration for tokenVerifier --- build/devenv/services/indexer.go | 10 +++++ build/devenv/services/tokenVerifier.go | 40 +++++++++++++++++++ .../services/tokenVerifier.template.toml | 22 ---------- common/toml.go | 7 +++- 4 files changed, 56 insertions(+), 23 deletions(-) diff --git a/build/devenv/services/indexer.go b/build/devenv/services/indexer.go index cf7d329a5..08bf9db48 100644 --- a/build/devenv/services/indexer.go +++ b/build/devenv/services/indexer.go @@ -142,6 +142,16 @@ func defaults(in *IndexerInput) { BatchSize: 100, MaxBatchWaitTime: 50, }, + { + Type: config.ReaderTypeRest, + RestReaderConfig: config.RestReaderConfig{ + BaseURL: "token-verifier-1:8700/v1/verification/results", + RequestTimeout: 10, + }, + Name: "Token Verifier (Primary)", + BatchSize: 10, + MaxBatchWaitTime: 100, + }, }, Storage: config.StorageConfig{ Strategy: config.StorageStrategySink, diff --git a/build/devenv/services/tokenVerifier.go b/build/devenv/services/tokenVerifier.go index 1448b4664..be23c33c7 100644 --- a/build/devenv/services/tokenVerifier.go +++ b/build/devenv/services/tokenVerifier.go @@ -9,6 +9,9 @@ import ( "strconv" "time" + "github.com/smartcontractkit/chainlink-ccip/ccv/chains/evm/deployment/v1_7_0/operations/cctp_verifier" + "github.com/smartcontractkit/chainlink-ccv/verifier/token/cctp" + "github.com/BurntSushi/toml" "github.com/Masterminds/semver/v3" @@ -50,6 +53,8 @@ type TokenVerifierInput struct { DefaultExecutorOnRampAddresses map[string]string `toml:"default_executor_on_ramp_addresses"` // Maps to rmn_remote_addresses in the verifier config toml. RMNRemoteAddresses map[string]string `toml:"rmn_remote_addresses"` + + CCTPVerifierAddresses map[string]string `toml:"cctp_verifier_addresses"` } type TokenVerifierOutput struct { @@ -202,6 +207,26 @@ func (v *TokenVerifierInput) buildVerifierConfiguration(config *token.Config) er config.VerifierID = v.ContainerName config.OnRampAddresses = v.OnRampAddresses config.RMNRemoteAddresses = v.RMNRemoteAddresses + if len(config.TokenVerifiers) == 0 { + config.TokenVerifiers = make([]token.VerifierConfig, 0) + } + + if len(v.CCTPVerifierAddresses) > 0 { + verifiers := make(map[string]any) + for k, addr := range v.CCTPVerifierAddresses { + verifiers[k] = addr + } + config.TokenVerifiers = append(config.TokenVerifiers, token.VerifierConfig{ + Type: "cctp", + Version: "2.0", + CCTPConfig: &cctp.CCTPConfig{ + AttestationAPI: "localhost:8080", + AttestationAPIInterval: 60 * time.Second, + AttestationAPITimeout: 10 * time.Second, + Verifiers: verifiers, + }, + }) + } return nil } @@ -210,6 +235,7 @@ func ResolveContractsForTokenVerifier(ds datastore.DataStore, blockchains []*blo ver.OnRampAddresses = make(map[string]string) ver.DefaultExecutorOnRampAddresses = make(map[string]string) ver.RMNRemoteAddresses = make(map[string]string) + ver.CCTPVerifierAddresses = make(map[string]string) for _, chain := range blockchains { networkInfo, err := chainsel.GetChainDetailsByChainIDAndFamily(chain.ChainID, chainsel.FamilyEVM) @@ -218,6 +244,20 @@ func ResolveContractsForTokenVerifier(ds datastore.DataStore, blockchains []*blo } selectorStr := strconv.FormatUint(networkInfo.ChainSelector, 10) + cctpTokenVerifierAddressRef, err := ds.Addresses().Get(datastore.NewAddressRefKey( + networkInfo.ChainSelector, + datastore.ContractType(cctp_verifier.ResolverType), + semver.MustParse(cctp_verifier.Deploy.Version()), + "CCTP", + )) + if err != nil { + framework.L.Info(). + Str("chainID", chain.ChainID). + Msg("Failed to get CCTP Verifier address from datastore") + } else { + ver.CCTPVerifierAddresses[selectorStr] = cctpTokenVerifierAddressRef.Address + } + onRampAddressRef, err := ds.Addresses().Get(datastore.NewAddressRefKey( networkInfo.ChainSelector, datastore.ContractType(onrampoperations.ContractType), diff --git a/build/devenv/services/tokenVerifier.template.toml b/build/devenv/services/tokenVerifier.template.toml index ca1c0fb6b..7a5f405bb 100644 --- a/build/devenv/services/tokenVerifier.template.toml +++ b/build/devenv/services/tokenVerifier.template.toml @@ -13,28 +13,6 @@ MetricReaderInterval = 5 TraceSampleRatio = 1.0 TraceBatchTimeout = 10 -[[token_verifiers]] -type = "lbtc" -version = "1.0" -attestation_api = "https://lbtc-api.example.com" -attestation_api_timeout = "10s" -attestation_api_interval = "100ms" - -[token_verifiers.addresses] -3379446385462418246 = "0x9ac06ca36bb3dfd6a70eeb508ea5a33dadecca55" -12922642891491394802 = "0xabb9d2d6f21b2be4d7250de972bd9f778accb3c5" - -[[token_verifiers]] -type = "cctp" -version = "2.0" -attestation_api = "https://cctp-api.example.com" -attestation_api_timeout = "10s" -attestation_api_interval = "100ms" - -[token_verifiers.addresses] -3379446385462418246 = "0x9ac06ca36bb3dfd6a70eeb508ea5a33dadecca55" -12922642891491394802 = "0xabb9d2d6f21b2be4d7250de972bd9f778accb3c5" - #[blockchain_infos] # [blockchain_infos.3379446385462418246] diff --git a/common/toml.go b/common/toml.go index a5cbd83b0..0cfc3cc48 100644 --- a/common/toml.go +++ b/common/toml.go @@ -55,7 +55,12 @@ func ParseAddressesMap(val any) (map[protocol.ChainSelector]protocol.UnknownAddr return nil, nil, fmt.Errorf("invalid verifier address for chain selector %s: expected string, got %T", key, value) } - result[protocol.ChainSelector(chainSelector)] = protocol.UnknownAddress(address) + addr, err := protocol.NewUnknownAddressFromHex(address) + if err != nil { + return nil, nil, fmt.Errorf("invalid verifier address for chain selector %s: %w", key, err) + } + + result[protocol.ChainSelector(chainSelector)] = addr } return result, v, nil } From a635641bc5bd6282573cc2c31900a565295c3f12 Mon Sep 17 00:00:00 2001 From: Mateusz Sekara Date: Fri, 16 Jan 2026 15:55:18 +0100 Subject: [PATCH 2/6] Fixing configuration for tokenVerifier --- build/devenv/fakes/air.toml | 2 +- build/devenv/fakes/cmd/main.go | 19 ++++--- build/devenv/fakes/pkg/cctp/api.go | 76 +++++++++++++++++++++++++ build/devenv/services/tokenVerifier.go | 6 +- build/devenv/tests/e2e/smoke_test.go | 1 - verifier/token/cctp/attestation_test.go | 4 +- verifier/token/http/http.go | 33 +++++++++-- verifier/token/http/http_test.go | 71 +++++++++++++++++++++++ 8 files changed, 194 insertions(+), 18 deletions(-) create mode 100644 build/devenv/fakes/pkg/cctp/api.go diff --git a/build/devenv/fakes/air.toml b/build/devenv/fakes/air.toml index 61199d37f..2c6d8f34a 100644 --- a/build/devenv/fakes/air.toml +++ b/build/devenv/fakes/air.toml @@ -1,7 +1,7 @@ root = "/app/build/devenv/fakes" [build] -cmd = "go build -o ./tmp/fake cmd" +cmd = "go build -o ./tmp/fake cmd/main.go" bin = "/app/build/devenv/fakes/tmp/fake" include_ext = ["go", "mod", "sum"] exclude_dir = ["tmp", "vendor", "testdata", ".git"] diff --git a/build/devenv/fakes/cmd/main.go b/build/devenv/fakes/cmd/main.go index fc9a5e47d..9c95d6435 100644 --- a/build/devenv/fakes/cmd/main.go +++ b/build/devenv/fakes/cmd/main.go @@ -3,9 +3,10 @@ package main import ( "log" - "github.com/smartcontractkit/devenv/ccip17/fakes/pkg/offchainstorage" - "github.com/smartcontractkit/chainlink-testing-framework/framework/components/fake" + + "github.com/smartcontractkit/devenv/ccip17/fakes/pkg/cctp" + "github.com/smartcontractkit/devenv/ccip17/fakes/pkg/offchainstorage" ) func main() { @@ -16,16 +17,18 @@ func main() { } // Create and configure the offchain storage API - api := offchainstorage.NewOffChainStorageAPI() - - // Register the API endpoints - err = api.Register() - if err != nil { + offchainStorage := offchainstorage.NewOffChainStorageAPI() + if err = offchainStorage.Register(); err != nil { panic(err) } - log.Printf("Fake offchain storage API running on port %d", fake.DefaultFakeServicePort) + cctpAttestations := cctp.NewAttestationAPI() + if err = cctpAttestations.Register(); err != nil { + panic(err) + } + log.Printf("Fake CCTP Attestation API running on port %d", fake.DefaultFakeServicePort) + // Keep the server running select {} } diff --git a/build/devenv/fakes/pkg/cctp/api.go b/build/devenv/fakes/pkg/cctp/api.go new file mode 100644 index 000000000..47df6866c --- /dev/null +++ b/build/devenv/fakes/pkg/cctp/api.go @@ -0,0 +1,76 @@ +package cctp + +import ( + "net/http" + "sync" + + "github.com/gin-gonic/gin" + + "github.com/smartcontractkit/chainlink-testing-framework/framework/components/fake" +) + +var attestationResponseBody = ` +{ + "messages": [ + { + "message": "0xcccccc22", + "eventNonce": "9681", + "attestation": "0xaaaaaa22", + "decodedMessage": { + "sourceDomain": "7", + "destinationDomain": "5", + "nonce": "569", + "sender": "0xb7317b4EFEa194a22bEB42506065D3772C2E95EF", + "recipient": "0xb7317b4EFEa194a22bEB42506065D3772C2E95EF", + "destinationCaller": "0xf2Edb1Ad445C6abb1260049AcDDCA9E84D7D8aaA", + "messageBody": "0x00000000000000050000000300000000000194c2a65fc943419a5ad590042fd67c9791fd015acf53a54cc823edb8ff81b9ed722e00000000000000000000000019330d10d9cc8751218eaf51e8885d058642e08a000000000000000000000000fc05ad74c6fe2e7046e091d6ad4f660d2a15976200000000c6fa7af3bedbad3a3d65f36aabc97431b1bbe4c2d2f6e0e47ca60203452f5d610000000000000000000000002d475f4746419c83be23056309a8e2ac33b30e3b0000000000000000000000000000000000000000000000000000000002b67df0feae5e08f5e6bf04d8c1de7dada9235c56996f4420b14371d6c6f3ddd2f2da78", + "decodedMessageBody": { + "burnToken": "0x4Bc078D75390C0f5CCc3e7f59Ae2159557C5eb85", + "mintRecipient": "0xb7317b4EFEa194a22bEB42506065D3772C2E95EF", + "amount": "5000", + "messageSender": "0xca9142d0b9804ef5e239d3bc1c7aa0d1c74e7350", + "hookData": "0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef" + } + }, + "cctpVersion": "2", + "status": "complete" + }, + { + "message": "0xbbbbbb22", + "eventNonce": "9682", + "attestation": "0xaaaaaa11", + "decodedMessage": { + "sourceDomain": "7", + "destinationDomain": "5", + "nonce": "569", + "sender": "0xb7317b4EFEa194a22bEB42506065D3772C2E95EF", + "recipient": "0xb7317b4EFEa194a22bEB42506065D3772C2E95EF", + "destinationCaller": "0xf2Edb1Ad445C6abb1260049AcDDCA9E84D7D8aaA", + "messageBody": "0x00000000000000050000000300000000000194c2a65fc943419a5ad590042fd67c9791fd015acf53a54cc823edb8ff81b9ed722e00000000000000000000000019330d10d9cc8751218eaf51e8885d058642e08a000000000000000000000000fc05ad74c6fe2e7046e091d6ad4f660d2a15976200000000c6fa7af3bedbad3a3d65f36aabc97431b1bbe4c2d2f6e0e47ca60203452f5d610000000000000000000000002d475f4746419c83be23056309a8e2ac33b30e3b0000000000000000000000000000000000000000000000000000000002b67df0feae5e08f5e6bf04d8c1de7dada9235c56996f4420b14371d6c6f3ddd2f2da78", + "decodedMessageBody": { + "burnToken": "0x4Bc078D75390C0f5CCc3e7f59Ae2159557C5eb85", + "mintRecipient": "0xb7317b4EFEa194a22bEB42506065D3772C2E95EF", + "amount": "5000", + "messageSender": "0xca9142d0b9804ef5e239d3bc1c7aa0d1c74e7350", + "hookData": "0x8e1d1a9d27ef33516b82274412e89de14ddc7788847fb81282bbe5d37e6f00dee150c2f3" + } + }, + "cctpVersion": "2", + "status": "complete" + } + ] +}` + +type AttestationAPI struct { + mu sync.RWMutex +} + +func NewAttestationAPI() *AttestationAPI { + return &AttestationAPI{} +} + +func (a *AttestationAPI) Register() error { + return fake.Func("GET", "/cctp/v2/messages/100", func(ctx *gin.Context) { + ctx.JSON(http.StatusOK, attestationResponseBody) + }) +} diff --git a/build/devenv/services/tokenVerifier.go b/build/devenv/services/tokenVerifier.go index be23c33c7..34b907fe5 100644 --- a/build/devenv/services/tokenVerifier.go +++ b/build/devenv/services/tokenVerifier.go @@ -220,9 +220,9 @@ func (v *TokenVerifierInput) buildVerifierConfiguration(config *token.Config) er Type: "cctp", Version: "2.0", CCTPConfig: &cctp.CCTPConfig{ - AttestationAPI: "localhost:8080", - AttestationAPIInterval: 60 * time.Second, - AttestationAPITimeout: 10 * time.Second, + AttestationAPI: "http://fake:9111/cctp", + AttestationAPIInterval: 100 * time.Millisecond, + AttestationAPITimeout: 1 * time.Second, Verifiers: verifiers, }, }) diff --git a/build/devenv/tests/e2e/smoke_test.go b/build/devenv/tests/e2e/smoke_test.go index 073d8c986..a00a1ed05 100644 --- a/build/devenv/tests/e2e/smoke_test.go +++ b/build/devenv/tests/e2e/smoke_test.go @@ -321,7 +321,6 @@ func TestE2ESmoke(t *testing.T) { } t.Run("USDC", func(t *testing.T) { - t.Skip("not implemented yet") usdcCombo := evm.USDCTokenPoolCombination() receiver := mustGetEOAReceiverAddress(t, destChain) runTokenTransferTestCase(t, usdcCombo, 0, receiver) diff --git a/verifier/token/cctp/attestation_test.go b/verifier/token/cctp/attestation_test.go index a861f4b89..d075bbf13 100644 --- a/verifier/token/cctp/attestation_test.go +++ b/verifier/token/cctp/attestation_test.go @@ -82,7 +82,9 @@ func Test_AttestationFetch(t *testing.T) { } server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - if r.URL.Path == "/v2/messages/100?transactionHash="+stringTxHash { + expectedPath := "/v2/messages/100" + expectedQuery := "transactionHash=" + stringTxHash + if r.URL.Path == expectedPath && r.URL.RawQuery == expectedQuery { _, err := w.Write(attestationResponseBody) require.NoError(t, err) } else { diff --git a/verifier/token/http/http.go b/verifier/token/http/http.go index 24570d82b..8ec7d5cd1 100644 --- a/verifier/token/http/http.go +++ b/verifier/token/http/http.go @@ -116,8 +116,10 @@ func newHTTPClient( } func (h *httpClient) Get(ctx context.Context, requestPath string) (protocol.ByteSlice, Status, error) { - requestURL := *h.apiURL - requestURL.Path = path.Join(requestURL.Path, requestPath) + requestURL, err := h.buildRequestURL(requestPath) + if err != nil { + return nil, http.StatusBadRequest, err + } response, httpStatus, err := h.callAPI(ctx, h.lggr, http.MethodGet, requestURL, nil) h.lggr.Debugw( @@ -135,8 +137,10 @@ func (h *httpClient) Post( requestPath string, requestData protocol.ByteSlice, ) (protocol.ByteSlice, Status, error) { - requestURL := *h.apiURL - requestURL.Path = path.Join(requestURL.Path, requestPath) + requestURL, err := h.buildRequestURL(requestPath) + if err != nil { + return nil, http.StatusBadRequest, err + } response, httpStatus, err := h.callAPI(ctx, h.lggr, http.MethodPost, requestURL, bytes.NewBuffer(requestData)) h.lggr.Debugw( @@ -150,6 +154,27 @@ func (h *httpClient) Post( return response, httpStatus, err } +// buildRequestURL combines the base API URL with the request path, properly handling query parameters. +func (h *httpClient) buildRequestURL(requestPath string) (url.URL, error) { + requestURL := *h.apiURL + + // Parse the requestPath to separate path and query components + parsedPath, err := url.Parse(requestPath) + if err != nil { + return url.URL{}, err + } + + // Join the base path with the request path + requestURL.Path = path.Join(requestURL.Path, parsedPath.Path) + + // Preserve query parameters from the request path + if parsedPath.RawQuery != "" { + requestURL.RawQuery = parsedPath.RawQuery + } + + return requestURL, nil +} + func (h *httpClient) callAPI( ctx context.Context, lggr logger.Logger, diff --git a/verifier/token/http/http_test.go b/verifier/token/http/http_test.go index a24b5a38a..c3aa216a0 100644 --- a/verifier/token/http/http_test.go +++ b/verifier/token/http/http_test.go @@ -376,3 +376,74 @@ func Test_HTTPClient_RateLimiting_Parallel(t *testing.T) { }) } } + +func Test_HTTPClient_QueryStringHandling(t *testing.T) { + tests := []struct { + name string + requestPath string + expectedPath string + expectedQuery string + method string + }{ + { + name: "GET with query parameters", + requestPath: "v2/messages/100?transactionHash=0x1234567890abcdef", + expectedPath: "/v2/messages/100", + expectedQuery: "transactionHash=0x1234567890abcdef", + method: http.MethodGet, + }, + { + name: "GET with multiple query parameters", + requestPath: "api/data?param1=value1¶m2=value2", + expectedPath: "/api/data", + expectedQuery: "param1=value1¶m2=value2", + method: http.MethodGet, + }, + { + name: "POST with query parameters", + requestPath: "v2/messages/100?transactionHash=0xabcdef", + expectedPath: "/v2/messages/100", + expectedQuery: "transactionHash=0xabcdef", + method: http.MethodPost, + }, + { + name: "GET without query parameters", + requestPath: "v2/messages/100", + expectedPath: "/v2/messages/100", + expectedQuery: "", + method: http.MethodGet, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + // Create a test server that validates the URL components + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, tc.expectedPath, r.URL.Path, "path mismatch") + assert.Equal(t, tc.expectedQuery, r.URL.RawQuery, "query mismatch") + w.WriteHeader(http.StatusOK) + _, err := w.Write(validAttestationResponse) + require.NoError(t, err) + })) + defer ts.Close() + + client, err := newHTTPClient(logger.Nop(), ts.URL, time.Millisecond, longTimeout, 0) + require.NoError(t, err) + + var response protocol.ByteSlice + var statusCode Status + switch tc.method { + case http.MethodGet: + response, statusCode, err = client.Get(context.Background(), tc.requestPath) + case http.MethodPost: + response, statusCode, err = client.Post(context.Background(), tc.requestPath, []byte("{}")) + default: + t.Fatalf("unknown method %s", tc.method) + } + + require.NoError(t, err) + require.Equal(t, http.StatusOK, int(statusCode)) + require.Equal(t, protocol.ByteSlice(validAttestationResponse), response) + }) + } +} From 1f552084ec4211bd56195da6f4ad8b2c733830d3 Mon Sep 17 00:00:00 2001 From: Mateusz Sekara Date: Fri, 16 Jan 2026 17:07:11 +0100 Subject: [PATCH 3/6] Fixing configuration for tokenVerifier --- build/devenv/fakes/pkg/cctp/api.go | 170 ++++++++++++++++++--------- build/devenv/tests/e2e/smoke_test.go | 108 ++++++++++++++++- verifier/token/cctp/attestation.go | 2 +- 3 files changed, 223 insertions(+), 57 deletions(-) diff --git a/build/devenv/fakes/pkg/cctp/api.go b/build/devenv/fakes/pkg/cctp/api.go index 47df6866c..d3a7c3d19 100644 --- a/build/devenv/fakes/pkg/cctp/api.go +++ b/build/devenv/fakes/pkg/cctp/api.go @@ -1,6 +1,8 @@ package cctp import ( + "encoding/json" + "fmt" "net/http" "sync" @@ -9,68 +11,126 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/framework/components/fake" ) -var attestationResponseBody = ` -{ - "messages": [ - { - "message": "0xcccccc22", - "eventNonce": "9681", - "attestation": "0xaaaaaa22", - "decodedMessage": { - "sourceDomain": "7", - "destinationDomain": "5", - "nonce": "569", - "sender": "0xb7317b4EFEa194a22bEB42506065D3772C2E95EF", - "recipient": "0xb7317b4EFEa194a22bEB42506065D3772C2E95EF", - "destinationCaller": "0xf2Edb1Ad445C6abb1260049AcDDCA9E84D7D8aaA", - "messageBody": "0x00000000000000050000000300000000000194c2a65fc943419a5ad590042fd67c9791fd015acf53a54cc823edb8ff81b9ed722e00000000000000000000000019330d10d9cc8751218eaf51e8885d058642e08a000000000000000000000000fc05ad74c6fe2e7046e091d6ad4f660d2a15976200000000c6fa7af3bedbad3a3d65f36aabc97431b1bbe4c2d2f6e0e47ca60203452f5d610000000000000000000000002d475f4746419c83be23056309a8e2ac33b30e3b0000000000000000000000000000000000000000000000000000000002b67df0feae5e08f5e6bf04d8c1de7dada9235c56996f4420b14371d6c6f3ddd2f2da78", - "decodedMessageBody": { - "burnToken": "0x4Bc078D75390C0f5CCc3e7f59Ae2159557C5eb85", - "mintRecipient": "0xb7317b4EFEa194a22bEB42506065D3772C2E95EF", - "amount": "5000", - "messageSender": "0xca9142d0b9804ef5e239d3bc1c7aa0d1c74e7350", - "hookData": "0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef" - } - }, - "cctpVersion": "2", - "status": "complete" - }, - { - "message": "0xbbbbbb22", - "eventNonce": "9682", - "attestation": "0xaaaaaa11", - "decodedMessage": { - "sourceDomain": "7", - "destinationDomain": "5", - "nonce": "569", - "sender": "0xb7317b4EFEa194a22bEB42506065D3772C2E95EF", - "recipient": "0xb7317b4EFEa194a22bEB42506065D3772C2E95EF", - "destinationCaller": "0xf2Edb1Ad445C6abb1260049AcDDCA9E84D7D8aaA", - "messageBody": "0x00000000000000050000000300000000000194c2a65fc943419a5ad590042fd67c9791fd015acf53a54cc823edb8ff81b9ed722e00000000000000000000000019330d10d9cc8751218eaf51e8885d058642e08a000000000000000000000000fc05ad74c6fe2e7046e091d6ad4f660d2a15976200000000c6fa7af3bedbad3a3d65f36aabc97431b1bbe4c2d2f6e0e47ca60203452f5d610000000000000000000000002d475f4746419c83be23056309a8e2ac33b30e3b0000000000000000000000000000000000000000000000000000000002b67df0feae5e08f5e6bf04d8c1de7dada9235c56996f4420b14371d6c6f3ddd2f2da78", - "decodedMessageBody": { - "burnToken": "0x4Bc078D75390C0f5CCc3e7f59Ae2159557C5eb85", - "mintRecipient": "0xb7317b4EFEa194a22bEB42506065D3772C2E95EF", - "amount": "5000", - "messageSender": "0xca9142d0b9804ef5e239d3bc1c7aa0d1c74e7350", - "hookData": "0x8e1d1a9d27ef33516b82274412e89de14ddc7788847fb81282bbe5d37e6f00dee150c2f3" - } - }, - "cctpVersion": "2", - "status": "complete" - } - ] -}` +type AttestationResponse struct { + Message string `json:"message"` + EventNonce string `json:"eventNonce"` + Attestation string `json:"attestation"` + DecodedMessage DecodedMessage `json:"decodedMessage"` + CCTPVersion string `json:"cctpVersion"` + Status string `json:"status"` +} + +type DecodedMessage struct { + SourceDomain string `json:"sourceDomain"` + DestinationDomain string `json:"destinationDomain"` + Nonce string `json:"nonce"` + Sender string `json:"sender"` + Recipient string `json:"recipient"` + DestinationCaller string `json:"destinationCaller"` + MessageBody string `json:"messageBody"` + DecodedMessageBody DecodedMessageBody `json:"decodedMessageBody"` +} + +type DecodedMessageBody struct { + BurnToken string `json:"burnToken"` + MintRecipient string `json:"mintRecipient"` + Amount string `json:"amount"` + MessageSender string `json:"messageSender"` + HookData string `json:"hookData"` +} + +type RegisterAttestationRequest struct { + SourceDomain string `json:"sourceDomain" binding:"required"` + HookData string `json:"hookData" binding:"required"` + Status string `json:"status" binding:"required"` +} type AttestationAPI struct { - mu sync.RWMutex + mu sync.RWMutex + responses map[string]AttestationResponse } func NewAttestationAPI() *AttestationAPI { - return &AttestationAPI{} + return &AttestationAPI{ + responses: make(map[string]AttestationResponse), + } +} + +// RegisterAttestation registers a new attestation response for a given sourceDomain +func (a *AttestationAPI) RegisterAttestation(sourceDomain, hookData, status string) AttestationResponse { + a.mu.Lock() + defer a.mu.Unlock() + + // Create a response based on the example attestation but with the provided sourceDomain, hookData and status + response := AttestationResponse{ + Message: "0xbbbbbb22", + EventNonce: "9682", + Attestation: "0xaaaaaa11", + DecodedMessage: DecodedMessage{ + SourceDomain: sourceDomain, + DestinationDomain: "5", + Nonce: "569", + Sender: "0xb7317b4EFEa194a22bEB42506065D3772C2E95EF", + Recipient: "0xb7317b4EFEa194a22bEB42506065D3772C2E95EF", + DestinationCaller: "0xf2Edb1Ad445C6abb1260049AcDDCA9E84D7D8aaA", + MessageBody: "0x00000000000000050000000300000000000194c2a65fc943419a5ad590042fd67c9791fd015acf53a54cc823edb8ff81b9ed722e00000000000000000000000019330d10d9cc8751218eaf51e8885d058642e08a000000000000000000000000fc05ad74c6fe2e7046e091d6ad4f660d2a15976200000000c6fa7af3bedbad3a3d65f36aabc97431b1bbe4c2d2f6e0e47ca60203452f5d610000000000000000000000002d475f4746419c83be23056309a8e2ac33b30e3b0000000000000000000000000000000000000000000000000000000002b67df0feae5e08f5e6bf04d8c1de7dada9235c56996f4420b14371d6c6f3ddd2f2da78", + DecodedMessageBody: DecodedMessageBody{ + BurnToken: "0x4Bc078D75390C0f5CCc3e7f59Ae2159557C5eb85", + MintRecipient: "0xb7317b4EFEa194a22bEB42506065D3772C2E95EF", + Amount: "5000", + MessageSender: "0x2609ac236def92d0992ff8bbcf810a59a9301bca", + HookData: hookData, + }, + }, + CCTPVersion: "2", + Status: status, + } + + a.responses[sourceDomain] = response + return response } func (a *AttestationAPI) Register() error { - return fake.Func("GET", "/cctp/v2/messages/100", func(ctx *gin.Context) { - ctx.JSON(http.StatusOK, attestationResponseBody) + // POST endpoint to register attestation responses + err := fake.Func("POST", "/cctp/v2/attestations", func(ctx *gin.Context) { + var req RegisterAttestationRequest + if err := ctx.ShouldBindJSON(&req); err != nil { + ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } + + response := a.RegisterAttestation(req.SourceDomain, req.HookData, req.Status) + ctx.JSON(http.StatusOK, response) }) + if err != nil { + return err + } + + // GET endpoint to retrieve attestation by sourceDomain + err = fake.Func("GET", "/cctp/v2/messages/:sourceDomain", func(ctx *gin.Context) { + sourceDomain := ctx.Param("sourceDomain") + + a.mu.RLock() + response, exists := a.responses[sourceDomain] + a.mu.RUnlock() + + if !exists { + ctx.JSON(http.StatusNotFound, gin.H{"error": fmt.Sprintf("no attestation found for sourceDomain: %s", sourceDomain)}) + return + } + + // Return as an array to match the expected format + responseBytes, err := json.Marshal([]AttestationResponse{response}) + if err != nil { + ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + ctx.Data(http.StatusOK, "application/json", responseBytes) + }) + if err != nil { + return err + } + + return nil } diff --git a/build/devenv/tests/e2e/smoke_test.go b/build/devenv/tests/e2e/smoke_test.go index a00a1ed05..b532bab3b 100644 --- a/build/devenv/tests/e2e/smoke_test.go +++ b/build/devenv/tests/e2e/smoke_test.go @@ -2,8 +2,11 @@ package e2e import ( "bytes" + "encoding/hex" + "encoding/json" "fmt" "math/big" + "net/http" "os" "testing" "time" @@ -63,6 +66,31 @@ type v2TestCase struct { numExpectedVerifications int } +// registerCCTPAttestation registers a CCTP attestation response with the fake service +func registerCCTPAttestation(t *testing.T, messageID [32]byte, status string) { + // Convert messageID to hex string (without 0x prefix) + hookData := "0x" + hex.EncodeToString(messageID[:]) + + reqBody := map[string]string{ + "sourceDomain": "100", + "hookData": hookData, + "status": status, + } + reqJSON, err := json.Marshal(reqBody) + require.NoError(t, err) + + // The fake service runs on port 9111 + resp, err := http.Post( + "http://fake:9111/cctp/v2/attestations", + "application/json", + bytes.NewBuffer(reqJSON), + ) + require.NoError(t, err) + defer resp.Body.Close() + + require.Equal(t, http.StatusOK, resp.StatusCode, "Failed to register CCTP attestation") +} + func TestE2ESmoke(t *testing.T) { smokeTestConfig := os.Getenv("SMOKE_TEST_CONFIG") if smokeTestConfig == "" { @@ -241,6 +269,84 @@ func TestE2ESmoke(t *testing.T) { destSelector = sel1 destChain = chainMap[destSelector] ) + runUSDCTestCase := func(t *testing.T, combo evm.TokenCombination, finalityConfig uint16, receiver protocol.UnknownAddress) { + sender := mustGetSenderAddress(t, sourceChain) + + srcToken := getTokenAddress(t, in, sourceSelector, combo.SourcePoolAddressRef().Qualifier) + destToken := getTokenAddress(t, in, destSelector, combo.DestPoolAddressRef().Qualifier) + + startBal, err := destChain.GetTokenBalance(ctx, receiver, destToken) + require.NoError(t, err) + l.Info().Str("Receiver", receiver.String()).Uint64("StartBalance", startBal.Uint64()).Str("Token", combo.DestPoolAddressRef().Qualifier).Msg("receiver start balance") + + srcStartBal, err := sourceChain.GetTokenBalance(ctx, sender, srcToken) + require.NoError(t, err) + l.Info().Str("Sender", sender.String()).Uint64("SrcStartBalance", srcStartBal.Uint64()).Str("Token", combo.SourcePoolAddressRef().Qualifier).Msg("sender start balance") + + seqNo, err := sourceChain.GetExpectedNextSequenceNumber(ctx, destSelector) + require.NoError(t, err) + l.Info().Uint64("SeqNo", seqNo).Str("Token", combo.SourcePoolAddressRef().Qualifier).Msg("expecting sequence number") + + messageOptions := cciptestinterfaces.MessageOptions{ + Version: 3, + ExecutionGasLimit: 200_000, + FinalityConfig: finalityConfig, + Executor: getContractAddress(t, in, sel0, datastore.ContractType(executor.ProxyType), executor.DeployProxy.Version(), evm.DefaultExecutorQualifier, "executor"), + } + + sendRes, err := sourceChain.SendMessage( + ctx, destSelector, + cciptestinterfaces.MessageFields{ + Receiver: receiver, + TokenAmount: cciptestinterfaces.TokenAmount{ + Amount: big.NewInt(1000), + TokenAddress: srcToken, + }, + }, + messageOptions, + ) + require.NoError(t, err) + require.NotNil(t, sendRes) + require.Len(t, sendRes.ReceiptIssuers, combo.ExpectedReceiptIssuers(), "expected %d receipt issuers for %s token", combo.ExpectedReceiptIssuers(), combo.SourcePoolAddressRef().Qualifier) + + sentEvt, err := sourceChain.WaitOneSentEventBySeqNo(ctx, destSelector, seqNo, defaultSentTimeout) + require.NoError(t, err) + msgID := sentEvt.MessageID + + // Register CCTP attestation response with the fake service + // Use the messageID as hookData and set status to "complete" for success + registerCCTPAttestation(t, msgID, "complete") + l.Info().Str("MessageID", hex.EncodeToString(msgID[:])).Msg("Registered CCTP attestation") + + testCtx := NewTestingContext(t, ctx, chainMap, defaultAggregatorClient, indexerMonitor) + + res, err := testCtx.AssertMessage(msgID, AssertMessageOptions{ + TickInterval: 1 * time.Second, + Timeout: 45 * time.Second, + ExpectedVerifierResults: combo.ExpectedVerifierResults(), + AssertVerifierLogs: false, + AssertExecutorLogs: false, + }) + + require.NoError(t, err) + require.NotNil(t, res.AggregatedResult) + + execEvt, err := destChain.WaitOneExecEventBySeqNo(ctx, sourceSelector, seqNo, 45*time.Second) + require.NoError(t, err) + require.NotNil(t, execEvt) + require.Equalf(t, cciptestinterfaces.ExecutionStateSuccess, execEvt.State, "unexpected state, return data: %x", execEvt.ReturnData) + + endBal, err := destChain.GetTokenBalance(ctx, receiver, destToken) + require.NoError(t, err) + require.Equal(t, new(big.Int).Add(new(big.Int).Set(startBal), big.NewInt(1000)), endBal) + l.Info().Uint64("EndBalance", endBal.Uint64()).Str("Token", combo.DestPoolAddressRef().Qualifier).Msg("receiver end balance") + + srcEndBal, err := sourceChain.GetTokenBalance(ctx, sender, srcToken) + require.NoError(t, err) + require.Equal(t, new(big.Int).Sub(new(big.Int).Set(srcStartBal), big.NewInt(1000)), srcEndBal) + l.Info().Uint64("SrcEndBalance", srcEndBal.Uint64()).Str("Token", combo.SourcePoolAddressRef().Qualifier).Msg("sender end balance") + } + runTokenTransferTestCase := func(t *testing.T, combo evm.TokenCombination, finalityConfig uint16, receiver protocol.UnknownAddress) { sender := mustGetSenderAddress(t, sourceChain) @@ -323,7 +429,7 @@ func TestE2ESmoke(t *testing.T) { t.Run("USDC", func(t *testing.T) { usdcCombo := evm.USDCTokenPoolCombination() receiver := mustGetEOAReceiverAddress(t, destChain) - runTokenTransferTestCase(t, usdcCombo, 0, receiver) + runUSDCTestCase(t, usdcCombo, 0, receiver) }) for _, combo := range evm.All17TokenCombinations() { diff --git a/verifier/token/cctp/attestation.go b/verifier/token/cctp/attestation.go index dd84a9541..8923c9268 100644 --- a/verifier/token/cctp/attestation.go +++ b/verifier/token/cctp/attestation.go @@ -109,7 +109,7 @@ func (h *HTTPAttestationService) extractAttestationFromResponse(response Message for _, msg := range response.Messages { err := cctpMatchesMessage(h.ccvVerifierVersion, h.ccvAddresses, msg, message) if err != nil { - h.lggr.Debugw( + h.lggr.Infow( "skipping CCTP message as it doesn't match CCIP message", "message", msg, "reason", err, From 256474e788db328dca5ea8fc176b5d74eb904bc4 Mon Sep 17 00:00:00 2001 From: Mateusz Sekara Date: Fri, 16 Jan 2026 17:26:58 +0100 Subject: [PATCH 4/6] Fixing configuration for tokenVerifier --- build/devenv/fakes/pkg/cctp/api.go | 25 ++++++++++++++++++------- build/devenv/tests/e2e/smoke_test.go | 10 +++++----- 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/build/devenv/fakes/pkg/cctp/api.go b/build/devenv/fakes/pkg/cctp/api.go index d3a7c3d19..d739aad65 100644 --- a/build/devenv/fakes/pkg/cctp/api.go +++ b/build/devenv/fakes/pkg/cctp/api.go @@ -41,8 +41,8 @@ type DecodedMessageBody struct { type RegisterAttestationRequest struct { SourceDomain string `json:"sourceDomain" binding:"required"` - HookData string `json:"hookData" binding:"required"` - Status string `json:"status" binding:"required"` + MessageID string `json:"messageID" binding:"required"` + Status string `json:"status" binding:"required"` } type AttestationAPI struct { @@ -56,11 +56,19 @@ func NewAttestationAPI() *AttestationAPI { } } -// RegisterAttestation registers a new attestation response for a given sourceDomain -func (a *AttestationAPI) RegisterAttestation(sourceDomain, hookData, status string) AttestationResponse { +// RegisterAttestation registers a new attestation response for a given sourceDomain. +func (a *AttestationAPI) RegisterAttestation(sourceDomain, messageID, status string) AttestationResponse { a.mu.Lock() defer a.mu.Unlock() + // Construct hookData as 0x8e1d1a9d + messageID (without 0x prefix) + // Strip 0x prefix from messageID if present + cleanMessageID := messageID + if len(messageID) > 2 && messageID[:2] == "0x" { + cleanMessageID = messageID[2:] + } + hookData := "0x8e1d1a9d" + cleanMessageID + // Create a response based on the example attestation but with the provided sourceDomain, hookData and status response := AttestationResponse{ Message: "0xbbbbbb22", @@ -99,7 +107,7 @@ func (a *AttestationAPI) Register() error { return } - response := a.RegisterAttestation(req.SourceDomain, req.HookData, req.Status) + response := a.RegisterAttestation(req.SourceDomain, req.MessageID, req.Status) ctx.JSON(http.StatusOK, response) }) if err != nil { @@ -119,8 +127,11 @@ func (a *AttestationAPI) Register() error { return } - // Return as an array to match the expected format - responseBytes, err := json.Marshal([]AttestationResponse{response}) + // Return wrapped in "messages" array to match the expected format + wrappedResponse := map[string][]AttestationResponse{ + "messages": {response}, + } + responseBytes, err := json.Marshal(wrappedResponse) if err != nil { ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return diff --git a/build/devenv/tests/e2e/smoke_test.go b/build/devenv/tests/e2e/smoke_test.go index b532bab3b..fa8cf2b2a 100644 --- a/build/devenv/tests/e2e/smoke_test.go +++ b/build/devenv/tests/e2e/smoke_test.go @@ -66,14 +66,14 @@ type v2TestCase struct { numExpectedVerifications int } -// registerCCTPAttestation registers a CCTP attestation response with the fake service +// registerCCTPAttestation registers a CCTP attestation response with the fake service. func registerCCTPAttestation(t *testing.T, messageID [32]byte, status string) { - // Convert messageID to hex string (without 0x prefix) - hookData := "0x" + hex.EncodeToString(messageID[:]) + // Convert messageID to hex string + messageIDHex := "0x" + hex.EncodeToString(messageID[:]) reqBody := map[string]string{ "sourceDomain": "100", - "hookData": hookData, + "messageID": messageIDHex, "status": status, } reqJSON, err := json.Marshal(reqBody) @@ -81,7 +81,7 @@ func registerCCTPAttestation(t *testing.T, messageID [32]byte, status string) { // The fake service runs on port 9111 resp, err := http.Post( - "http://fake:9111/cctp/v2/attestations", + "http://localhost:9111/cctp/v2/attestations", "application/json", bytes.NewBuffer(reqJSON), ) From b436f108d3916fa47e4a090d9b15185b5ca72d90 Mon Sep 17 00:00:00 2001 From: Mateusz Sekara Date: Fri, 16 Jan 2026 17:34:06 +0100 Subject: [PATCH 5/6] Fixing configuration for tokenVerifier --- build/devenv/fakes/go.mod | 11 +++ build/devenv/fakes/go.sum | 98 +++++++++++++++++++++++++- build/devenv/fakes/pkg/cctp/api.go | 47 +++--------- build/devenv/tests/e2e/cctp_helpers.go | 36 ++++++++++ build/devenv/tests/e2e/smoke_test.go | 27 ------- 5 files changed, 154 insertions(+), 65 deletions(-) create mode 100644 build/devenv/tests/e2e/cctp_helpers.go diff --git a/build/devenv/fakes/go.mod b/build/devenv/fakes/go.mod index 84414f3bc..58af8f83a 100644 --- a/build/devenv/fakes/go.mod +++ b/build/devenv/fakes/go.mod @@ -45,6 +45,7 @@ require ( github.com/go-resty/resty/v2 v2.16.5 // indirect github.com/goccy/go-json v0.10.5 // indirect github.com/google/uuid v1.6.0 // indirect + github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect github.com/holiman/uint256 v1.3.2 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/compress v1.18.2 // indirect @@ -64,6 +65,7 @@ require ( github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/morikuni/aec v1.0.0 // indirect + github.com/mr-tron/base58 v1.2.0 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.1 // indirect github.com/pelletier/go-toml/v2 v2.2.4 // indirect @@ -73,7 +75,11 @@ require ( github.com/rs/zerolog v1.34.0 // indirect github.com/shirou/gopsutil/v4 v4.25.9 // indirect github.com/sirupsen/logrus v1.9.3 // indirect + github.com/smartcontractkit/chain-selectors v1.0.79 // indirect + github.com/smartcontractkit/chainlink-common v0.9.6-0.20260114190811-74301cd99dc3 // indirect + github.com/smartcontractkit/chainlink-protos/chainlink-ccv/verifier v0.0.0-20251211142334-5c3421fe2c8d // indirect github.com/smartcontractkit/chainlink-testing-framework/framework v0.12.6 // indirect + github.com/smartcontractkit/libocr v0.0.0-20250912173940-f3ab0246e23d // indirect github.com/stretchr/testify v1.11.1 // indirect github.com/testcontainers/testcontainers-go v0.39.0 // indirect github.com/tklauser/go-sysconf v0.3.15 // indirect @@ -87,12 +93,17 @@ require ( go.opentelemetry.io/otel/metric v1.38.0 // indirect go.opentelemetry.io/otel/trace v1.38.0 // indirect go.uber.org/multierr v1.11.0 // indirect + go.uber.org/zap v1.27.0 // indirect golang.org/x/arch v0.21.0 // indirect golang.org/x/crypto v0.46.0 // indirect + golang.org/x/exp v0.0.0-20250711185948-6ae5c78190dc // indirect golang.org/x/net v0.47.0 // indirect golang.org/x/sync v0.19.0 // indirect golang.org/x/sys v0.39.0 // indirect golang.org/x/text v0.32.0 // indirect + golang.org/x/time v0.12.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5 // indirect + google.golang.org/grpc v1.76.0 // indirect google.golang.org/protobuf v1.36.11 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/build/devenv/fakes/go.sum b/build/devenv/fakes/go.sum index e17020dd4..cc1582724 100644 --- a/build/devenv/fakes/go.sum +++ b/build/devenv/fakes/go.sum @@ -8,8 +8,14 @@ github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERo github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= 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/XSAM/otelsql v0.37.0 h1:ya5RNw028JW0eJW8Ma4AmoKxAYsJSGuNVbC7F1J457A= +github.com/XSAM/otelsql v0.37.0/go.mod h1:LHbCu49iU8p255nCn1oi04oX2UjSoRcUMiKEHo2a5qM= +github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7Dml6nw9rQ= +github.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP2+08jFMw88y4klk= github.com/avast/retry-go/v4 v4.6.1 h1:VkOLRubHdisGrHnTu89g08aQEWEgRU7LVEop3GbIcMk= github.com/avast/retry-go/v4 v4.6.1/go.mod h1:V6oF8njAwxJ5gRo1Q7Cxab24xs5NCWZBeaHHBklR8mA= +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.24.0 h1:H4x4TuulnokZKvHLfzVRTHJfFfnHEeSYJizujEZvmAM= github.com/bits-and-blooms/bitset v1.24.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= github.com/block-vision/sui-go-sdk v1.1.2 h1:p9DPfb51mEcTmF0Lx9ORpH+Nh9Rzg4Sv3Pu5gsJZ2AA= @@ -24,6 +30,12 @@ github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK3 github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/cenkalti/backoff/v5 v5.0.2 h1:rIfFVxEf1QsI7E1ZHfp/B4DF/6QBAUhmgkxc0H7Zss8= github.com/cenkalti/backoff/v5 v5.0.2/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +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/cloudwego/base64x v0.1.6 h1:t11wG9AECkCDk5fMSoxmufanudBtJ+/HemLstXDLI2M= github.com/cloudwego/base64x v0.1.6/go.mod h1:OFcloc187FXDaYHvrNIjxSe8ncn0OOM8gEHfghB2IPU= github.com/consensys/gnark-crypto v0.18.1 h1:RyLV6UhPRoYYzaFnPQA4qK3DyuDgkTgskDdoGqFt3fI= @@ -65,7 +77,7 @@ github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4 github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/ebitengine/purego v0.9.0 h1:mh0zpKBIXDceC63hpvPuGLiJ8ZAa3DfrFTudmfi8A4k= github.com/ebitengine/purego v0.9.0/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= -github.com/ethereum/c-kzg-4844 v1.0.0 h1:0X1LBXxaEtYD9xsyj9B9ctQEZIpnvVDeoBx8aHEwTNA= +github.com/ethereum/c-kzg-4844 v1.0.3 h1:IEnbOHwjixW2cTvKRUlAAUOeleV7nNM/umJR+qy4WDs= github.com/ethereum/c-kzg-4844/v2 v2.1.5 h1:aVtoLK5xwJ6c5RiqO8g8ptJ5KU+2Hdquf6G3aXiHh5s= github.com/ethereum/c-kzg-4844/v2 v2.1.5/go.mod h1:u59hRTTah4Co6i9fDWtiCjTrblJv0UwsqZKCc0GfgUs= github.com/ethereum/go-ethereum v1.16.8 h1:LLLfkZWijhR5m6yrAXbdlTeXoqontH+Ga2f9igY7law= @@ -103,6 +115,8 @@ github.com/go-resty/resty/v2 v2.16.5/go.mod h1:hkJtXbA2iKHzJheXYvQ8snQES5ZLGKMwQ github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4= github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= 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= @@ -112,8 +126,28 @@ github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aN github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 h1:5ZPtiqj0JL5oKWmcsq4VMaAW5ukBEgSGXEN89zeH1Jo= github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3/go.mod h1:ndYquD05frm2vACXE1nsccT4oJzjhw2arTS2cpUD1PI= +github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= +github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/holiman/uint256 v1.3.2 h1:a9EgMPSC1AAaj1SZL5zIQD3WbwTuHrMGOerLjGmM/TA= github.com/holiman/uint256 v1.3.2/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E= +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 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/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= +github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= +github.com/jackc/pgproto3/v2 v2.3.3 h1:1HLSx5H+tXR9pW3in3zaztoEwQYRC9SQaYUHjTSUOag= +github.com/jackc/pgproto3/v2 v2.3.3/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= +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 v1.14.4 h1:fKuNiCumbKTAIxQwXfB/nsrnkEI6bPJrrSiMKgbJ2j8= +github.com/jackc/pgtype v1.14.4/go.mod h1:aKeozOde08iifGosdJpz9MBZonJOUJxqNpPBcMJTlVA= +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/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o= +github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY= 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/klauspost/compress v1.18.2 h1:iiPHWW0YrcFgpBYhsA6D1+fqHssJscY/Tm/y2Uqnapk= @@ -126,6 +160,8 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 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.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= +github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lufia/plan9stats v0.0.0-20251013123823-9fd1530e3ec3 h1:PwQumkgq4/acIiZhtifTV5OUqqiP82UAl0h87xj/l9k= github.com/lufia/plan9stats v0.0.0-20251013123823-9fd1530e3ec3/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg= github.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE= @@ -160,10 +196,18 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +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/oapi-codegen/runtime v1.1.2 h1:P2+CubHq8fO4Q6fV1tqDBZHCwpVpvPg7oKiYzQgXIyI= +github.com/oapi-codegen/runtime v1.1.2/go.mod h1:SK9X900oXmPWilYR5/WKPzt3Kqxn/uS/+lbpREv+eCg= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040= github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M= +github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= +github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= 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/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -173,21 +217,43 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 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 v1.23.0 h1:ust4zpdl9r4trLY/gSjlm07PuiBq2ynaXXlptpfy8Uc= +github.com/prometheus/client_golang v1.23.0/go.mod h1:i/o0R9ByOnHX0McrTMTyhYvKE4haaf2mW08I+jGAjEE= +github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= +github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= +github.com/prometheus/common v0.65.0 h1:QDwzd+G1twt//Kwj/Ww6E9FQq1iVMmODnILtW1t2VzE= +github.com/prometheus/common v0.65.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8= +github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= +github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= 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/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0= github.com/rs/zerolog v1.34.0 h1:k43nTLIwcTVQAncfCw4KZ2VY6ukYoZaBPNOE8txlOeY= github.com/rs/zerolog v1.34.0/go.mod h1:bJsvje4Z08ROH4Nhs5iH600c3IkWhwp44iRc54W6wYQ= +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/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI= github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/shirou/gopsutil/v4 v4.25.9 h1:JImNpf6gCVhKgZhtaAHJ0serfFGtlfIlSC08eaKdTrU= github.com/shirou/gopsutil/v4 v4.25.9/go.mod h1:gxIxoC+7nQRwUl/xNhutXlD8lq+jxTgpIkEf3rADHL8= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/smartcontractkit/chain-selectors v1.0.79 h1:TQ9FFUrKxMv5rNYES8dyKQLHaTRCnQzM+B0CYyCfw9s= +github.com/smartcontractkit/chain-selectors v1.0.79/go.mod h1:xsKM0aN3YGcQKTPRPDDtPx2l4mlTN1Djmg0VVXV40b8= +github.com/smartcontractkit/chainlink-common v0.9.6-0.20260114190811-74301cd99dc3 h1:VINIWIvYhgbGJpaI7O3aBuBOAZgMEN6BGA61zQIqvFw= +github.com/smartcontractkit/chainlink-common v0.9.6-0.20260114190811-74301cd99dc3/go.mod h1:DAwaVSiQMgAsCjHa8nOnIAM9GixuIQWsgEZFGpf3JxE= +github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.10 h1:FJAFgXS9oqASnkS03RE1HQwYQQxrO4l46O5JSzxqLgg= +github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.10/go.mod h1:oiDa54M0FwxevWwyAX773lwdWvFYYlYHHQV1LQ5HpWY= +github.com/smartcontractkit/chainlink-protos/chainlink-ccv/committee-verifier v0.0.0-20251211142334-5c3421fe2c8d h1:VYoBBNnQpZ5p+enPTl8SkKBRaubqyGpO0ul3B1np++I= +github.com/smartcontractkit/chainlink-protos/chainlink-ccv/committee-verifier v0.0.0-20251211142334-5c3421fe2c8d/go.mod h1:oNFoKHRIerxuaANa8ASNejtHrdsG26LqGtQ2XhSac2g= +github.com/smartcontractkit/chainlink-protos/chainlink-ccv/verifier v0.0.0-20251211142334-5c3421fe2c8d h1:AJy55QJ/pBhXkZjc7N+ATnWfxrcjq9BI9DmdtdjwDUQ= +github.com/smartcontractkit/chainlink-protos/chainlink-ccv/verifier v0.0.0-20251211142334-5c3421fe2c8d/go.mod h1:5JdppgngCOUS76p61zCinSCgOhPeYQ+OcDUuome5THQ= github.com/smartcontractkit/chainlink-testing-framework/framework v0.12.6 h1:+Pjg5HsFo+AG6Id/iN/VHHHuU1HRfXNLBc/HHu30yjg= github.com/smartcontractkit/chainlink-testing-framework/framework v0.12.6/go.mod h1:2p+lXQtkaJmD5dXw+HaAf+lFoQtNJy3NwkRfprU3VlY= github.com/smartcontractkit/chainlink-testing-framework/framework/components/fake v0.10.1-0.20250711120409-5078050f9db4 h1:6iIj+U1SA19xftdEJwubATHBoGm4yc8q+MwWz6rlBDc= github.com/smartcontractkit/chainlink-testing-framework/framework/components/fake v0.10.1-0.20250711120409-5078050f9db4/go.mod h1:YEQbZRHFojvlQKeuckG/70t0WkAqOBmArSbkacgHSbc= +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/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 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= @@ -222,30 +288,58 @@ github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= 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.63.0 h1:RbKq8BG0FI8OiXhBfcRtqqHcZcka+gU3cskNuf05R18= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0/go.mod h1:h06DGIukJOevXaj/xrNjhi/2098RZzcLTbc0jDAUbsg= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= +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.37.0 h1:Ahq7pZmv87yiyn3jeFz/LekZmPLLdKejuO3NcK9MssM= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0/go.mod h1:MJTqhM0im3mRLw1i8uGHnCvUEeS7VwRyxlLC78PA18M= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.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.36.0 h1:nRVXXvf78e00EwY6Wp0YII8ww2JVWshZ20HfTlE11AM= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.36.0/go.mod h1:r49hO7CgrxY9Voaj3Xe8pANWtr0Oq916d0XAmOoCZAQ= +go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.13.0 h1:yEX3aC9KDgvYPhuKECHbOlr5GLwH6KTjLJ1sBSkkxkc= +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.13.0 h1:yoxRoIZcohB6Xf0lNv9QIyCzQvrtGZklVbdCoyb7dls= +go.opentelemetry.io/otel/log v0.13.0/go.mod h1:INKfG4k1O9CL25BaM1qLe0zIedOpvlS5Z7XgSbmN83E= go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= +go.opentelemetry.io/otel/sdk/log v0.13.0 h1:I3CGUszjM926OphK8ZdzF+kLqFvfRY/IIoFq/TjwfaQ= +go.opentelemetry.io/otel/sdk/log v0.13.0/go.mod h1:lOrQyCCXmpZdN7NchXb6DOZZa1N5G1R2tm5GMMTpDBw= go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= go.opentelemetry.io/proto/otlp v1.7.0 h1:jX1VolD6nHuFzOYso2E73H85i92Mv8JQYk0K9vz09os= go.opentelemetry.io/proto/otlp v1.7.0/go.mod h1:fSKjH6YJ7HDlwzltzyMj036AJ3ejJLCgCSHGj4efDDo= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= 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/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= golang.org/x/arch v0.21.0 h1:iTC9o7+wP6cPWpDWkivCvQFGAHDQ59SrSxsLPcnkArw= golang.org/x/arch v0.21.0/go.mod h1:dNHoOeKiyja7GTvF9NJS1l3Z2yntpQNzgrjh1cU103A= golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU= golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0= +golang.org/x/exp v0.0.0-20250711185948-6ae5c78190dc h1:TS73t7x3KarrNd5qAipmspBDS1rkMcgVG/fS1aRb4Rc= +golang.org/x/exp v0.0.0-20250711185948-6ae5c78190dc/go.mod h1:A+z0yzpGtvnG90cToK5n2tu8UJVP2XUATh+r+sfOOOc= golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= @@ -266,6 +360,8 @@ golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE= golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= +gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= +gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5 h1:BIRfGDEjiHRrk0QKZe3Xv2ieMhtgRGeLcZQ0mIVn4EY= google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5/go.mod h1:j3QtIyytwqGr1JUDtYXwtMXWPKsEa5LtzIFN1Wn5WvE= google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5 h1:eaY8u2EuxbRv7c3NiGK0/NedzVsCcV6hDuU5qPX5EGE= diff --git a/build/devenv/fakes/pkg/cctp/api.go b/build/devenv/fakes/pkg/cctp/api.go index d739aad65..02916e5cc 100644 --- a/build/devenv/fakes/pkg/cctp/api.go +++ b/build/devenv/fakes/pkg/cctp/api.go @@ -8,37 +8,10 @@ import ( "github.com/gin-gonic/gin" + cctpclient "github.com/smartcontractkit/chainlink-ccv/verifier/token/cctp" "github.com/smartcontractkit/chainlink-testing-framework/framework/components/fake" ) -type AttestationResponse struct { - Message string `json:"message"` - EventNonce string `json:"eventNonce"` - Attestation string `json:"attestation"` - DecodedMessage DecodedMessage `json:"decodedMessage"` - CCTPVersion string `json:"cctpVersion"` - Status string `json:"status"` -} - -type DecodedMessage struct { - SourceDomain string `json:"sourceDomain"` - DestinationDomain string `json:"destinationDomain"` - Nonce string `json:"nonce"` - Sender string `json:"sender"` - Recipient string `json:"recipient"` - DestinationCaller string `json:"destinationCaller"` - MessageBody string `json:"messageBody"` - DecodedMessageBody DecodedMessageBody `json:"decodedMessageBody"` -} - -type DecodedMessageBody struct { - BurnToken string `json:"burnToken"` - MintRecipient string `json:"mintRecipient"` - Amount string `json:"amount"` - MessageSender string `json:"messageSender"` - HookData string `json:"hookData"` -} - type RegisterAttestationRequest struct { SourceDomain string `json:"sourceDomain" binding:"required"` MessageID string `json:"messageID" binding:"required"` @@ -47,17 +20,17 @@ type RegisterAttestationRequest struct { type AttestationAPI struct { mu sync.RWMutex - responses map[string]AttestationResponse + responses map[string]cctpclient.Message } func NewAttestationAPI() *AttestationAPI { return &AttestationAPI{ - responses: make(map[string]AttestationResponse), + responses: make(map[string]cctpclient.Message), } } // RegisterAttestation registers a new attestation response for a given sourceDomain. -func (a *AttestationAPI) RegisterAttestation(sourceDomain, messageID, status string) AttestationResponse { +func (a *AttestationAPI) RegisterAttestation(sourceDomain, messageID, status string) cctpclient.Message { a.mu.Lock() defer a.mu.Unlock() @@ -70,11 +43,11 @@ func (a *AttestationAPI) RegisterAttestation(sourceDomain, messageID, status str hookData := "0x8e1d1a9d" + cleanMessageID // Create a response based on the example attestation but with the provided sourceDomain, hookData and status - response := AttestationResponse{ + response := cctpclient.Message{ Message: "0xbbbbbb22", EventNonce: "9682", Attestation: "0xaaaaaa11", - DecodedMessage: DecodedMessage{ + DecodedMessage: cctpclient.DecodedMessage{ SourceDomain: sourceDomain, DestinationDomain: "5", Nonce: "569", @@ -82,7 +55,7 @@ func (a *AttestationAPI) RegisterAttestation(sourceDomain, messageID, status str Recipient: "0xb7317b4EFEa194a22bEB42506065D3772C2E95EF", DestinationCaller: "0xf2Edb1Ad445C6abb1260049AcDDCA9E84D7D8aaA", MessageBody: "0x00000000000000050000000300000000000194c2a65fc943419a5ad590042fd67c9791fd015acf53a54cc823edb8ff81b9ed722e00000000000000000000000019330d10d9cc8751218eaf51e8885d058642e08a000000000000000000000000fc05ad74c6fe2e7046e091d6ad4f660d2a15976200000000c6fa7af3bedbad3a3d65f36aabc97431b1bbe4c2d2f6e0e47ca60203452f5d610000000000000000000000002d475f4746419c83be23056309a8e2ac33b30e3b0000000000000000000000000000000000000000000000000000000002b67df0feae5e08f5e6bf04d8c1de7dada9235c56996f4420b14371d6c6f3ddd2f2da78", - DecodedMessageBody: DecodedMessageBody{ + DecodedMessageBody: cctpclient.DecodedMessageBody{ BurnToken: "0x4Bc078D75390C0f5CCc3e7f59Ae2159557C5eb85", MintRecipient: "0xb7317b4EFEa194a22bEB42506065D3772C2E95EF", Amount: "5000", @@ -91,7 +64,7 @@ func (a *AttestationAPI) RegisterAttestation(sourceDomain, messageID, status str }, }, CCTPVersion: "2", - Status: status, + Status: cctpclient.AttestationStatus(status), } a.responses[sourceDomain] = response @@ -128,8 +101,8 @@ func (a *AttestationAPI) Register() error { } // Return wrapped in "messages" array to match the expected format - wrappedResponse := map[string][]AttestationResponse{ - "messages": {response}, + wrappedResponse := cctpclient.Messages{ + Messages: []cctpclient.Message{response}, } responseBytes, err := json.Marshal(wrappedResponse) if err != nil { diff --git a/build/devenv/tests/e2e/cctp_helpers.go b/build/devenv/tests/e2e/cctp_helpers.go new file mode 100644 index 000000000..ecf7ae24c --- /dev/null +++ b/build/devenv/tests/e2e/cctp_helpers.go @@ -0,0 +1,36 @@ +package e2e + +import ( + "bytes" + "encoding/hex" + "encoding/json" + "net/http" + "testing" + + "github.com/stretchr/testify/require" +) + +// registerCCTPAttestation registers a CCTP attestation response with the fake service. +func registerCCTPAttestation(t *testing.T, messageID [32]byte, status string) { + // Convert messageID to hex string + messageIDHex := "0x" + hex.EncodeToString(messageID[:]) + + reqBody := map[string]string{ + "sourceDomain": "100", + "messageID": messageIDHex, + "status": status, + } + reqJSON, err := json.Marshal(reqBody) + require.NoError(t, err) + + // The fake service runs on port 9111 + resp, err := http.Post( + "http://localhost:9111/cctp/v2/attestations", + "application/json", + bytes.NewBuffer(reqJSON), + ) + require.NoError(t, err) + defer resp.Body.Close() + + require.Equal(t, http.StatusOK, resp.StatusCode, "Failed to register CCTP attestation") +} diff --git a/build/devenv/tests/e2e/smoke_test.go b/build/devenv/tests/e2e/smoke_test.go index fa8cf2b2a..8172e254c 100644 --- a/build/devenv/tests/e2e/smoke_test.go +++ b/build/devenv/tests/e2e/smoke_test.go @@ -3,10 +3,8 @@ package e2e import ( "bytes" "encoding/hex" - "encoding/json" "fmt" "math/big" - "net/http" "os" "testing" "time" @@ -66,31 +64,6 @@ type v2TestCase struct { numExpectedVerifications int } -// registerCCTPAttestation registers a CCTP attestation response with the fake service. -func registerCCTPAttestation(t *testing.T, messageID [32]byte, status string) { - // Convert messageID to hex string - messageIDHex := "0x" + hex.EncodeToString(messageID[:]) - - reqBody := map[string]string{ - "sourceDomain": "100", - "messageID": messageIDHex, - "status": status, - } - reqJSON, err := json.Marshal(reqBody) - require.NoError(t, err) - - // The fake service runs on port 9111 - resp, err := http.Post( - "http://localhost:9111/cctp/v2/attestations", - "application/json", - bytes.NewBuffer(reqJSON), - ) - require.NoError(t, err) - defer resp.Body.Close() - - require.Equal(t, http.StatusOK, resp.StatusCode, "Failed to register CCTP attestation") -} - func TestE2ESmoke(t *testing.T) { smokeTestConfig := os.Getenv("SMOKE_TEST_CONFIG") if smokeTestConfig == "" { From 59e387c5b2c51b455c62b51cbb1c76bd12ec21c6 Mon Sep 17 00:00:00 2001 From: Mateusz Sekara Date: Fri, 16 Jan 2026 17:35:40 +0100 Subject: [PATCH 6/6] Fixing configuration for tokenVerifier --- build/devenv/tests/e2e/smoke_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/build/devenv/tests/e2e/smoke_test.go b/build/devenv/tests/e2e/smoke_test.go index 8172e254c..1dd4e5e59 100644 --- a/build/devenv/tests/e2e/smoke_test.go +++ b/build/devenv/tests/e2e/smoke_test.go @@ -400,6 +400,7 @@ func TestE2ESmoke(t *testing.T) { } t.Run("USDC", func(t *testing.T) { + t.Skip("not yet implemented") usdcCombo := evm.USDCTokenPoolCombination() receiver := mustGetEOAReceiverAddress(t, destChain) runUSDCTestCase(t, usdcCombo, 0, receiver)