Skip to content

Declarative manifest resource model and asset-safe execution - #37

Merged
jonatns merged 8 commits into
mainfrom
apply
Aug 14, 2026
Merged

Declarative manifest resource model and asset-safe execution#37
jonatns merged 8 commits into
mainfrom
apply

Conversation

@jonatns

@jonatns jonatns commented Aug 14, 2026

Copy link
Copy Markdown
Owner

Summary

alkanes.hcl becomes a full deployment resource model, and the executor gains three safety fixes that make exact-asset contract flows work end to end.

Manifest resource model

  • alkane blocks bind names to external on-chain ids — no deploy, no dependency edge. Ids are one [block, tx] binding for every network or a per-network map (id = { regtest = [4, 65012], signet = [2, 190213] }, keys validated against known networks); plan fails fast when the active network is unbound, before compiling or touching the chain.
  • Namespaced references: contract.<name>.<field> orders that deploy first, alkane.<name>.<field> resolves immediately; fields id/block/tx. Unknown names and the old bare name.id form are parse errors with migration hints.
  • Named args matched to ABI parameter names (args = { underlying = contract.fire.id, ... }), reordered before encoding; hard error without a typed opcode-0 constructor. AlkaneId params take whole references and flatten to two cellpack fields in the encoder.
  • plan/apply (CLI + MCP) reconcile against labcoat.lock, the per-network call journal, and live chain state; spec hashes canonicalize named args order-independently.
  • Scaffold, SKILL guidance, and the covered-call example teach the deployment-only principle: the manifest is done when the topology is correct and inert; value-moving operations live in tests/e2e.rs.

Executor behavior changes (review these as decisions)

  1. Funding never spends token-bearing UTXOs unless the transaction explicitly requires those alkanes. Outpoints come from protorunes_by_address (the wallet's has_alkanes flag is never populated on this stack). Previously a deploy could sweep a 546-sat dust output carrying freshly minted tokens and burn them.
  2. No implicit DIESEL mint (skip_diesel_mint: true). The mint landed on the same pointer output as the transaction's own tokens, so every minted UTXO carried a stray asset that strict contracts reject. Wallets no longer accumulate DIESEL as a side effect.
  3. Exact alkane inputs via a splitter protostone. Upstream's alkanes-change handling is hard-disabled (&& false /* DISABLED */ in alkanes-cli-common), so calls received whole UTXO balances (e.g. 10,000 tUSD into a contract expecting exactly 7,500). Calls with alkane requirements now prepend an edict-only protostone that forwards exact amounts to the call (p1) and returns excess to output 0; caller pN references shift accordingly. The durable fix belongs upstream — this is a spec-layer workaround with an exit path.

Verification

  • 150 workspace tests, clippy clean on --all-targets, sync-reference.mjs --check clean.
  • Real-world validation: the strata covered-call two-wallet e2e (labcoat test --e2e) passes end to end against this branch — typed-AlkaneId named-arg deploys, funding, CALL transfer, exercise with correct 2,500 tUSD change, redeem, and all balance assertions.

Follow-ups

  • File an upstream issue for the disabled alkanes-change handling and drop the splitter once fixed.
  • Re-pin strata's labcoat-test dependency from its local path to this branch's rev.

🤖 Generated with Claude Code

jonatns and others added 5 commits August 14, 2026 17:02
Three executor behavior changes, all validated by the strata covered-call
e2e against a live Labcoat Network:

- Funding selection now excludes UTXOs the alkanes indexer reports as
  carrying tokens (protorunes_by_address; the wallet's has_alkanes flag is
  never populated on this stack), except outpoints holding an alkane the
  transaction explicitly requires. Deploys could previously spend a
  token-bearing dust output as plain bitcoin and burn the tokens.
- No implicit DIESEL mint (skip_diesel_mint: true): the mint landed on the
  same pointer output as the transaction's own tokens, contaminating every
  minted UTXO with a stray asset that strict contracts reject.
- Calls with alkane input requirements get a prepended edict-only splitter
  protostone that forwards exactly the required amounts to the call (p1)
  and returns excess to output 0. The upstream executor's alkanes-change
  handling is hard-disabled, so contracts otherwise receive whole UTXO
  balances. Caller pN references are shifted for the extra protostone.

Also carries the TxOptions/spec_with_options plumbing the manifest apply
engine builds on.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
alkanes.hcl gains a full resource model:

- alkane blocks bind names to external on-chain ids: no deploy, no
  dependency edge. Ids are one [block, tx] binding for every network or a
  per-network map (id = { regtest = [...], signet = [...] }) validated
  against the known network targets; plan fails fast when the active
  network is unbound.
- References are namespaced: contract.<name>.<field> creates a deploy
  ordering edge, alkane.<name>.<field> resolves immediately; fields are
  id/block/tx. Unknown names and the old bare form are parse errors with
  migration hints.
- Constructor and call args may be named objects matched to ABI parameter
  names (reordered before encoding; hard error without a typed opcode-0
  constructor). AlkaneId params take whole id references and flatten to
  two cellpack fields in the encoder.
- Raw cellpack fallbacks reject block:tx-shaped values instead of silently
  encoding their ASCII bytes into one u128.

plan/apply reconcile against labcoat.lock, the per-network call journal,
and live chain state; alkane ids seed resolution up front and spec hashes
canonicalize named args order-independently.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…est model

- labcoat plan / labcoat apply --broadcast (with --manifest override) and
  matching MCP tools.
- Scaffold template ships a deployment-only alkanes.hcl (the manifest is
  done when the topology is correct and inert; usage calls belong in
  tests/e2e.rs) plus an e2e starter test.
- MANIFEST_INVALID guidance and regenerated CLI reference.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
labcoat_test::e2e drives labcoat test --e2e flows: lockfile-resolved
contracts, disposable faucet-funded wallets, fluent Deploy/Call builders
with inputs/to/pointer/refund/edicts, balances, and mining helpers.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The covered-call example shows the full resource model: an external
alkane binding for the buyer-deployed tUSD, named AlkaneId constructor
args, and a deployment-only manifest with every value-moving step in
tests/e2e.rs. SKILL guidance documents namespaced references,
per-network ids, named args, and the deployment-only principle.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@vercel

vercel Bot commented Aug 14, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
labcoat-web Ready Ready Preview Aug 14, 2026 9:37pm

jonatns and others added 2 commits August 14, 2026 17:25
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- pnpm 11.13.0 was retroactively marked a broken release upstream
  (ERR_PNPM_BROKEN_PNPM_RELEASE); pin the current latest 11.21.0.
- Fix the two latent shellcheck findings actionlint reports in ci.yml
  (unused loop variable; single-quoted regex false positive). They only
  surface when the web job runs, which this branch is the first to
  trigger since the actionlint pin.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Freshly scaffolded projects resolve the latest transitive deps, and icu 2.3
(via url/idna) now requires rustc 1.88 — the project-smoke job and any new
user project fail on 1.86. A newer rustc still builds the pinned alkanes-rs
rev; TOOLCHAIN.md documents the deviation from upstream's pin. Includes the
clippy 1.88 uninlined_format_args fixes across the workspace.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@jonatns
jonatns merged commit 2c207ea into main Aug 14, 2026
6 checks passed
@jonatns
jonatns deleted the apply branch August 17, 2026 22:40
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