events

package
v0.6.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 6, 2026 License: MIT Imports: 12 Imported by: 0

Documentation

Overview

Package events provides operations for polling and verifying events from CREC.

Events are blockchain occurrences detected by watchers and signed by the Decentralized Oracle Network (DON). This package enables fetching events from channels, verifying their cryptographic signatures, and decoding the event data into structured Go types.

Usage

Events are typically accessed through the main SDK client:

client, _ := crec.NewClient(
    baseURL,
    apiKey,
    crec.WithOrgID("my-org-id"),
    crec.WithEventVerification(3, []string{
        "0x5db070ceabcf97e45d96b4f951a1df050ddb5559",
        "0xadebb9657c04692275973230b06adfabacc899bc",
        "0xc868bbb5d93e97b9d780fc93811a00ca7c016751",
    }),
)

events, hasMore, err := client.Events.Poll(ctx, channelID, nil)

For advanced use cases, create the client directly:

eventsClient, err := events.NewClient(&events.Options{
    CRECClient:            apiClient,
    MinRequiredSignatures: 3,
    ValidSigners:          []string{"0x...", "0x...", "0x..."},
    OrgID:                 "my-org-id", // optional; enables Verify(event) without passing org ID
})

Polling Events

Use Client.Poll to fetch events from a channel:

// Poll with default parameters
events, hasMore, err := client.Events.Poll(ctx, channelID, nil)

// Poll with pagination
params := &apiClient.GetChannelsChannelIdEventsParams{
    Limit: ptr(100),
}
events, hasMore, err := client.Events.Poll(ctx, channelID, params)

Verifying Events

CRITICAL: Always verify events before processing. Verification ensures the event was signed by enough trusted DON members and matches the expected workflow.

## Verifying Watcher Events

For single-org use, set OrgID when creating the client (or use crec.WithOrgID) and call Client.Verify:

for _, event := range events {
    verified, err := client.Events.Verify(&event)
    if err != nil {
        // Handle verification error (e.g., ErrOrgIDRequired if no default org configured)
        continue
    }
    if !verified {
        // Not enough valid signatures or workflow mismatch, skip this event
        continue
    }
    processEvent(event)
}

For multi-org use, you can either create separate clients (one per org) with OrgID set, or use a single client and call Client.VerifyWithOrgID with an explicit org ID per event:

verified, err := client.Events.VerifyWithOrgID(&event, orgID)

If you have the workflow owner address, use Client.Verify when the client has it as default (Options.WorkflowOwner), or Client.VerifyWithWorkflowOwner with explicit address per event:

verified, err := client.Events.Verify(&event)
// or
verified, err := client.Events.VerifyWithWorkflowOwner(&event, workflowOwnerAddress)

## Verifying Operation Status Events

Use Client.VerifyOperationStatus when the client has a default OrgID, or Client.VerifyOperationStatusWithOrgID for multi-org with an explicit org ID:

verified, err := client.Events.VerifyOperationStatus(&event)
// or
verified, err := client.Events.VerifyOperationStatusWithOrgID(&event, orgID)

With a known workflow owner address, use Client.VerifyOperationStatus when the client has it as default, or Client.VerifyOperationStatusWithWorkflowOwner with explicit address per event:

verified, err := client.Events.VerifyOperationStatus(&event)
// or
verified, err := client.Events.VerifyOperationStatusWithWorkflowOwner(&event, workflowOwnerAddress)

## Deriving Workflow Owner from Org ID

Use Client.WorkflowOwnerFromOrgID to derive the workflow owner Ethereum address from an org ID without performing verification:

ownerAddress, err := client.Events.WorkflowOwnerFromOrgID(orgID)

Decoding Events

Use Client.Decode to unpack event data into a Go struct:

var decodedEvent MyEventStruct
err := client.Events.Decode(&event, &decodedEvent)

Or decode to a map for dynamic handling:

var data map[string]interface{}
err := client.Events.Decode(&event, &data)

Decoding Verifiable Events

The event payload contains a base64-encoded VerifiableEvent field with rich event metadata. Use Client.DecodeVerifiableEvent to decode it into a models.VerifiableEvent struct:

import "github.com/smartcontractkit/crec-api-go/models"

// Get the watcher event payload
watcherPayload, err := event.Payload.AsWatcherEventPayload()
if err != nil {
    // Handle error
}

