Skip to content

docs: view Chainlink CRE usage examples and documentation#168

Merged
MicBun merged 3 commits intomainfrom
creExample
Dec 24, 2025
Merged

docs: view Chainlink CRE usage examples and documentation#168
MicBun merged 3 commits intomainfrom
creExample

Conversation

@MicBun
Copy link
Copy Markdown
Member

@MicBun MicBun commented Dec 24, 2025

resolves: https://github.com/truflation/website/issues/3055

Summary by CodeRabbit

  • New Features

    • CRE support with integrated transport, automatic nonce/fee management, and retry for transaction submission
    • Three CRE workflows (write, read, cleanup) + orchestration script demonstrating end-to-end TRUF+CRE flows
  • Documentation

    • CRE Integration Guide, updated API reference, README nav and examples docs, quick-start and config guidance
  • Bug Fixes

    • Corrected transaction result handling for improved error detection
  • Chores

    • Updated ignore rules for CRE build artifacts and example env files

✏️ Tip: You can customize this high-level summary in your review settings.

@MicBun MicBun self-assigned this Dec 24, 2025
@MicBun MicBun added the enhancement New feature or request label Dec 24, 2025
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Dec 24, 2025

📝 Walkthrough

Walkthrough

This PR adds Chainlink Runtime Environment (CRE) integration: a CRE transport with nonce management and retry/broadcast logic, new CRE-focused documentation, and a three-workflow CRE example (write, read, cleanup) with configs, scripts, and wasm-build artifacts ignored.

Changes

Cohort / File(s) Summary
Core Transport Enhancement
core/tnclient/transport_cre.go
Adds CRETransport nonce state and mutex, auto-fetch of nonce on first Execute, incrementing reuse, retry loop for nonce-related errors (up to 3 attempts), executeOnce helper, chain ID caching, manual JSON-RPC user.broadcast path (pre-serialize + direct RPC), and improved broadcast error decoding and logging.
Documentation & API Reference
README.md, docs/CRE_INTEGRATION.md, docs/api-reference.md, docs/readme.md, docs/stream-lifecycle.md
Adds CRE integration guide and API docs (WithCRETransport, WithCRETransportAndSigner), navigation entry, quick-start and build guidance; fixes tx result field usage (txRes.Result.Code).
Examples — Workflows & Code
examples/truf-cre-demo/truf-write-workflow/main.go, examples/truf-cre-demo/truf-read-workflow/main.go, examples/truf-cre-demo/truf-cleanup-workflow/main.go
Adds three Wasip1 CRE workflows (write: deploy+insert, read: top-5 records, cleanup: delete stream), each with exported Config/ExecutionResult types, InitWorkflow entrypoints, signer helpers, cron triggers, and CRE transport usage.
Examples — Config, Orchestration & Module
examples/truf-cre-demo/config.json, examples/truf-cre-demo/go.mod, examples/truf-cre-demo/project.yaml, examples/truf-cre-demo/*.yaml, examples/truf-cre-demo/run-full-demo.sh, examples/truf-cre-demo/secrets.yaml, examples/truf-cre-demo/README.md, examples/README.md
Adds example project config, CRE workflow YAML targets, secrets stub, Go module, orchestration script to run workflows sequentially, and expanded example READMEs.
Build & Ignore Configuration
.gitignore, examples/truf-cre-demo/.gitignore
Ignores CRE wasm artifacts (*.wasm) in root .gitignore and example .env in example .gitignore.

Sequence Diagram(s)

sequenceDiagram
    participant SDK as SDK Client
    participant CRE as CRETransport
    participant RPC as JSON-RPC Endpoint
    participant SIG as Signer

    rect rgb(240,248,255)
    Note over SDK,CRE: Prepare & Sign
    SDK->>CRE: Execute(tx)
    CRE->>CRE: ensure chainID cached
    CRE->>SIG: request signing (uses chainID, nonce)
    SIG-->>CRE: signed tx (bytes)
    end

    rect rgb(255,250,205)
    Note over CRE,RPC: Broadcast (first tx → nonce fetch)
    alt currentNonce unknown
        CRE->>RPC: user.account RPC -> get nonce
        RPC-->>CRE: account nonce
        CRE->>CRE: store nonce
    end
    CRE->>RPC: user.broadcast (pre-serialized JSON-RPC)
    RPC-->>CRE: success / error (-201 with data)
    end

    rect rgb(255,240,245)
    Note over CRE,RPC: Retry on nonce error
    alt nonce-related error
        CRE->>CRE: reset nonce state
        CRE->>RPC: user.account RPC (refetch)
        CRE->>CRE: retry executeOnce (up to 3 attempts)
    end
    CRE-->>SDK: final result or error
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • pr-time-tracker

Poem

🐰 Hopping through CRE with a nonce in my paw,

Retries and broadcasts — I fix what I saw.
Three workflows I tend, deploy, read, and sweep,
CR E + TRUF in a bundle so neat.
A carrot for docs, and examples to keep.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 76.92% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: adding Chainlink CRE (Chainlink Runtime Environment) documentation and usage examples to the repository.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch creExample

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@holdex
Copy link
Copy Markdown

holdex bot commented Dec 24, 2025

Time Submission Status

Member Status Time Action Last Update
MicBun ✅ Submitted 6h Update time Dec 24, 2025, 2:35 PM

@MicBun
Copy link
Copy Markdown
Member Author

MicBun commented Dec 24, 2025

@coderabbitai full review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Dec 24, 2025

✅ Actions performed

Full review triggered.

@MicBun
Copy link
Copy Markdown
Member Author

MicBun commented Dec 24, 2025

@coderabbitai full review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Dec 24, 2025

✅ Actions performed

Full review triggered.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

♻️ Duplicate comments (1)
examples/truf-cre-demo/truf-cleanup-workflow/main.go (1)

124-162: Same createSigner duplication as other workflows.

This is identical to the implementation in the read and write workflows. See the suggestion in the read workflow review for extracting to a shared package.

🧹 Nitpick comments (9)
examples/truf-cre-demo/secrets.yaml (1)

1-1: Add example secret entries or clarify the setup with comments.

The secretsNames key is empty, which may confuse users following this example. Since this PR aims to provide CRE usage examples, consider either:

  1. Including at least one example entry to guide users on the expected format, or
  2. Adding a comment explaining how to populate this file

This will help users understand the required structure for CRE secrets configuration.

🔎 Suggested additions

Option 1: Add an example secret name

 secretsNames:
+  - mySecret
+  - anotherSecret

Option 2: Add clarifying comments

+# List of secret names required by the CRE workflows
+# Users should populate this with the names of secrets available in their CRE environment
 secretsNames:

Option 3: Combine both for maximum clarity

+# List of secret names required by the CRE workflows
+# Example entries shown below; replace with actual secrets for your environment
 secretsNames:
+  - PRIVATE_KEY
+  - API_ENDPOINT
examples/truf-cre-demo/project.yaml (1)

1-20: LGTM! Consider documenting public RPC limitations.

The CRE project configuration is well-structured with helpful comments. The use of a public RPC endpoint for Sepolia testnet is appropriate for example code.

Optional enhancement: Consider adding a comment about public RPC limitations:

 workflow-settings:
   rpcs:
     - chain-name: ethereum-testnet-sepolia
+      # Note: Public RPC endpoints may have rate limits. For production use, configure your own RPC provider.
       url: https://ethereum-sepolia-rpc.publicnode.com
examples/truf-cre-demo/README.md (1)

149-172: Add language specifier to fenced code blocks.

The output examples should have a language specifier (e.g., text or console) for consistency and to satisfy the linter.

🔎 Suggested fix
 ### Write Workflow
-```
+```text
 === TRUF CRE Write Workflow: Deploy & Insert Demo ===

Apply the same pattern to the Read Workflow output (line 159), Cleanup Workflow output (line 168), and Project Structure (line 219) blocks.

core/tnclient/transport_cre.go (2)

288-294: Consider removing or converting debug printf statements to structured logging.

Multiple fmt.Printf("[DEBUG]...") statements throughout the file will write to stdout unconditionally. For a library, consider:

  1. Removing debug statements before release
  2. Using a proper logger if debug output is needed (the transport doesn't currently have logger access)
🔎 Example locations with debug prints
  • Line 288: Execute attempt logging
  • Line 291, 294: Error and retry logging
  • Line 311: executeOnce entry
  • Line 377, 381, 388: Nonce management logging

497-511: Duplicated broadcast error handling.

The broadcast error decoding logic (code -201) is duplicated between doJSONRPC (lines 199-211) and executeOnce (lines 497-511). Consider extracting to a helper function for maintainability.

🔎 Suggested helper
func formatJSONRPCError(rpcErr *jsonrpc.Error) error {
    if rpcErr.Code == -201 && len(rpcErr.Data) > 0 {
        var broadcastErr struct {
            Code    uint32 `json:"code"`
            Hash    string `json:"hash"`
            Message string `json:"message"`
        }
        if err := json.Unmarshal(rpcErr.Data, &broadcastErr); err == nil {
            return fmt.Errorf("JSON-RPC error: %s (code: %d) [Broadcast: code=%d, hash=%s, msg=%s]",
                rpcErr.Message, rpcErr.Code,
                broadcastErr.Code, broadcastErr.Hash, broadcastErr.Message)
        }
    }
    return fmt.Errorf("JSON-RPC error: %s (code: %d)", rpcErr.Message, rpcErr.Code)
}
examples/truf-cre-demo/truf-read-workflow/main.go (2)

190-228: createSigner function is duplicated across all workflow examples.

This function is identical in truf-read-workflow, truf-write-workflow, and truf-cleanup-workflow. Consider extracting to a shared package under examples/truf-cre-demo/shared/ to reduce duplication and ensure consistency.

🔎 Suggested structure
examples/truf-cre-demo/
├── shared/
│   └── signer.go  # createSigner function
├── truf-read-workflow/
├── truf-write-workflow/
└── truf-cleanup-workflow/

152-160: Consider using sort.Slice for cleaner sorting.

The manual bubble sort works but sort.Slice is more idiomatic Go and clearer:

🔎 Suggested refactor
+import "sort"

 // Sort records in descending order by eventTime (newest first)
 records := actionResult.Results
-for i := 0; i < len(records)-1; i++ {
-    for j := i + 1; j < len(records); j++ {
-        if records[i].EventTime < records[j].EventTime {
-            records[i], records[j] = records[j], records[i]
-        }
-    }
-}
+sort.Slice(records, func(i, j int) bool {
+    return records[i].EventTime > records[j].EventTime
+})
examples/truf-cre-demo/run-full-demo.sh (1)

1-2: Consider adding set -euo pipefail for robustness.

While you have explicit $? checks after each command, adding shell options at the start provides an additional safety net for any unhandled failures.

🔎 Proposed fix
 #!/bin/bash
+set -euo pipefail
 
 # TRUF CRE Complete Workflow Demo
examples/truf-cre-demo/truf-write-workflow/main.go (1)

117-122: Inconsistent error handling pattern.

This segment returns (result, nil) after an error, while earlier error paths (lines 84, 92, 108) return (result, err). This inconsistency could mask errors in the workflow result since the caller won't see a non-nil error.

Consider aligning the error handling—either always return the error, or document why partial results with nil error are preferred for certain failures.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between dc627bd and 695d0a1.

⛔ Files ignored due to path filters (1)
  • examples/truf-cre-demo/go.sum is excluded by !**/*.sum
📒 Files selected for processing (23)
  • .gitignore
  • README.md
  • core/tnclient/transport_cre.go
  • docs/CRE_INTEGRATION.md
  • docs/api-reference.md
  • docs/readme.md
  • docs/stream-lifecycle.md
  • examples/README.md
  • examples/truf-cre-demo/.gitignore
  • examples/truf-cre-demo/README.md
  • examples/truf-cre-demo/go.mod
  • examples/truf-cre-demo/project.yaml
  • examples/truf-cre-demo/run-full-demo.sh
  • examples/truf-cre-demo/secrets.yaml
  • examples/truf-cre-demo/truf-cleanup-workflow/config.json
  • examples/truf-cre-demo/truf-cleanup-workflow/main.go
  • examples/truf-cre-demo/truf-cleanup-workflow/workflow.yaml
  • examples/truf-cre-demo/truf-read-workflow/config.json
  • examples/truf-cre-demo/truf-read-workflow/main.go
  • examples/truf-cre-demo/truf-read-workflow/workflow.yaml
  • examples/truf-cre-demo/truf-write-workflow/config.json
  • examples/truf-cre-demo/truf-write-workflow/main.go
  • examples/truf-cre-demo/truf-write-workflow/workflow.yaml
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-07-10T15:39:48.576Z
Learnt from: MicBun
Repo: trufnetwork/sdk-go PR: 138
File: examples/cache_example.go:21-21
Timestamp: 2025-07-10T15:39:48.576Z
Learning: For example code in the trufnetwork/sdk-go repository, the maintainer MicBun prefers to keep examples simple and focused on demonstrating functionality rather than implementing production-ready security practices like environment variables for sensitive values.

Applied to files:

  • README.md
  • examples/truf-cre-demo/go.mod
  • examples/truf-cre-demo/README.md
📚 Learning: 2025-12-24T07:10:07.366Z
Learnt from: MicBun
Repo: trufnetwork/sdk-go PR: 166
File: core/tnclient/transport_cre.go:657-678
Timestamp: 2025-12-24T07:10:07.366Z
Learning: In the trufnetwork/sdk-go repository, the gateway authentication in `core/tnclient/transport_cre.go` uses a custom SIWE-like format (not standard SIWE). The custom format intentionally omits the account address line and uses "Issue At" instead of "Issued At" to match the kwil-db gateway's expectations.

Applied to files:

  • examples/truf-cre-demo/go.mod
  • docs/api-reference.md
  • core/tnclient/transport_cre.go
🧬 Code graph analysis (3)
examples/truf-cre-demo/truf-read-workflow/main.go (5)
examples/truf-cre-demo/truf-write-workflow/main.go (1)
  • RecordData (33-38)
core/logging/logging.go (1)
  • Logger (7-7)
core/tnclient/client.go (1)
  • NewClient (31-59)
core/tnclient/options_cre.go (1)
  • WithCRETransportAndSigner (101-109)
core/types/stream.go (1)
  • GetRecordInput (12-21)
examples/truf-cre-demo/truf-write-workflow/main.go (8)
core/logging/logging.go (1)
  • Logger (7-7)
core/util/stream_id.go (2)
  • NewStreamId (33-43)
  • StreamId (29-31)
core/tnclient/client.go (1)
  • NewClient (31-59)
core/tnclient/options_cre.go (1)
  • WithCRETransportAndSigner (101-109)
core/contractsapi/primitive_stream.go (1)
  • LoadPrimitiveActions (28-34)
core/contractsapi/deploy_stream.go (1)
  • DeployStream (19-24)
core/types/contract_values.go (1)
  • StreamTypePrimitive (12-12)
core/types/primitive_stream.go (1)
  • InsertRecordInput (10-15)
examples/truf-cre-demo/truf-cleanup-workflow/main.go (4)
core/util/stream_id.go (1)
  • NewStreamId (33-43)
core/tnclient/client.go (1)
  • NewClient (31-59)
core/tnclient/options_cre.go (1)
  • WithCRETransportAndSigner (101-109)
core/contractsapi/destroy_stream.go (1)
  • DestroyStream (17-23)
🪛 markdownlint-cli2 (0.18.1)
examples/truf-cre-demo/README.md

150-150: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


159-159: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


168-168: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


219-219: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🔇 Additional comments (29)
examples/truf-cre-demo/go.mod (4)

3-3: Verify Go 1.25.3 compatibility with team infrastructure.

Go 1.25.3 was released 2025-10-13 and is a very recent version. Ensure all developers and CI/CD infrastructure have access to this version, as older toolchains may not recognize it.

Consider documenting the minimum Go version requirement in the project's README or contributing guide, especially for contributors who may still be using Go 1.24 or earlier.


8-8: Confirm beta dependency is intentional for example code.

The cron scheduler dependency uses v1.0.0-beta.0, which indicates active development. While appropriate for example/demo code, verify this aligns with the project's intent for this package. If stability is desired, consider whether a stable release is available.


1-44: Module structure and replace directive are well-configured.

The use of a local replace directive to point to the parent SDK is appropriate for the monorepo structure, and the module name clearly indicates this is a demo. The indirect dependencies are reasonable for CRE integration and SDK usage.


9-10: Dependencies resolve cleanly with no conflicts; no action required.

The go mod graph confirms that sdk-go v0.5.2 (December 2025) explicitly depends on and was tested with kwil-db/core v0.4.3 (July 2025). The date gap reflects intentional version pinning to known-working versions, not outdated or untested transitive dependencies. Module resolution completed without errors.

