Commit graph

2 commits

Author SHA1 Message Date
eb192fa676 fix(escrow_wip): apply 2026-05-09 internal audit findings
Two HIGH validator-side bugs + several MED/LOW off-chain issues found
in the subagent-driven audit on this branch. New validator hash:
a8081acef26935d9b5f44b92052178e17301b6d6e6808c91c5b56f5d.

## HIGH-1: Deposit redeemer let depositors drain tokens

aiken-escrow/validators/escrow.ak Deposit branch now requires
`value_geq_value(new_value, in_value)` before computing net_added.
Previously net_added could carry negative quantities (when new_value
< in_value component-wise), letting a depositor write a matching
new_d.deposits with reduced values and pocket the difference as
wallet change. Latent under v1 ADA-only MCP usage but the validator
must hold against all callers.

## HIGH-2: Empty/partial deposits enabled funds drain via Veto/Refund

Veto and Refund branches now require
`value_eq(deposits_to_value(d.deposits), in_value)` — the tracked
deposits must account for the full locked value. Previously
`refund_outputs_satisfy(_, [])` was vacuously true on empty deposits,
so a driver could fire Veto/Refund on an escrow opened with
`initial_contributor=None` (deposits=[], in_value>0) and pocket the
input's lovelace as change.

Defense in depth: escrow_open builder now refuses
`initial_contributor=None`. New helper `deposits_to_value` folds
deposit FlatValues into a Value via `assets.add` for the equality
check.

## MED: off-chain fixes

- escrow_open min-utxo bumped 1M → 2M (Conway-era inline-datum
  + script-address outputs need ~1.4-1.7 ADA, NOT the 1 ADA default).
- escrow_settle_unsigned + escrow_refund_timeout_unsigned now derive
  `validity_lower_ms` via slot_to_posix_ms(network, slot) instead of
  Koios's `block_time*1000` — the chain reconstructs `lower` from the
  slot, so Koios's ~1s drift could pass off-chain preflight while the
  chain rejects at the strict-`>` boundary.
- escrow_open_unsigned MCP tool no longer accepts (and silently
  discards) `fee_lovelace` — the unsigned-tx builder auto-estimates.

## LOW: defensive depth

- escrow_veto + escrow_refund_timeout: `qty as u64` → `u64::try_from`
  so a corrupt or adversarial datum with negative i128 qty can't slip
  through with a wraparound.

## Tests

- 36 escrow builder tests pass (added rejects_no_initial_contributor)
- 132 dao tests pass under --features escrow_wip
- aldabra-mcp release build clean

## Infra

- Validator artifact files (plutus.json, validator.cbor.hex)
  regenerated. Dockerfile already wired to bake them at
  /etc/aldabra/escrow/ for MCP tools' validator_script_path arg.
- Internal audit findings written up at
  audits/2026-05-09-escrow-internal-audit.md including the v2-deferred
  items (multi-asset spend-input, lovelace-not-cross-checked, etc.)

Third-party audit still required before any mainnet deployment.
2026-05-09 14:06:17 -07:00
78ed92304e feat(escrow_wip): aiken validator + plutus.json blueprint
⚠ WIP — UNAUDITED. Plutus V3, Aiken v1.1.21. Preprod-only.

Five-redeemer two-party agreement-with-veto escrow validator. Mirrors the
off-chain codecs at crates/aldabra-dao/src/agora/escrow.rs.

Validator script hash: 223aa7ace4a98ff5b8f8988c1c07b846c046de1a2bc9e8dc77411486
Compiled UPLC size: 7902 bytes.

Datum: ProductIsData (Constr 0 [a, b, recipient, deadline, lock, state, deposits]).
Redeemer: Constr 0..4 (Deposit | Agree | Veto | Settle | Refund).
DepositEntry.value uses concrete Pairs<ByteArray, Pairs<ByteArray, Int>>
since cardano/assets.Value is opaque (datums require concrete types).
Pairs encode as Plutus Map at the dataType layer — matches the off-chain
EscrowValue codec's PlutusData::Map(KeyValuePairs) emission.

Build: cd aiken-escrow && aiken build (produces plutus.json blueprint).

Threat-model gaps explicitly documented in aiken-escrow/README.md:
- CBOR canonicality of Pairs serialisation (validator equality check)
- Stake-credential null'd on refund outputs (intentional — protects pool
  delegation privacy at cost of stake reward routing)
- No min-utxo enforcement on refund legs (off-chain builder's job)
- No multi-script-input cross-UTxO consistency

External audit gates mainnet deployment.
2026-05-09 11:38:45 -07:00