Skip to content

Feat: build unsigned simple transactions - #6

Merged
h33p merged 7 commits into
mainfrom
feat/public-fee-estimation
Oct 7, 2026
Merged

h33p merged 7 commits into
mainfrom
feat/public-fee-estimation

Conversation

@thomas-kroes

@thomas-kroes thomas-kroes commented Jun 11, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • Add the read-only nock_buildSimpleTransaction provider primitive. It returns the exact unsigned V1 NockchainTx, selected native input-note sidecars, projected outputs, a witness-independent intentId, and canonical amount/fee/change metadata.
  • Keep builds unreserved and side-effect-free. Wallets must revalidate the committed inputs before signing and must not silently substitute a different transaction after approval.
  • Retain estimateTransactionFee() as deprecated SDK convenience sugar over buildSimpleTransaction(); there is no separate fee-estimation wire method.
  • Allow sendTransaction.fee to be omitted. Explicit fees remain exact overrides; omitted fees are calculated by the wallet.
  • Correct sendTransaction() to return the API 1 runtime object { txid, amount, fee } instead of the inaccurate string type.
  • Normalize legacy API 0 bare transaction IDs to { txid } for API 1 callers, while preserving the bare-ID response for callers bridged back to API 0.
  • Accept number, canonical-string, and SDK bigint nicks inputs, normalizing bigint values before Chrome messaging.

Security and lifecycle contract

  • intentId is derived from the witnessless spends and remains stable across signing; callers must not bind approval to the unsigned raw transaction ID because signatures change it.
  • Returned notes are compatibility/inspection sidecars, not trusted signing authority. A wallet must resolve the transaction's committed input names against its own state.
  • A build is a point-in-time snapshot and does not reserve funds. Stale inputs must produce a rebuild-required failure at signing/sending.
  • fee is the actual fee encoded in the transaction (curFee); minimumFee is the independently calculated minimum (calcFee). Explicit fees below the minimum are rejected.

Dependency status

#7 is merged and this branch is based on the resulting iris-sdk/main.

Do not merge or publish SDK 0.3.0 from this head yet. After @nockbox/iris-wasm@0.2.1 is published from the coordinated iris-rs work, update the SDK's exact WASM dependency from 0.2.0 to 0.2.1, regenerate the lockfile, and rerun validation on that final dependency graph.

Compatibility

  • Existing sendTransaction({ to, amount, fee? }) request shapes and explicit-fee semantics are preserved.
  • API 1 wallets return canonical amount and actual fee; these fields remain optional only when bridging a legacy API 0 wallet that historically returned only a transaction ID.
  • buildSimpleTransaction was introduced with API 1. Compatibility mapping passes the method through unchanged; older wallets may return their normal method-not-found error.
  • estimateTransactionFee() remains available as a deprecated SDK helper and now calls buildSimpleTransaction().
  • TypeScript breaking correction: sendTransaction() is typed as returning an object rather than string; callers that used the result directly as a transaction ID must read result.txid.
  • API 0 callers retain their historical bare transaction-ID response. API 1 callers receive the object response.

Validation

  • Typecheck and TypeScript build
  • Prettier check
  • Node regression tests for complete build-response passthrough, JSON/structured-clone safety, bigint normalization, omitted optional fee, deprecated helper delegation, and preserved send inputs
  • Example TypeScript/Vite production build
  • Package dry-run including README and compiled SDK surface
  • GitHub CI on the current head

Development-only Vite/PostCSS/esbuild advisories remain outside the shipped runtime dependency set; a major Vite upgrade is intentionally outside this focused change.

@greptile-apps

greptile-apps Bot commented Jun 11, 2026 •

Copy link
Copy Markdown

Greptile Summary

This PR introduces the read-only nock_estimateTransactionFee provider method, makes the fee field optional on SendTransactionRequest, and corrects the sendTransaction() return type from string to SendTransactionResponse. Bigint nick values are normalized to canonical strings before crossing Chrome's extension messaging boundary.

  • New estimateTransactionFee method in NockchainProvider with full JSDoc, bigint normalization, and a matching EstimateTransactionFeeResponse type.
  • Compat bridge updated to normalize legacy API 0 bare-string sendTransaction responses to { txid } for API 1 callers, and to strip the object back to a bare txid for API 0 callers bridged to an API 1 wallet.
  • Node regression tests added (tests/provider-nicks.test.mjs) and wired into CI, covering bigint normalization and preservation of string/number inputs.

Confidence Score: 5/5

Safe to merge once the WASM 0.2.1 dependency is published and the lockfile is updated per the release prerequisite in the PR description.

The fee-estimation path is purely read-only and additive. The sendTransaction normalization is narrow — only bigints are converted to strings; numbers and Nicks strings pass through unchanged. The compat response mapper handles both directions of the legacy bridge correctly, including the defensive passthrough for already-normalized responses. The regression tests exercise all three normalization shapes and JSON serializability. No logic paths were left untested that could silently corrupt data.