Likely an incorrect or invalid review comment.

examples/truf-cre-demo/.gitignore (1)

1-1: LGTM!

Excluding environment files from version control is a security best practice.

.gitignore (1)

33-35: LGTM!

Excluding WASM build artifacts from version control is appropriate. The section comment clearly documents the purpose.

examples/README.md (1)

54-66: LGTM! Clear and well-structured documentation.

The new CRE integration section effectively documents the new feature, explains the architectural decisions (separate workflows for request limits), and provides appropriate links to detailed documentation.

docs/stream-lifecycle.md (1)

33-38: No changes needed — the field path txRes.Result.Code is correct.

The code already accesses the correct field from the transaction response. Throughout the codebase (tests, examples, and integration code), all usages consistently access txRes.Result.Code and txRes.Result.Log. No TxResult field exists in the SDK's transaction response structure. The field path in this documentation matches the actual SDK implementation from github.com/trufnetwork/kwil-db/core/types.

Likely an incorrect or invalid review comment.

examples/truf-cre-demo/truf-read-workflow/workflow.yaml (1)

1-23: Configuration looks correct for a CRE workflow example.

The workflow settings follow the expected CRE conventions. The empty secrets-path is appropriate for a demo that uses config-based credentials.

examples/truf-cre-demo/truf-write-workflow/workflow.yaml (1)

1-23: LGTM!

Workflow configuration is consistent with the read workflow pattern.

examples/truf-cre-demo/README.md (1)

94-102: Security notice is appropriate for example code.

The warning about the test private key is good. Based on learnings, example code in this repository prioritizes simplicity over production-ready security practices, so this approach is acceptable for demonstration purposes.

docs/api-reference.md (1)

158-338: Comprehensive CRE API documentation.

The documentation thoroughly covers:

  • Transport options and their parameters
  • Build requirements (wasip1 tag)
  • Usage examples for read-only and write operations
  • Limitations and resources

This provides clear guidance for developers integrating CRE workflows.

docs/CRE_INTEGRATION.md (2)

167-168: Important option ordering constraint is well documented.

Good callout about WithSigner needing to come before WithCRETransport when using separate options. This prevents a common integration mistake.


46-51: Incorrect Go version specified.

Same issue as in README.md - Go 1.25.3 does not exist. Update to a valid Go version.

🔎 Suggested fix
 1. **Go 1.25.3 or later**