// Decode the verifiable event
verifiableEvent, err := client.Events.DecodeVerifiableEvent(&watcherPayload)
if err != nil {
    // Handle error
}

// Access event metadata
fmt.Printf("Event: %s at %v\n", verifiableEvent.Name, verifiableEvent.Timestamp)
if verifiableEvent.ChainFamily != nil {
    fmt.Printf("Chain Family: %s\n", *verifiableEvent.ChainFamily)
}

// Access chain event details (for EVM chains)
if verifiableEvent.ChainEvent != nil {
    evmEvent, err := verifiableEvent.ChainEvent.AsEVMEvent()
    if err == nil {
        fmt.Printf("Contract: %s, Block: %d\n", evmEvent.Address, evmEvent.BlockNumber)
        fmt.Printf("Tx Hash: %s\n", evmEvent.TxHash)
        // Access event parameters
        if evmEvent.Params != nil {
            for key, value := range *evmEvent.Params {
                fmt.Printf("  %s: %v\n", key, value)
            }
        }
    }
}

For operation status events, use Client.DecodeOperationStatusVerifiableEvent:

opStatusPayload, _ := event.Payload.AsOperationStatusPayload()
verifiableEvent, err := client.Events.DecodeOperationStatusVerifiableEvent(&opStatusPayload)

JSON Serialization

Convert events to JSON for logging or storage:

jsonBytes, err := client.Events.ToJSON(&event)

Event Types

Events can be:

  • Watcher events: Blockchain events captured by watchers (verify with Client.Verify)
  • Operation status events: Status updates for operations (verify with Client.VerifyOperationStatus)
  • Application events: Other status updates for watchers, etc.

Both watcher events and operation status events support cryptographic verification.

Error Handling

All errors can be inspected with errors.Is:

if errors.Is(err, ErrChannelNotFound) {
    // Handle missing channel
}
if errors.Is(err, ErrInvalidEventHash) {
    // Event data was tampered with
}
if errors.Is(err, ErrOnlyWatcherEventsSupported) {
    // Tried to verify a non-watcher event with Verify
}
if errors.Is(err, ErrOnlyOperationStatusSupported) {
    // Tried to verify a non-operation-status event with VerifyOperationStatus
}
if errors.Is(err, ErrDecodeVerifiableEvent) {
    // Failed to decode base64 verifiable event (invalid base64 or JSON)
}
if errors.Is(err, ErrDeriveWorkflowOwner) {
    // Failed to derive workflow owner address from org ID
}
if errors.Is(err, ErrOrgIDOrWorkflowOwnerReq) {
    // Called Verify or VerifyOperationStatus without org ID or workflow owner configured
}
if errors.Is(err, ErrWorkflowOwnerRequired) {
    // Passed empty workflow owner to VerifyWithWorkflowOwner or VerifyOperationStatusWithWorkflowOwner
}

Index

Constants

View Source
const (
	CreMainlineTenantID = "1" // CRE mainline tenant ID used as default for workflow owner address derivation
)

Variables

View Source
var (
	// Validation errors
	ErrChannelIDRequired  = errors.New("channel_id is required")
	ErrOptionsRequired    = errors.New("options is required")
	ErrCRECClientRequired = errors.New("CRECClient is required")

	// API operation errors
	ErrChannelNotFound       = errors.New("channel not found")
	ErrPollEvents            = errors.New("failed to poll events")
	ErrSearchEvents          = errors.New("failed to search events")
	ErrGetEvents             = errors.New("failed to get events")
	ErrVerifyEvent           = errors.New("failed to verify event")
	ErrDecodeEvent           = errors.New("failed to decode event")
	ErrDecodeVerifiableEvent = errors.New("failed to decode verifiable event")

	// Parsing errors
	ErrParseSignature               = errors.New("failed to parse signature")
	ErrRecoverPubKeyFromSignature   = errors.New("failed to recover public key from signature")
	ErrParseOCRReport               = errors.New("failed to parse OCR report")
	ErrParseOCRContext              = errors.New("failed to parse OCR context")
	ErrParseEventPayload            = errors.New("failed to parse event payload")
	ErrOnlyWatcherEventsSupported   = errors.New("only watcher events are supported for event verification")
	ErrOnlyOperationStatusSupported = errors.New("only operation status events are supported for operation status verification")
	ErrMarshalEventPayload          = errors.New("failed to marshal event payload")
	ErrMarshalEventToJSON           = errors.New("failed to marshal event to JSON")

	// Verification errors
	ErrInvalidEventHash = errors.New("event hash verification failed")

	// OCR Proof errors
	ErrNoOCRProofs       = errors.New("no OCR proofs found")
	ErrMultipleOCRProofs = errors.New("multiple OCR proofs found but should be 1")

	// Response errors
	ErrUnexpectedStatusCode = errors.New("unexpected status code")
	ErrNilResponseBody      = errors.New("unexpected nil response body")
	ErrBadRequest           = errors.New("invalid request parameters")
	ErrOCRReportTooShort    = errors.New("OCR report is too short")

	// Configuration errors
	ErrVerificationNotConfigured = errors.New("event verification not configured: no valid signers")

	// Derivation errors
	ErrDeriveWorkflowOwner = errors.New("failed to derive workflow owner from org ID")

	// Configuration errors for verification identity
	ErrOrgIDRequired           = errors.New("org ID required for verification (set in client options or pass as parameter)")
	ErrWorkflowOwnerRequired   = errors.New("workflow owner required for verification (set in client options or pass as parameter)")
	ErrOrgIDOrWorkflowOwnerReq = errors.New("org ID or workflow owner required for verification (set in client options or pass as parameter)")
)

Functions

This section is empty.

Types

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client provides operations for polling and verifying events from CREC.

func NewClient

func NewClient(opts *Options) (*Client, error)

NewClient creates a new CREC events client with the provided CREC client and options. Returns a pointer to the Client and an error if any issues occur during initialization. If the CREC client or options are nil, it returns an error.

  • opts: Options for configuring the CREC events client, see Options for details.

func (*Client) Decode

func (c *Client) Decode(event *apiClient.Event, payload any) error

Decode decodes a verifiable event into a specified payload structure.

  • event: The event to decode.
  • payload: A pointer to the structure where the decoded event will be stored.

func (*Client) DecodeOperationStatusVerifiableEvent

func (c *Client) DecodeOperationStatusVerifiableEvent(payload *apiClient.OperationStatusPayload) (*models.VerifiableEvent, error)

DecodeOperationStatusVerifiableEvent decodes the base64-encoded VerifiableEvent from an OperationStatusPayload into a models.VerifiableEvent struct.

func (*Client) DecodeVerifiableEvent

func (c *Client) DecodeVerifiableEvent(payload *apiClient.WatcherEventPayload) (*models.VerifiableEvent, error)

DecodeVerifiableEvent decodes the base64-encoded VerifiableEvent from a WatcherEventPayload into a models.VerifiableEvent struct containing the full event data.

func (*Client) EventHash

func (c *Client) EventHash(event *apiClient.WatcherEventPayload) (common.Hash, error)

EventHash computes the "EventHash" of an event used for verification.

func (*Client) OperationStatusHash

func (c *Client) OperationStatusHash(payload *apiClient.OperationStatusPayload) (common.Hash, error)

OperationStatusHash computes the "EventHash" of an OperationStatusPayload used for verification. The hash is computed using the pattern: eventName + "." + base64VerifiableEvent Note: VerifiableEvent must be present and non-empty (should be validated by caller).

func (*Client) Poll

Poll retrieves events from the CREC service for a specific channel.

  • ctx: Context for the request, used for cancellation and timeouts.
  • channelID: The UUID of the channel to retrieve events from.
  • params: parameters for filtering events, see apiClient.GetChannelsChannelIdEventsParams for details.

func (*Client) SearchEvents

func (c *Client) SearchEvents(
	ctx context.Context, channelID uuid.UUID, params *apiClient.GetChannelsChannelIdEventsSearchParams,
) ([]apiClient.Event, bool, error)

SearchEvents queries and searches historical events from a channel with filtering capabilities. Use this method for historical queries and searches. For real-time polling, use PollEvents.

  • ctx: Context for the request, used for cancellation and timeouts.
  • channelID: The UUID of the channel to search events from.
  • params: Parameters for filtering events, see client.GetChannelsChannelIdEventsSearchParams for details.

func (*Client) ToJSON

func (c *Client) ToJSON(event apiClient.Event) ([]byte, error)

ToJSON converts a verifiable event into its JSON representation.

  • event: The event to convert.

