Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions public/changelog.json
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,20 @@
}
},
"data": [
{
"category": "release",
"date": "2026-07-16",
"description": "CRE CLI version 1.26.0 is now available. Confidential compute simulation now warns on prod-rejected HTTP endpoints and acknowledges TEE execution. Deployment access request messaging is clearer. Simulation error messages now show the correct workflow directory path.\n\nUpdate your CLI by running `cre update` when prompted, or follow the [CLI Installation guide](https://docs.chain.link/cre/getting-started/cli-installation) for fresh installations.\n\n[See all changes on GitHub](https://github.com/smartcontractkit/cre-cli/compare/v1.25.0...v1.26.0)",
"title": "CRE CLI v1.26.0 — Confidential Simulate Improvements",
"topic": "CRE"
},
{
"category": "release",
"date": "2026-07-14",
"description": "CRE CLI version 1.25.0 is now available. Solana mainnet mock forwarder support for `cre workflow simulate` enables local simulation of Solana write workflows on mainnet. Cross-command execution discovery hints help surface available workflows. Improved Linux asset suffix handling.\n\nUpdate your CLI by running `cre update` when prompted, or follow the [CLI Installation guide](https://docs.chain.link/cre/getting-started/cli-installation) for fresh installations.\n\n[See all changes on GitHub](https://github.com/smartcontractkit/cre-cli/compare/v1.24.0...v1.25.0)",
"title": "CRE CLI v1.25.0 — Solana Mainnet Simulation and Discovery Hints",
"topic": "CRE"
},
{
"category": "integration",
"date": "2026-07-14",
Expand Down
18 changes: 16 additions & 2 deletions src/components/QuickLinks/data/productChainLinks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import automationLogo from "../../../assets/product-logos/automation-logo.svg"
import dataFeedsLogo from "../../../assets/product-logos/data-feeds-logo.svg"
import dataStreamsLogo from "../../../assets/product-logos/data-streams-logo.svg"
import creLogo from "../../../assets/product-logos/cre-logo.svg"
import { c } from "node_modules/vite/dist/node/moduleRunnerTransport.d-DJ_mE5sf.js"

export interface ProductData {
learnMoreLink: string
Expand Down Expand Up @@ -115,14 +114,29 @@ export const productChainLinks: ProductChainLinks = {
learnMoreLink: "cre",
logo: creLogo,
chains: {
"adi-network": "/cre/supported-networks",
arbitrum: "/cre/supported-networks",
avalanche: "/cre/supported-networks",
base: "/cre/supported-networks",
"bnb-chain": "/cre/supported-networks",
celo: "/cre/supported-networks",
ethereum: "/cre/supported-networks",
"gnosis-chain": "/cre/supported-networks",
hyperevm: "/cre/supported-networks",
ink: "/cre/supported-networks",
jovay: "/cre/supported-networks",
linea: "/cre/supported-networks",
mantle: "/cre/supported-networks",
megaeth: "/cre/supported-networks",
optimism: "/cre/supported-networks",
pharos: "/cre/supported-networks",
plasma: "/cre/supported-networks",
polygon: "/cre/supported-networks",
scroll: "/cre/supported-networks",
solana: "/cre/supported-networks",
sonic: "/cre/supported-networks",
worldchain: "/cre/supported-networks",
xlayer: "/cre/supported-networks",
zksync: "/cre/supported-networks",
},
},
Expand Down Expand Up @@ -412,7 +426,7 @@ export const chainNames: Record<string, string> = {
treasure: "Treasure",
lens: "Lens",
unichain: "Unichain",
hyperevm: "HyperEVM",
hyperevm: "Hyperliquid",
merlin: "Merlin",
fraxtal: "Fraxtal",
zeta: "Zeta",
Expand Down
1 change: 1 addition & 0 deletions src/config/sidebar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -475,6 +475,7 @@ export const SIDEBAR: Partial<Record<Sections, SectionEntry[]>> = {
{
title: "Using Randomness in Workflows",
url: "cre/guides/workflow/using-randomness",
highlightAsCurrent: ["cre/guides/workflow/using-randomness-ts", "cre/guides/workflow/using-randomness-go"],
},
],
},
Expand Down
6 changes: 5 additions & 1 deletion src/config/versions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,10 @@ export const VERSIONS = {
},
// CRE CLI Versions — update LATEST here for each new release
"cre-cli": {
LATEST: "v1.24.0",
LATEST: "v1.26.0",
ALL: [
"v1.26.0",
"v1.25.0",
"v1.24.0",
"v1.23.0",
"v1.22.0",
Expand All @@ -98,6 +100,8 @@ export const VERSIONS = {
"v1.8.0",
] as const,
RELEASE_DATES: {
"v1.26.0": "2026-07-16T00:00:00Z",
"v1.25.0": "2026-07-14T00:00:00Z",
"v1.24.0": "2026-07-09T00:00:00Z",
"v1.23.0": "2026-07-02T00:00:00Z",
"v1.22.0": "2026-06-25T00:00:00Z",
Expand Down
37 changes: 30 additions & 7 deletions src/content/cre/concepts/non-determinism-ts.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,13 @@ The failure pattern: Code diverges → Different request IDs → No quorum → W

## Quick reference: Common pitfalls

| Don't Use | Use Instead |
| ---------------------------- | -------------------------------------------- |
| Unordered object iteration | Sort keys first, then iterate |
| `Promise.race()` | Call `.result()` in deterministic order |
| `Date.now()` or `new Date()` | `runtime.now()` |
| LLM free-text responses | Structured output with field-level consensus |
| Don't Use | Use Instead |
| --------------------------------------- | -------------------------------------------- |
| Unordered object iteration | Sort keys first, then iterate |
| `Promise.race()` | Call `.result()` in deterministic order |
| `Date.now()` or `new Date()` | `runtime.now()` |
| `Math.random()` outside the CRE runtime | `Math.random()` inside the CRE WASM runtime |
| LLM free-text responses | Structured output with field-level consensus |

## 1. Object and Map iteration

Expand Down Expand Up @@ -190,7 +191,26 @@ runtime.log(`Current time: ${now.toISOString()}`)

The `runtime.now()` method returns a `Date` object representing DON Time—a consensus-derived timestamp that all nodes agree on. See [Time in CRE](/cre/guides/workflow/time-in-workflows-ts) for more details.

## 4. Working with LLMs
## 4. Randomness

Never use randomness from outside the CRE runtime in DON mode. Standard `Math.random()` in Node.js or the browser uses a per-process seed, so each node would produce a different sequence and break consensus.

**Bad: Using randomness outside the CRE runtime**

```typescript
// If this code runs outside the CRE WASM runtime, each node gets a different seed
const randomIndex = Math.floor(Math.random() * 10) // Different on each node
```

**Good: Use Math.random() inside the CRE WASM runtime**

```typescript
const randomIndex = Math.floor(Math.random() * 10) // Same on all nodes
```

Inside the CRE WASM runtime, `Math.random()` is overridden to use a seed coordinated by the CRE platform, so all nodes produce the same sequence. See [Using Randomness in Workflows](/cre/guides/workflow/using-randomness-ts) for more details.

## 5. Working with LLMs

Large Language Models (LLMs) generate different responses for the same prompt, even with temperature set to 0. This inherent non-determinism breaks consensus in workflows.

Expand All @@ -206,17 +226,20 @@ Large Language Models (LLMs) generate different responses for the same prompt, e
- Use Maps and Sets when insertion order matters
- Call `.result()` in a fixed, deterministic order
- Use `runtime.now()` for all time operations
- Use `Math.random()` inside the CRE WASM runtime for randomness
- Request structured output from LLMs

### Don't:

- Iterate objects with `for...in` without sorting keys
- Use `Promise.race()`, `Promise.any()`, or unpredictable `Promise.all()` patterns
- Use `Date.now()` or `new Date()` for timestamps
- Use `Math.random()` outside the CRE WASM runtime
- Rely on free-text LLM responses

## Related concepts

- **[Time in CRE](/cre/guides/workflow/time-in-workflows-ts)**: Learn about DON Time and why `runtime.now()` is required
- **[Using Randomness in Workflows](/cre/guides/workflow/using-randomness-ts)**: Understand consensus-safe random number generation
- **[Consensus Computing](/cre/concepts/consensus-computing)**: Deep dive into how nodes reach agreement
- **[Core SDK Reference](/cre/reference/sdk/core-ts)**: Details on `Runtime`, `NodeRuntime`, and the `.result()` pattern
11 changes: 10 additions & 1 deletion src/content/cre/getting-started/before-you-build-ts.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -100,9 +100,18 @@ If your workflow uses timestamps (e.g., for API authentication or time-based que
See [Using Time in Workflows](/cre/guides/workflow/time-in-workflows) for details on DON time and best practices.
</Aside>

## Working with randomness

If your workflow needs random values (e.g., selecting a winner or generating nonces), use `Math.random()` inside the CRE WASM runtime instead of browser or Node.js random APIs. The CRE runtime overrides `Math.random()` with a consensus-safe generator so all nodes produce the same sequence and can reach consensus.

{/* prettier-ignore */}
<Aside type="tip" title="Learn more">
See [Using Randomness in Workflows](/cre/guides/workflow/using-randomness) for usage examples and best practices.
</Aside>

{/* prettier-ignore */}
<Aside type="note" title="Going deeper">
These are the most common cases. For a complete guide to non-determinism (object iteration, Promise handling, and more), see [Avoiding Non-Determinism in Workflows](/cre/concepts/non-determinism).
Time and randomness are the most common cases. For a complete guide to non-determinism (object iteration, Promise handling, and more), see [Avoiding Non-Determinism in Workflows](/cre/concepts/non-determinism).
</Aside>

## What's next?
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@
section: cre
title: "Using Randomness in Workflows"
sdkLang: "go"
pageId: "using-randomness"
date: Last Modified
metadata:
description: "Generate random numbers safely in CRE: use runtime.Rand() to ensure all nodes get the same values and maintain consensus."
datePublished: "2025-11-04"
lastModified: "2026-03-17"
lastModified: "2026-07-17"
---

import { Aside } from "@components"
Expand Down
198 changes: 198 additions & 0 deletions src/content/cre/guides/workflow/using-randomness-ts.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
---
section: cre
title: "Using Randomness in Workflows"
sdkLang: "ts"
pageId: "using-randomness"
date: Last Modified
metadata:
description: "Generate random numbers safely in CRE: use Math.random() in the CRE WASM runtime to ensure all nodes get the same values and maintain consensus."
datePublished: "2025-11-04"
lastModified: "2026-07-17"
---

import { Aside } from "@components"

<Aside type="note" title="TL;DR">
Use `Math.random()` inside the CRE WASM runtime to generate random numbers in your TypeScript workflows. The runtime
overrides `Math.random()` with a consensus-safe generator that ensures all nodes in the network produce the same
sequence and can reach consensus. Do **not** rely on Node.js or browser-specific random APIs. Note that this
randomness is **not** cryptographically secure.
</Aside>

## The problem: Why randomness needs special handling

Workflows often need randomness for various purposes: generating nonces, selecting winners from a list, or creating unpredictable values. However, in a decentralized network, naive use of random number generators creates a critical problem:

**If each node generates different random values, they cannot reach consensus on the workflow's output.**

For example, if your workflow selects a lottery winner using each node's local random generator, different nodes would select different winners, making it impossible to agree on a single result to write onchain.

## The solution: Consensus-safe randomness

CRE provides randomness through the `Math.random()` function inside the CRE WASM runtime. The SDK's WASM plugin overrides `Math.random()` with a seeded pseudo-random generator managed by the CRE platform. This ensures all nodes generate the same sequence of random values, enabling consensus while still providing unpredictability across different workflow executions.

### Usage

```typescript
// Math.random() returns a value in the range [0, 1)
const randomFloat = Math.random()

// Convert to an integer in a range [0, 100)
const randomInt = Math.floor(Math.random() * 100)

// Convert to a bigint in a range [0, max)
const max = 1000000000000000000n // 1 ETH in wei
const randomBigInt = BigInt(Math.floor(Number(max) * Math.random()))
```

## Common use cases

- Selecting a winner from a lottery or pool
- Generating nonces for transactions
- Creating random identifiers or values
- Any random selection that needs to be agreed upon by all nodes

## Working with bigint random values

For Solidity `uint256` types, you often need random `bigint` values:

```typescript
// Generate a random number in the range [0, max)
const max = 1000000000000000000n // 1 ETH in wei

const randomAmount = BigInt(Math.floor(Number(max) * Math.random()))
// randomAmount is a random value between 0 and 1 ETH
```

Because `Math.random()` returns a JavaScript `number`, be careful not to exceed `Number.MAX_SAFE_INTEGER` when scaling. For ranges larger than `Number.MAX_SAFE_INTEGER`, scale the float by a safe integer first, then combine with additional random draws, or use a deterministic multi-precision approach. For most workflow use cases (nonces, lottery prizes, identifiers), the safe-integer range is sufficient.

## Complete example: Random lottery

Here's a complete example that demonstrates using DON mode randomness to select a lottery winner and generate a prize amount:

```typescript
import { CronCapability, handler, type Runtime, type CronPayload } from "@chainlink/cre-sdk"

type Config = {
schedule: string
}

type MyResult = {
winnerIndex: number
winner: string
randomBigInt: string
}

const onCronTrigger = (runtime: Runtime<Config>, payload: CronPayload): MyResult => {
runtime.log("Running random lottery")

// Define participants
const participants = ["Alice", "Bob", "Charlie", "Diana", "Eve"]
runtime.log(`Participants in lottery: ${participants.join(", ")}`)

// Select a random winner (index in range [0, 5))
const winnerIndex = Math.floor(Math.random() * participants.length)
const winner = participants[winnerIndex]
runtime.log(`Selected winner: ${winner} (index ${winnerIndex})`)

// Generate a random prize amount up to 1,000,000 wei
const maxPrize = 1000000n
const randomPrize = BigInt(Math.floor(Number(maxPrize) * Math.random()))
runtime.log(`Generated random prize: ${randomPrize.toString()}`)

// Return the results
const result: MyResult = {
winnerIndex,
winner,
randomBigInt: randomPrize.toString(),
}

runtime.log(`Random lottery complete! ${JSON.stringify(result)}`)
return result
}

const initWorkflow = (config: Config) => {
const cron = new CronCapability()

return [handler(cron.trigger({ schedule: config.schedule }), onCronTrigger)]
}

export async function main() {
const runner = await Runner.newRunner<Config>()
await runner.run(initWorkflow)
}
```

**What this example demonstrates:**

1. **DON mode context**: The randomness is called directly in the trigger callback (DON mode), ensuring all nodes in the network would select the same winner and prize amount.

1. **Random selection**: Uses `Math.floor(Math.random() * participants.length)` to select a random index from the participant list.

1. **Random bigint for Solidity**: Generates a `bigint` value suitable for use with Solidity `uint256` types.

1. **Logging**: Uses `runtime.log()` for output in the WASM environment.

When you run this workflow multiple times, each execution will select different winners and prize amounts (because each execution gets a different seed), but within a single execution, all nodes in the DON would arrive at the same winner.

## Best practices

### Do:

- **Always use `Math.random()` inside the CRE WASM runtime** for randomness in your workflows
- **Use `runtime.log()`** instead of `console.log` for output in the WASM environment

### Don't:

- **Don't use Node.js or browser random APIs** directly. Always use `Math.random()` inside the CRE WASM runtime.

## Mode-aware behavior

The randomness provided by `Math.random()` is **mode-aware**. The examples above demonstrate DON mode (the default execution mode for workflows). There is also a Node mode with different random behavior, used in advanced scenarios. Each mode provides a different type of randomness.

### DON mode (default)

The examples above all use DON mode. In this mode:

- All nodes generate the **same** random sequence
- Enables consensus on random values
- This is the mode your main workflow callback runs in

### Node mode

When using `runtime.runInNodeMode()`, you can access Node mode randomness:

- Each node generates **different** random values
- Useful for scenarios where per-node variability is accepted
- `Math.random()` inside the Node mode function uses the node-mode seed

**Example:**

```typescript
import { consensusMedianAggregation, type Runtime, type NodeRuntime } from "@chainlink/cre-sdk"

const result = runtime
.runInNodeMode((nodeRuntime: NodeRuntime<Config>): number => {
// Each node generates a different value
return Math.floor(Math.random() * 100)
}, consensusMedianAggregation<number>())()
.result()
```

### Important: Mode isolation

Random generators are tied to the mode they are called in. **Do not** attempt to use a random value generated in one mode inside another mode in a way that affects consensus — it will cause a panic and crash your workflow.

## FAQ

**Is the randomness cryptographically secure?**

No. `Math.random()` returns values from a seeded pseudo-random number generator. The seed is coordinated by the CRE platform so that all nodes in the DON produce the same sequence — that is what makes consensus possible — but it is not cryptographically secure. Do not use it for key generation, signature nonces, or any security-sensitive purpose. For cryptographic randomness, use a vetted library that works in the QuickJS/WASM environment, such as <a href="https://paulmillr.com/noble/" target="_blank" rel="noopener noreferrer">Noble</a>, and verify it in simulation before deploying.

**What happens if I try to use randomness in the wrong mode?**

The SDK will panic with the error: `"random cannot be used outside the mode it was created in"`. This is intentional — it prevents subtle consensus bugs.

**Can I use the same random generator across multiple calls?**

Yes. Once you are inside the CRE runtime, you can call `Math.random()` multiple times within the same execution mode. Each call produces the next value in the deterministic sequence.
Loading
Loading