Skip to content

feat(options): v0.2.0 — curated transfer builder + rehydration helper (#1288) - #2

Merged
MichaelTaylor3d merged 1 commit into
mainfrom
loop/1288-transfer-builder/impl
Jul 20, 2026
Merged

feat(options): v0.2.0 — curated transfer builder + rehydration helper (#1288)#2
MichaelTaylor3d merged 1 commit into
mainfrom
loop/1288-transfer-builder/impl

Conversation

@MichaelTaylor3d

@MichaelTaylor3d MichaelTaylor3d commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Closes DIG-Network/dig_ecosystem#1288.

What

Two additive v0.2.0 builders (SPEC.md §5.6/§5.7; §5.1 additive — no existing symbol edited):

  1. transfer(ctx, owner, created, new_owner_puzzle_hash) -> OptionSpend — curated option-ticket transfer, composing OptionContract::transfer so dig-wallet-backend stops reaching past dig-options into the SDK primitive (Appendix B: the expert crate owns option lifecycle logic). Returns the re-homed option as created: Some(..); a wrong-party Standard owner is rejected up front.
  2. rehydrate(option, terms, underlying_coin) -> CreatedOption + parse_metadata(ctx, launcher_solution) -> OptionMetadata — reconstruct a full, operable CreatedOption from on-chain state. v0.1.0 parse/parse_child recover only identity fields; rehydrate rebuilds the OptionUnderlying from caller-supplied creator ph + metadata-recovered expiry/strike + the observed underlying coin, and VERIFIES it against the option's on-chain commitments (1-of-2 path hash, delegated-puzzle hash, underlying coin id). A wrong term is rejected with InvalidInput — never a handle that builds an unspendable bundle. This unblocks transfer AND exercise of previously-minted options (dig-wallet-backend#12, Lane dig_ecosystem#1123).

New public surface: transfer, rehydrate, parse_metadata, RehydratedTerms, OptionMetadata (re-export).

How verified

  • 20 tests green (4 new). Real spend/coin structure asserted, not just no-error:
    • transfer_moves_option_then_new_owner_exercises — mint→transfer bob→carol→carol exercises; asserts new p2 hash, confirmed re-homed coin, and value conservation (carol nets underlying−strike, original creator alice receives the strike).
    • transfer_rejects_wrong_owner — up-front guard.
    • rehydrate_recovers_operable_option — reconstruct purely from on-chain state (parse singleton, parse_metadata from launcher solution, fetch underlying coin), assert recovered terms == minted, then EXERCISE the rehydrated handle to prove operability.
    • rehydrate_rejects_wrong_creator — wrong creator ph rejected at the 1-of-2 path check.
  • cargo fmt --check, cargo clippy --all-targets -D warnings, cargo doc --no-deps all clean.

Blast radius (gitnexus disabled — ripgrep + reads)

Purely additive: two new modules (transfer.rs, rehydrate.rs) + lib.rs re-exports + SPEC/CHANGELOG/version. No existing symbol edited (confirmed by diff); create/exercise/clawback/parse untouched. Reuses SDK OptionContract::transfer, OptionContract::parse_metadata, OptionUnderlying — no hand-rolled puzzle logic. Level-00 foundation crate: no DIG-crate deps added.

Bump rationale

0.1.0 → 0.2.0 (minor) — new public capability, fully additive, no breaking change (§2.4 SemVer). Release-first: merge cuts the v0.2.0 crates.io tag; dig-wallet-backend adopts on its follow-up.

Branch HEAD: 056520a

@MichaelTaylor3d
MichaelTaylor3d force-pushed the loop/1288-transfer-builder/impl branch from 04110e2 to 056520a Compare July 20, 2026 14:43
@MichaelTaylor3d
MichaelTaylor3d marked this pull request as ready for review July 20, 2026 14:44

@MichaelTaylor3d MichaelTaylor3d left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

REVIEW GATE — PASS (verdict recorded as a comment; self-approval is a 422, branch protection needs 0 approvals)

Reviewed @ 056520a as a fresh, skeptical, security-critical (spend-building/custody) gate. Verdict: PASS.

Scope & spec

  • Matches #1288 + the scope-expansion comment exactly: curated transfer(ctx, owner, created, new_owner_puzzle_hash) -> Result<OptionSpend> + rehydrate / parse_metadata. API shape matches the dig-wallet-backend#12 seam (build_transfer_option / build_exercise_option).
  • SPEC.md §§1/4/5.6/5.7/7/8 updated in-unit, normative voice, no drift from the code. CHANGELOG + rustdoc on every new item. 0.1.0 → 0.2.0 (minor) correct for additive capability.

§5.1 additive discipline

Diff touches only new files (src/transfer.rs, src/rehydrate.rs) + mod/pub use/rustdoc in lib.rs + CHANGELOG/Cargo/SPEC/tests. create/exercise/clawback/parse/parse_child bodies are untouched — no existing symbol changed, renamed, or repurposed.

Adversarial custody verification (all lenses clear)

  • Verified-not-trusted (rehydrate): the reconstructed 1-of-2 path hash binds launcher_id + creator_ph + expiry + amount + strike to underlying_coin.puzzle_hash; the delegated-puzzle hash and underlying_coin_id are independently checked. Any wrong term changes a committed hash → InvalidInput, never an operable-but-mistargeted handle. Covered by rehydrate_rejects_wrong_creator.
  • Fund-safety (transfer): faithfully composes OptionContract::transfer — SDK emits the recipient hint; only the singleton re-homes at the same amount; the underlying + terms are untouched. Wrong-party Standard owner rejected up front; Custom correctly documented as consensus-enforced (PH not derivable).
  • Keys/custody: key-free types throughout; both new fns are pure builders (no signing, no I/O, no key held).
  • Back-compat/replay: additive only; no wire/format/parse change.

Gates

CI green (Format/Clippy/Build/Docs, Coverage >=80%, version-increment, commitlint, CodeQL rust + js). cargo test locally: 20/20 pass. Zero open review threads, no GHAS findings.

Non-gating observation (does NOT block merge)

src/types.rs OptionSpend doc (~L130-138) and CreatedOption doc (~L109-115) still read as if created is Some only for create and terms are unrecoverable — now also true of transfer (returns Some) and lifted by rehydrate. Cosmetic doc-drift; safe to tidy opportunistically in a later touch, not a blocker for this PR.

Add two additive builders (SPEC.md §5.6/§5.7, §5.1-compatible):

- transfer(ctx, owner, created, new_owner_puzzle_hash): move the option ticket
  to a new owner, composing OptionContract::transfer so consumers stop reaching
  past dig-options into the SDK primitive. Returns the re-homed option as the
  created handle; guards a wrong-party Standard owner up front.
- rehydrate(option, terms, underlying_coin) + parse_metadata(ctx, launcher_solution):
  reconstruct a full, operable CreatedOption from on-chain state, VERIFIED against
  the option's commitments. Per the chia-wallet-sdk 0.30 OptionUnderlying derivation
  the three checks bind disjoint field sets and are jointly load-bearing: the 1-of-2
  path hash (launcher id + expiry + creator ph only) catches a wrong creator hash;
  the delegated-puzzle hash catches a wrong strike type (and amount); the coin-id
  check rejects a substituted same-shape coin. A wrong term is rejected, never
  yields an unspendable handle.

Tests (22 green): transfer round-trip + wrong-owner guard; rehydrate round-trip +
wrong-creator/wrong-strike/wrong-amount rejections. clippy -D warnings clean.

Closes #1288.

Co-Authored-By: Claude <noreply@anthropic.com>
@MichaelTaylor3d
MichaelTaylor3d force-pushed the loop/1288-transfer-builder/impl branch from 056520a to bddfa1b Compare July 20, 2026 15:02
@MichaelTaylor3d
MichaelTaylor3d merged commit f28d9a3 into main Jul 20, 2026
7 checks passed
@MichaelTaylor3d
MichaelTaylor3d deleted the loop/1288-transfer-builder/impl branch July 20, 2026 15:12
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