diff --git a/src/config/sidebar.ts b/src/config/sidebar.ts index d0ae37ca3dd..b2d8cee01b6 100644 --- a/src/config/sidebar.ts +++ b/src/config/sidebar.ts @@ -565,6 +565,10 @@ export const SIDEBAR: Partial> = { url: "cre/reference/sdk/consensus", highlightAsCurrent: ["cre/reference/sdk/consensus-ts", "cre/reference/sdk/consensus-go"], }, + { + title: "Type Conversions", + url: "cre/reference/sdk/type-conversions-ts", + }, ], }, ], diff --git a/src/content/cre/reference/sdk/confidential-http-client-ts.mdx b/src/content/cre/reference/sdk/confidential-http-client-ts.mdx index 3a0b49acd70..01c0752e65d 100644 --- a/src/content/cre/reference/sdk/confidential-http-client-ts.mdx +++ b/src/content/cre/reference/sdk/confidential-http-client-ts.mdx @@ -27,7 +27,7 @@ The [Confidential HTTP](/cre/capabilities/confidential-http-ts) Client lets you {/* prettier-ignore */} ### `ConfidentialHTTPRequest` / `ConfidentialHTTPRequestJson` diff --git a/src/content/cre/reference/sdk/core-go.mdx b/src/content/cre/reference/sdk/core-go.mdx index 3e22abf709f..09508822774 100644 --- a/src/content/cre/reference/sdk/core-go.mdx +++ b/src/content/cre/reference/sdk/core-go.mdx @@ -253,3 +253,70 @@ func onTrigger(config *Config, runtime cre.Runtime, ...) (string, error) { //... } ``` + +## `runtime.GetSecret()` + +Retrieves a secret from the Vault DON. Secrets are key-value pairs stored securely and made available to your workflow at runtime. The `GetSecret` method is available on the `Runtime` interface through the embedded `SecretsProvider`. + +**Signature:** + +```go +runtime.GetSecret(req *SecretRequest) Promise[*Secret] +``` + +### `SecretRequest` + +| Field | Type | Required | Description | +| ----------- | -------- | -------- | ----------------------------------------- | +| `Id` | `string` | Yes | The identifier of the secret to retrieve. | +| `Namespace` | `string` | Yes | The namespace the secret belongs to. | + +### `Secret` + +The value returned when the promise resolves. + +| Field | Type | Description | +| ----------- | -------- | -------------------------------- | +| `Id` | `string` | The secret identifier. | +| `Namespace` | `string` | The secret namespace. | +| `Owner` | `string` | The address of the secret owner. | +| `Value` | `string` | The secret value. | + +### `SecretsProvider` interface + +The `SecretsProvider` interface is embedded in `Runtime`, which means `GetSecret` is available directly on the runtime object. It is also passed as a parameter to [`InitWorkflow`](#initworkflow), allowing you to access secrets during workflow initialization. + +```go +type SecretsProvider interface { + GetSecret(req *SecretRequest) Promise[*Secret] +} +``` + +### Example + +```go +import "github.com/smartcontractkit/cre-sdk-go/cre" + +func onTrigger(config *Config, runtime cre.Runtime, ...) (string, error) { + secretPromise := runtime.GetSecret(&cre.SecretRequest{ + Id: "my-api-key", + Namespace: "default", + }) + + secret, err := secretPromise.Await() + if err != nil { + return "", fmt.Errorf("failed to get secret: %w", err) + } + + logger := runtime.Logger() + logger.Info("Secret retrieved", "owner", secret.Owner) + + // Use secret.Value in your workflow logic + return "done", nil +} +``` + + diff --git a/src/content/cre/reference/sdk/core-ts.mdx b/src/content/cre/reference/sdk/core-ts.mdx index cb9a1011c3a..0bfe4c279d3 100644 --- a/src/content/cre/reference/sdk/core-ts.mdx +++ b/src/content/cre/reference/sdk/core-ts.mdx @@ -389,12 +389,64 @@ runtime.runInNodeMode( - `fn`: A function that receives a `NodeRuntime` and executes on each individual node - `consensusAggregation`: An aggregation function (e.g., `consensusMedianAggregation()`) -- `unwrapOptions`: Optional configuration for how to unwrap complex return types +- `unwrapOptions`: Optional configuration for how to deserialize the consensus result. See [`UnwrapOptions`](#unwrapoptions) below. **Returns:** A function that, when called with any additional arguments, returns an object with a `.result()` method. +### `UnwrapOptions` + +When `runInNodeMode` returns a non-primitive type, the SDK needs to know how to deserialize the consensus result back into a typed object. The `unwrapOptions` parameter tells the SDK which deserialization strategy to use. + +{/* prettier-ignore */} + + +**Type definition:** + +```typescript +type UnwrapOptions = { instance: T } | { schema: StandardSchemaV1 } | { factory: () => T } +``` + +**Variants:** + +| Variant | When to use | Example | +| ----------------------- | ---------------------------------------------------------------------------- | ------------------------------------------------ | +| `{ instance: value }` | Primitive types (`string`, `number`, `bigint`, `boolean`) | `{ instance: 0n }` | +| `{ schema: validator }` | Objects with a Zod or Standard Schema validator | `{ schema: myZodSchema }` | +| `{ factory: () => T }` | Objects without a schema — provide a factory that returns a default instance | `{ factory: () => ({ price: 0n, source: "" }) }` | + +**Example with `schema` (most common for complex types):** + +```typescript +import { HTTPClient, consensusMedianAggregation, type Runtime, type NodeRuntime } from "@chainlink/cre-sdk" +import { z } from "zod" + +const priceResultSchema = z.object({ + price: z.bigint(), + source: z.string(), +}) + +type PriceResult = z.infer + +const fetchPrice = (nodeRuntime: NodeRuntime): PriceResult => { + const httpClient = new HTTPClient() + // ... fetch and parse price ... + return { price: 42000n, source: "api.example.com" } +} + +const onTrigger = (runtime: Runtime): string => { + const price = runtime + .runInNodeMode(fetchPrice, consensusMedianAggregation(), { schema: priceResultSchema })() + .result() + + runtime.log(`Price: ${price.price} from ${price.source}`) + return "done" +} +``` + **Example:** This example uses `runInNodeMode` to fetch data from an API on each node, and then uses the DON-level `Runtime` to write the aggregated result onchain. @@ -437,3 +489,65 @@ const onTrigger = (runtime: Runtime, ...): string => { The pattern `runInNodeMode(fn, aggregation)()` requires calling the returned function immediately with `()` before calling `.result()`. This is because `runInNodeMode` returns a function that can accept additional arguments. + +## `runtime.getSecret()` + +Retrieves a secret from the Vault DON. Secrets are key-value pairs stored securely and made available to your workflow at runtime. + +**Signature:** + +```typescript +runtime.getSecret( + req: SecretRequest | SecretRequestJson +): { result: () => Secret } +``` + +### `SecretRequest` / `SecretRequestJson` + +| Field | Type | Required | Description | +| ----------- | -------- | -------- | ----------------------------------------- | +| `id` | `string` | Yes | The identifier of the secret to retrieve. | +| `namespace` | `string` | Yes | The namespace the secret belongs to. | + +### `Secret` + +The object returned by `.result()`. + +| Field | Type | Description | +| ----------- | -------- | -------------------------------- | +| `id` | `string` | The secret identifier. | +| `namespace` | `string` | The secret namespace. | +| `owner` | `string` | The address of the secret owner. | +| `value` | `string` | The secret value. | + +### Using secrets in `initWorkflow` + +To use `runtime.getSecret()`, your `initWorkflow` function must accept a `SecretsProvider` as its second parameter. This wires secret access into the runtime. + +```typescript +import { handler, type Runtime, type SecretsProvider } from "@chainlink/cre-sdk" + +const initWorkflow = (config: Config, secretsProvider: SecretsProvider) => { + return [handler(triggerInstance, onTrigger)] +} +``` + +### Example + +```typescript +import { type Runtime } from "@chainlink/cre-sdk" + +const onTrigger = (runtime: Runtime): string => { + const secret = runtime.getSecret({ id: "my-api-key", namespace: "default" }).result() + + runtime.log(`Secret owner: ${secret.owner}`) + + // Use secret.value in your workflow logic + return "done" +} +``` + +{/* prettier-ignore */} + diff --git a/src/content/cre/reference/sdk/evm-client-ts.mdx b/src/content/cre/reference/sdk/evm-client-ts.mdx index d26104691e8..f319d5b758a 100644 --- a/src/content/cre/reference/sdk/evm-client-ts.mdx +++ b/src/content/cre/reference/sdk/evm-client-ts.mdx @@ -639,6 +639,123 @@ See [Custom Block Depths](/cre/guides/workflow/using-evm-client/onchain-read-ts# --- +### `hexToBytes()` + +Converts a `0x`-prefixed hex string to a `Uint8Array`. + +**Signature:** + +```typescript +function hexToBytes(hex: Hex): Uint8Array +``` + +**Usage:** + +```typescript +import { hexToBytes } from "@chainlink/cre-sdk" + +const bytes = hexToBytes("0xabcdef") +// → Uint8Array [171, 205, 239] +``` + +--- + +### `base64ToHex()` + +Converts a base64-encoded string to a `0x`-prefixed hex string. This is useful for converting protobuf `bytes` fields (which are base64-encoded in JSON form) back to hex for use with viem or other EVM libraries. + +**Signature:** + +```typescript +function base64ToHex(base64: string): Hex +``` + +**Usage:** + +```typescript +import { base64ToHex } from "@chainlink/cre-sdk" + +const hex = base64ToHex("q83v") +// → "0xabcdef" +``` + +--- + +### `bigintToBytes()` + +Converts a native JavaScript `bigint` to a big-endian `Uint8Array`. This is useful when you need to encode a `bigint` as raw bytes for protobuf fields or ABI encoding. + +**Signature:** + +```typescript +function bigintToBytes(n: bigint): Uint8Array +``` + +**Usage:** + +```typescript +import { bigintToBytes } from "@chainlink/cre-sdk" + +const bytes = bigintToBytes(256n) +// → Uint8Array [1, 0] +``` + +--- + +### `bytesToBigint()` + +Converts a big-endian `Uint8Array` to a native JavaScript `bigint`. This is the inverse of `bigintToBytes()`. + +**Signature:** + +```typescript +function bytesToBigint(bytes: Uint8Array): bigint +``` + +**Usage:** + +```typescript +import { bytesToBigint } from "@chainlink/cre-sdk" + +const value = bytesToBigint(new Uint8Array([1, 0])) +// → 256n +``` + +--- + +### `bigintToProtoBigInt()` + +Converts a native `bigint`, `number`, or `string` to the protobuf `BigIntJson` format used by SDK methods. The [`blockNumber()`](#blocknumber) function is a convenience alias for this function. + +**Signature:** + +```typescript +function bigintToProtoBigInt(n: number | bigint | string): BigIntJson +``` + +**Returns:** + +A `BigIntJson` object with `absVal` (base64-encoded big-endian bytes) and `sign` (`"1"`, `"0"`, or `"-1"`). + +**Usage:** + +```typescript +import { bigintToProtoBigInt } from "@chainlink/cre-sdk" + +const protoBigInt = bigintToProtoBigInt(12345678n) +// → { absVal: "ALxhTg==", sign: "1" } + +const negative = bigintToProtoBigInt(-42n) +// → { absVal: "Kg==", sign: "-1" } + +const zero = bigintToProtoBigInt(0n) +// → { absVal: "", sign: "0" } +``` + +See [Type Conversions](/cre/reference/sdk/type-conversions-ts#protobigint) for more details on the `ProtoBigInt` format. + +--- + ### `prepareReportRequest()` Prepares a report request with default EVM encoding parameters for use with `runtime.report()`. This helper simplifies report generation by automatically setting the standard encoding configuration (`evm`, `ecdsa`, `keccak256`) required for EVM-based workflows. diff --git a/src/content/cre/reference/sdk/overview-ts.mdx b/src/content/cre/reference/sdk/overview-ts.mdx index d39951e37fa..ee95f7e9685 100644 --- a/src/content/cre/reference/sdk/overview-ts.mdx +++ b/src/content/cre/reference/sdk/overview-ts.mdx @@ -24,6 +24,7 @@ The SDK Reference is broken down into several pages, each corresponding to a cor - **[HTTP Client](/cre/reference/sdk/http-client-ts)**: Provides a reference for the `HTTPClient`, used for making offchain API requests from individual nodes. - **[Confidential HTTP Client](/cre/reference/sdk/confidential-http-client-ts)**: Provides a reference for the `ConfidentialHTTPClient`, used for privacy-preserving API requests with enclave execution and optional response encryption. - **[Consensus & Aggregation](/cre/reference/sdk/consensus-ts)**: Describes how to use aggregators like `consensusMedianAggregation` and `ConsensusAggregationByFields` with `runtime.runInNodeMode()` to process and consolidate data from multiple nodes. +- **[Type Conversions](/cre/reference/sdk/type-conversions-ts)**: Explains the dual `Type` / `TypeJson` system, protobuf-to-TypeScript type mappings, and the `ProtoBigInt` format used for block numbers, balances, and gas values. ## Package Structure diff --git a/src/content/cre/reference/sdk/type-conversions-ts.mdx b/src/content/cre/reference/sdk/type-conversions-ts.mdx new file mode 100644 index 00000000000..87a2d5022ef --- /dev/null +++ b/src/content/cre/reference/sdk/type-conversions-ts.mdx @@ -0,0 +1,145 @@ +--- +section: cre +title: "SDK Reference: Type Conversions" +date: Last Modified +metadata: + description: "Reference for TypeScript protobuf type conversions: understanding Type vs TypeJson variants, ProtoBigInt, and conversion helpers." + datePublished: "2026-03-02" + lastModified: "2026-03-02" +--- + +import { Aside } from "@components" + +The CRE TypeScript SDK uses Protocol Buffers under the hood. Each protobuf message generates **two** TypeScript representations: + +- **`Type`** (runtime form): Uses native binary types like `Uint8Array` and `bigint`. These are what the SDK returns from `.result()` calls. +- **`TypeJson`** (JSON-serializable form): Uses `string` and plain objects. These are what you pass _into_ SDK methods when constructing requests. + +{/* prettier-ignore */} + + +## Conversion table + +This table shows how protobuf types map to their TypeScript runtime and JSON-serializable forms. + +| Protobuf Type | Runtime (`Type`) | JSON (`TypeJson`) | Notes | +| --------------------------- | ------------------------------------------------ | -------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `bytes` | `Uint8Array` | `string` (base64) | Use [`hexToBase64()`](/cre/reference/sdk/evm-client-ts#hextobase64) and [`base64ToHex()`](/cre/reference/sdk/evm-client-ts#base64tohex) to convert between hex and base64. | +| `int64` / `uint64` | `bigint` | `string` | Numeric strings like `"12345"`. | +| `enum` | Enum constant (`number`) | String name | For example, `TX_STATUS_SUCCESS` (number) vs `"TX_STATUS_SUCCESS"` (string). | +| `google.protobuf.Duration` | `Duration` object | `string` (e.g. `"5s"`) | Duration strings use Go-style format: `"5s"`, `"1.5m"`, `"200ms"`. | +| `google.protobuf.Timestamp` | `Timestamp` `{ seconds: bigint, nanos: number }` | `{ seconds?: string, nanos?: number }` | | +| `BigInt` (CRE custom) | `{ absVal: Uint8Array, sign: bigint }` | `{ absVal: string, sign: string }` | See [ProtoBigInt](#protobigint) below. | + +## ProtoBigInt + +`BigInt` is a CRE-specific protobuf type used to represent arbitrarily large integers. It appears in block numbers, account balances, gas values, and other EVM-related fields. + +### Structure + +The protobuf `BigInt` encodes a signed arbitrary-precision integer as two fields: + +| Field | Runtime type | JSON type | Description | +| -------- | ------------ | ----------------- | ---------------------------------------------------------------------------- | +| `absVal` | `Uint8Array` | `string` (base64) | The absolute value as a big-endian byte array (base64-encoded in JSON form). | +| `sign` | `bigint` | `string` | The sign: `"1"` for positive, `"0"` for zero, `"-1"` for negative. | + +### Converting between `bigint` and `ProtoBigInt` + +Use the SDK helpers to convert between native JavaScript `bigint` and the protobuf format: + +**Native `bigint` to protobuf `BigIntJson`** (for request objects): + +```typescript +import { blockNumber, bigintToProtoBigInt } from "@chainlink/cre-sdk" + +// blockNumber() is a convenience alias for bigintToProtoBigInt() +const block = blockNumber(12345678n) +// → { absVal: "ALxhTg==", sign: "1" } + +// Equivalent: +const block2 = bigintToProtoBigInt(12345678n) +``` + +**Protobuf `BigInt` to native `bigint`** (for response processing): + +```typescript +import { protoBigIntToBigint } from "@chainlink/cre-sdk" + +const header = evmClient.headerByNumber(runtime, {}).result() +const blockNum = protoBigIntToBigint(header.header.blockNumber) +// → e.g., 12345678n +``` + +### Special constants + +The SDK provides pre-built `BigIntJson` constants for common block reference values: + +```typescript +import { LATEST_BLOCK_NUMBER, LAST_FINALIZED_BLOCK_NUMBER } from "@chainlink/cre-sdk" + +// LATEST_BLOCK_NUMBER → most recent mined block +// LAST_FINALIZED_BLOCK_NUMBER → most recent finalized block +``` + +These are negative sentinel values that the CRE platform interprets as symbolic references rather than literal block heights. + +### Common patterns + +**Reading a balance and doing arithmetic:** + +```typescript +import { EVMClient, getNetwork, protoBigIntToBigint, LAST_FINALIZED_BLOCK_NUMBER } from "@chainlink/cre-sdk" + +const balance = evmClient + .balanceAt(runtime, { + account: "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb2", + blockNumber: LAST_FINALIZED_BLOCK_NUMBER, + }) + .result() + +// balance.balance is already a native bigint — no conversion needed +const balanceInEth = balance.balance / 10n ** 18n +``` + +**Specifying a custom block depth:** + +```typescript +import { protoBigIntToBigint, blockNumber } from "@chainlink/cre-sdk" + +// Get the latest block number +const header = evmClient.headerByNumber(runtime, {}).result() +const latest = protoBigIntToBigint(header.header.blockNumber) + +// Query 100 blocks back +const contractCall = evmClient + .callContract(runtime, { + call: encodedCall, + blockNumber: blockNumber(latest - 100n), + }) + .result() +``` + +## `bytes` fields + +Protobuf `bytes` fields appear as `Uint8Array` in runtime types and as base64-encoded `string` in JSON types. When working with EVM data, you often need to convert between hex strings and these representations. + +```typescript +import { hexToBase64, bytesToHex, hexToBytes, base64ToHex } from "@chainlink/cre-sdk" + +// Hex → base64 (for request objects) +const base64Data = hexToBase64("0xabcdef") + +// base64 → hex (for processing responses) +const hexData = base64ToHex("q83v") + +// Hex → Uint8Array +const bytes = hexToBytes("0xabcdef") + +// Uint8Array → hex +const hex = bytesToHex(new Uint8Array([0xab, 0xcd, 0xef])) +``` + +See the [EVM Client helper functions](/cre/reference/sdk/evm-client-ts#helper-functions) for the full list of conversion utilities.