Cardano Adapter
Status: prototype, last checked 2026-11-02. Source: cardano-invoicing dev at bbbe39b. Not audited, no mainnet deployment. main is behind dev and still has the older validator in placeholder.ak.
The prototype is a Plutus V3 spending validator written in Aiken , with TypeScript scripts for the preview testnet. It is not yet connected to SPORE or SPAWN.
Destinations are script addresses
Cardano has no CREATE2 and no deployment step. A script address comes from the hash of the compiled validator with its parameters applied, so the address is known as soon as the parameters are. Funds can be sent to it right away, and the script code is supplied when the funds are spent.
This has a few consequences:
- Changing any parameter gives a new address. The expiry is a parameter, so changing the deadline does too.
- Recompiling with a different compiler or dependency can change the hash. A commitment has to pin the compiled code as well as the source.
- The payment credential comes from the script, and an address can also carry a stake credential. Agree on the full address, not only the script hash.
Binding a chain-neutral SPAWN commitment to this address is not designed yet. One candidate is deriving the invoice_id parameter from the commitment.
Parameters
| Parameter | Type | Purpose |
|---|---|---|
payer | Address | Gets the refund on cancel |
expiry | Int | POSIX time in milliseconds when cancel opens |
recipient | Address | Gets the funds on complete |
admin | VerificationKeyHash | May use the rescue path |
policy | PolicyId | Policy of the invoice asset |
value | Int | Required quantity |
asset_name | ByteArray | Name of the invoice asset |
invoice_id | ByteArray | Identifier checked on complete |
The scripts attach an empty inline datum, and the validator ignores it. All state lives in the parameters.
Spend paths
| Redeemer | Allowed when | Result |
|---|---|---|
Complete { invoiceId } | Id matches, the input holds exactly value, every output goes to recipient, and no other assets leave | Pays the recipient |
Cancel | After expiry, every output goes to payer, and no other assets leave | Refunds the payer |
Rescue | admin signs and no output contains the invoice asset | Recovers UTxOs without the invoice asset |
Any other script purpose fails.
Known limits
Read these before calling the contract escrow. They come from reading the validator and have not been confirmed by a transaction on testnet.
- Complete has no condition beyond the id. It needs no signature from the payer, and the id is visible once the script is. Anyone can send locked funds to the recipient at any time. That can’t divert funds, but it doesn’t support milestone or approval-based release either.
- A wrong amount waits for expiry. A UTxO that doesn’t hold exactly
valuecan’t complete. Its only exit is cancel after expiry. - Mixed UTxOs can get stuck. A UTxO holding the invoice asset plus an asset under another policy fails complete and cancel, and rescue requires that the invoice asset not appear in any output. With an asset nobody can burn, such as a real stablecoin, that UTxO has no way out. Wallets and payment links must not bundle other assets into the locking output.
- Rescue trusts the admin for any UTxO at the address without the invoice asset, including its ADA.
- All outputs must go to one address. Change from whoever submits the transaction goes to the recipient or payer as well, which complicates relayers and third-party fee payment.
Assets and fees
Every UTxO has to carry minimum ADA alongside native assets. The tests lock 2 ADA next to the invoice asset. The scripts use a one-signature test token, not a stablecoin, so real stablecoin behavior is untested. Execution units from the unit tests are recorded in the repo, though real transaction costs have not been published.
Testing
| Item | State |
|---|---|
| Unit tests | 10 of 10 recorded as passing in benchmarks.json, not re-run for this page |
| Preview scripts | setup, lock, complete and cancel exist. Rescue is not covered |
| Recorded preview transactions | None in the repo |
| Indexer, confirmation policy, receipts | Not built. The scripts use Blockfrost |
Standards
There is no ratified Cardano invoice standard that we know of. The closest proposal, CIP-0157 Cardano URIs: Enhanced Payments , is an open, unmerged pull request about payment URIs rather than invoice metadata. Any invoice format Dial proposes would be a standards-alignment goal, and Dial makes no claim to an official Cardano standard. See interoperability.
Next: Cardano invoicing guide.
Explore invoicing: Programmable Invoicing and invoicing on Cardano