Skip to content

feat(wit): add nexum:value-flow types package v0.1.0#247

Merged
mfw78 merged 1 commit into
dev/m1from
feat/m1-wit-value-flow
Jul 15, 2026
Merged

feat(wit): add nexum:value-flow types package v0.1.0#247
mfw78 merged 1 commit into
dev/m1from
feat/m1-wit-value-flow

Conversation

@mfw78

@mfw78 mfw78 commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

What

Adds the nexum:value-flow WIT types package at 0.1.0, the shared,
dependency-free vocabulary for value in motion (settlement, asset,
asset-amount) that intent headers, simulation balance diffs, and analyser
verdicts will all use to describe a spend the same way.

  • Adds wit/nexum-value-flow/types.wit defining interface types with:
    • settlement: evm-chain(u64) | offchain(string)
    • service-desc: kind, summary
    • offchain-desc: domain, summary
    • asset: native-token(settlement) | erc20/erc721/erc1155 as
      (chain id, address[, id]) tuples | service(service-desc) |
      offchain(offchain-desc)
    • asset-amount: asset plus a big-endian unsigned-byte amount
  • The package carries no dependency (bare u64, no import of
    nexum:host/types), per the zero-dependency foundation mandate.
  • Adds a #[cfg(test)] wasmtime bindgen smoke in
    crates/nexum-runtime/src/bindings.rs that imports the interface through a
    throwaway inline world and names every generated type, variant, and field
    by its plain Rust spelling, enforcing the identifier-hygiene gate at
    compile time.

Why

This is the platform's hardest-freezing contract: the vocabulary for where a
deal settles, what asset moves, and how much of it, shared by intent
headers, simulation balance diffs, and analyser verdict subjects so a spend
is written the same way everywhere. Identifier hygiene is a freeze gate:
every identifier is checked against WIT keywords (including in-flight
proposals) and against the reserved words of the nine binding-target
languages, so a two-word kebab id is preferred wherever a single word is a
keyword anywhere (native-token not native, offchain not external).
Getting this package right now, before anything binds to it, avoids
escaped identifiers surfacing later in generated bindings for the personas
the SDK exists to serve.

Testing

  • cargo test --workspace (covers the new bindgen smoke test)
  • cargo fmt --all -- --check
  • cargo clippy --workspace --all-targets -- -D warnings

Red-teamed with no blocker or major findings. The identifier-hygiene gate
was confirmed sensitive by injecting a Rust-keyword field name (kind to
type), which forced an r# escape and failed compilation; the file was
then restored to the exact committed state (git diff HEAD empty).

AI Assistance

Claude (Opus) used for the implementation.

Closes #226

@mfw78 mfw78 force-pushed the fix/m1-sdk-sweep branch from 4cff6f2 to b13ab15 Compare July 7, 2026 23:12
@mfw78 mfw78 force-pushed the feat/m1-wit-value-flow branch from b153193 to 0f0ed06 Compare July 7, 2026 23:12
@mfw78 mfw78 force-pushed the fix/m1-sdk-sweep branch from b13ab15 to 769b1a1 Compare July 8, 2026 00:42
@mfw78 mfw78 force-pushed the feat/m1-wit-value-flow branch from 0f0ed06 to 5c11b93 Compare July 8, 2026 00:42
@mfw78 mfw78 force-pushed the fix/m1-sdk-sweep branch from 769b1a1 to ce23c56 Compare July 8, 2026 01:19
@mfw78 mfw78 force-pushed the feat/m1-wit-value-flow branch from 5c11b93 to 74e5e9c Compare July 8, 2026 01:19
@mfw78 mfw78 force-pushed the fix/m1-sdk-sweep branch from ce23c56 to 3f4c6da Compare July 8, 2026 01:44
@mfw78 mfw78 force-pushed the feat/m1-wit-value-flow branch from 74e5e9c to 3ce6d08 Compare July 8, 2026 01:44
@mfw78 mfw78 force-pushed the fix/m1-sdk-sweep branch from 3f4c6da to 69fcae9 Compare July 8, 2026 02:10
@mfw78 mfw78 force-pushed the feat/m1-wit-value-flow branch from 3ce6d08 to 6b6d8d6 Compare July 8, 2026 02:10
@mfw78 mfw78 force-pushed the fix/m1-sdk-sweep branch from 69fcae9 to ddc7774 Compare July 8, 2026 02:19
@mfw78 mfw78 force-pushed the feat/m1-wit-value-flow branch from 6b6d8d6 to b07179d Compare July 8, 2026 02:19
@mfw78 mfw78 force-pushed the fix/m1-sdk-sweep branch from ddc7774 to a640b7a Compare July 8, 2026 02:23
@mfw78 mfw78 force-pushed the feat/m1-wit-value-flow branch 2 times, most recently from 924d20c to fbcf754 Compare July 8, 2026 03:03
@mfw78 mfw78 force-pushed the fix/m1-sdk-sweep branch from 2176ef6 to 851e779 Compare July 8, 2026 04:59
@mfw78 mfw78 force-pushed the feat/m1-wit-value-flow branch from fbcf754 to f7de776 Compare July 8, 2026 04:59
@mfw78 mfw78 force-pushed the fix/m1-sdk-sweep branch from 851e779 to a35e537 Compare July 8, 2026 05:31
@mfw78 mfw78 force-pushed the feat/m1-wit-value-flow branch from f7de776 to b80c646 Compare July 8, 2026 05:31
@mfw78 mfw78 force-pushed the fix/m1-sdk-sweep branch from a35e537 to 7f4ee70 Compare July 8, 2026 06:21
@mfw78 mfw78 force-pushed the feat/m1-wit-value-flow branch from b80c646 to 1f82918 Compare July 8, 2026 06:21
@mfw78 mfw78 force-pushed the fix/m1-sdk-sweep branch from 7f4ee70 to e5454cd Compare July 8, 2026 06:40
@mfw78 mfw78 force-pushed the feat/m1-wit-value-flow branch from 1f82918 to 54e8a9a Compare July 8, 2026 06:40
@mfw78 mfw78 force-pushed the fix/m1-sdk-sweep branch from e5454cd to a7ba3d3 Compare July 8, 2026 07:07
@mfw78 mfw78 force-pushed the feat/m1-wit-value-flow branch from 54e8a9a to bd20a66 Compare July 8, 2026 07:07
@mfw78 mfw78 force-pushed the fix/m1-sdk-sweep branch from a7ba3d3 to 565c768 Compare July 8, 2026 07:21
@mfw78 mfw78 force-pushed the feat/m1-wit-value-flow branch from bd20a66 to ea71759 Compare July 8, 2026 07:21
@mfw78 mfw78 force-pushed the fix/m1-sdk-sweep branch from 565c768 to 296102e Compare July 8, 2026 07:36
@mfw78 mfw78 force-pushed the feat/m1-wit-value-flow branch from ea71759 to 371ce2c Compare July 8, 2026 07:36
@mfw78 mfw78 force-pushed the fix/m1-sdk-sweep branch from 296102e to 572452a Compare July 8, 2026 07:46
@mfw78 mfw78 force-pushed the fix/m1-sdk-sweep branch from 3e99bc7 to 90f051f Compare July 8, 2026 08:55
@mfw78 mfw78 force-pushed the feat/m1-wit-value-flow branch from 042fc45 to b382ce3 Compare July 8, 2026 08:55
@mfw78 mfw78 force-pushed the fix/m1-sdk-sweep branch from 90f051f to 9e2a2ce Compare July 8, 2026 09:02
@mfw78 mfw78 force-pushed the feat/m1-wit-value-flow branch from b382ce3 to a094a83 Compare July 8, 2026 09:02
@mfw78 mfw78 force-pushed the fix/m1-sdk-sweep branch from 9e2a2ce to 978b1bd Compare July 8, 2026 09:18
@mfw78 mfw78 force-pushed the feat/m1-wit-value-flow branch from a094a83 to ca289a0 Compare July 8, 2026 09:18
@mfw78 mfw78 force-pushed the fix/m1-sdk-sweep branch from 978b1bd to 9d1db95 Compare July 8, 2026 12:10
@mfw78 mfw78 force-pushed the feat/m1-wit-value-flow branch from ca289a0 to 94b8bc9 Compare July 8, 2026 12:10
@mfw78 mfw78 force-pushed the fix/m1-sdk-sweep branch from 9d1db95 to ff616ec Compare July 8, 2026 12:20
@mfw78 mfw78 force-pushed the feat/m1-wit-value-flow branch from 94b8bc9 to 84afc84 Compare July 8, 2026 12:20
@mfw78 mfw78 force-pushed the fix/m1-sdk-sweep branch from ff616ec to 73029f4 Compare July 8, 2026 12:50
@mfw78 mfw78 force-pushed the feat/m1-wit-value-flow branch from 84afc84 to 043b770 Compare July 8, 2026 12:50
@mfw78 mfw78 force-pushed the fix/m1-sdk-sweep branch from 73029f4 to 374d085 Compare July 8, 2026 13:40
@mfw78 mfw78 force-pushed the feat/m1-wit-value-flow branch from 043b770 to 0c264f1 Compare July 8, 2026 13:41
@mfw78 mfw78 force-pushed the fix/m1-sdk-sweep branch from 374d085 to 5740e54 Compare July 8, 2026 13:59
@mfw78 mfw78 force-pushed the feat/m1-wit-value-flow branch from 0c264f1 to 0786338 Compare July 8, 2026 13:59
@mfw78 mfw78 force-pushed the fix/m1-sdk-sweep branch from 5740e54 to a8430a4 Compare July 8, 2026 14:08
@mfw78 mfw78 force-pushed the feat/m1-wit-value-flow branch from 0786338 to cefe6e8 Compare July 8, 2026 14:09

@lgahdl lgahdl left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Clean package and good hygiene gate. Three items below.

Comment on lines +60 to +66
/// `native-token` wraps `settlement` because a chain's own gas token is
/// the one asset that exists on every settlement domain. Each token
/// tuple carries raw big-endian bytes: a 20-byte address, and for the
/// NFT cases a token id of arbitrary width.
variant asset {
/// The settlement domain's own gas token (ETH, BZZ, ...).
native-token(settlement),

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Two issues with native-token(settlement):

  1. The BZZ example is wrong. BZZ is an ERC-20 on Ethereum/Gnosis Chain, not the native gas token of any chain. Correct examples: ETH, xDAI, MATIC, BNB.

  2. native-token(offchain(...)) is a structurally valid but semantically empty combination. No real domain has an off-chain-settled native gas token; an analyser receiving this case has no oracle, no AMM pool, and no contract address to price against. The rationale for wrapping settlement is that each EVM chain has its own native token — that maps only to settlement::evm-chain. Either restrict native-token to hold a bare u64 (consistent with ERC cases), or add a comment explicitly forbidding the offchain arm and stating what consumers must do if they see it.

Comment on lines +68 to +72
erc20(tuple<u64, list<u8>>),
/// An ERC-721 NFT: (chain id, 20-byte contract address, token id).
erc721(tuple<u64, list<u8>, list<u8>>),
/// An ERC-1155 token: (chain id, 20-byte contract address, token id).
erc1155(tuple<u64, list<u8>, list<u8>>),

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The ERC cases use anonymous positional tuples for a package described as the "hardest-freezing contract." The second position (address) is already opaque; at a frozen interface, adding a third field means a semver bump even for optional metadata. Named records would make positions self-documenting and leave room for a non-breaking extension:

record evm-token   { chain-id: u64, address: list<u8> }
record evm-nft     { chain-id: u64, address: list<u8>, token-id: list<u8> }

erc20(evm-token),
erc721(evm-nft),
erc1155(evm-nft),

This is easier pre-freeze than post.

/// field holds the pair (a header's `gives` vs `wants`), not here.
record asset-amount {
asset: asset,
amount: list<u8>,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The amount field is missing its doc comment — the encoding convention (big-endian, empty = zero, no negative) is documented on the record but not on the field itself. WIT tooling renders field docs separately.

Suggested change
amount: list<u8>,
/// Big-endian unsigned integer, most-significant byte first; empty encodes zero.
amount: list<u8>,

@mfw78 mfw78 force-pushed the feat/m1-wit-value-flow branch from cefe6e8 to 31f524f Compare July 8, 2026 22:33
@mfw78 mfw78 force-pushed the fix/m1-sdk-sweep branch 2 times, most recently from 1795182 to f7f2f3a Compare July 8, 2026 23:05
@mfw78 mfw78 force-pushed the feat/m1-wit-value-flow branch 2 times, most recently from a8b7932 to e04f395 Compare July 8, 2026 23:24
@mfw78 mfw78 force-pushed the fix/m1-sdk-sweep branch from f7f2f3a to 8d59644 Compare July 8, 2026 23:24
@mfw78 mfw78 force-pushed the feat/m1-wit-value-flow branch from e04f395 to c0ffbc5 Compare July 8, 2026 23:29
@mfw78 mfw78 force-pushed the fix/m1-sdk-sweep branch 2 times, most recently from acaa0f8 to 4e2ce66 Compare July 9, 2026 02:09
@mfw78 mfw78 force-pushed the feat/m1-wit-value-flow branch from c0ffbc5 to 1e89474 Compare July 9, 2026 02:09
Add the egress-neutral value-flow vocabulary at 0.1.0: the settlement
domain (evm-chain or offchain), the asset variant (native-token, erc20,
erc721, erc1155, service, offchain), the service and offchain
descriptors, and the big-endian asset-amount. The package is
dependency-free so it can outlive any interface built on it.

Every identifier is vetted against WIT keywords, in-flight component-model
proposals, and the nine binding-target reserved-word lists, preferring a
two-word kebab id wherever a single word is a keyword anywhere:
native-token over native (a Java modifier), offchain over external (a
Dart keyword), value-flow over value (value-imports is circling that
word). A wasmtime bindgen smoke, compiled under test in the host crate
through a throwaway world, names every generated type and field by its
plain Rust spelling so a keyword collision surfaces as an escaped
identifier and fails the build rather than a downstream binding.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr-train Part of the current stacked PR train; lands in sequence, do not merge out of order.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants