events

package
v0.6.3 Latest Latest
Warning

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

Go to latest
Published: Mar 23, 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 is the CRE mainline tenant ID used as default for workflow owner address derivation.
	CreMainlineTenantID = "1"
)

Variables

View Source
var (
	// ErrChannelIDRequired is returned when the channel ID is nil or missing.
	ErrChannelIDRequired = errors.New("channel_id is required")
	// ErrOptionsRequired is returned when the options parameter is nil.
	ErrOptionsRequired = errors.New("options is required")
	// ErrCRECClientRequired is returned when the CREC client is nil in options.
	ErrCRECClientRequired = errors.New("CRECClient is required")

	// ErrChannelNotFound is returned when the channel does not exist (404 response).
	ErrChannelNotFound = errors.New("channel not found")
	// ErrPollEvents is returned when polling events fails.
	ErrPollEvents = errors.New("failed to poll events")
	// ErrSearchEvents is returned when searching events fails.
	ErrSearchEvents = errors.New("failed to search events")
	// ErrGetEvents is returned when fetching events fails.
	ErrGetEvents = errors.New("failed to get events")
	// ErrVerifyEvent is returned when event verification fails.
	ErrVerifyEvent = errors.New("failed to verify event")
	// ErrDecodeEvent is returned when decoding an event fails.
	ErrDecodeEvent = errors.New("failed to decode event")
	// ErrDecodeVerifiableEvent is returned when decoding the verifiable event payload fails.
	ErrDecodeVerifiableEvent = errors.New("failed to decode verifiable event")

	// ErrParseSignature is returned when parsing a signature from hex fails.
	ErrParseSignature = errors.New("failed to parse signature")
	// ErrRecoverPubKeyFromSignature is returned when recovering the public key from a signature fails.
	ErrRecoverPubKeyFromSignature = errors.New("failed to recover public key from signature")
	// ErrParseOCRReport is returned when parsing the OCR report from hex fails.
	ErrParseOCRReport = errors.New("failed to parse OCR report")
	// ErrParseOCRContext is returned when parsing the OCR context from hex fails.
	ErrParseOCRContext = errors.New("failed to parse OCR context")
	// ErrParseEventPayload is returned when parsing the event payload fails.
	ErrParseEventPayload = errors.New("failed to parse event payload")
	// ErrOnlyWatcherEventsSupported is returned when verifying a non-watcher event type.
	ErrOnlyWatcherEventsSupported = errors.New("only watcher events are supported for event verification")
	// ErrOnlyOperationStatusSupported is returned when verifying a non-operation-status event type.
	ErrOnlyOperationStatusSupported = errors.New("only operation status events are supported for operation status verification")
	// ErrMarshalEventPayload is returned when marshaling the event payload to JSON fails.
	ErrMarshalEventPayload = errors.New("failed to marshal event payload")
	// ErrMarshalEventToJSON is returned when marshaling the event to JSON fails.
	ErrMarshalEventToJSON = errors.New("failed to marshal event to JSON")

	// ErrInvalidEventHash is returned when the event hash verification fails.
	ErrInvalidEventHash = errors.New("event hash verification failed")

	// ErrNoOCRProofs is returned when the event has no OCR proofs.
	ErrNoOCRProofs = errors.New("no OCR proofs found")
	// ErrMultipleOCRProofs is returned when the event has more than one OCR proof.
	ErrMultipleOCRProofs = errors.New("multiple OCR proofs found but should be 1")

	// ErrUnexpectedStatusCode is returned when the API returns an unexpected HTTP status code.
	ErrUnexpectedStatusCode = errors.New("unexpected status code")
	// ErrNilResponseBody is returned when the API response body is nil.
	ErrNilResponseBody = errors.New("unexpected nil response body")
	// ErrBadRequest is returned when the request parameters are invalid.
	ErrBadRequest = errors.New("invalid request parameters")
	// ErrOCRReportTooShort is returned when the OCR report is shorter than the minimum required length.
	ErrOCRReportTooShort = errors.New("OCR report is too short")

	// ErrVerificationNotConfigured is returned when the client has no valid signers configured.
	ErrVerificationNotConfigured = errors.New("event verification not configured: no valid signers")

	// ErrDeriveWorkflowOwner is returned when deriving the workflow owner address from org ID fails.
	ErrDeriveWorkflowOwner = errors.New("failed to derive workflow owner from org ID")

	// ErrOrgIDRequired is returned when org ID is required for verification but not set.
	ErrOrgIDRequired = errors.New("org ID required for verification (set in client options or pass as parameter)")
	// ErrWorkflowOwnerRequired is returned when workflow owner is required for verification but not set.
	ErrWorkflowOwnerRequired = errors.New("workflow owner required for verification (set in client options or pass as parameter)")
	// ErrOrgIDOrWorkflowOwnerReq is returned when neither org ID nor workflow owner is configured for verification.
	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 Keccak256 hash of the verifiable event string used for signature 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