func (*Client) Verify

func (c *Client) Verify(event *apiClient.Event) (bool, error)

Verify verifies the authenticity of a given watcher event using the default org ID or workflow owner configured on the client. Prefers OrgID when set (derives workflow owner); otherwise uses WorkflowOwner when set. Returns ErrOrgIDOrWorkflowOwnerReq if neither is configured.

  • event: The event to verify.

Returns true if the event is valid and signed by enough authorized signers, false otherwise.

func (*Client) VerifyOCRSignatures

func (c *Client) VerifyOCRSignatures(ocrReport, ocrContext string, signatures []string) (bool, error)

VerifyOCRSignatures verifies that the OCR proof contains valid DON signatures. This is a lower-level verification that checks only signatures, without requiring a full Event structure or validating event hash/workflow owner.

Returns true if at least minRequiredSignatures valid signatures are found.

func (*Client) VerifyOperationStatus

func (c *Client) VerifyOperationStatus(event *apiClient.Event) (bool, error)

VerifyOperationStatus verifies the authenticity of an operation status event using the default org ID or workflow owner configured on the client. Prefers OrgID when set; otherwise uses WorkflowOwner. Returns ErrOrgIDOrWorkflowOwnerReq if neither is configured.

  • event: The event to verify.

Returns true if the event is valid and signed by enough authorized signers, false otherwise.

func (*Client) VerifyOperationStatusWithOrgID

func (c *Client) VerifyOperationStatusWithOrgID(event *apiClient.Event, orgID string) (bool, error)

VerifyOperationStatusWithOrgID verifies the authenticity of an operation status event using an explicit org ID. It derives the expected workflow owner address and delegates to Client.VerifyOperationStatusWithWorkflowOwner. Use this for multi-org scenarios.

  • event: The event to verify.
  • orgID: The organization ID used to derive the workflow owner address.

Returns true if the event is valid and signed by enough authorized signers, false otherwise.

func (*Client) VerifyOperationStatusWithWorkflowOwner

func (c *Client) VerifyOperationStatusWithWorkflowOwner(event *apiClient.Event, workflowOwner string) (bool, error)

VerifyOperationStatusWithWorkflowOwner verifies the authenticity of an operation status event using an explicit workflow owner address. Use this for multi-org or per-event workflow owner. For client-default verification, use Client.VerifyOperationStatus.

  • event: The event to verify.
  • workflowOwner: The workflow owner address (Ethereum address) that deployed the workflow.

Returns true if the event is valid and signed by enough authorized signers, false otherwise.

func (*Client) VerifyWithOrgID

func (c *Client) VerifyWithOrgID(event *apiClient.Event, orgID string) (bool, error)

VerifyWithOrgID verifies the authenticity of a given watcher event using an explicit org ID. It derives the expected workflow owner address from the org ID and delegates to the workflow owner verification. Use this for multi-org scenarios where a single client verifies events from different organizations.

  • event: The event to verify.
  • orgID: The organization ID used to derive the workflow owner address.

Returns true if the event is valid and signed by enough authorized signers, false otherwise.

func (*Client) VerifyWithWorkflowOwner

func (c *Client) VerifyWithWorkflowOwner(event *apiClient.Event, workflowOwner string) (bool, error)

VerifyWithWorkflowOwner verifies the authenticity of a given watcher event using an explicit workflow owner address. Use this for multi-org or when you have the address per event. For client-default verification, use Client.Verify.

  • event: The event to verify.
  • workflowOwner: The workflow owner address (Ethereum address) that deployed the workflow.

Returns true if the event is valid and signed by enough authorized signers, false otherwise.

func (*Client) WorkflowOwnerFromOrgID added in v0.6.1

func (c *Client) WorkflowOwnerFromOrgID(orgID string) (string, error)

WorkflowOwnerFromOrgID derives the workflow owner Ethereum address from an organization ID. It uses the CRE canonical CREATE2-style address derivation with the client's configured CRE tenant ID.

type Options

type Options struct {
	Logger                *slog.Logger
	CRECClient            *apiClient.ClientWithResponses
	MinRequiredSignatures int
	ValidSigners          []string
	OrgID                 string
	WorkflowOwner         string
	CRETenantID           string
}

Options holds the configuration options for the CREC events client. It includes options for logging and event retrieval.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL