diff --git a/public/changelog.json b/public/changelog.json index ac221b76b22..1625c07491d 100644 --- a/public/changelog.json +++ b/public/changelog.json @@ -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", diff --git a/src/components/QuickLinks/data/productChainLinks.ts b/src/components/QuickLinks/data/productChainLinks.ts index 268fa15bad3..4d40851a821 100644 --- a/src/components/QuickLinks/data/productChainLinks.ts +++ b/src/components/QuickLinks/data/productChainLinks.ts @@ -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 @@ -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", }, }, @@ -412,7 +426,7 @@ export const chainNames: Record = { treasure: "Treasure", lens: "Lens", unichain: "Unichain", - hyperevm: "HyperEVM", + hyperevm: "Hyperliquid", merlin: "Merlin", fraxtal: "Fraxtal", zeta: "Zeta", diff --git a/src/config/sidebar.ts b/src/config/sidebar.ts index f1a0c6fcc40..988f6966d48 100644 --- a/src/config/sidebar.ts +++ b/src/config/sidebar.ts @@ -475,6 +475,7 @@ export const SIDEBAR: Partial> = { { title: "Using Randomness in Workflows", url: "cre/guides/workflow/using-randomness", + highlightAsCurrent: ["cre/guides/workflow/using-randomness-ts", "cre/guides/workflow/using-randomness-go"], }, ], }, diff --git a/src/config/versions/index.ts b/src/config/versions/index.ts index 2ae69917e75..b4595938c86 100644 --- a/src/config/versions/index.ts +++ b/src/config/versions/index.ts @@ -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", @@ -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", diff --git a/src/content/cre/concepts/non-determinism-ts.mdx b/src/content/cre/concepts/non-determinism-ts.mdx index ce1b70975b9..32382e0a108 100644 --- a/src/content/cre/concepts/non-determinism-ts.mdx +++ b/src/content/cre/concepts/non-determinism-ts.mdx @@ -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 @@ -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. @@ -206,6 +226,7 @@ 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: @@ -213,10 +234,12 @@ Large Language Models (LLMs) generate different responses for the same prompt, e - 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 diff --git a/src/content/cre/getting-started/before-you-build-ts.mdx b/src/content/cre/getting-started/before-you-build-ts.mdx index 4cd184fff16..8e8f5bc0268 100644 --- a/src/content/cre/getting-started/before-you-build-ts.mdx +++ b/src/content/cre/getting-started/before-you-build-ts.mdx @@ -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. +## 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 */} + + {/* prettier-ignore */} ## What's next? diff --git a/src/content/cre/guides/workflow/using-randomness.mdx b/src/content/cre/guides/workflow/using-randomness-go.mdx similarity index 99% rename from src/content/cre/guides/workflow/using-randomness.mdx rename to src/content/cre/guides/workflow/using-randomness-go.mdx index 613855636d4..708a0b1f810 100644 --- a/src/content/cre/guides/workflow/using-randomness.mdx +++ b/src/content/cre/guides/workflow/using-randomness-go.mdx @@ -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" diff --git a/src/content/cre/guides/workflow/using-randomness-ts.mdx b/src/content/cre/guides/workflow/using-randomness-ts.mdx new file mode 100644 index 00000000000..88419f914f8 --- /dev/null +++ b/src/content/cre/guides/workflow/using-randomness-ts.mdx @@ -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" + + + +## 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, 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() + 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): number => { + // Each node generates a different value + return Math.floor(Math.random() * 100) + }, consensusMedianAggregation())() + .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 Noble, 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. diff --git a/src/content/cre/llms-full-go.txt b/src/content/cre/llms-full-go.txt index ea6f358e373..9d04a28d98b 100644 --- a/src/content/cre/llms-full-go.txt +++ b/src/content/cre/llms-full-go.txt @@ -514,10 +514,40 @@ To help us assist you faster, please include: # Release Notes Source: https://docs.chain.link/cre/release-notes -Last Updated: 2026-07-09 +Last Updated: 2026-07-16 This page provides detailed release notes for CRE. It includes information on new features, significant changes, and known limitations. +## CLI v1.26.0 - July 16, 2026 + +**CRE CLI version 1.26.0 is now available.** + +- **Confidential simulate improvements**: When using confidential compute simulation, the CLI now warns if the HTTP endpoint rejects production traffic and acknowledges TEE execution, making it clearer when simulation paths diverge from production behavior. +- **Deployment access request messaging**: The access request flow during deployment now provides clearer messaging about what access is being requested and why. +- **Error message fix**: The workflow directory path displayed in simulation error messages is now correct. + +**How to update:** + +- **Automatic update**: When you run any CRE command, the CLI will automatically detect if a newer version is available and prompt you to update. Simply run `cre update` to install the latest version. +- **Fresh installation**: If you're installing the CLI for the first time, follow the [CLI Installation guide](/cre/getting-started/cli-installation). + +[See all changes on GitHub](https://github.com/smartcontractkit/cre-cli/compare/v1.25.0...v1.26.0) + +## CLI v1.25.0 - July 14, 2026 + +**CRE CLI version 1.25.0 is now available.** + +- **Solana mainnet mock forwarder for simulation**: `cre workflow simulate` now supports Solana mainnet via a mock forwarder, enabling local simulation of Solana write workflows on mainnet before deployment. +- **Cross-command execution discovery hints**: The CLI now surfaces hints across related commands to help you discover available execution workflows and next steps more easily. +- **Linux asset suffix handling**: Improved asset detection for Linux builds. + +**How to update:** + +- **Automatic update**: When you run any CRE command, the CLI will automatically detect if a newer version is available and prompt you to update. Simply run `cre update` to install the latest version. +- **Fresh installation**: If you're installing the CLI for the first time, follow the [CLI Installation guide](/cre/getting-started/cli-installation). + +[See all changes on GitHub](https://github.com/smartcontractkit/cre-cli/compare/v1.24.0...v1.25.0) + ## CLI v1.24.0 - July 9, 2026 **CRE CLI version 1.24.0 is now available.** @@ -5435,227 +5465,6 @@ By following this pattern, you can manage your secrets securely without ever exp --- -# Using Randomness in Workflows -Source: https://docs.chain.link/cre/guides/workflow/using-randomness -Last Updated: 2026-03-17 - - - -## 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 `runtime.Rand()` method, which returns a standard Go `*rand.Rand` object. This random generator is managed by the CRE platform to ensure all nodes generate the same sequence of random values, enabling consensus while still providing unpredictability across different workflow executions. - -### Usage - -```go -// Get the random generator from the runtime -rnd, err := runtime.Rand() -if err != nil { - return err -} - -// Use it with standard Go rand methods -randomInt := rnd.Intn(100) // Random int in [0, 100) -randomBigInt := new(big.Int).Rand(rnd, big.NewInt(1000)) // Random big.Int -``` - -## 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 big.Int random values - -For Solidity `uint256` types, you often need random `*big.Int` values: - -```go -rnd, err := runtime.Rand() -if err != nil { - return err -} - -// Generate a random number in the range [0, max) -max := new(big.Int) -max.SetString("1000000000000000000", 10) // 1 ETH in wei - -randomAmount := new(big.Int).Rand(rnd, max) -// randomAmount is a random value between 0 and 1 ETH -``` - -## 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: - -```go -//go:build wasip1 - -package main - -import ( - "fmt" - "log/slog" - "math/big" - - "github.com/smartcontractkit/cre-sdk-go/capabilities/scheduler/cron" - "github.com/smartcontractkit/cre-sdk-go/cre" - "github.com/smartcontractkit/cre-sdk-go/cre/wasm" -) - -type Config struct { - Schedule string `json:"schedule"` -} - -type MyResult struct { - WinnerIndex int - Winner string - RandomBigInt string -} - -func InitWorkflow(config *Config, logger *slog.Logger, secretsProvider cre.SecretsProvider) (cre.Workflow[*Config], error) { - return cre.Workflow[*Config]{ - cre.Handler(cron.Trigger(&cron.Config{Schedule: config.Schedule}), onCronTrigger), - }, nil -} - -func onCronTrigger(config *Config, runtime cre.Runtime, trigger *cron.Payload) (*MyResult, error) { - logger := runtime.Logger() - logger.Info("Running random lottery") - - // Define participants - participants := []string{"Alice", "Bob", "Charlie", "Diana", "Eve"} - logger.Info("Participants in lottery", "count", len(participants), "names", participants) - - // Get the DON mode random generator - rnd, err := runtime.Rand() - if err != nil { - return nil, fmt.Errorf("failed to get random generator: %w", err) - } - - // Select a random winner (index in range [0, 5)) - winnerIndex := rnd.Intn(len(participants)) - winner := participants[winnerIndex] - logger.Info("Selected winner", "index", winnerIndex, "winner", winner) - - // Generate a random prize amount up to 1,000,000 wei - maxPrize := big.NewInt(1000000) - randomPrize := new(big.Int).Rand(rnd, maxPrize) - logger.Info("Generated random prize", "amount", randomPrize.String()) - - // Return the results - result := &MyResult{ - WinnerIndex: winnerIndex, - Winner: winner, - RandomBigInt: randomPrize.String(), - } - - logger.Info("Random lottery complete!", "result", result) - return result, nil -} - -func main() { - wasm.NewRunner(cre.ParseJSON[Config]).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. - -2. **Random selection**: Uses `rnd.Intn(len(participants))` to select a random index from the participant list. The `Intn(n)` method returns a value in the range `[0, n)`. - -3. **Random big.Int for Solidity**: Generates a `*big.Int` value suitable for use with Solidity `uint256` types. - -4. **Error handling**: Properly checks for errors when calling `runtime.Rand()`. - -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 `runtime.Rand()`** for randomness in your workflows -- **Check for errors** when calling `runtime.Rand()` - ```go - rnd, err := runtime.Rand() - if err != nil { - return fmt.Errorf("failed to get random generator: %w", err) - } - ``` - -### Don't: - -- **Don't use Go's global `rand` package** directly. Always get your random generator from `runtime.Rand()` first. - -## Mode-aware behavior - -The randomness provided by `runtime.Rand()` 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 `cre.RunInNodeMode`, you can access Node mode randomness: - -- Each node generates **different** random values -- Useful for scenarios where per-node variability is accepted -- Access via `nodeRuntime.Rand()` inside the Node mode function - -**Example:** - -```go -resultPromise := cre.RunInNodeMode(config, runtime, - func(config *Config, nodeRuntime cre.NodeRuntime) (int, error) { - rnd, err := nodeRuntime.Rand() - if err != nil { - return 0, err - } - // Each node generates a different value - return rnd.Intn(100), nil - }, - cre.ConsensusMedianAggregation[int](), -) -``` - -### Important: Mode isolation - -Random generators are tied to the mode they were created in. **Do not** attempt to use a random generator from one mode in another mode—it will cause a panic and crash your workflow. - -## FAQ - -**Is the randomness cryptographically secure?** - -No. `runtime.Rand()` returns a seeded pseudo-random number generator (Go's `math/rand`). 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 Go's `crypto/rand` package. - -**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 call `runtime.Rand()` and get a `*rand.Rand` object, you can reuse it within the same execution mode. Each call to methods like `Intn()` will produce the next value in the deterministic sequence. - ---- - # Simulating Workflows Source: https://docs.chain.link/cre/guides/operations/simulating-workflows Last Updated: 2026-06-11 @@ -17069,6 +16878,227 @@ After a successful [`cre.ParseReport()`](/cre/reference/sdk/core-go#creparserepo --- +# Using Randomness in Workflows +Source: https://docs.chain.link/cre/guides/workflow/using-randomness-go +Last Updated: 2026-07-17 + + + +## 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 `runtime.Rand()` method, which returns a standard Go `*rand.Rand` object. This random generator is managed by the CRE platform to ensure all nodes generate the same sequence of random values, enabling consensus while still providing unpredictability across different workflow executions. + +### Usage + +```go +// Get the random generator from the runtime +rnd, err := runtime.Rand() +if err != nil { + return err +} + +// Use it with standard Go rand methods +randomInt := rnd.Intn(100) // Random int in [0, 100) +randomBigInt := new(big.Int).Rand(rnd, big.NewInt(1000)) // Random big.Int +``` + +## 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 big.Int random values + +For Solidity `uint256` types, you often need random `*big.Int` values: + +```go +rnd, err := runtime.Rand() +if err != nil { + return err +} + +// Generate a random number in the range [0, max) +max := new(big.Int) +max.SetString("1000000000000000000", 10) // 1 ETH in wei + +randomAmount := new(big.Int).Rand(rnd, max) +// randomAmount is a random value between 0 and 1 ETH +``` + +## 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: + +```go +//go:build wasip1 + +package main + +import ( + "fmt" + "log/slog" + "math/big" + + "github.com/smartcontractkit/cre-sdk-go/capabilities/scheduler/cron" + "github.com/smartcontractkit/cre-sdk-go/cre" + "github.com/smartcontractkit/cre-sdk-go/cre/wasm" +) + +type Config struct { + Schedule string `json:"schedule"` +} + +type MyResult struct { + WinnerIndex int + Winner string + RandomBigInt string +} + +func InitWorkflow(config *Config, logger *slog.Logger, secretsProvider cre.SecretsProvider) (cre.Workflow[*Config], error) { + return cre.Workflow[*Config]{ + cre.Handler(cron.Trigger(&cron.Config{Schedule: config.Schedule}), onCronTrigger), + }, nil +} + +func onCronTrigger(config *Config, runtime cre.Runtime, trigger *cron.Payload) (*MyResult, error) { + logger := runtime.Logger() + logger.Info("Running random lottery") + + // Define participants + participants := []string{"Alice", "Bob", "Charlie", "Diana", "Eve"} + logger.Info("Participants in lottery", "count", len(participants), "names", participants) + + // Get the DON mode random generator + rnd, err := runtime.Rand() + if err != nil { + return nil, fmt.Errorf("failed to get random generator: %w", err) + } + + // Select a random winner (index in range [0, 5)) + winnerIndex := rnd.Intn(len(participants)) + winner := participants[winnerIndex] + logger.Info("Selected winner", "index", winnerIndex, "winner", winner) + + // Generate a random prize amount up to 1,000,000 wei + maxPrize := big.NewInt(1000000) + randomPrize := new(big.Int).Rand(rnd, maxPrize) + logger.Info("Generated random prize", "amount", randomPrize.String()) + + // Return the results + result := &MyResult{ + WinnerIndex: winnerIndex, + Winner: winner, + RandomBigInt: randomPrize.String(), + } + + logger.Info("Random lottery complete!", "result", result) + return result, nil +} + +func main() { + wasm.NewRunner(cre.ParseJSON[Config]).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. + +2. **Random selection**: Uses `rnd.Intn(len(participants))` to select a random index from the participant list. The `Intn(n)` method returns a value in the range `[0, n)`. + +3. **Random big.Int for Solidity**: Generates a `*big.Int` value suitable for use with Solidity `uint256` types. + +4. **Error handling**: Properly checks for errors when calling `runtime.Rand()`. + +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 `runtime.Rand()`** for randomness in your workflows +- **Check for errors** when calling `runtime.Rand()` + ```go + rnd, err := runtime.Rand() + if err != nil { + return fmt.Errorf("failed to get random generator: %w", err) + } + ``` + +### Don't: + +- **Don't use Go's global `rand` package** directly. Always get your random generator from `runtime.Rand()` first. + +## Mode-aware behavior + +The randomness provided by `runtime.Rand()` 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 `cre.RunInNodeMode`, you can access Node mode randomness: + +- Each node generates **different** random values +- Useful for scenarios where per-node variability is accepted +- Access via `nodeRuntime.Rand()` inside the Node mode function + +**Example:** + +```go +resultPromise := cre.RunInNodeMode(config, runtime, + func(config *Config, nodeRuntime cre.NodeRuntime) (int, error) { + rnd, err := nodeRuntime.Rand() + if err != nil { + return 0, err + } + // Each node generates a different value + return rnd.Intn(100), nil + }, + cre.ConsensusMedianAggregation[int](), +) +``` + +### Important: Mode isolation + +Random generators are tied to the mode they were created in. **Do not** attempt to use a random generator from one mode in another mode—it will cause a panic and crash your workflow. + +## FAQ + +**Is the randomness cryptographically secure?** + +No. `runtime.Rand()` returns a seeded pseudo-random number generator (Go's `math/rand`). 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 Go's `crypto/rand` package. + +**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 call `runtime.Rand()` and get a `*rand.Rand` object, you can reuse it within the same execution mode. Each call to methods like `Intn()` will produce the next value in the deterministic sequence. + +--- + # Solana Forwarder Directory Source: https://docs.chain.link/cre/guides/workflow/using-solana-client/forwarder-directory-go Last Updated: 2026-07-15 diff --git a/src/content/cre/llms-full-ts.txt b/src/content/cre/llms-full-ts.txt index 5a3c6e82dc9..722702b0db3 100644 --- a/src/content/cre/llms-full-ts.txt +++ b/src/content/cre/llms-full-ts.txt @@ -514,10 +514,40 @@ To help us assist you faster, please include: # Release Notes Source: https://docs.chain.link/cre/release-notes -Last Updated: 2026-07-09 +Last Updated: 2026-07-16 This page provides detailed release notes for CRE. It includes information on new features, significant changes, and known limitations. +## CLI v1.26.0 - July 16, 2026 + +**CRE CLI version 1.26.0 is now available.** + +- **Confidential simulate improvements**: When using confidential compute simulation, the CLI now warns if the HTTP endpoint rejects production traffic and acknowledges TEE execution, making it clearer when simulation paths diverge from production behavior. +- **Deployment access request messaging**: The access request flow during deployment now provides clearer messaging about what access is being requested and why. +- **Error message fix**: The workflow directory path displayed in simulation error messages is now correct. + +**How to update:** + +- **Automatic update**: When you run any CRE command, the CLI will automatically detect if a newer version is available and prompt you to update. Simply run `cre update` to install the latest version. +- **Fresh installation**: If you're installing the CLI for the first time, follow the [CLI Installation guide](/cre/getting-started/cli-installation). + +[See all changes on GitHub](https://github.com/smartcontractkit/cre-cli/compare/v1.25.0...v1.26.0) + +## CLI v1.25.0 - July 14, 2026 + +**CRE CLI version 1.25.0 is now available.** + +- **Solana mainnet mock forwarder for simulation**: `cre workflow simulate` now supports Solana mainnet via a mock forwarder, enabling local simulation of Solana write workflows on mainnet before deployment. +- **Cross-command execution discovery hints**: The CLI now surfaces hints across related commands to help you discover available execution workflows and next steps more easily. +- **Linux asset suffix handling**: Improved asset detection for Linux builds. + +**How to update:** + +- **Automatic update**: When you run any CRE command, the CLI will automatically detect if a newer version is available and prompt you to update. Simply run `cre update` to install the latest version. +- **Fresh installation**: If you're installing the CLI for the first time, follow the [CLI Installation guide](/cre/getting-started/cli-installation). + +[See all changes on GitHub](https://github.com/smartcontractkit/cre-cli/compare/v1.24.0...v1.25.0) + ## CLI v1.24.0 - July 9, 2026 **CRE CLI version 1.24.0 is now available.** @@ -10414,12 +10444,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 @@ -10579,7 +10610,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. @@ -10595,6 +10645,7 @@ 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: @@ -10602,11 +10653,13 @@ Large Language Models (LLMs) generate different responses for the same prompt, e - 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 @@ -10704,9 +10757,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. +## 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. + + + + ## What's next? @@ -16766,6 +16828,197 @@ After a successful [`Report.parse()`](/cre/reference/sdk/core-ts#report-verifica --- +# Using Randomness in Workflows +Source: https://docs.chain.link/cre/guides/workflow/using-randomness-ts +Last Updated: 2026-07-17 + + + +## 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, 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() + 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. + +2. **Random selection**: Uses `Math.floor(Math.random() * participants.length)` to select a random index from the participant list. + +3. **Random bigint for Solidity**: Generates a `bigint` value suitable for use with Solidity `uint256` types. + +4. **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): number => { + // Each node generates a different value + return Math.floor(Math.random() * 100) + }, consensusMedianAggregation())() + .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 Noble, 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. + +--- + # Solana Forwarder Directory Source: https://docs.chain.link/cre/guides/workflow/using-solana-client/forwarder-directory-ts Last Updated: 2026-07-15 diff --git a/src/content/cre/release-notes.mdx b/src/content/cre/release-notes.mdx index 055b69938e4..7725c0ac724 100644 --- a/src/content/cre/release-notes.mdx +++ b/src/content/cre/release-notes.mdx @@ -5,13 +5,43 @@ date: Last Modified metadata: description: "Discover what's new in CRE: latest features, changes, and improvements in each release of the Chainlink Runtime Environment." datePublished: "2025-11-04" - lastModified: "2026-07-09" + lastModified: "2026-07-16" --- import { Aside } from "@components" This page provides detailed release notes for CRE. It includes information on new features, significant changes, and known limitations. +## CLI v1.26.0 - July 16, 2026 + +**CRE CLI version 1.26.0 is now available.** + +- **Confidential simulate improvements**: When using confidential compute simulation, the CLI now warns if the HTTP endpoint rejects production traffic and acknowledges TEE execution, making it clearer when simulation paths diverge from production behavior. +- **Deployment access request messaging**: The access request flow during deployment now provides clearer messaging about what access is being requested and why. +- **Error message fix**: The workflow directory path displayed in simulation error messages is now correct. + +**How to update:** + +- **Automatic update**: When you run any CRE command, the CLI will automatically detect if a newer version is available and prompt you to update. Simply run `cre update` to install the latest version. +- **Fresh installation**: If you're installing the CLI for the first time, follow the [CLI Installation guide](/cre/getting-started/cli-installation). + +[See all changes on GitHub](https://github.com/smartcontractkit/cre-cli/compare/v1.25.0...v1.26.0) + +## CLI v1.25.0 - July 14, 2026 + +**CRE CLI version 1.25.0 is now available.** + +- **Solana mainnet mock forwarder for simulation**: `cre workflow simulate` now supports Solana mainnet via a mock forwarder, enabling local simulation of Solana write workflows on mainnet before deployment. +- **Cross-command execution discovery hints**: The CLI now surfaces hints across related commands to help you discover available execution workflows and next steps more easily. +- **Linux asset suffix handling**: Improved asset detection for Linux builds. + +**How to update:** + +- **Automatic update**: When you run any CRE command, the CLI will automatically detect if a newer version is available and prompt you to update. Simply run `cre update` to install the latest version. +- **Fresh installation**: If you're installing the CLI for the first time, follow the [CLI Installation guide](/cre/getting-started/cli-installation). + +[See all changes on GitHub](https://github.com/smartcontractkit/cre-cli/compare/v1.24.0...v1.25.0) + ## CLI v1.24.0 - July 9, 2026 **CRE CLI version 1.24.0 is now available.**