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 WorkflowOwnerFromOrgID to derive the workflow owner Ethereum address from an org ID without performing verification:
ownerAddress, err := 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 ¶
- Variables
- func WorkflowOwnerFromOrgID(orgID string) (string, error)
- type Client
- func (c *Client) Decode(event *apiClient.Event, payload any) error
- func (c *Client) DecodeOperationStatusVerifiableEvent(payload *apiClient.OperationStatusPayload) (*models.VerifiableEvent, error)
- func (c *Client) DecodeVerifiableEvent(payload *apiClient.WatcherEventPayload) (*models.VerifiableEvent, error)
- func (c *Client) EventHash(event *apiClient.WatcherEventPayload) (common.Hash, error)
- func (c *Client) OperationStatusHash(payload *apiClient.OperationStatusPayload) (common.Hash, error)
- func (c *Client) Poll(ctx context.Context, channelID uuid.UUID, ...) ([]apiClient.Event, bool, error)
- func (c *Client) SearchEvents(ctx context.Context, channelID uuid.UUID, ...) ([]apiClient.Event, bool, error)
- func (c *Client) ToJSON(event apiClient.Event) ([]byte, error)
- func (c *Client) Verify(event *apiClient.Event) (bool, error)
- func (c *Client) VerifyOCRSignatures(ocrReport, ocrContext string, signatures []string) (bool, error)
- func (c *Client) VerifyOperationStatus(event *apiClient.Event) (bool, error)
- func (c *Client) VerifyOperationStatusWithOrgID(event *apiClient.Event, orgID string) (bool, error)
- func (c *Client) VerifyOperationStatusWithWorkflowOwner(event *apiClient.Event, workflowOwner string) (bool, error)
- func (c *Client) VerifyWithOrgID(event *apiClient.Event, orgID string) (bool, error)
- func (c *Client) VerifyWithWorkflowOwner(event *apiClient.Event, workflowOwner string) (bool, error)
- type Options
Constants ¶
This section is empty.
Variables ¶
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 ¶
func WorkflowOwnerFromOrgID ¶
WorkflowOwnerFromOrgID derives the workflow owner Ethereum address from an organization ID. It uses the CRE canonical CREATE2-style address derivation with an empty prefix (to be replaced with tenant_id in a future release).
Types ¶
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client provides operations for polling and verifying events from CREC.
func NewClient ¶
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 ¶
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) 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 ¶
func (c *Client) Poll( ctx context.Context, channelID uuid.UUID, params *apiClient.GetChannelsChannelIdEventsParams, ) ([]apiClient.Event, bool, error)
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 ¶
ToJSON converts a verifiable event into its JSON representation.
- event: The event to convert.
func (*Client) Verify ¶
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 ¶
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 ¶
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 ¶
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.
type Options ¶
type Options struct {
Logger *slog.Logger
CRECClient *apiClient.ClientWithResponses
MinRequiredSignatures int
ValidSigners []string
OrgID string
WorkflowOwner string
}
Options holds the configuration options for the CREC events client. It includes options for logging and event retrieval.
- Logger: Optional logger instance.
- CRECClient: A client instance for interacting with the CREC system (required).
- MinRequiredSignatures: Minimum number of valid signatures required to verify an event.
- ValidSigners: List of valid signer addresses (as hex strings).
- OrgID: Optional default organization ID for Client.Verify and Client.VerifyOperationStatus. When set, those methods can be called without passing org ID. For multi-org use, omit and use Client.VerifyWithOrgID or Client.VerifyOperationStatusWithOrgID with explicit org ID.
- WorkflowOwner: Optional default workflow owner address for Client.Verify and Client.VerifyOperationStatus. When set (and OrgID is not), those methods use it. For explicit workflow owner per event, use Client.VerifyWithWorkflowOwner or Client.VerifyOperationStatusWithWorkflowOwner.