+1. **Go 1.22 or later**
 ```bash
 go version  # Should show 1.25.3+
+go version  # Should show 1.22+
</details>




> Likely an incorrect or invalid review comment.

</blockquote></details>
<details>
<summary>core/tnclient/transport_cre.go (4)</summary><blockquote>

`285-306`: **Retry logic for nonce errors is well-implemented.**

The retry mechanism correctly:
- Limits retries to 3 attempts
- Resets `nonceFetched` on nonce errors to refetch from the gateway
- Only retries on nonce-specific errors

This handles the common case where nonces become stale due to concurrent transactions.

---

`346-392`: **Nonce management logic is correct but has a subtle edge case.**

The nonce is incremented before the transaction is broadcast (lines 387-389). If the broadcast fails for non-nonce reasons, the local nonce counter advances but the on-chain nonce doesn't. Subsequent transactions will use incorrect nonces until a nonce error triggers a refetch.

For CRE workflows with the 5 HTTP request limit, this is unlikely to be a practical issue. The retry mechanism (lines 285-306) will recover by refetching the nonce on failure.

---

`443-457`: **WASM pointer corruption workaround is well-documented.**

The comment clearly explains the Go WASM issue (golang/go#59156, golang/go#66984) and why manual JSON construction is necessary. This is a valid workaround for the known pointer size mismatch between 64-bit Go and 32-bit WASM runtime.

---

`418-424`: **Critical fix for fee serialization is well-documented.**

The comment clearly explains why `Fee` must be `big.NewInt(0)` rather than `nil`. This prevents the serialization mismatch that causes signature verification failures.

</blockquote></details>
<details>
<summary>examples/truf-cre-demo/truf-read-workflow/main.go (2)</summary><blockquote>

`108-113`: **Inconsistent error handling pattern.**

On line 112, when `getRecordsCount` fails, the code sets `result.Error` but returns `nil` for the error. Earlier error cases (lines 79-81, 93-95) return both the error and set `result.Error`. Consider being consistent - either always return the error or always return nil with error in result.

Current pattern allows workflow to "succeed" with an error message, which may be intentional for CRE consensus but should be documented.

---

`1-59`: **Workflow setup is well-structured.**

The workflow initialization follows CRE patterns correctly:
- Build tag `wasip1` is present
- `InitWorkflow` returns proper CRE workflow
- Cron trigger is configured from config
- Handler is properly registered

</blockquote></details>
<details>
<summary>examples/truf-cre-demo/truf-cleanup-workflow/main.go (2)</summary><blockquote>

`106-111`: **Consistent error handling with other workflows.**

The pattern of returning `nil` error while setting `result.Error` is consistent with the read workflow. This allows the CRE workflow to complete with an error message in the result rather than failing entirely.

---

`40-49`: **Workflow entry point is properly structured.**

`InitWorkflow` correctly initializes the CRE workflow with cron trigger and handler registration.

</blockquote></details>
<details>
<summary>examples/truf-cre-demo/truf-cleanup-workflow/workflow.yaml (1)</summary><blockquote>

`17-23`: **LGTM!**

The workflow settings are properly structured with clear documentation. The configuration correctly references the local directory for the workflow path and config.json for configuration.

</blockquote></details>
<details>
<summary>examples/truf-cre-demo/truf-write-workflow/main.go (4)</summary><blockquote>

`26-51`: **LGTM!**

The struct definitions are well-organized with proper JSON and consensus aggregation tags for CRE workflow execution.

---

`53-62`: **LGTM!**

The `InitWorkflow` function correctly wires the cron trigger to the handler. The unused `secretsProvider` parameter is required by the CRE interface signature.

---

`192-230`: **LGTM!**

The `createSigner` function properly validates the private key format, derives the Ethereum address using go-ethereum, and creates the signer using kwil-db crypto. The dual-library approach is necessary for compatibility.

---

`232-234`: **LGTM!**

Standard CRE WASM entry point correctly wiring the JSON parser and workflow initialization.

</blockquote></details>
<details>
<summary>docs/readme.md (1)</summary><blockquote>

`6-6`: **LGTM!**

Good addition to the navigation with a clear description of the CRE integration guide.

</blockquote></details>
<details>
<summary>README.md (1)</summary><blockquote>

`63-74`: **LGTM!**

The new CRE section is well-structured, provides clear context, and links appropriately to both external Chainlink documentation and internal guides. The feature list accurately summarizes CRE capabilities, and both the integration guide and demo example are present and functional.

</blockquote></details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
examples/truf-cre-demo/README.md (1)

232-232: Incorrect Go version specified.

Go 1.25.3 does not exist. Current stable Go versions are in the 1.22.x and 1.23.x range. This should be corrected to reflect the actual minimum Go version requirement.

🔎 Suggested fix
 ### Prerequisites
-- Go 1.25.3 or later
+- Go 1.22 or later
 - CRE CLI installed
 - Access to TRUF.NETWORK gateway
🧹 Nitpick comments (2)
examples/truf-cre-demo/README.md (2)

165-191: Consider adding language identifiers to code blocks.

The expected output examples are clear and helpful. As a minor markdown style improvement, consider adding language identifiers to the fenced code blocks (e.g., ```text or ```console) for better syntax highlighting and linting compliance.

🔎 Example of adding language identifiers
 ### Write Workflow
-```
+```text
 === TRUF CRE Write Workflow: Deploy & Insert Demo ===

Apply similar changes to code blocks at lines 177 and 186.


237-252: Consider adding language identifier for better rendering.

The project structure diagram would benefit from a language identifier for proper markdown rendering. Consider using ```text or ```tree.

🔎 Suggested improvement
 ### Project Structure
-```
+```text
 truf-cre-demo/
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 695d0a1 and 40167ef.

📒 Files selected for processing (5)
  • examples/truf-cre-demo/README.md
  • examples/truf-cre-demo/config.json
  • examples/truf-cre-demo/truf-cleanup-workflow/workflow.yaml
  • examples/truf-cre-demo/truf-read-workflow/workflow.yaml
  • examples/truf-cre-demo/truf-write-workflow/workflow.yaml
✅ Files skipped from review due to trivial changes (1)
  • examples/truf-cre-demo/config.json
🚧 Files skipped from review as they are similar to previous changes (2)
  • examples/truf-cre-demo/truf-write-workflow/workflow.yaml
  • examples/truf-cre-demo/truf-cleanup-workflow/workflow.yaml
🧰 Additional context used
🧠 Learnings (5)
📓 Common learnings
Learnt from: MicBun
Repo: trufnetwork/sdk-go PR: 168
File: examples/truf-cre-demo/truf-read-workflow/config.json:1-5
Timestamp: 2025-12-24T14:18:35.598Z
Learning: Chainlink Runtime Environment (CRE) has a limitation of 5 HTTP requests per workflow, which is why the truf-cre-demo example in trufnetwork/sdk-go is split into 3 separate workflows (write, read, cleanup).
Learnt from: MicBun
Repo: trufnetwork/sdk-go PR: 168
File: examples/truf-cre-demo/truf-read-workflow/config.json:1-5
Timestamp: 2025-12-24T14:18:35.598Z
Learning: In the trufnetwork/sdk-go repository's CRE examples, each workflow requires its own config.json file following the CRE CLI (`cre init`) format requirements, which necessitates config file duplication across workflows.
📚 Learning: 2025-12-24T14:18:35.598Z
Learnt from: MicBun
Repo: trufnetwork/sdk-go PR: 168
File: examples/truf-cre-demo/truf-read-workflow/config.json:1-5
Timestamp: 2025-12-24T14:18:35.598Z
Learning: In the trufnetwork/sdk-go repository's CRE examples, each workflow requires its own config.json file following the CRE CLI (`cre init`) format requirements, which necessitates config file duplication across workflows.

Applied to files:

  • examples/truf-cre-demo/truf-read-workflow/workflow.yaml
  • examples/truf-cre-demo/README.md
📚 Learning: 2025-12-24T14:18:35.598Z
Learnt from: MicBun
Repo: trufnetwork/sdk-go PR: 168
File: examples/truf-cre-demo/truf-read-workflow/config.json:1-5
Timestamp: 2025-12-24T14:18:35.598Z
Learning: Chainlink Runtime Environment (CRE) has a limitation of 5 HTTP requests per workflow, which is why the truf-cre-demo example in trufnetwork/sdk-go is split into 3 separate workflows (write, read, cleanup).

Applied to files:

  • examples/truf-cre-demo/README.md
📚 Learning: 2025-12-24T14:18:35.598Z
Learnt from: MicBun
Repo: trufnetwork/sdk-go PR: 168
File: examples/truf-cre-demo/truf-read-workflow/config.json:1-5
Timestamp: 2025-12-24T14:18:35.598Z
Learning: In the trufnetwork/sdk-go repository's examples/truf-cre-demo directory, the private key "0000000000000000000000000000000000000000000000000000000000000001" is a dummy/placeholder key used for demonstration purposes in the CRE workflow examples.

Applied to files:

  • examples/truf-cre-demo/README.md
📚 Learning: 2025-07-10T15:39:48.576Z
Learnt from: MicBun
Repo: trufnetwork/sdk-go PR: 138
File: examples/cache_example.go:21-21
Timestamp: 2025-07-10T15:39:48.576Z
Learning: For example code in the trufnetwork/sdk-go repository, the maintainer MicBun prefers to keep examples simple and focused on demonstrating functionality rather than implementing production-ready security practices like environment variables for sensitive values.

Applied to files:

  • examples/truf-cre-demo/README.md
🪛 markdownlint-cli2 (0.18.1)
examples/truf-cre-demo/README.md

168-168: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


177-177: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


186-186: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


237-237: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: test
🔇 Additional comments (10)
examples/truf-cre-demo/truf-read-workflow/workflow.yaml (1)

1-23: LGTM! Configuration is well-structured.

The workflow settings file is correctly configured with:

  • Clear documentation comments explaining the structure
  • Proper workflow-name identifier for the read workflow
  • Correct path references for shared config (as noted in learnings, all 3 workflows share the same config.json)
  • Valid empty secrets-path

Based on learnings, the shared config approach via ../config.json is intentional and correct for this CRE demo.

examples/truf-cre-demo/README.md (9)

1-14: LGTM! Clear overview of the demo structure.

The documentation effectively explains the 3-workflow split strategy to work within CRE's 5 HTTP request limit per workflow. Based on learnings, this architectural decision is well-justified.


15-32: LGTM! Setup instructions are clear and secure.

The configuration instructions properly guide users to:

  • Replace the placeholder private key with their own
  • Ensure proper permissions on the TRUF node
  • Understand that all workflows share the same config.json

The security note about replacing the placeholder is appropriate for documentation.


33-56: LGTM! Clear and actionable quick start instructions.

The commands are properly formatted for CRE CLI usage, with clear instructions for both complete demo execution and individual workflow testing.


57-107: LGTM! Comprehensive workflow documentation.

The workflow descriptions effectively detail:

  • HTTP request breakdown for each workflow
  • Operations performed and their purposes
  • Expected results

The request counts (5/5, 4/5, 5/5) demonstrate awareness of CRE's 5-request limit, consistent with learnings.


108-121: LGTM! Configuration example with appropriate security warning.

The configuration section clearly shows the required fields and includes an important security warning. Based on learnings, the dummy private key shown is acceptable for demonstration purposes, and the warning at line 120 appropriately advises users about production security practices.


122-164: LGTM! Well-explained architecture and SDK features.

The architecture section effectively explains:

  • Why the 3-workflow split is necessary (5 HTTP request limit per workflow)
  • Key SDK integration patterns with clear code examples
  • Complete CRUD lifecycle demonstration

Based on learnings, the architectural rationale is correct and well-justified.


192-228: LGTM! Valuable implementation details and gotchas.

This section provides critical insights:

  • Graceful handling of duplicate streams
  • Important fee initialization fix (nil vs big.NewInt(0) causing signature verification issues)
  • Clear explanation of automatic nonce management

These details are essential for developers working with the SDK.


253-270: LGTM! Clear instructions with appropriate warning.

The section provides practical guidance for extending the example while correctly warning about the 5 HTTP request limit constraint. The suggestion to create an additional workflow for bulk inserts demonstrates understanding of CRE's limitations.


271-301: LGTM! Comprehensive troubleshooting and guidance.

The documentation concludes with:

  • Practical troubleshooting for common CRE integration issues
  • Relevant resource links
  • Clear contributing guidelines emphasizing the 5 HTTP request limit
  • Important security reminder for production deployments

This provides excellent support for developers using the example.

@MicBun MicBun merged commit c848ac7 into main Dec 24, 2025
4 of 5 checks passed
@MicBun MicBun deleted the creExample branch December 24, 2025 14:32
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
core/tnclient/transport_cre.go (1)

435-514: Consider extracting duplicated broadcast error handling.

Lines 489-504 duplicate the broadcast error handling logic from lines 199-211. This code appears in both doJSONRPC and executeOnce.

While the WASM pointer workaround necessitates manual JSON-RPC construction here (well-documented in lines 436-439), the error-handling logic could be extracted into a helper function to reduce duplication.

Additionally, the manual JSON string construction at lines 447-449 assumes the transaction JSON is valid and properly formatted. While this is likely safe given the prior json.Marshal call, be aware that this approach bypasses normal JSON encoding safeguards.

🔎 Suggested refactoring to extract broadcast error handling

Add a helper function to handle broadcast errors:

// decodeBroadcastError decodes detailed broadcast error information from JSON-RPC error data
func decodeBroadcastError(rpcErr *jsonrpc.Error) error {
	if rpcErr.Code == -201 && len(rpcErr.Data) > 0 {
		var broadcastErr struct {
			Code    uint32 `json:"code"`
			Hash    string `json:"hash"`
			Message string `json:"message"`
		}
		if err := json.Unmarshal(rpcErr.Data, &broadcastErr); err == nil {
			return fmt.Errorf("JSON-RPC error: %s (code: %d) [Broadcast: code=%d, hash=%s, msg=%s]",
				rpcErr.Message, rpcErr.Code,
				broadcastErr.Code, broadcastErr.Hash, broadcastErr.Message)
		}
	}
	return fmt.Errorf("JSON-RPC error: %s (code: %d)", rpcErr.Message, rpcErr.Code)
}

Then use it at lines 199-211 and 489-504:

 if rpcResp.Error != nil {
-	// For broadcast errors (-201), decode the BroadcastError details
-	if rpcResp.Error.Code == -201 && len(rpcResp.Error.Data) > 0 {
-		var broadcastErr struct {
-			Code    uint32 `json:"code"`
-			Hash    string `json:"hash"`
-			Message string `json:"message"`
-		}
-		if err := json.Unmarshal(rpcResp.Error.Data, &broadcastErr); err == nil {
-			return fmt.Errorf("JSON-RPC error: %s (code: %d) [Broadcast: code=%d, hash=%s, msg=%s]",
-				rpcResp.Error.Message, rpcResp.Error.Code,
-				broadcastErr.Code, broadcastErr.Hash, broadcastErr.Message)
-		}
-	}
-	return fmt.Errorf("JSON-RPC error: %s (code: %d)", rpcResp.Error.Message, rpcResp.Error.Code)
+	return decodeBroadcastError(rpcResp.Error)
 }
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 40167ef and 8c68776.

📒 Files selected for processing (1)
  • core/tnclient/transport_cre.go
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: MicBun
Repo: trufnetwork/sdk-go PR: 168
File: examples/truf-cre-demo/truf-read-workflow/config.json:1-5
Timestamp: 2025-12-24T14:18:35.598Z
Learning: Chainlink Runtime Environment (CRE) has a limitation of 5 HTTP requests per workflow, which is why the truf-cre-demo example in trufnetwork/sdk-go is split into 3 separate workflows (write, read, cleanup).
📚 Learning: 2025-12-24T07:10:07.366Z
Learnt from: MicBun
Repo: trufnetwork/sdk-go PR: 166
File: core/tnclient/transport_cre.go:657-678
Timestamp: 2025-12-24T07:10:07.366Z
Learning: In the trufnetwork/sdk-go repository, the gateway authentication in `core/tnclient/transport_cre.go` uses a custom SIWE-like format (not standard SIWE). The custom format intentionally omits the account address line and uses "Issue At" instead of "Issued At" to match the kwil-db gateway's expectations.

Applied to files:

  • core/tnclient/transport_cre.go
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: test
🔇 Additional comments (5)
core/tnclient/transport_cre.go (5)

10-10: LGTM: Nonce tracking infrastructure.

The new fields and import support the nonce auto-management feature. The mutex ensures thread-safe nonce increments.

Also applies to: 67-69


124-124: LGTM: Enhanced error diagnostics.

The improved error messages will aid debugging, especially the detailed broadcast error decoding at lines 199-211.

Also applies to: 199-212


410-416: LGTM: Fee nil handling prevents signature mismatch.

The comment clearly explains the serialization issue and the fix is appropriate.


427-427: LGTM: Explicit serialization type for EthPersonalSigner.

Setting the serialization type explicitly ensures compatibility with EthPersonalSigner.


733-733: LGTM: Enhanced authentication error messages.

Adding "kgw.authn" context to error messages improves debugging clarity.

Also applies to: 755-755

Comment on lines +285 to +303
// Retry loop for nonce errors
const maxRetries = 3
for attempt := 0; attempt < maxRetries; attempt++ {
txHash, err := t.executeOnce(ctx, namespace, action, inputs, opts...)
if err != nil {
// Check if it's a nonce error
if strings.Contains(err.Error(), "invalid nonce") && attempt < maxRetries-1 {
// Reset nonce tracking to refetch on next attempt
t.nonceMu.Lock()
t.nonceFetched = false
t.nonceMu.Unlock()
continue // Retry
}
return types.Hash{}, err
}
return txHash, nil
}

return types.Hash{}, fmt.Errorf("max retries exceeded")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# First, let's verify the file exists and check the code at the specified lines
cat -n core/tnclient/transport_cre.go | sed -n '280,305p'

Repository: trufnetwork/sdk-go

Length of output: 1076


🏁 Script executed:

# Also check the isTransientTxError function mentioned at lines 586-591
cat -n core/tnclient/transport_cre.go | sed -n '580,600p'

Repository: trufnetwork/sdk-go

Length of output: 857


🏁 Script executed:

# Search for nonce error handling patterns and structured error codes in the codebase
rg -n -C3 --type go 'nonce|transient.*error|error.*code' core/tnclient/ | head -100

Repository: trufnetwork/sdk-go

Length of output: 6712


🏁 Script executed:

# Look for error type definitions or error handling patterns related to gateway API
fd --type go -x grep -l 'error\|Error' core/tnclient/ | head -20

Repository: trufnetwork/sdk-go

Length of output: 231


🏁 Script executed:

# Find jsonrpc error code definitions
rg -n --type go 'ErrorCode|ErrorTx|ErrorTimeout|ErrorNonce|error.*nonce' --max-count 50 core/tnclient/

Repository: trufnetwork/sdk-go

Length of output: 872


🏁 Script executed:

# Search for gateway API documentation or error type definitions
find . -name '*.go' -type f | xargs grep -l 'jsonrpc\|ErrorCode' | head -10

Repository: trufnetwork/sdk-go

Length of output: 94


🏁 Script executed:

# Look for comments or error message patterns related to nonce
rg -n 'invalid nonce|nonce.*error|error.*nonce' --type go

Repository: trufnetwork/sdk-go

Length of output: 411


Fragile error detection for nonce errors.

The retry logic uses substring matching strings.Contains(err.Error(), "invalid nonce") to detect nonce errors. This is fragile—if the gateway changes the error message format, retries will fail silently. Consider checking if the gateway API provides a structured error code for nonce errors (similar to the -202 and -32001 codes handled in isTransientTxError at lines 586–591). If available, use it instead of string matching.

🤖 Prompt for AI Agents
In core/tnclient/transport_cre.go around lines 285 to 303, the retry loop
currently detects nonce errors by substring-matching the error message ("invalid
nonce"); replace this fragile check with structured error-code detection:
inspect the returned error for the gateway/json-rpc error type (or unwrap to the
underlying error) and compare its numeric error code against the known
nonce-related codes used elsewhere (reuse the same checks as isTransientTxError
or add a helper like isNonceError that checks for the specific codes), and only
when that code is present perform the nonceMu reset and retry; otherwise return
the error. Ensure you handle nil unwraps and preserve existing behavior of
limiting retries to maxRetries.

Comment on lines +341 to +384
// Auto-manage nonce if not explicitly provided
if txOpts.Nonce == 0 {
t.nonceMu.Lock()

// Fetch nonce from gateway on first transaction only
if !t.nonceFetched {
// Create AccountID from signer
acctID := &types.AccountID{
Identifier: t.signer.CompactID(),
KeyType: t.signer.PubKey().Type(),
}

// Fetch account info via user.account RPC call
params := map[string]any{
"id": acctID,
}

var accountResp struct {
ID *types.AccountID `json:"id"`
Balance string `json:"balance"`
Nonce int64 `json:"nonce"`
}

err := t.callJSONRPC(ctx, "user.account", params, &accountResp)
if err != nil {
// If account doesn't exist yet, start with nonce 0
if !strings.Contains(err.Error(), "not found") && !strings.Contains(err.Error(), "does not exist") {
t.nonceMu.Unlock()
return types.Hash{}, fmt.Errorf("failed to fetch account nonce: %w", err)
}
t.currentNonce = 0
} else {
// Account nonce is the LAST used nonce, so NEXT nonce is nonce+1
t.currentNonce = accountResp.Nonce + 1
}
t.nonceFetched = true
}

// Use current nonce and increment
txOpts.Nonce = t.currentNonce
t.currentNonce++

t.nonceMu.Unlock()
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash

# Search for other error handling patterns with callJSONRPC
echo "=== Error handling patterns with callJSONRPC ==="
rg -n -B2 -A5 'callJSONRPC|err\.Error' core/tnclient/transport_cre.go | head -100

# Look for error type definitions
echo -e "\n=== Error type definitions ==="
rg -n 'type.*Error|error.*struct|ErrAccountNotFound|ErrNotFound' --type go core/tnclient/ | head -50

# Check for similar error string matching patterns
echo -e "\n=== String matching for errors in RPC context ==="
rg -n 'strings\.Contains.*Error|err.*not found|err.*does not exist' --type go core/tnclient/ | head -50

# Look at gateway client implementation
echo -e "\n=== Gateway interaction code ==="
find core/tnclient -name '*.go' -type f | xargs wc -l | sort -n | tail -20

Repository: trufnetwork/sdk-go

Length of output: 6893


🏁 Script executed:

#!/bin/bash

# Get more context around the error handling in transport_cre.go
echo "=== Full context of user.account error handling ==="
sed -n '365,375p' core/tnclient/transport_cre.go

# Search for how errors are returned from gateway RPC
echo -e "\n=== Other RPC calls and their error handling ==="
rg -n -B3 -A8 'callJSONRPC\(ctx' core/tnclient/transport_cre.go | head -150

# Check if there's a gateway error response structure
echo -e "\n=== Response structures in transport ==="
ast-grep --pattern 'type $_ struct {
  $$$
  Error $_ `$_`
  $$$
}'

Repository: trufnetwork/sdk-go

Length of output: 6184


🏁 Script executed:

#!/bin/bash

# Search for account error handling in related test files or docs
echo "=== Test files for user.account handling ==="
find . -name '*test*.go' -type f | xargs grep -l 'user\.account' 2>/dev/null || echo "No test files found"

# Look for any gateway documentation or error constants
echo -e "\n=== Error constants or patterns ==="
rg -n 'account.*not.*found|does.*not.*exist' --type go --type md | head -30

# Check the overall structure of the transport client
echo -e "\n=== Transport client structure ==="
head -100 core/tnclient/transport_cre.go

Repository: trufnetwork/sdk-go

Length of output: 3750


🏁 Script executed:

#!/bin/bash

# Search for error code constants or definitions
echo "=== Looking for error code definitions ==="
rg -n 'code.*int|ErrorCode|error.*code' --type go core/tnclient/ | head -40

# Check if there's a types file defining error codes
echo -e "\n=== Checking types package ==="
find . -name 'types.go' -o -name 'error*.go' | head -10

# Look for account error handling in gateway package or types
echo -e "\n=== Account-related types ==="
rg -n 'type.*Account|account.*error' --type go | head -30

# Search for JSON-RPC error code patterns in gateway responses
echo -e "\n=== JSON-RPC error response structures ==="
rg -n 'type.*Error|Error.*struct' --type go core/tnclient/transport_cre.go -A 5 | head -50

Repository: trufnetwork/sdk-go

Length of output: 4508


🏁 Script executed:

#!/bin/bash

# Check the doJSONRPC function to see full error structure
echo "=== doJSONRPC error handling ==="
sed -n '460,520p' core/tnclient/transport_cre.go

# Look for JSON-RPC response structure definition
echo -e "\n=== JSON-RPC response structure ==="
ast-grep --pattern 'type $_ struct {
  Error struct {
    $$$
  }
  $$$
}'

Repository: trufnetwork/sdk-go

Length of output: 2097


Use error codes instead of string matching for account lookup failures.

Line 367 uses fragile string matching ("not found", "does not exist") to detect non-existent accounts. JSON-RPC error responses include structured error codes, which are reliably extracted elsewhere in the codebase (line 583). The codebase comment at line 565 explicitly acknowledges this: "Consider adding structured error codes to the gateway API for better reliability."

The mutex locking correctly prevents race conditions during nonce fetching and incrementing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant