Skip to content

contracts: the contract engine, in the kit and its wasm build - #35

Merged
GracedEternalKingCabbageMan merged 1 commit into
sequentiafrom
feature/contract-engine
Oct 8, 2026
Merged

GracedEternalKingCabbageMan merged 1 commit into
sequentiafrom
feature/contract-engine

Conversation

@GracedEternalKingCabbageMan

Copy link
Copy Markdown
Collaborator

The kit's contract engine, lwk_contracts, and its wasm bindings: a wallet can now read a sequentia-contracts template, recognise an instance's output and spend one of its paths.

What it does

  • Reads descriptors (versions 1 and 2) with sequentia-contracts' own reader (pinned at ad8ed18) and checks them with the pinned compiler (simplicityhl 0.7.2) from resolved source texts (Descriptor::validate_sources, contracts doc: point every repository link at the ConcatenaLabs organisation #13/doc: add the standing documentation rules #14), so it runs in a browser.
  • Recomputes an instance's output, address and control blocks; lists each path and what it needs (witness values, the signing key, a tapscript's relative lock or lock time).
  • Builds the spend of a chosen path from a request. It refuses:
    • an output the request mislabels (a "return to the contract" that pays another script, a "pay this wallet" that is not the wallet's);
    • a confidential output, a missing or second fee, and outputs that do not balance the coin;
    • a relative lock (BIP68) or lock time the chain would refuse now.
  • Signs only with a contract key under m/8383h/{coin}h/0h (the Simplex fork's account), and only the key the path names. Runs the program against the final transaction (naming the source check that fails), and pads with an annex under the budget rule (ported from the Simplex fork).
  • drip::plan: the faucet drip covenant's tier, interval and successor, as its program checks them.
  • Carries sequentia/one-key, one-key-exit and faucet-drip, their vectors and the refusal corpus (templates/PIN.json).
  • lwk_wasm: ContractTemplate, ContractInstance, ContractSpend. build-web.sh builds the browser package with build-machine paths remapped, and fails if one remains.
  • CI: a contracts job.

Why the SDK is not a dependency: smplx-sdk needs Rust 1.87; the kit pins 1.85. The engine therefore uses the SDK's libraries directly. Lock changes: bitcoin_hashes 0.14.0→0.14.1, semver 1.0.27→1.0.28, psm held at 0.1.26. simplicity-sys 0.7 links beside lwk_simplicity's 0.6 (versioned C symbols).

Proof (node v25.2.1, elementsregtest, Simplicity from genesis, -par=1)

  • cargo test -p lwk_contracts: all 30 vectors reproduced (one_key 6, one_key_exit 10, faucet_drip 8, v2 fixture 6); 75 refusals made for their reason, 1 accepted; budget padding equals S1.2's 742-byte case. Before this change: package ID specification lwk_contracts did not match any packages.
  • wasm (--target nodejs): contract_vectors.js gives the same counts.
  • SEQUENTIA_BIN=… cargo test -p lwk_contracts --test drip_regtest:
    • a drip confirms at 581 vB / 2,323 WU (the template's measured size); cost 422,597 milli-WU of a 5,466 WU budget;
    • a second drip before the interval: the engine refuses (non-BIP68-final); forced, mempool non-BIP68-final, block TestBlockValidity failed: bad-txns-nonfinal;
    • a drip one atom above the tier: the planner refuses, and the program run refuses the check that fails is assert!(jet::le_64(drip, tier(reserve, floors, maxes))); forced, mempool and block Assertion failed inside jet;
    • a successor paid to another script: the accounting refuses, and the program run refuses (assert!(jet::eq_256(script, script_hash))); forced, the same block error;
    • another wallet's key and a key outside the contract account are refused.
  • Release web build: 17,392,427 bytes, no build-machine path.
  • Existing wasm suites arca_signers.js and ark_records.js pass.

A wallet that holds a key a contract names had no way to read the
contract, recognise its output or spend it: lwk_simplicity handles one
leaf with no tree, no annex, no budget check and no fee asset, and it is
in no shipped wasm build.

lwk_contracts reads a sequentia-contracts descriptor (versions 1 and 2)
with that repository's own reader, and checks it with its pinned
compiler from the resolved source texts it is handed, so it runs in a
browser. It recomputes an instance's output, address and control blocks
exactly as the golden vectors and the other readers do, lists each
spending path and what it needs, and builds the spend of a chosen path
from a request: it refuses an output the request mislabels, a
confidential output, a missing or second fee and unbalanced outputs, and
a lock the chain would refuse now. It signs only with a contract key
(m/8383h/{coin}h/0h, the Simplex fork's account) and only the one the
path names, runs the program against the final transaction (naming the
source check that fails when it refuses), and pads under the budget rule.
The faucet drip covenant has a planner for its tier, interval and
successor.

The kit carries the three published templates, their vectors and the
refusal corpus, pinned in templates/PIN.json. The Simplex SDK needs Rust
1.87 against the kit's 1.85, so the engine uses its libraries directly
and ports its budget rule; that moved bitcoin_hashes and semver one
patch each and held psm at 0.1.26.

lwk_wasm exposes ContractTemplate, ContractInstance and ContractSpend.
build-web.sh builds the browser package with every build-machine path
remapped and fails if one remains. CI gains a contracts job.
@GracedEternalKingCabbageMan
GracedEternalKingCabbageMan merged commit 0b8721c into sequentia Oct 8, 2026
12 of 18 checks passed
@GracedEternalKingCabbageMan
GracedEternalKingCabbageMan deleted the feature/contract-engine branch October 8, 2026 02:45
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.

1 participant