Skip to content

Documenting Gaps with the built-in policy object in practice #299

@Crypto2099

Description

@Crypto2099

policy object ergonomics — property access, asset binding, and auto-witness

Summary

The policy constructor supports hash, script, and ref fields, but these fields are currently only used as metadata in the TII output. They can't be referenced from expressions, can't be used in asset definitions, and aren't leveraged by the compiler to reduce boilerplate. This makes the constructor form only marginally more useful than the assign form (policy X = 0x...).

Current behavior

policy NativeScriptPolicy {
    hash: 0xbd3ae991...777,
    script: 0x820181820400,
}

// Can't reference the policy name in asset definitions
asset NativeToken = NativeScriptPolicy."NATIVE";           // ERROR: invalid type (Undefined)
asset NativeToken = 0xbd3ae991...777."NATIVE";             // must repeat the hex literal

// Can't access sub-fields in expressions
cardano::native_witness {
    script: NativeScriptPolicy.script,                     // ERROR: not in scope: script
    script: 0x820181820400,                                // must repeat the hex literal
}

// Policy name resolves to hash in expressions (this works)
mint {
    amount: AnyAsset(NativeScriptPolicy, "NATIVE", 10),   // OK — resolves to hash
}

This means that when defining a policy with script: or ref:, the user must manually repeat those same values in asset definitions, cardano::native_witness, cardano::plutus_witness, and reference blocks. The policy object doesn't reduce duplication.

Missing validation: policy constructor without hash passes check but crashes build

The grammar allows a policy constructor with any subset of fields, so this is valid syntax:

policy ScriptOnly {
    script: 0x820181820400,
}

trix check passes — the analyzer doesn't validate that hash is present. But trix build panics at the lowering stage:

called `Result::unwrap()` on an `Err` value: InvalidAst("Missing policy hash")

The analyzer should either:

  • Require hash in every policy constructor and emit a diagnostic if it's missing, or
  • Derive the hash from the script CBOR when only script is provided (which would also address the ergonomic gap of needing to know/specify both)

Proposed improvements

  • Validate hash field in analyzer — A policy constructor without hash should produce a clear error at trix check time, not a panic at trix build time
  • Property access on policy objects — Allow MyPolicy.hash, MyPolicy.script, MyPolicy.ref as expressions so policy fields can be referenced without repetition
  • asset definitions accept policy namesasset Token = MyPolicy."NAME" should resolve MyPolicy to its hash, the same way AnyAsset(MyPolicy, ...) already does in tx bodies
  • asset definitions accept env varsasset Token = my_env_var."NAME" currently fails type resolution when my_env_var is a Bytes env var
  • Auto-witness injection (stretch) — When the compiler sees a mint referencing a policy that has a script: field, it could automatically inject the corresponding cardano::native_witness or cardano::plutus_witness block. Similarly for ref: and reference blocks. This would be the biggest ergonomic win but also the most complex change.

Workaround

Today, users must duplicate hex literals across the policy definition and the tx body. The policy_variants.tx3 example documents this pattern with comments explaining the limitation.

Context

Discovered while auditing example coverage for all grammar features. The policy_def_constructor grammar rule supports subsets of fields (hash-only, hash+script, hash+ref), but the value of defining these extra fields is limited without being able to reference them.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Status

    No status

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions