feat(lang): attach ref-backed policy script as a reference input#332
Merged
Conversation
When a policy declared with a `ref` UTxO is used as the `from` of an input, the lowering previously kept only the policy hash and discarded its script source. As a result the policy's reference-script UTxO never reached the transaction's `reference_inputs`, so the compiled Cardano tx had no way to find the script validating the spend. Capture the policy's `ref` at the lowering decision point and drain it into `Tx.references` once the tx body is lowered, deduped against explicit `reference` blocks and repeated policy uses. The Cardano backend already maps `Tx.references` to `reference_inputs`, so no backend change is needed. Scope: the input `from` path for ref-backed policies. Hash-only policies and non-address uses are unaffected (no-op). Mint/burn and embedded witness-set attachment remain out of scope. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add a checks variant to `test_lowering!` that binds the lowered TIRs (keyed by tx name) to an identifier, so an example can carry inline assertions instead of separate hand-rolled tests. Expand the policy_reference_script example to cover all three edge cases in one file (ref-backed `from`, dedup across two inputs, hash-only policy) and migrate the loose unit tests into the macro's checks block. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Extend reference-script tracking to mint and burn blocks: a ref-backed policy used as the policy of a minted or burned asset now contributes its `ref` UTxO to the transaction's reference inputs, just like a policy used as an input's `from`. Introduce a sticky `capture_policy_ref` context flag (carried through the `enter_*` transitions like `script_refs`) set over the mint/burn amount subtree. `Symbol::PolicyDef` captures the ref whenever the policy stands in for a script that must run — an address credential or a mint/burn policy — while still lowering to a plain hash outside address context. Expand the policy_reference_script example with mint/burn txs (ref-backed and hash-only) and corresponding checks. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
scarmuega
added a commit
that referenced
this pull request
Jun 7, 2026
PR #332 captured a ref-backed policy's `ref` UTxO whenever the policy appeared in an address position, keyed on `is_address_expr()`. But that flag is also set for an output's `to`, so sending funds *to* a script address wrongly pulled the policy's reference script into the transaction — the script does not run when receiving, only when spending. Drive the capture solely off the explicit `capture_policy_ref` signal, set at the script-executing sites: an input's `from` and mint/burn amounts. Output `to` keeps its address lowering but no longer captures. Add a `send_to_policy` example tx that outputs to a ref-backed policy without spending from it, asserting it contributes no reference input. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This was referenced Jun 7, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Context
Today a
policyin tx3 is effectively a named hash. You can declare a ref-backed policy:…and the
refis captured during lowering — but whenValidatoris used as thefromof aninput(spending a script-locked UTxO), the lowering threw the script source away and kept only the hash. As a result the policy'srefUTxO was never added to the transaction'sreference_inputs, so the compiled Cardano tx had no way to find the script that must validate the spend.This closes that gap for the flow:
policy P { hash, ref }Pasfromin aninputP'srefUTxO to appear in the compiled tx'sreference_inputsIn Cardano, including the ref UTxO (which carries the script) as a reference input is the complete and correct mechanism for a ref-backed policy — no witness-set script bytes are needed.
Changes
All in
crates/tx3-lang/src/lowering.rs:Contextgains a shared ref accumulator (Rc<RefCell<…>>) carried across everyenter_*clone, withrecord_script_ref/drain_script_refshelpers. Dedups on insert.Symbol::PolicyDeflowering — when a policy is used in address context, capturepolicy.script.as_utxo_ref()into the accumulator before returningBuildScriptAddress(hash). Hash-only policies yieldNone(no-op).TxDef::into_lowerrestructured to seed the accumulator with explicitreferenceblocks first, lower the body (which records policy refs), then drain intoTx.references. Explicit refs keep their leading position; coincident refs dedup to one entry.No backend change —
compile_reference_inputsintx3-cardanoalready mapsTx.references→ Cardanoreference_inputs.Scope
Input
frompath for ref-backed policies. Out of scope (noted for follow-up): mint/burn under a ref-backed policy, and embedded-script (witness-set) attachment.Verification
examples/policy_reference_script.tx3+ generated.tirsnapshot: ref UTxO appears inreferences, input resolves toBuildScriptAddress(hash).cargo test -p tx3-lang: 170 passed, 0 failed — all pre-existing snapshots byte-identical (no regressions).🤖 Generated with Claude Code