Extensions Overview

CRE Connect extensions are first-party Go modules that wrap the generic crec-sdk with service-specific helpers. Each extension provides three things:

  1. An operation builder that packs calldata for the service's smart contracts so you don't have to manage the ABI yourself.
  2. A typed event decoder so that dta.SubscriptionRequested arrives as a Go struct, not a map[string]any.
  3. One-call watcher provisioning. CRE Connect ships pre-packaged watchers for the service so a single SDK call provisions every watcher the service needs.

Extensions are independent Go modules; you import only the ones you need.

Available extensions

ExtensionModuleUse when
DTA (Digital Transfer Agent)github.com/smartcontractkit/crec-sdk-ext-dtaTokenised funds: subscriptions, redemptions, distributor lifecycle.

The DTA extension repository uses contract versioning: each deployed contract ABI is exposed as a separate import path (/v1, /v2, …) under the same Go module. Per the extension's README, this versioning matches the on-chain contract ABI version and is independent of Go module semantic versioning. The CRE Connect documentation focuses on the v2 import path; if you operate against v1 contracts, import the corresponding /v1 sub-package and consult the extension README for v1-specific operation signatures.

Anatomy of an extension

Take DTA v2 as the example. The module exposes three sub-packages:

crec-sdk-ext-dta/v2
├── /                    // Decode helper: v2.DecodeFromEvent
├── /events              // Typed event structs + EventName constants + decoders
├── /operations          // Extension client: PrepareXxxOperation builders
└── /watcher/bundle      // bundle.Get(): service name + ABIs (consumed by CRE Connect)

v2/operations exposes an Extension struct with one PrepareXxxOperation method per on-chain action. Each method returns a *types.Operation ready to sign and send through crec-sdk/transact:

import "github.com/smartcontractkit/crec-sdk-ext-dta/v2/operations"

ext, err := operations.New(&operations.Options{
    AccountAddress:              smartAccount.Hex(),
    DTARequestManagementAddress: managementAddr.Hex(),
    DTARequestSettlementAddress: settlementAddr.Hex(),
})
op, err := ext.PrepareRequestSubscriptionOperation(fundAdmin, fundTokenId, amount, referenceID)

v2/events declares one Go struct per Solidity event (e.g. SubscriptionRequested, DistributorRegistered) and an EventName enum. The root v2.DecodeFromEvent(ctx, ev) helper combines watcher decoding with on-chain reference-data enrichment.

v2/watcher/bundle ships the service descriptor (name + ABIs) that CRE Connect uses to expose this service to watchers.CreateWithService. You typically don't import this package directly; only use it if you want to inspect the published service name or event list from your own code.

Why extensions matter

  • No ABI bookkeeping. Calldata packing happens inside the extension; bumping a contract version is a single-module dependency upgrade.
  • Typed events. events.SubscriptionRequested carries FundAdminAddr common.Address, Amount *big.Int, etc.: no string casting.
  • One-call watcher provisioning. Pass Service: "dta.v2" to watchers.CreateWithService and CRE Connect sets up every watcher in bundle.Get().Events.
  • Backwards-compatible upgrades. When an event schema or operation signature changes, the extension version bumps and you get a compile error rather than a silent runtime drift.

Using an extension

Three integration points:

import (
    crec "github.com/smartcontractkit/crec-sdk"
    dta "github.com/smartcontractkit/crec-sdk-ext-dta/v2"
    dtaop "github.com/smartcontractkit/crec-sdk-ext-dta/v2/operations"
)

client, _ := crec.NewClient(baseURL, apiKey)

ext, _ := dtaop.New(&dtaop.Options{
    AccountAddress:              smartAccount.Hex(),
    DTARequestManagementAddress: mgmtAddr.Hex(),
    DTARequestSettlementAddress: settleAddr.Hex(),
})

op, _ := ext.PrepareRequestSubscriptionOperation(fundAdmin, fundTokenId, amount, refID)
opr, _ := client.Transact.ExecuteOperation(ctx, channelID, signer, op, chainSelector)

events, _, _ := client.Events.Poll(ctx, channelID, nil)
for _, ev := range events {
    decoded, err := dta.DecodeFromEvent(ctx, ev)
    if err != nil { continue }
    fmt.Println(decoded.EventName(), decoded.ConcreteEvent)
}

What's next

Get the latest Chainlink content straight to your inbox.