Files Needing Attention: No files require special attention. The compat.ts response mapping for SEND_TRANSACTION is the most nuanced new logic but follows the established pattern used by the CONNECT and SIGN_MESSAGE mappers.

Important Files Changed

Filename Overview
src/provider.ts Adds estimateTransactionFee method and normalizeNicksForRpc helper; changes sendTransaction return type to SendTransactionResponse; bigint normalization is correct and tested.
src/compat.ts Adds SEND_TRANSACTION response mapping: normalizes legacy bare-string txid to { txid } for API 1 callers and strips back to bare txid for API 0 callers; defensive object-shape check handles pre-normalized responses correctly.
src/types.ts Adds SendTransactionResponse, EstimateTransactionFeeRequest, EstimateTransactionFeeResponse; widens amount to NicksLike; makes fee optional with clear semantics in JSDoc.
src/constants.ts Adds ESTIMATE_TRANSACTION_FEE: 'nock_estimateTransactionFee' constant; straightforward addition.
tests/provider-nicks.test.mjs New regression tests covering bigint normalization, string/number passthrough, and omitted-fee handling; uses Node's built-in test runner, wired into CI.
.github/workflows/ci.yml Adds npm test step after the example build to run the new regression suite in CI.
README.md New README covering security model, compatibility notes, fee semantics, 0.3 migration guide, and trust-boundary documentation.

Sequence Diagram

sequenceDiagram
    participant dApp
    participant NockchainProvider
    participant InjectedWallet

    Note over dApp,InjectedWallet: estimateTransactionFee (new, API 1 only)
    dApp->>NockchainProvider: "estimateTransactionFee({ to, amount: 99n })"
    NockchainProvider->>NockchainProvider: normalizeNicksForRpc(99n) → "99"
    NockchainProvider->>InjectedWallet: "request({ method: nock_estimateTransactionFee, params: { to, amount: "99" } })"
    InjectedWallet-->>NockchainProvider: "{ fee: "3" }"
    NockchainProvider-->>dApp: "EstimateTransactionFeeResponse { fee: "3" }"

    Note over dApp,InjectedWallet: sendTransaction — fee omitted (API 1)
    dApp->>NockchainProvider: "sendTransaction({ to, amount: 42n })"
    NockchainProvider->>NockchainProvider: normalizeNicksForRpc(42n) → "42"
    NockchainProvider->>InjectedWallet: "request({ method: nock_sendTransaction, params: { to, amount: "42" } })"
    InjectedWallet-->>NockchainProvider: "{ txid, amount, fee }"
    NockchainProvider-->>dApp: "SendTransactionResponse { txid, amount?, fee? }"

    Note over dApp,InjectedWallet: compat bridge: API 1 caller → legacy API 0 wallet
    dApp->>NockchainProvider: sendTransaction(...)
    NockchainProvider->>InjectedWallet: request (via requestBridge, fee omitted from params if absent)
    InjectedWallet-->>NockchainProvider: "bare-txid-string"
    NockchainProvider->>NockchainProvider: "mapResponse(!fromV1 → toV1): wrap → { txid }"
    NockchainProvider-->>dApp: "SendTransactionResponse { txid }"
Loading

Reviews (2): Last reviewed commit: "fix: normalize bigint RPC inputs" | Re-trigger Greptile

Comment thread src/types.ts Resolved
thomas-kroes pushed a commit that referenced this pull request Jun 11, 2026
Mirror the type-coercion note from SendTransactionRequest.amount so the
two parallel interfaces document the same accepted runtime types
(legacy number + canonical string/bigint).

Addresses review feedback on PR #6.
claude and others added 5 commits July 31, 2026 14:16
Adds a public, read-only provider method so dApps can query the
required network fee for a simple send without duplicating wallet/WASM
transaction-building logic:

- PROVIDER_METHODS.ESTIMATE_TRANSACTION_FEE ('nock_estimateTransactionFee')
- EstimateTransactionFeeRequest / EstimateTransactionFeeResponse types
- NockchainProvider.estimateTransactionFee({ to, amount }) -> { fee }
  (fee in nicks, canonical string)

Also documents the optional-fee semantics on SendTransactionRequest:
when fee is omitted the wallet estimates it for the approval popup,
auto-calculates the exact fee at build time, and reports the actual
fee used in the response.

The method is API 1-only; compat v0 mapping passes it through untouched
(default case), which is intentional.
Mirror the type-coercion note from SendTransactionRequest.amount so the
two parallel interfaces document the same accepted runtime types
(legacy number + canonical string/bigint).

Addresses review feedback on PR #6.
@thomas-kroes
thomas-kroes force-pushed the feat/public-fee-estimation branch from d21922b to e2bffef Compare July 31, 2026 12:21
@cursor

cursor Bot commented Aug 17, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

@thomas-kroes thomas-kroes changed the title Feat/public fee estimation Feat: build unsigned simple transactions Aug 17, 2026
@h33p
h33p merged commit 95024ce into main Oct 7, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants