@@ -6,10 +6,8 @@ import (
66 "encoding/json"
77 "fmt"
88 "log/slog"
9- "math"
109 "math/big"
1110 "reflect"
12- "strconv"
1311 "strings"
1412 "time"
1513
@@ -301,7 +299,7 @@ func MustEvent(abiJSON, eventName string) gethAbi.Event {
301299// BuildAndHashEventEnvelope builds the base64 verifiable-event JSON and computes keccak256(type+"."+b64).
302300// Note: parameters and metadata are treated as read-only; they are not mutated.
303301func BuildAndHashEventEnvelope (
304- service string ,
302+ service * string ,
305303 eventName string ,
306304 contractAddress string ,
307305 eventABIJSON string ,
@@ -323,14 +321,16 @@ func BuildAndHashEventEnvelope(
323321 }
324322
325323 event := map [string ]any {
326- "service" : service ,
327324 "name" : eventName ,
328325 "address" : contractAddress ,
329326 "topic_hash" : eventABI .ID .Hex (),
330327 "log_index" : logIndex ,
331328 "block_number" : blockNumber ,
332329 "parameters" : parameters ,
333330 }
331+ if service != nil {
332+ event ["service" ] = * service
333+ }
334334
335335 transaction := map [string ]any {
336336 "timestamp" : timestamp ,
@@ -350,7 +350,11 @@ func BuildAndHashEventEnvelope(
350350
351351 marshalledVerifiableEvent , _ := json .Marshal (verifiableEventBody )
352352 base64VerifiableEvent := base64 .StdEncoding .EncodeToString (marshalledVerifiableEvent )
353- typeName := service + "." + eventName
353+ // Build typeName: if service is nil, use just eventName, otherwise use service.eventName
354+ typeName := eventName
355+ if service != nil {
356+ typeName = * service + "." + eventName
357+ }
354358 payloadToSign := typeName + "." + base64VerifiableEvent
355359 eventHash := crypto .Keccak256Hash ([]byte (payloadToSign ))
356360
@@ -364,12 +368,12 @@ func BuildAndHashEventEnvelope(
364368
365369// ResolveAPIKey returns the API key to use for Courier requests.
366370// Only the secret-based approach is supported:
367- // - cfg.ApiKeySecret MUST be set to the secret ID.
371+ // - apiKeySecret MUST be set to the secret ID.
368372// - The secret MUST resolve via rt.GetSecret.
369373//
370374// If resolution fails, an empty string is returned and callers should error.
371- func ResolveAPIKey (rt cre.Runtime , cfg * Config ) string {
372- secretID := strings .TrimSpace (cfg . ApiKeySecret )
375+ func ResolveAPIKey (rt cre.Runtime , apiKeySecret string ) string {
376+ secretID := strings .TrimSpace (apiKeySecret )
373377 if secretID == "" {
374378 return ""
375379 }
@@ -378,7 +382,7 @@ func ResolveAPIKey(rt cre.Runtime, cfg *Config) string {
378382 s , err := rt .GetSecret (& cre.SecretRequest {Id : secretID }).Await ()
379383
380384 if err != nil {
381- slog . Warn ("failed to resolve API key secret" , "error" , err )
385+ rt . Logger (). Warn ("ResolveAPIKey failed to get secret" , "error" , err )
382386 return ""
383387 }
384388
@@ -400,20 +404,12 @@ func PostSignedEvent(cfg *Config, rt cre.Runtime, eventName, address string, pre
400404 }
401405 rpb := report .X_GeneratedCodeOnly_Unwrap ()
402406
403- // Convert ChainSelector to uint64
404- chainSelector , err := strconv .ParseUint (cfg .ChainSelector , 10 , 64 )
405- if err != nil {
406- return "" , fmt .Errorf ("invalid chain selector: %w" , err )
407- }
408-
409407 // Compose HTTP body
410408 bodyMap := map [string ]any {
411- "event_id" : uuid .New ().String (),
412409 "created_at" : int64 (pre .BlockTimestamp ) * 1000 , // Convert seconds to milliseconds for server
413410 "watcher_id" : cfg .WatcherID ,
414- "domain" : cfg .Service ,
415411 "name" : eventName ,
416- "chain_selector" : chainSelector ,
412+ "chain_selector" : cfg . ChainSelector ,
417413 "address" : address ,
418414 "ocr_report" : "0x" + hex .EncodeToString (rpb .RawReport ),
419415 "ocr_context" : "0x" + hex .EncodeToString (rpb .ReportContext ),
@@ -427,42 +423,66 @@ func PostSignedEvent(cfg *Config, rt cre.Runtime, eventName, address string, pre
427423 return out
428424 }(),
429425 }
426+ if cfg .Service != nil {
427+ bodyMap ["domain" ] = * cfg .Service
428+ }
430429 body , _ := json .Marshal (bodyMap )
431430
432431 // HTTP POST with identical consensus
432+ // We aggregate only the integer StatusCode to ensure compatibility with Identical consensus.
433433 client := & httpcap.Client {}
434- key := ResolveAPIKey (rt , cfg )
435-
436- _ , err = httpcap .SendRequest (cfg , rt , client , func (_ * Config , _ * slog.Logger , sr * httpcap.SendRequester ) (* httpcap.Response , error ) {
437- if key == "" {
438- return nil , fmt .Errorf ("courier API key is required but not configured" )
439- }
440- headers := map [string ]string {
441- "Content-Type" : "application/json" ,
442- "Api-Key" : key ,
443- }
444- req := & httpcap.Request {
445- Url : strings .TrimRight (cfg .CourierURL , "/" ) + "/system/onchain-watcher-events" ,
446- Method : "POST" ,
447- Headers : headers ,
448- Body : body ,
449- }
450- return sr .SendRequest (req ).Await ()
451- }, cre .ConsensusIdenticalAggregation [* httpcap.Response ]()).Await ()
434+ key := ResolveAPIKey (rt , cfg .ApiKeySecret )
435+
436+ _ , err = httpcap .SendRequest (
437+ cfg ,
438+ rt ,
439+ client ,
440+ func (_ * Config , _ * slog.Logger , sr * httpcap.SendRequester ) (int , error ) {
441+ if key == "" {
442+ return 0 , fmt .Errorf ("courier API key is required but not configured" )
443+ }
444+ headers := map [string ]string {
445+ "Content-Type" : "application/json" ,
446+ "Api-Key" : key ,
447+ }
448+ req := & httpcap.Request {
449+ Url : strings .TrimRight (cfg .CourierURL , "/" ) + "/system/onchain-watcher-events" ,
450+ Method : "POST" ,
451+ Headers : headers ,
452+ Body : body ,
453+ }
454+ resp , err := sr .SendRequest (req ).Await ()
455+ if err != nil {
456+ return 0 , err
457+ }
458+ if resp == nil {
459+ return 0 , fmt .Errorf ("nil response" )
460+ }
461+ // Treat any 4xx/5xx as an error (caller may retry).
462+ if resp .StatusCode >= 400 {
463+ return 0 , fmt .Errorf ("courier API responded with status %d" , resp .StatusCode )
464+ }
465+ return int (resp .StatusCode ), nil
466+ },
467+ cre .ConsensusIdenticalAggregation [int ](),
468+ ).Await ()
452469 if err != nil {
453470 return "" , err
454471 }
472+
455473 return pre .Base64Event , nil
456474}
457475
458- // CheckResponse validates an HTTP response status code and returns it as int.
459- // Returns an error if the status code exceeds int32 bounds.
460- func CheckResponse (resp * httpcap.Response ) (int , error ) {
461- code := resp .StatusCode
462- if code > math .MaxInt32 {
463- return 0 , fmt .Errorf ("API responded with invalid status code %d" , code )
476+ // CheckResponse validates the httpcap response and returns it unchanged if acceptable.
477+ func CheckResponse (resp * httpcap.Response ) (* httpcap.Response , error ) {
478+ if resp == nil {
479+ return nil , fmt .Errorf ("nil response" )
480+ }
481+ // Treat any 4xx/5xx as an error (caller may retry).
482+ if resp .StatusCode >= 400 {
483+ return nil , fmt .Errorf ("courier API responded with status %d" , resp .StatusCode )
464484 }
465- return int ( code ) , nil
485+ return resp , nil
466486}
467487
468488// DecodeEventParams decodes an EVM log's topics/data into a named parameter map, using the provided ABI JSON and event-name.
0 commit comments