From eb192fa676f66803f624aa41eba569f7fcc07372 Mon Sep 17 00:00:00 2001 From: Kayos Date: Sat, 9 May 2026 14:06:17 -0700 Subject: [PATCH] fix(escrow_wip): apply 2026-05-09 internal audit findings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- Dockerfile | 10 + aiken-escrow/plutus.json | 8 +- aiken-escrow/validator.cbor.hex | 1 + aiken-escrow/validators/escrow.ak | 59 +++++- audits/2026-05-09-escrow-internal-audit.md | 186 ++++++++++++++++++ crates/aldabra-dao/src/builder/escrow_open.rs | 126 +++++++----- .../src/builder/escrow_refund_timeout.rs | 10 +- crates/aldabra-dao/src/builder/escrow_veto.rs | 10 +- crates/aldabra-mcp/src/tools.rs | 33 ++-- 9 files changed, 378 insertions(+), 65 deletions(-) create mode 100644 aiken-escrow/validator.cbor.hex create mode 100644 audits/2026-05-09-escrow-internal-audit.md diff --git a/Dockerfile b/Dockerfile index b69701b..5f34cc2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -66,6 +66,16 @@ RUN apt-get update && \ COPY --from=builder /build/target/release/aldabra /usr/local/bin/aldabra +# Escrow V3 validator CBOR (escrow_wip surface). Baked at /etc/aldabra/ +# escrow/validator.cbor.hex so MCP escrow_*_unsigned tools can pass it +# via `validator_script_path`. The MCP arg-truncation bug at >4500 hex +# chars makes the inline `validator_script_cbor_hex` option unusable +# for the 7902-char compiled validator. Validator hash: +# a8081acef26935d9b5f44b92052178e17301b6d6e6808c91c5b56f5d — check +# against the file's compiled hash before invoking on-chain ops. +COPY aiken-escrow/validator.cbor.hex /etc/aldabra/escrow/validator.cbor.hex +COPY aiken-escrow/plutus.json /etc/aldabra/escrow/plutus.json + # Default data dir — mount a volume here in compose / k8s / docker run. ENV ALDABRA_DATA=/var/lib/aldabra RUN mkdir -p /var/lib/aldabra && chmod 700 /var/lib/aldabra diff --git a/aiken-escrow/plutus.json b/aiken-escrow/plutus.json index c29d950..c4269bd 100644 --- a/aiken-escrow/plutus.json +++ b/aiken-escrow/plutus.json @@ -25,16 +25,16 @@ "$ref": "#/definitions/escrow~1EscrowRedeemer" } }, - "compiledCode": "590f6c01010029800aba2aba1aba0aab9faab9eaab9dab9a488888896600264653001300800198041804800cdc3a400530080024888966002600460106ea800e3300130093754007370e90024dc3a40013008375400891111991192cc004c01401226464b30013016002801c590131bae3014001301037540171598009804802456600260206ea802e0031640451598009803002456600260206ea802e00316404515980099b87480180122b3001301037540170018b20228acc004cdc3a401000915980098081baa00b800c5901145900e201c4038807100e0acc004c010c038dd5000c4c8cc8966002600e60226ea800a330013015301237540052301630170019180b180b980b980b980b980b980b800c8c058c05cc05c0064446466446600400400244b3001001801c4c8c96600266e440180062b30013371e00c0031375a60340050054061133004004301e00340606eb8c060004c06c005019191919800800803112cc004006007132325980099b910080018acc004cdc7804000c4dd5980d801401501944cc010010c07c00d0191bae3019001301c0014068297adef6c6014800244646600200200644b30010018a518acc004c00cc064006266004004603400314a080a101748c010cc054c010cc054dd4800a5eb80cc055300103d87a80004bd704888c8cc00400401089660020031004899801980d00099801001180d800a03091194c0040060070024004444b30010028800c4c8cc8a600200d301e0059919800800802912cc00400626603c66ec0dd48021ba60034bd6f7b63044c8cc896600266e4401c00a2b30013371e00e0051325980099baf4c101a000374c003100289981119bb037520106e9800400901e194c0040066eacc08001200e800888966002005100189919914c00401a605200b32330010010052259800800c4cc0a4cdd81ba9004375000697adef6c6089919912cc004cdc8803801456600266e3c01c00a264b30013370e00266e052000007880144cc0b4cdd81ba9008375066e0000401c0090291bad302a00389981619bb0375200e6ea001801102844cc0b000ccc0140140050281bae3027001302c002302a00140a08030dd718110009bad30230013025002408d133021337606ea401cdd3003002203a89981080199802802800a03a375c60380026042004603e00280e90061bae301700137566030002603400480c24602c602e602e602e0032301630173017301730173017301730170019180b180b980b980b980b980b800cc044dd5006c8c058c05cc05cc05cc05c006446466002002006446600600260040052232330010013758603060326032603260326032603260326032602a6ea800c896600200314a115980099b8f375c603200200714a3133002002301a001405080ba4646600200200444b30010018a5eb82264664466446600400400244b30010018801c4c8cc074dd39980e9ba90053301d301a0013301d301b0014bd7019801801980f801180e800a036375660300066eb8c054004cc00c00cc068008c0600050164dd7a6103d8798000488888888888888888a60026eacc044c090dd5180898121baa012981398121baa3011302437540252232330010010022259800800c528c566002646464660286eacc060c0acdd50019191980b1bab302d0022337126eb4c0b800660020090029bae302d00140606eb8c0ac006600200d4bd6f7b6304896600266ebcc0bcc0b0dd5001001c4cc048004dd5980c98161baa0028800a054404460226eb8c0b0c0a4dd50009815800c4cc008008c0b0006294102620529192cc004c07cc094dd5000c4c05ccc0a0c0a4c098dd5000a5eb822980103d87a800040906050604a6ea8c0a0c094dd5180498129baa0019119912cc0040060051598009816000c4c8c966002604060526ea8006264b30013020302a375400313232323232323298009bac30350019bae30350079bae30350069bae30350059bad30350049bad3035003488888966002607800f1323322598009818001456600260766ea800e0031640f1159800981a00144c8c96600260820050038b207c375a607e00260766ea800e2c81c9039181c1baa001133019007225980080144c0b0cc0f4dd39981e8089981e9814181d9baa0134bd7025eb82264b30013031303b37540031323322598009821800c4cc07cdd59821000912cc00400a2600e608a01113232330233756608600444b300100289802982480344c8cc88c010c130014dd718228009bad3046001304800241186eb8c104004c1100090424590401bae30400013041001303c37540031640e8607c00481e0c0ec0222c81c8606a0026068002606600260640026062002606000260566ea80062c8148c0b4c0a8dd5000c530103d87a800040a0602860526ea8004c0ac00600481490290a6103d87a800032330010010032259800800c52f5c1133225980099baf302d302a375400400b13302c00233004004001899802002000a050302b001302c00140a4911112cc004c07802e264b30013007300d302a3754033159800acc004cdc78009bae302d302a375403314a313371e0026eb8c05cc0a8dd500ca0508acc004cc024088006264b30013020302a3754003132325980099b8f375c6060605a6ea8004dd7181818169baa01c8acc004cdc79bae301a302d37540026eb8c068c0b4dd500e456600266e3cdd7180c18169baa001375c6030605a6ea80722b30013370e6eb4c048c0b4dd50009bad3012302d375403915980099b87375a601c605a6ea8004dd6980718169baa01c8acc004c028c040c0b4dd5000c4ca600244466008006464b30013371e0020091337606ea4004dd3001c4cdd81ba9001303300240c46eb8c0c400644646600200200644b30010018801c4cc0d0c0d4004cc008008c0d8005033488c8cc00400400c896600200314c0103d87a80008992cc004cdc78021bae3032001898121981a9819800a5eb82266006006606e0048188c0d4005033244466e3cdd99ba798009111919800800802112cc0040062009133003303900133002002303a00140dd3758603a60626ea808264660020026020660306eacc0d4c0d801cc8cc00400403c896600200314bd6f7b63044c8cc0dccdd8181a0009ba632330010013756606c00444b30010018a5eb7bdb1822646607466ec0c0dc004dd419b8148000dd6981c00099801801981e001181d000a070330030033039002303700140d444b30010018a5eb7bdb182265300130380019bae303700199801801981c00124453001375c6074007375a6074607600733007001002488966002605e60726ea800633001004802ccc02cdd5981e981d1baa0013303c337606ea400cdd400125eb7bdb18100c44cc02c010cc0f0cdd81ba9005374c6607866ec0dd48019ba80024bd6f7b63025eb7bdb18103806eb0c0d80050342444b300132330010010032259800800c528456600266e3cdd7181c981b1baa303900100d8a51899801001181d000a06840dd132330010010032259800800c52f5c1133038325980099b8f375c6074606e6ea800403a26050660726074606e6ea8004cc0e4dd34c0040126eacc090c0dcdd5000c88c8cc8966002606260766ea800a33001004801e60020033756607e60786ea800a44646644b3001303630403754005132330150052325980099b8f001006899bb037520026ea000e266ec0dd480098220012084375c608400266e00dd6982218209baa0020018998090021982199bb037520066ea00052f5bded8c081f8c8cc00400400c896600200314c0103d87a80008992cc004cdc78021bae304100189819998221821000a5eb82266006006608c0048200c1100050421bad303f003375c607a004805900e44cc034010cc0f8cdd81ba9003374c00297adef6c6040e8660140040026eacc0e800cdd7181c001200c4bd7044005035181c80099801001181d000a06e8991919800800802112cc0040062007133039303a00133002002303b00140e06606c604a6606c6ea402ccc0d8dd3000a5eb812f5c081906eccc074c0c4dd5002888c8cc00400400c896600200314bd6f7b63044cc0ccc00cc0d0004cc008008c0d400503245902b45902b45902b45902b45902b45902b18178009bac302e302b37540031640a4660046eb0c054c0a8dd5011002c590284590284590281bae302c302937540491325980098118064566002600e601a60546ea80662b300133009022375c605a60546ea80662b300133009022375c602e60546ea8066264b30013020302a37540031325980099b89001375a602260586ea806e264b30013022302c3754003132332259800acc004cc01c00403226600e01800314a081722b30013371e6eb8c0ccc0c0dd50011bae30333030375403f15980099b8f375c603a60606ea8008dd7180e98181baa01f8acc004cdc79bae301b303037540046eb8c06cc0c0dd500fc56600266e1cdd6980a98181baa002375a602a60606ea807e2b30013370e6eb4c044c0c0dd50011bad30113030375403f15980099b8f3766603860606ea8008dd9980e18181baa01f899baf30133030375400466e95200233032375000a97ae08b205c8b205c8b205c8b205c8b205c8b205c8b205c30310013756606260640026eb0c0c0c0b4dd5000c5902b198021bac3017302c375404800f1640a86eb4c0b8c0acdd5000c59029192cc004c090c0a8dd5000c4c070cc0b4c0b8c0acdd5000a5eb82298103d87a800040a4605a60546ea8c05cc0a8dd5180718151baa0228b20508b20508b20508acc004c0800322b3001302330293754601a60546ea80662b300159800998048111bae302d302a375403314a3133009022375c602e60546ea806502844cc010dd6180a98151baa0223758602c60546ea80662c81422c81422b30013370e900300644c966002604860546ea8006264b30013021302b375400315980099b88337006eb4c0bcc0b0dd50011bad300d302c37540366eb4c0bcc0b0dd5000c4c8cc01260026eb0c060c0b4dd5012d2f5bded8c1225980099baf3032302f375400400713301500137566038605e6ea800a20028169014004980a1bae3017302c37540371640a91640a860080471640a4601a60546ea80662b30013007300d302a375403313259800981018151baa0018acc004cdc41bad3010302b37540346eb4c0b8c0acdd5000c4cc014dd6180b18159baa0233758602e60566ea806a2c814a2c8148c00c08a2c8141028205040a0446466002002601400444b30010018a518acc004c8c8cdc49bad3032303300198008034dd718190014dd71819000a03230320013758606000313300200230310018a5040ac8171027116404064660020026eb0c050c044dd5004912cc004006298103d87a80008992cc004cdd7980b18099baa001006898021980a800a5eb82266006006602e0048088c054005013180998081baa002374a900045900d18080021808180880222c8038601000260066ea802229344d95900101", - "hash": "223aa7ace4a98ff5b8f8988c1c07b846c046de1a2bc9e8dc77411486" + "compiledCode": "59106c01010029800aba2aba1aba0aab9faab9eaab9dab9a488888896600264653001300800198041804800cdc3a400530080024888966002600460106ea800e3300130093754007370e90024dc3a40013008375400891111991192cc004c01401226464b30013016002801c590131bae3014001301037540171598009804802456600260206ea802e0031640451598009803002456600260206ea802e00316404515980099b87480180122b3001301037540170018b20228acc004cdc3a401000915980098081baa00b800c5901145900e201c4038807100e0acc004c010c038dd5000c4c8cc8966002600e60226ea800a330013015301237540052301630170019180b180b980b800c8888c8cc004004014896600200313301a337606ea4014dd400225eb7bdb1822646644b30013372201000515980099b8f0080028cc0040226eb4c06c00e00f23301e337606ea4024dd40008014400500644cc074cdd81ba9008375000e00880ca26603a0066600a00a00280c8dd7180c000980e801180d800a03291111919800800802912cc00400626603466ec0dd48029ba60044bd6f7b63044c8cc896600266e4402000a2b30013371e010005198008044dd5980d801c01e46603c66ec0dd48049ba60010028800a00c89980e99bb037520106e9801c01101944cc07400ccc0140140050191bae3018001301d002301b00140651222225980099b87004337029000001c0062600466e0001000d0154888c8cc88cc0080080048966002003003899192cc004cdc8803000c56600266e3c01800626eb4c06800a00a80c2266008008603c00680c0dd7180c000980d800a0323232330010010062259800800c00e26464b30013372201000315980099b8f00800189bab301b002802a032899802002180f801a032375c6032002603800280d052f5bded8c029000488c8cc00400400c896600200314a31598009801980c800c4cc008008c0680062941014202e918021980a98021980a9ba90014bd701980aa6103d87a80004bd704888c8cc00400401089660020031004899801980d00099801001180d800a0309180b180b980b980b980b980b980b800c888c8cc00400401089660020031004899801980d00099801001180d800a03091919800800801112cc004006297ae08991991199119801001000912cc00400620071323301d374e6603a6ea4014cc074c068004cc074c06c0052f5c066006006603e004603a00280d8dd5980c0019bae301500133003003301a00230180014059230163017301730170019180b180b980b980b980b980b980b980b800c8c058c05cc05cc05cc05cc05c00660226ea80364602c602e602e602e602e003223233001001003223300300130020029119198008009bac3018301930193019301930193019301930193015375400644b30010018a508acc004cdc79bae30190010038a51899801001180d000a028405d375e98103d8798000488888888888888888888a60026eacc050c09cdd5180a18139baa015981518139baa30143027375402b22329800800c00e00480088896600200510018994c004012606200798008014dd71816000cdd59816800c88888c96600266ebd30101a000374c00300289801800a06232329800800c01a00a80088896600200510018994c004012607600798008014dd7181b000cdd6981b800c0150222008303900240dca03680b90041817801205a94c00400697adef6c60914c004dd5980b98151baa002800c88ca60026eacc0b400e005223322598009813000c400e33001003802ccc0cccdd81ba9002375000297adef6c6091111192cc004cdd7a6101a000374c00300289801800a06a9800802401e00d501f408480d902f1bae302e002375a605e0048080dd71815801201a4035223233001001300c0022259800800c528c566002646466e24dd698181818800cc00401a6eb8c0c000a6eb8c0c000501518180009bac302e0018998010011817800c528205240b123259800981118141baa0018980d19815981618149baa0014bd7045300103d87a8000409c605660506ea8c0acc0a0dd5180418141baa0019119912cc0040060051598009817800c4c8c966002604660586ea8006264b30013023302d375400313232323232323298009bac30380019bae30380079bae30380069bae30380059bad30380049bad3038003488888966002607e00f13233225980098198014566002607c6ea800e0031640fd159800981b80144c8c96600260880050038b2082375a6084002607c6ea800e2c81e103c181d9baa001133018007225980080144c0bccc100dd399820008998201815981f1baa0134bd7025eb82264b30013034303e37540031323322598009823000c4cc078dd59822800912cc00400a2600e609001113232330223756608c00444b300100289802982600344c8cc88c010c13c014dd718240009bad3049001304b00241246eb8c110004c11c0090454590431bae30430013044001303f37540031640f4608200481f8c0f80222c81e06070002606e002606c002606a00260680026066002605c6ea80062c8160c0c0c0b4dd5000c530103d87a800040ac603060586ea8004c0b8006004816102c0a6103d87a800032330010010032259800800c52f5c1133225980099baf3030302d375400400b13302f00233004004001899802002000a056302e001302f00140b0911111119912cc004c09403a264b3001300b301030313754041159800acc004cdc78009bae30343031375404114a313371e0026eb8c078c0c4dd5010205e8acc004cc0300a4006264b300130273031375400313233225980099805000807456600266e3cdd7181c181a9baa002375c6070606a6ea80922b30013371e6eb8c088c0d4dd50011bae30223035375404915980099b8f375c6042606a6ea8008dd71810981a9baa0248acc004cdc39bad3016303537540046eb4c058c0d4dd5012456600266e1cdd69809181a9baa002375a6024606a6ea80922b3001300f3014303537540051329800911198020019192cc004cdc780080244cdd81ba9001374c0071337606ea4004c0ec0090391bae3039001911919800800801912cc004006200713303c303d00133002002303e00140ed2232330010010032259800800c5300103d87a80008992cc004cdc78021bae303a001898161981e981d800a5eb82266006006607e00481c8c0f400503b244466e3cdd99ba73322598009919800800801912cc00400629422b30013371e6eb8c100c0f4dd51820000806c528c4cc008008c10400503b207c89919800800801912cc004006297ae089981f992cc004cdc79bae3041303e375400201d1302f330403041303e3754002660806e9a600200937566056607c6ea800644646644b300130383042375400519800802400f30010019bab3046304337540052232332259800981e98239baa0028991980a0029192cc004cdc780080344cdd81ba900137500071337606ea4004c12c0090491bae3049001337006eb4c12cc120dd5001000c4cc044010cc128cdd81ba9003375000297adef6c604118646600200200644b30010018a6103d87a80008992cc004cdc78021bae30480018981d198259824800a5eb82266006006609a0048238c12c0050491bad3046003375c6088004813100d44cc030010cc114cdd81ba9003374c00297adef6c604104660120040026eacc10400cdd7181f80120424bd704400503c1820000998010011820800a07c8991919800800802112cc0040062007133040304100133002002304200140fc6607a60586607a6ea402ccc0f4dd3000a5eb812f5c081c8dd6180e981c9baa0283233001001301c3301100632330010010142259800800c52f5bded8c11323303f3376060780026e98c8cc004004dd5981f001112cc004006297adef6c608991982119bb0303f001375066e052000375a608000266006006608800460840028200cc00c00cc104008c0fc00503d112cc004006297adef6c608994c004c1000066eb8c0fc0066600600660800049114c004dd71821001cdd698211821801ccc01c00400922259800981b98209baa0018cc00401200b3300b3756608a60846ea8004cc110cdd81ba9003375000497adef6c60403113300b00433044337606ea4014dd31982219bb037520066ea00092f5bded8c097adef6c6041001bac303e00140f06eccc074c0e4dd5003088c8cc00400400c896600200314bd6f7b63044cc0ecc00cc0f0004cc008008c0f400503a459033459033459033459033459033459033459033181b0009bab303630370013758606a60646ea80062c8180cc010dd6180e98189baa0290098b205e8b205e8b205e375c606660606ea80ae2b3001302900e8acc004c028c03cc0c0dd500fc566002660160506eb8c0ccc0c0dd500fc566002660160506eb8c074c0c0dd500fc4c966002604c60606ea8006264b3001337120026eb4c04cc0c8dd5010c4c966002605060646ea80062646644b30015980099805800807c4cc02c03c0062941034456600266e3cdd7181c981b1baa002375c6072606c6ea80962b30013371e6eb8c08cc0d8dd50011bae30233036375404b15980099b8f375c6044606c6ea8008dd71811181b1baa0258acc004cdc39bad3017303637540046eb4c05cc0d8dd5012c56600266e1cdd69809981b1baa002375a6026606c6ea80962b30013371e6eccc068c0d8dd50011bb3301a3036375404b13375e602a606c6ea8008cdd2a4004660706ea00152f5c11640d11640d11640d11640d11640d11640d11640d0606e0026eacc0dcc0e0004dd6181b18199baa0018b2062330053758603c60646ea80a802a2c8180dd6981a18189baa0018b205e3259800981518181baa0018981119819981a18189baa0014bd7045300103d87a800040bc606660606ea8c074c0c0dd5180818181baa0288b205c8b205c8b205c8acc004c09803a2b30013029302f3754601e60606ea807e2b300159800998058141bae30333030375403f14a313300b028375c603a60606ea807d02e456600266002600c6eb0c050c0c0dd500f804c4cc008dd6180e18181baa0283758602860606ea807e2c81722c81722c81722b30013370e900300744c966002605460606ea8006264b300130273031375400315980099b88337006eb4c0d4c0c8dd50011bad300f303237540426eb4c0d4c0c8dd5000c4c8cc02260026eb0c07cc0ccdd5015d2f5bded8c1225980099baf30383035375400400713300c00137566044606a6ea800a20028199018006180c1bae301e303237540431640c11640c0600a0531640bc601e60606ea807e2b3001300a300f3030375403f13259800981318181baa0018acc004cdc41bad3012303137540406eb4c0d0c0c4dd5000c56600266004600e6eb0c054c0c4dd501000544cc00cdd6180e98189baa0293758602a60626ea80822c817a2c817a2c8178c0100a22c817102e205c40b8817088c8cc004004008896600200314a31598009919191980e1bab3022303537540064646603c6eacc0dc0088cdc49bad30380019800802400a6eb8c0dc0050201bae3035001980080352f5bded8c1225980099baf30393036375400400713300d00137566046606c6ea800a200281a1019180c9bae303630333754002606a00313300200230360018a5040c0819889660026600a0040031330050010028a5040b845901019198008009bac30143011375401244b30010018a60103d87a80008992cc004cdd7980b18099baa001006898021980a800a5eb82266006006602e0048088c054005013180998081baa002374a900045900d18080021808180880222c8038601000260066ea802229344d95900101", + "hash": "a8081acef26935d9b5f44b92052178e17301b6d6e6808c91c5b56f5d" }, { "title": "escrow.escrow.else", "redeemer": { "schema": {} }, - "compiledCode": "590f6c01010029800aba2aba1aba0aab9faab9eaab9dab9a488888896600264653001300800198041804800cdc3a400530080024888966002600460106ea800e3300130093754007370e90024dc3a40013008375400891111991192cc004c01401226464b30013016002801c590131bae3014001301037540171598009804802456600260206ea802e0031640451598009803002456600260206ea802e00316404515980099b87480180122b3001301037540170018b20228acc004cdc3a401000915980098081baa00b800c5901145900e201c4038807100e0acc004c010c038dd5000c4c8cc8966002600e60226ea800a330013015301237540052301630170019180b180b980b980b980b980b980b800c8c058c05cc05c0064446466446600400400244b3001001801c4c8c96600266e440180062b30013371e00c0031375a60340050054061133004004301e00340606eb8c060004c06c005019191919800800803112cc004006007132325980099b910080018acc004cdc7804000c4dd5980d801401501944cc010010c07c00d0191bae3019001301c0014068297adef6c6014800244646600200200644b30010018a518acc004c00cc064006266004004603400314a080a101748c010cc054c010cc054dd4800a5eb80cc055300103d87a80004bd704888c8cc00400401089660020031004899801980d00099801001180d800a03091194c0040060070024004444b30010028800c4c8cc8a600200d301e0059919800800802912cc00400626603c66ec0dd48021ba60034bd6f7b63044c8cc896600266e4401c00a2b30013371e00e0051325980099baf4c101a000374c003100289981119bb037520106e9800400901e194c0040066eacc08001200e800888966002005100189919914c00401a605200b32330010010052259800800c4cc0a4cdd81ba9004375000697adef6c6089919912cc004cdc8803801456600266e3c01c00a264b30013370e00266e052000007880144cc0b4cdd81ba9008375066e0000401c0090291bad302a00389981619bb0375200e6ea001801102844cc0b000ccc0140140050281bae3027001302c002302a00140a08030dd718110009bad30230013025002408d133021337606ea401cdd3003002203a89981080199802802800a03a375c60380026042004603e00280e90061bae301700137566030002603400480c24602c602e602e602e0032301630173017301730173017301730170019180b180b980b980b980b980b800cc044dd5006c8c058c05cc05cc05cc05c006446466002002006446600600260040052232330010013758603060326032603260326032603260326032602a6ea800c896600200314a115980099b8f375c603200200714a3133002002301a001405080ba4646600200200444b30010018a5eb82264664466446600400400244b30010018801c4c8cc074dd39980e9ba90053301d301a0013301d301b0014bd7019801801980f801180e800a036375660300066eb8c054004cc00c00cc068008c0600050164dd7a6103d8798000488888888888888888a60026eacc044c090dd5180898121baa012981398121baa3011302437540252232330010010022259800800c528c566002646464660286eacc060c0acdd50019191980b1bab302d0022337126eb4c0b800660020090029bae302d00140606eb8c0ac006600200d4bd6f7b6304896600266ebcc0bcc0b0dd5001001c4cc048004dd5980c98161baa0028800a054404460226eb8c0b0c0a4dd50009815800c4cc008008c0b0006294102620529192cc004c07cc094dd5000c4c05ccc0a0c0a4c098dd5000a5eb822980103d87a800040906050604a6ea8c0a0c094dd5180498129baa0019119912cc0040060051598009816000c4c8c966002604060526ea8006264b30013020302a375400313232323232323298009bac30350019bae30350079bae30350069bae30350059bad30350049bad3035003488888966002607800f1323322598009818001456600260766ea800e0031640f1159800981a00144c8c96600260820050038b207c375a607e00260766ea800e2c81c9039181c1baa001133019007225980080144c0b0cc0f4dd39981e8089981e9814181d9baa0134bd7025eb82264b30013031303b37540031323322598009821800c4cc07cdd59821000912cc00400a2600e608a01113232330233756608600444b300100289802982480344c8cc88c010c130014dd718228009bad3046001304800241186eb8c104004c1100090424590401bae30400013041001303c37540031640e8607c00481e0c0ec0222c81c8606a0026068002606600260640026062002606000260566ea80062c8148c0b4c0a8dd5000c530103d87a800040a0602860526ea8004c0ac00600481490290a6103d87a800032330010010032259800800c52f5c1133225980099baf302d302a375400400b13302c00233004004001899802002000a050302b001302c00140a4911112cc004c07802e264b30013007300d302a3754033159800acc004cdc78009bae302d302a375403314a313371e0026eb8c05cc0a8dd500ca0508acc004cc024088006264b30013020302a3754003132325980099b8f375c6060605a6ea8004dd7181818169baa01c8acc004cdc79bae301a302d37540026eb8c068c0b4dd500e456600266e3cdd7180c18169baa001375c6030605a6ea80722b30013370e6eb4c048c0b4dd50009bad3012302d375403915980099b87375a601c605a6ea8004dd6980718169baa01c8acc004c028c040c0b4dd5000c4ca600244466008006464b30013371e0020091337606ea4004dd3001c4cdd81ba9001303300240c46eb8c0c400644646600200200644b30010018801c4cc0d0c0d4004cc008008c0d8005033488c8cc00400400c896600200314c0103d87a80008992cc004cdc78021bae3032001898121981a9819800a5eb82266006006606e0048188c0d4005033244466e3cdd99ba798009111919800800802112cc0040062009133003303900133002002303a00140dd3758603a60626ea808264660020026020660306eacc0d4c0d801cc8cc00400403c896600200314bd6f7b63044c8cc0dccdd8181a0009ba632330010013756606c00444b30010018a5eb7bdb1822646607466ec0c0dc004dd419b8148000dd6981c00099801801981e001181d000a070330030033039002303700140d444b30010018a5eb7bdb182265300130380019bae303700199801801981c00124453001375c6074007375a6074607600733007001002488966002605e60726ea800633001004802ccc02cdd5981e981d1baa0013303c337606ea400cdd400125eb7bdb18100c44cc02c010cc0f0cdd81ba9005374c6607866ec0dd48019ba80024bd6f7b63025eb7bdb18103806eb0c0d80050342444b300132330010010032259800800c528456600266e3cdd7181c981b1baa303900100d8a51899801001181d000a06840dd132330010010032259800800c52f5c1133038325980099b8f375c6074606e6ea800403a26050660726074606e6ea8004cc0e4dd34c0040126eacc090c0dcdd5000c88c8cc8966002606260766ea800a33001004801e60020033756607e60786ea800a44646644b3001303630403754005132330150052325980099b8f001006899bb037520026ea000e266ec0dd480098220012084375c608400266e00dd6982218209baa0020018998090021982199bb037520066ea00052f5bded8c081f8c8cc00400400c896600200314c0103d87a80008992cc004cdc78021bae304100189819998221821000a5eb82266006006608c0048200c1100050421bad303f003375c607a004805900e44cc034010cc0f8cdd81ba9003374c00297adef6c6040e8660140040026eacc0e800cdd7181c001200c4bd7044005035181c80099801001181d000a06e8991919800800802112cc0040062007133039303a00133002002303b00140e06606c604a6606c6ea402ccc0d8dd3000a5eb812f5c081906eccc074c0c4dd5002888c8cc00400400c896600200314bd6f7b63044cc0ccc00cc0d0004cc008008c0d400503245902b45902b45902b45902b45902b45902b18178009bac302e302b37540031640a4660046eb0c054c0a8dd5011002c590284590284590281bae302c302937540491325980098118064566002600e601a60546ea80662b300133009022375c605a60546ea80662b300133009022375c602e60546ea8066264b30013020302a37540031325980099b89001375a602260586ea806e264b30013022302c3754003132332259800acc004cc01c00403226600e01800314a081722b30013371e6eb8c0ccc0c0dd50011bae30333030375403f15980099b8f375c603a60606ea8008dd7180e98181baa01f8acc004cdc79bae301b303037540046eb8c06cc0c0dd500fc56600266e1cdd6980a98181baa002375a602a60606ea807e2b30013370e6eb4c044c0c0dd50011bad30113030375403f15980099b8f3766603860606ea8008dd9980e18181baa01f899baf30133030375400466e95200233032375000a97ae08b205c8b205c8b205c8b205c8b205c8b205c8b205c30310013756606260640026eb0c0c0c0b4dd5000c5902b198021bac3017302c375404800f1640a86eb4c0b8c0acdd5000c59029192cc004c090c0a8dd5000c4c070cc0b4c0b8c0acdd5000a5eb82298103d87a800040a4605a60546ea8c05cc0a8dd5180718151baa0228b20508b20508b20508acc004c0800322b3001302330293754601a60546ea80662b300159800998048111bae302d302a375403314a3133009022375c602e60546ea806502844cc010dd6180a98151baa0223758602c60546ea80662c81422c81422b30013370e900300644c966002604860546ea8006264b30013021302b375400315980099b88337006eb4c0bcc0b0dd50011bad300d302c37540366eb4c0bcc0b0dd5000c4c8cc01260026eb0c060c0b4dd5012d2f5bded8c1225980099baf3032302f375400400713301500137566038605e6ea800a20028169014004980a1bae3017302c37540371640a91640a860080471640a4601a60546ea80662b30013007300d302a375403313259800981018151baa0018acc004cdc41bad3010302b37540346eb4c0b8c0acdd5000c4cc014dd6180b18159baa0233758602e60566ea806a2c814a2c8148c00c08a2c8141028205040a0446466002002601400444b30010018a518acc004c8c8cdc49bad3032303300198008034dd718190014dd71819000a03230320013758606000313300200230310018a5040ac8171027116404064660020026eb0c050c044dd5004912cc004006298103d87a80008992cc004cdd7980b18099baa001006898021980a800a5eb82266006006602e0048088c054005013180998081baa002374a900045900d18080021808180880222c8038601000260066ea802229344d95900101", - "hash": "223aa7ace4a98ff5b8f8988c1c07b846c046de1a2bc9e8dc77411486" + "compiledCode": "59106c01010029800aba2aba1aba0aab9faab9eaab9dab9a488888896600264653001300800198041804800cdc3a400530080024888966002600460106ea800e3300130093754007370e90024dc3a40013008375400891111991192cc004c01401226464b30013016002801c590131bae3014001301037540171598009804802456600260206ea802e0031640451598009803002456600260206ea802e00316404515980099b87480180122b3001301037540170018b20228acc004cdc3a401000915980098081baa00b800c5901145900e201c4038807100e0acc004c010c038dd5000c4c8cc8966002600e60226ea800a330013015301237540052301630170019180b180b980b800c8888c8cc004004014896600200313301a337606ea4014dd400225eb7bdb1822646644b30013372201000515980099b8f0080028cc0040226eb4c06c00e00f23301e337606ea4024dd40008014400500644cc074cdd81ba9008375000e00880ca26603a0066600a00a00280c8dd7180c000980e801180d800a03291111919800800802912cc00400626603466ec0dd48029ba60044bd6f7b63044c8cc896600266e4402000a2b30013371e010005198008044dd5980d801c01e46603c66ec0dd48049ba60010028800a00c89980e99bb037520106e9801c01101944cc07400ccc0140140050191bae3018001301d002301b00140651222225980099b87004337029000001c0062600466e0001000d0154888c8cc88cc0080080048966002003003899192cc004cdc8803000c56600266e3c01800626eb4c06800a00a80c2266008008603c00680c0dd7180c000980d800a0323232330010010062259800800c00e26464b30013372201000315980099b8f00800189bab301b002802a032899802002180f801a032375c6032002603800280d052f5bded8c029000488c8cc00400400c896600200314a31598009801980c800c4cc008008c0680062941014202e918021980a98021980a9ba90014bd701980aa6103d87a80004bd704888c8cc00400401089660020031004899801980d00099801001180d800a0309180b180b980b980b980b980b980b800c888c8cc00400401089660020031004899801980d00099801001180d800a03091919800800801112cc004006297ae08991991199119801001000912cc00400620071323301d374e6603a6ea4014cc074c068004cc074c06c0052f5c066006006603e004603a00280d8dd5980c0019bae301500133003003301a00230180014059230163017301730170019180b180b980b980b980b980b980b980b800c8c058c05cc05cc05cc05cc05c00660226ea80364602c602e602e602e602e003223233001001003223300300130020029119198008009bac3018301930193019301930193019301930193015375400644b30010018a508acc004cdc79bae30190010038a51899801001180d000a028405d375e98103d8798000488888888888888888888a60026eacc050c09cdd5180a18139baa015981518139baa30143027375402b22329800800c00e00480088896600200510018994c004012606200798008014dd71816000cdd59816800c88888c96600266ebd30101a000374c00300289801800a06232329800800c01a00a80088896600200510018994c004012607600798008014dd7181b000cdd6981b800c0150222008303900240dca03680b90041817801205a94c00400697adef6c60914c004dd5980b98151baa002800c88ca60026eacc0b400e005223322598009813000c400e33001003802ccc0cccdd81ba9002375000297adef6c6091111192cc004cdd7a6101a000374c00300289801800a06a9800802401e00d501f408480d902f1bae302e002375a605e0048080dd71815801201a4035223233001001300c0022259800800c528c566002646466e24dd698181818800cc00401a6eb8c0c000a6eb8c0c000501518180009bac302e0018998010011817800c528205240b123259800981118141baa0018980d19815981618149baa0014bd7045300103d87a8000409c605660506ea8c0acc0a0dd5180418141baa0019119912cc0040060051598009817800c4c8c966002604660586ea8006264b30013023302d375400313232323232323298009bac30380019bae30380079bae30380069bae30380059bad30380049bad3038003488888966002607e00f13233225980098198014566002607c6ea800e0031640fd159800981b80144c8c96600260880050038b2082375a6084002607c6ea800e2c81e103c181d9baa001133018007225980080144c0bccc100dd399820008998201815981f1baa0134bd7025eb82264b30013034303e37540031323322598009823000c4cc078dd59822800912cc00400a2600e609001113232330223756608c00444b300100289802982600344c8cc88c010c13c014dd718240009bad3049001304b00241246eb8c110004c11c0090454590431bae30430013044001303f37540031640f4608200481f8c0f80222c81e06070002606e002606c002606a00260680026066002605c6ea80062c8160c0c0c0b4dd5000c530103d87a800040ac603060586ea8004c0b8006004816102c0a6103d87a800032330010010032259800800c52f5c1133225980099baf3030302d375400400b13302f00233004004001899802002000a056302e001302f00140b0911111119912cc004c09403a264b3001300b301030313754041159800acc004cdc78009bae30343031375404114a313371e0026eb8c078c0c4dd5010205e8acc004cc0300a4006264b300130273031375400313233225980099805000807456600266e3cdd7181c181a9baa002375c6070606a6ea80922b30013371e6eb8c088c0d4dd50011bae30223035375404915980099b8f375c6042606a6ea8008dd71810981a9baa0248acc004cdc39bad3016303537540046eb4c058c0d4dd5012456600266e1cdd69809181a9baa002375a6024606a6ea80922b3001300f3014303537540051329800911198020019192cc004cdc780080244cdd81ba9001374c0071337606ea4004c0ec0090391bae3039001911919800800801912cc004006200713303c303d00133002002303e00140ed2232330010010032259800800c5300103d87a80008992cc004cdc78021bae303a001898161981e981d800a5eb82266006006607e00481c8c0f400503b244466e3cdd99ba73322598009919800800801912cc00400629422b30013371e6eb8c100c0f4dd51820000806c528c4cc008008c10400503b207c89919800800801912cc004006297ae089981f992cc004cdc79bae3041303e375400201d1302f330403041303e3754002660806e9a600200937566056607c6ea800644646644b300130383042375400519800802400f30010019bab3046304337540052232332259800981e98239baa0028991980a0029192cc004cdc780080344cdd81ba900137500071337606ea4004c12c0090491bae3049001337006eb4c12cc120dd5001000c4cc044010cc128cdd81ba9003375000297adef6c604118646600200200644b30010018a6103d87a80008992cc004cdc78021bae30480018981d198259824800a5eb82266006006609a0048238c12c0050491bad3046003375c6088004813100d44cc030010cc114cdd81ba9003374c00297adef6c604104660120040026eacc10400cdd7181f80120424bd704400503c1820000998010011820800a07c8991919800800802112cc0040062007133040304100133002002304200140fc6607a60586607a6ea402ccc0f4dd3000a5eb812f5c081c8dd6180e981c9baa0283233001001301c3301100632330010010142259800800c52f5bded8c11323303f3376060780026e98c8cc004004dd5981f001112cc004006297adef6c608991982119bb0303f001375066e052000375a608000266006006608800460840028200cc00c00cc104008c0fc00503d112cc004006297adef6c608994c004c1000066eb8c0fc0066600600660800049114c004dd71821001cdd698211821801ccc01c00400922259800981b98209baa0018cc00401200b3300b3756608a60846ea8004cc110cdd81ba9003375000497adef6c60403113300b00433044337606ea4014dd31982219bb037520066ea00092f5bded8c097adef6c6041001bac303e00140f06eccc074c0e4dd5003088c8cc00400400c896600200314bd6f7b63044cc0ecc00cc0f0004cc008008c0f400503a459033459033459033459033459033459033459033181b0009bab303630370013758606a60646ea80062c8180cc010dd6180e98189baa0290098b205e8b205e8b205e375c606660606ea80ae2b3001302900e8acc004c028c03cc0c0dd500fc566002660160506eb8c0ccc0c0dd500fc566002660160506eb8c074c0c0dd500fc4c966002604c60606ea8006264b3001337120026eb4c04cc0c8dd5010c4c966002605060646ea80062646644b30015980099805800807c4cc02c03c0062941034456600266e3cdd7181c981b1baa002375c6072606c6ea80962b30013371e6eb8c08cc0d8dd50011bae30233036375404b15980099b8f375c6044606c6ea8008dd71811181b1baa0258acc004cdc39bad3017303637540046eb4c05cc0d8dd5012c56600266e1cdd69809981b1baa002375a6026606c6ea80962b30013371e6eccc068c0d8dd50011bb3301a3036375404b13375e602a606c6ea8008cdd2a4004660706ea00152f5c11640d11640d11640d11640d11640d11640d11640d0606e0026eacc0dcc0e0004dd6181b18199baa0018b2062330053758603c60646ea80a802a2c8180dd6981a18189baa0018b205e3259800981518181baa0018981119819981a18189baa0014bd7045300103d87a800040bc606660606ea8c074c0c0dd5180818181baa0288b205c8b205c8b205c8acc004c09803a2b30013029302f3754601e60606ea807e2b300159800998058141bae30333030375403f14a313300b028375c603a60606ea807d02e456600266002600c6eb0c050c0c0dd500f804c4cc008dd6180e18181baa0283758602860606ea807e2c81722c81722c81722b30013370e900300744c966002605460606ea8006264b300130273031375400315980099b88337006eb4c0d4c0c8dd50011bad300f303237540426eb4c0d4c0c8dd5000c4c8cc02260026eb0c07cc0ccdd5015d2f5bded8c1225980099baf30383035375400400713300c00137566044606a6ea800a20028199018006180c1bae301e303237540431640c11640c0600a0531640bc601e60606ea807e2b3001300a300f3030375403f13259800981318181baa0018acc004cdc41bad3012303137540406eb4c0d0c0c4dd5000c56600266004600e6eb0c054c0c4dd501000544cc00cdd6180e98189baa0293758602a60626ea80822c817a2c817a2c8178c0100a22c817102e205c40b8817088c8cc004004008896600200314a31598009919191980e1bab3022303537540064646603c6eacc0dc0088cdc49bad30380019800802400a6eb8c0dc0050201bae3035001980080352f5bded8c1225980099baf30393036375400400713300d00137566046606c6ea800a200281a1019180c9bae303630333754002606a00313300200230360018a5040c0819889660026600a0040031330050010028a5040b845901019198008009bac30143011375401244b30010018a60103d87a80008992cc004cdd7980b18099baa001006898021980a800a5eb82266006006602e0048088c054005013180998081baa002374a900045900d18080021808180880222c8038601000260066ea802229344d95900101", + "hash": "a8081acef26935d9b5f44b92052178e17301b6d6e6808c91c5b56f5d" } ], "definitions": { diff --git a/aiken-escrow/validator.cbor.hex b/aiken-escrow/validator.cbor.hex new file mode 100644 index 0000000..a6e2787 --- /dev/null +++ b/aiken-escrow/validator.cbor.hex @@ -0,0 +1 @@ +59106c01010029800aba2aba1aba0aab9faab9eaab9dab9a488888896600264653001300800198041804800cdc3a400530080024888966002600460106ea800e3300130093754007370e90024dc3a40013008375400891111991192cc004c01401226464b30013016002801c590131bae3014001301037540171598009804802456600260206ea802e0031640451598009803002456600260206ea802e00316404515980099b87480180122b3001301037540170018b20228acc004cdc3a401000915980098081baa00b800c5901145900e201c4038807100e0acc004c010c038dd5000c4c8cc8966002600e60226ea800a330013015301237540052301630170019180b180b980b800c8888c8cc004004014896600200313301a337606ea4014dd400225eb7bdb1822646644b30013372201000515980099b8f0080028cc0040226eb4c06c00e00f23301e337606ea4024dd40008014400500644cc074cdd81ba9008375000e00880ca26603a0066600a00a00280c8dd7180c000980e801180d800a03291111919800800802912cc00400626603466ec0dd48029ba60044bd6f7b63044c8cc896600266e4402000a2b30013371e010005198008044dd5980d801c01e46603c66ec0dd48049ba60010028800a00c89980e99bb037520106e9801c01101944cc07400ccc0140140050191bae3018001301d002301b00140651222225980099b87004337029000001c0062600466e0001000d0154888c8cc88cc0080080048966002003003899192cc004cdc8803000c56600266e3c01800626eb4c06800a00a80c2266008008603c00680c0dd7180c000980d800a0323232330010010062259800800c00e26464b30013372201000315980099b8f00800189bab301b002802a032899802002180f801a032375c6032002603800280d052f5bded8c029000488c8cc00400400c896600200314a31598009801980c800c4cc008008c0680062941014202e918021980a98021980a9ba90014bd701980aa6103d87a80004bd704888c8cc00400401089660020031004899801980d00099801001180d800a0309180b180b980b980b980b980b980b800c888c8cc00400401089660020031004899801980d00099801001180d800a03091919800800801112cc004006297ae08991991199119801001000912cc00400620071323301d374e6603a6ea4014cc074c068004cc074c06c0052f5c066006006603e004603a00280d8dd5980c0019bae301500133003003301a00230180014059230163017301730170019180b180b980b980b980b980b980b980b800c8c058c05cc05cc05cc05cc05c00660226ea80364602c602e602e602e602e003223233001001003223300300130020029119198008009bac3018301930193019301930193019301930193015375400644b30010018a508acc004cdc79bae30190010038a51899801001180d000a028405d375e98103d8798000488888888888888888888a60026eacc050c09cdd5180a18139baa015981518139baa30143027375402b22329800800c00e00480088896600200510018994c004012606200798008014dd71816000cdd59816800c88888c96600266ebd30101a000374c00300289801800a06232329800800c01a00a80088896600200510018994c004012607600798008014dd7181b000cdd6981b800c0150222008303900240dca03680b90041817801205a94c00400697adef6c60914c004dd5980b98151baa002800c88ca60026eacc0b400e005223322598009813000c400e33001003802ccc0cccdd81ba9002375000297adef6c6091111192cc004cdd7a6101a000374c00300289801800a06a9800802401e00d501f408480d902f1bae302e002375a605e0048080dd71815801201a4035223233001001300c0022259800800c528c566002646466e24dd698181818800cc00401a6eb8c0c000a6eb8c0c000501518180009bac302e0018998010011817800c528205240b123259800981118141baa0018980d19815981618149baa0014bd7045300103d87a8000409c605660506ea8c0acc0a0dd5180418141baa0019119912cc0040060051598009817800c4c8c966002604660586ea8006264b30013023302d375400313232323232323298009bac30380019bae30380079bae30380069bae30380059bad30380049bad3038003488888966002607e00f13233225980098198014566002607c6ea800e0031640fd159800981b80144c8c96600260880050038b2082375a6084002607c6ea800e2c81e103c181d9baa001133018007225980080144c0bccc100dd399820008998201815981f1baa0134bd7025eb82264b30013034303e37540031323322598009823000c4cc078dd59822800912cc00400a2600e609001113232330223756608c00444b300100289802982600344c8cc88c010c13c014dd718240009bad3049001304b00241246eb8c110004c11c0090454590431bae30430013044001303f37540031640f4608200481f8c0f80222c81e06070002606e002606c002606a00260680026066002605c6ea80062c8160c0c0c0b4dd5000c530103d87a800040ac603060586ea8004c0b8006004816102c0a6103d87a800032330010010032259800800c52f5c1133225980099baf3030302d375400400b13302f00233004004001899802002000a056302e001302f00140b0911111119912cc004c09403a264b3001300b301030313754041159800acc004cdc78009bae30343031375404114a313371e0026eb8c078c0c4dd5010205e8acc004cc0300a4006264b300130273031375400313233225980099805000807456600266e3cdd7181c181a9baa002375c6070606a6ea80922b30013371e6eb8c088c0d4dd50011bae30223035375404915980099b8f375c6042606a6ea8008dd71810981a9baa0248acc004cdc39bad3016303537540046eb4c058c0d4dd5012456600266e1cdd69809181a9baa002375a6024606a6ea80922b3001300f3014303537540051329800911198020019192cc004cdc780080244cdd81ba9001374c0071337606ea4004c0ec0090391bae3039001911919800800801912cc004006200713303c303d00133002002303e00140ed2232330010010032259800800c5300103d87a80008992cc004cdc78021bae303a001898161981e981d800a5eb82266006006607e00481c8c0f400503b244466e3cdd99ba73322598009919800800801912cc00400629422b30013371e6eb8c100c0f4dd51820000806c528c4cc008008c10400503b207c89919800800801912cc004006297ae089981f992cc004cdc79bae3041303e375400201d1302f330403041303e3754002660806e9a600200937566056607c6ea800644646644b300130383042375400519800802400f30010019bab3046304337540052232332259800981e98239baa0028991980a0029192cc004cdc780080344cdd81ba900137500071337606ea4004c12c0090491bae3049001337006eb4c12cc120dd5001000c4cc044010cc128cdd81ba9003375000297adef6c604118646600200200644b30010018a6103d87a80008992cc004cdc78021bae30480018981d198259824800a5eb82266006006609a0048238c12c0050491bad3046003375c6088004813100d44cc030010cc114cdd81ba9003374c00297adef6c604104660120040026eacc10400cdd7181f80120424bd704400503c1820000998010011820800a07c8991919800800802112cc0040062007133040304100133002002304200140fc6607a60586607a6ea402ccc0f4dd3000a5eb812f5c081c8dd6180e981c9baa0283233001001301c3301100632330010010142259800800c52f5bded8c11323303f3376060780026e98c8cc004004dd5981f001112cc004006297adef6c608991982119bb0303f001375066e052000375a608000266006006608800460840028200cc00c00cc104008c0fc00503d112cc004006297adef6c608994c004c1000066eb8c0fc0066600600660800049114c004dd71821001cdd698211821801ccc01c00400922259800981b98209baa0018cc00401200b3300b3756608a60846ea8004cc110cdd81ba9003375000497adef6c60403113300b00433044337606ea4014dd31982219bb037520066ea00092f5bded8c097adef6c6041001bac303e00140f06eccc074c0e4dd5003088c8cc00400400c896600200314bd6f7b63044cc0ecc00cc0f0004cc008008c0f400503a459033459033459033459033459033459033459033181b0009bab303630370013758606a60646ea80062c8180cc010dd6180e98189baa0290098b205e8b205e8b205e375c606660606ea80ae2b3001302900e8acc004c028c03cc0c0dd500fc566002660160506eb8c0ccc0c0dd500fc566002660160506eb8c074c0c0dd500fc4c966002604c60606ea8006264b3001337120026eb4c04cc0c8dd5010c4c966002605060646ea80062646644b30015980099805800807c4cc02c03c0062941034456600266e3cdd7181c981b1baa002375c6072606c6ea80962b30013371e6eb8c08cc0d8dd50011bae30233036375404b15980099b8f375c6044606c6ea8008dd71811181b1baa0258acc004cdc39bad3017303637540046eb4c05cc0d8dd5012c56600266e1cdd69809981b1baa002375a6026606c6ea80962b30013371e6eccc068c0d8dd50011bb3301a3036375404b13375e602a606c6ea8008cdd2a4004660706ea00152f5c11640d11640d11640d11640d11640d11640d11640d0606e0026eacc0dcc0e0004dd6181b18199baa0018b2062330053758603c60646ea80a802a2c8180dd6981a18189baa0018b205e3259800981518181baa0018981119819981a18189baa0014bd7045300103d87a800040bc606660606ea8c074c0c0dd5180818181baa0288b205c8b205c8b205c8acc004c09803a2b30013029302f3754601e60606ea807e2b300159800998058141bae30333030375403f14a313300b028375c603a60606ea807d02e456600266002600c6eb0c050c0c0dd500f804c4cc008dd6180e18181baa0283758602860606ea807e2c81722c81722c81722b30013370e900300744c966002605460606ea8006264b300130273031375400315980099b88337006eb4c0d4c0c8dd50011bad300f303237540426eb4c0d4c0c8dd5000c4c8cc02260026eb0c07cc0ccdd5015d2f5bded8c1225980099baf30383035375400400713300c00137566044606a6ea800a20028199018006180c1bae301e303237540431640c11640c0600a0531640bc601e60606ea807e2b3001300a300f3030375403f13259800981318181baa0018acc004cdc41bad3012303137540406eb4c0d0c0c4dd5000c56600266004600e6eb0c054c0c4dd501000544cc00cdd6180e98189baa0293758602a60626ea80822c817a2c817a2c8178c0100a22c817102e205c40b8817088c8cc004004008896600200314a31598009919191980e1bab3022303537540064646603c6eacc0dc0088cdc49bad30380019800802400a6eb8c0dc0050201bae3035001980080352f5bded8c1225980099baf30393036375400400713300d00137566046606c6ea800a200281a1019180c9bae303630333754002606a00313300200230360018a5040c0819889660026600a0040031330050010028a5040b845901019198008009bac30143011375401244b30010018a60103d87a80008992cc004cdd7980b18099baa001006898021980a800a5eb82266006006602e0048088c054005013180998081baa002374a900045900d18080021808180880222c8038601000260066ea802229344d95900101 diff --git a/aiken-escrow/validators/escrow.ak b/aiken-escrow/validators/escrow.ak index 800930f..779e518 100644 --- a/aiken-escrow/validators/escrow.ak +++ b/aiken-escrow/validators/escrow.ak @@ -23,7 +23,7 @@ use aiken/crypto.{VerificationKeyHash} use aiken/interval.{Finite} use aiken/cbor use cardano/address.{Address, VerificationKey} -use cardano/assets.{Value, flatten, merge, negate, quantity_of, zero} +use cardano/assets.{Value, add, flatten, merge, negate, quantity_of, zero} use cardano/transaction.{ Transaction, Output, OutputReference, InlineDatum, find_input, } @@ -166,6 +166,44 @@ fn value_geq_flat(paid: Value, flat: FlatValue) -> Bool { ) } +/// Sum every entry across all deposits into a single on-chain `Value`. +/// Used by Veto / Refund-timeout to enforce the invariant +/// `sum(deposits.value) == in_value` — i.e., the escrow's tracked +/// deposits must account for every lovelace + token actually locked +/// at the script. Without this, an escrow opened with empty deposits +/// + non-zero locked value (or one griefed via a token send) lets the +/// driver pocket untracked funds via vacuous-true `refund_outputs_satisfy`. +/// HIGH-2 fix from 2026-05-09 internal audit. +fn deposits_to_value(deposits: List) -> Value { + list.foldr( + deposits, + zero, + fn(d, acc) { + list.foldr( + d.value, + acc, + fn(policy_entry, acc2) { + let Pair(policy, assets_) = policy_entry + list.foldr( + assets_, + acc2, + fn(asset_entry, acc3) { + let Pair(name, qty) = asset_entry + add(acc3, policy, name, qty) + }, + ) + }, + ) + }, + ) +} + +/// Component-wise equality on opaque `Value`. Cheaper than two-direction +/// `value_geq_value` because we can short-circuit on the first mismatch. +fn value_eq(a: Value, b: Value) -> Bool { + value_geq_value(a, b) && value_geq_value(b, a) +} + /// For each Deposit entry, an output to that contributor's base address /// must pay at least the entry's value. fn refund_outputs_satisfy( @@ -299,6 +337,13 @@ validator escrow { expect signed_by(self, contributor) expect Some((new_d, new_value)) = find_continuing_output(self.outputs, script_addr) + // HIGH-1 fix (2026-05-09 audit): without this, `net_added` from + // `flatten(merge(new_value, negate(in_value)))` could carry + // negative quantities and the depositor could DRAIN tokens + // while writing a matching new_d.deposits with reduced values. + // Forcing new_value ≥ in_value component-wise ensures every + // net_added entry is non-negative. + expect value_geq_value(new_value, in_value) // Datum unchanged except `deposits` expect new_d.party_a == d.party_a expect new_d.party_b == d.party_b @@ -334,6 +379,14 @@ validator escrow { Veto -> { expect Agreed { .. } = d.state expect signed_by(self, d.party_a) || signed_by(self, d.party_b) + // HIGH-2 fix (2026-05-09 audit): without this, an escrow whose + // deposits don't account for every lovelace at the script + // (e.g. opened with `initial_contributor=None`, or griefed via + // a token-send) lets the driver pocket untracked funds as + // change because `refund_outputs_satisfy` is vacuously true on + // empty / partial deposits. Enforcing equality forces the + // tracked deposits to be the FULL accounting of locked value. + expect value_eq(deposits_to_value(d.deposits), in_value) refund_outputs_satisfy(self.outputs, d.deposits) } @@ -361,6 +414,10 @@ validator escrow { expect d.state == Open expect Some(lower) = tx_lower_ms(self) expect lower > d.open_deadline_ms + // HIGH-2 fix (2026-05-09 audit): same invariant as Veto — + // deposits must account for full in_value, else driver + // pockets untracked funds via vacuous refund_outputs_satisfy. + expect value_eq(deposits_to_value(d.deposits), in_value) refund_outputs_satisfy(self.outputs, d.deposits) } } diff --git a/audits/2026-05-09-escrow-internal-audit.md b/audits/2026-05-09-escrow-internal-audit.md new file mode 100644 index 0000000..82d5f76 --- /dev/null +++ b/audits/2026-05-09-escrow-internal-audit.md @@ -0,0 +1,186 @@ +# Escrow internal audit — 2026-05-09 + +Subagent-driven correctness/security audit of the `escrow_wip` surface +on `kayos/escrow-wip-v1` before preprod deployment. Two HIGH findings +on the validator, several MED on the off-chain builders + MCP layer, +LOW polish items. + +This is **internal review only** — third-party audit still required +before any mainnet deployment. Findings here are best-effort by an +agent reviewing the code; assume they don't catch everything. + +## Validator hash before / after + +| | hash | UPLC chars | +|--|--|--| +| Pre-fix | `223aa7ace4a98ff5b8f8988c1c07b846c046de1a2bc9e8dc77411486` | 7902 | +| Post-fix | `a8081acef26935d9b5f44b92052178e17301b6d6e6808c91c5b56f5d` | 8414 | + +The CBOR grew ~6.5% from the two HIGH-fix checks. The script address +derived from the new hash is the v1 deploy target. + +## HIGH findings + +### HIGH-1 — Deposit redeemer didn't bound `net_added` to non-negative + +**File**: `aiken-escrow/validators/escrow.ak` Deposit branch. + +**What was wrong**: + +```aiken +let net_added = value_to_flat(merge(new_value, negate(in_value))) +let expected = expected_deposits_after(d.deposits, contributor, net_added) +cbor.serialise(expected) == cbor.serialise(new_d.deposits) +``` + +`flatten(merge(new_value, negate(in_value)))` includes negative quantities +when `new_value < in_value` component-wise. A depositor could construct a +tx where `new_value` had MORE ADA but FEWER tokens than `in_value`, +producing `net_added = (+5 ADA, -50 TOKEN)`. `expected_deposits_after` +would write the matching deposit entry as `(value: ADA=15, TOKEN=50)`, +and the cbor equality check would pass. The 50 missing tokens flow out +as the depositor's wallet change — **token theft**. + +Latent under v1 ADA-only MCP usage (no tokens ever land in the script +UTxO), but the validator must hold against any caller, not just our +MCP layer. + +**Fix**: + +```aiken +expect Some((new_d, new_value)) = + find_continuing_output(self.outputs, script_addr) +expect value_geq_value(new_value, in_value) // NEW +let net_added = value_to_flat(merge(new_value, negate(in_value))) +``` + +### HIGH-2 — Vacuous `refund_outputs_satisfy([], _)` on Veto + Refund + +**File**: `aiken-escrow/validators/escrow.ak` Veto + Refund branches. + +**What was wrong**: + +`refund_outputs_satisfy(tx_outputs, deposits)` is `list.all(deposits, ...)`. +When `deposits = []`, it's vacuously `True`. The validator passes, +the input UTxO is consumed, no refund outputs are required, and the +input's lovelace flows out as the driver's wallet change — **funds theft**. + +Trigger paths (all observed pre-fix): + +1. `escrow_open` with `initial_contributor=None` and `initial_lovelace>0` + creates exactly this state (deposits=[], in_value>0). +2. Any escrow with `sum(deposits.values) < in_value` — e.g., an escrow + griefed via a token send that landed in the same UTxO via a coin- + selection edge case. Currently impossible under MCP usage but the + validator must hold against direct CBOR construction. + +**Fix** (validator-side): + +```aiken +Veto -> { + expect Agreed { .. } = d.state + expect signed_by(self, d.party_a) || signed_by(self, d.party_b) + expect value_eq(deposits_to_value(d.deposits), in_value) // NEW + refund_outputs_satisfy(self.outputs, d.deposits) +} + +Refund -> { + expect d.state == Open + expect Some(lower) = tx_lower_ms(self) + expect lower > d.open_deadline_ms + expect value_eq(deposits_to_value(d.deposits), in_value) // NEW + refund_outputs_satisfy(self.outputs, d.deposits) +} +``` + +`deposits_to_value` and `value_eq` are new helpers: fold every deposit's +FlatValue into a Value via `assets.add`, then `value_geq_value` both +directions for equality. Component-wise. + +**Fix** (builder-side, defense in depth): + +`escrow_open` now refuses `initial_contributor=None`. New test +`rejects_no_initial_contributor`. The "open empty, top up later" UX +was never useful — party_a can just open + first-deposit in a single +call. + +## MED findings (addressed) + +### MED-2/3 — Settle/Refund used Koios `block_time*1000` for `lower_ms` + +**File**: `crates/aldabra-mcp/src/tools.rs` (escrow_settle_unsigned, escrow_refund_timeout_unsigned) + +The chain reconstructs `lower` from `valid_from_slot(slot)` via slot↔ms math. +Koios's `block_time` field can drift up to ~1s from the slot's true ms. +At the strict-`>` validator boundary (`lower > agreed_at + lock_period`, +`lower > open_deadline_ms`), the off-chain preflight could pass while +the chain rejects. Fee + collateral burned. + +**Fix**: derive `validity_lower_ms = slot_to_posix_ms(network, validity_lower_slot)` +in both tools so the off-chain ms matches what the chain reconstructs. + +### MED-5 — escrow_open min-utxo floor too low + +**File**: `crates/aldabra-dao/src/builder/escrow_open.rs` + +Used `params.min_utxo_lovelace` (default 1_000_000). Conway-era inline- +datum + script-address outputs need ~1.4-1.7 ADA depending on datum +size. Tx could pass preflight, fail at pallas-txbuilder build. + +**Fix**: hardcoded `ESCROW_OPEN_MIN_LOVELACE = 2_000_000` to match the +existing `ESCROW_OUTPUT_MIN_LOVELACE` used by Deposit. + +### MED-7 — escrow_open_unsigned silently discarded `fee_lovelace` + +**File**: `crates/aldabra-mcp/src/tools.rs` (`escrow_open_unsigned`) + +`fee_lovelace` was on the args struct with `let _ = fee_lovelace;` — +caller's value ignored, payment-extras builder did its own estimation. +Misleading. + +**Fix**: removed `fee_lovelace` from `EscrowOpenUnsignedArgs`. The +unsigned-tx builder still auto-estimates. + +## LOW findings (addressed) + +### LOW — `qty as u64` truncated negative i128 in veto + refund_timeout + +**File**: `crates/aldabra-dao/src/builder/escrow_veto.rs`, +`escrow_refund_timeout.rs` + +A corrupt or adversarial datum with negative qty would silently +wraparound. Defensive depth. + +**Fix**: `u64::try_from(qty).map_err(...)` — surfaces clear error. + +## Findings deferred to v2 + +These were flagged but not addressed in this round; v1 ADA-only scope +side-steps them. + +- **MED-1, MED-6**: `build_escrow_spend_in` hardcodes `assets: vec![]` + on the spend input. Multi-asset escrows would have outputs missing + tokens. v2 needs an `escrow_in_assets` arg or chain-side discovery. +- **MED-4**: `EscrowUtxoIn.lovelace` is caller-supplied, no chain + cross-check. Wrong value silently produces a chain-rejecting tx. + v2 should fetch via Koios. +- **LOW**: negative `open_deadline_ms` / `lock_period_ms` not + rejected. Edge-case; v2 polish. +- **LOW**: `change_address` could theoretically equal + `escrow_script_address`. MCP layer always uses wallet address so + safe in practice. +- **LOW**: `find_continuing_output` returns `None` on DatumHash + outputs, builders only emit InlineDatum so no real risk. +- **LOW**: `fetch_tip_slot_ms` error messages are generic. + +## Tests after fixes + +- 36 escrow builder tests pass (added `rejects_no_initial_contributor`). +- 132 dao tests pass under `--features escrow_wip`. +- aldabra-mcp release build clean. + +## Audit lineage + +This was an automated audit by a subagent — it is NOT a third-party +review. The validator must still go through external audit (TxPipe / +Anastasia Labs / MLabs / Tweag) before any mainnet deployment. diff --git a/crates/aldabra-dao/src/builder/escrow_open.rs b/crates/aldabra-dao/src/builder/escrow_open.rs index d904999..2c63b91 100644 --- a/crates/aldabra-dao/src/builder/escrow_open.rs +++ b/crates/aldabra-dao/src/builder/escrow_open.rs @@ -88,41 +88,60 @@ pub struct UnsignedEscrowOpen { /// Build the unsigned escrow_open tx. pub fn build_unsigned_escrow_open(args: EscrowOpenArgs) -> DaoResult { // ---- preflight ---- - if let Some(c) = args.initial_contributor { - if c != args.party_a_pkh && c != args.party_b_pkh { - return Err(DaoError::State( - "initial_contributor must be party_a or party_b".to_string(), - )); - } + // + // HIGH-2 fix (2026-05-09 audit): refuse `initial_contributor=None` + // entirely. Previously this opened an escrow with `deposits=[]` and + // `initial_lovelace > 0`, which the validator (pre-fix) treated as + // a refundable-by-anyone escrow because `refund_outputs_satisfy(_, [])` + // is vacuously true. Even with the validator now enforcing + // `sum(deposits) == in_value`, the empty-deposits path produces a + // permanently-stuck escrow (no Veto/Refund possible until somebody + // deposits). Cleaner v1 invariant: every escrow has at least one + // contributor at open. The "open empty, top up later" UX was never + // useful anyway — party_a can just open + deposit in a single call. + let initial_contributor = args.initial_contributor.ok_or_else(|| { + DaoError::State( + "initial_contributor is required — open an escrow with at least one contributor (party_a or party_b)" + .into(), + ) + })?; + if initial_contributor != args.party_a_pkh && initial_contributor != args.party_b_pkh { + return Err(DaoError::State( + "initial_contributor must be party_a or party_b".to_string(), + )); } - // The output must clear the validator's min-utxo for an inline-datum - // + asset-bearing output. We use the protocol-param floor as a lower - // bound; the actual min depends on serialized output size and is - // computed by pallas-txbuilder when building the tx. - if args.initial_lovelace < args.params.min_utxo_lovelace { + + // MED-5 fix (2026-05-09 audit): the escrow output bears an inline + // datum + sits at a script address — Conway-era min-utxo computes + // to ~1.4-1.7 ADA depending on datum size, NOT the 1 ADA default. + // Bump our floor to match the deposit/spend builders' constant + // (2 ADA) so an open tx that passes preflight also passes + // pallas-txbuilder's actual min-utxo computation. + const ESCROW_OPEN_MIN_LOVELACE: u64 = 2_000_000; + if args.initial_lovelace < ESCROW_OPEN_MIN_LOVELACE { return Err(DaoError::State(format!( - "initial_lovelace {} below min_utxo_lovelace {}", - args.initial_lovelace, args.params.min_utxo_lovelace + "initial_lovelace {} below escrow output min-utxo floor {ESCROW_OPEN_MIN_LOVELACE}", + args.initial_lovelace ))); } // ---- build the datum ---- - let deposits = match args.initial_contributor { - Some(c) => { - // Build the EscrowValue mirroring what's actually paid into - // the script output: lovelace + any native assets. - let mut value = EscrowValue::ada(args.initial_lovelace); - for a in &args.initial_assets { - let policy = hex::decode(&a.policy_id_hex) - .map_err(|e| DaoError::Config(format!("policy_id_hex parse: {e}")))?; - let name = hex::decode(&a.asset_name_hex) - .map_err(|e| DaoError::Config(format!("asset_name_hex parse: {e}")))?; - value.policies.push((policy, vec![(name, a.quantity as i128)])); - } - vec![EscrowDeposit { contributor: c, value }] - } - None => vec![], - }; + // + // initial_contributor is now mandatory (see HIGH-2 fix above). Build + // the EscrowValue mirroring what's actually paid into the script + // output: lovelace + any native assets. + let mut value = EscrowValue::ada(args.initial_lovelace); + for a in &args.initial_assets { + let policy = hex::decode(&a.policy_id_hex) + .map_err(|e| DaoError::Config(format!("policy_id_hex parse: {e}")))?; + let name = hex::decode(&a.asset_name_hex) + .map_err(|e| DaoError::Config(format!("asset_name_hex parse: {e}")))?; + value.policies.push((policy, vec![(name, a.quantity as i128)])); + } + let deposits = vec![EscrowDeposit { + contributor: initial_contributor, + value, + }]; let datum = EscrowDatum { party_a: args.party_a_pkh, party_b: args.party_b_pkh, @@ -151,21 +170,13 @@ pub fn build_unsigned_escrow_open(args: EscrowOpenArgs) -> DaoResult format!( - "escrow_open: lock {} lovelace + {} assets at {} (initial contributor {})", - args.initial_lovelace, - args.initial_assets.len(), - args.escrow_script_address, - hex::encode(c), - ), - None => format!( - "escrow_open: lock {} lovelace + {} assets at {} (no initial contributor)", - args.initial_lovelace, - args.initial_assets.len(), - args.escrow_script_address, - ), - }; + let summary = format!( + "escrow_open: lock {} lovelace + {} assets at {} (initial contributor {})", + args.initial_lovelace, + args.initial_assets.len(), + args.escrow_script_address, + hex::encode(initial_contributor), + ); Ok(UnsignedEscrowOpen { tx_cbor_hex: payment.cbor_hex, @@ -184,6 +195,33 @@ mod tests { [seed; PKH_LEN] } + #[test] + fn rejects_no_initial_contributor() { + // HIGH-2 fix: opening an escrow with `None` initial_contributor + // is now refused (formerly produced a deposits=[] escrow that + // could be drained on Veto / Refund via vacuous-true + // refund_outputs_satisfy). + let args = EscrowOpenArgs { + network: Network::Preprod, + escrow_script_address: "addr_test1wpyt48l...".to_string(), + party_a_pkh: pkh(0xa1), + party_b_pkh: pkh(0xb2), + recipient_pkh: pkh(0xb2), + open_deadline_ms: 1_700_000_000_000, + lock_period_ms: 30 * 60 * 1000, + initial_contributor: None, + initial_lovelace: 5_000_000, + initial_assets: vec![], + change_address: "addr_test1...".to_string(), + wallet_utxos: vec![], + params: ProtocolParams::default(), + }; + let r = build_unsigned_escrow_open(args); + assert!(matches!(r, Err(DaoError::State(_)))); + let msg = r.unwrap_err().to_string(); + assert!(msg.contains("initial_contributor is required"), "got: {msg}"); + } + #[test] fn rejects_unauthorized_initial_contributor() { let args = EscrowOpenArgs { diff --git a/crates/aldabra-dao/src/builder/escrow_refund_timeout.rs b/crates/aldabra-dao/src/builder/escrow_refund_timeout.rs index fa6d4df..0f5b68b 100644 --- a/crates/aldabra-dao/src/builder/escrow_refund_timeout.rs +++ b/crates/aldabra-dao/src/builder/escrow_refund_timeout.rs @@ -258,8 +258,16 @@ pub fn build_unsigned_escrow_refund_timeout( policy.len() ))); }; + // LOW fix (2026-05-09 audit): `qty as u64` silently truncates + // negative i128 from CBOR. Use try_from so a corrupt or + // adversarial datum can't slip through with a wraparound. + let qty_u64 = u64::try_from(qty).map_err(|_| { + DaoError::State(format!( + "deposit qty {qty} not representable as u64 (negative or > u64::MAX)" + )) + })?; out = out - .add_asset(policy_hash, name, qty as u64) + .add_asset(policy_hash, name, qty_u64) .map_err(|e| DaoError::Backend(format!("refund add_asset: {e}")))?; } staging = staging.output(out); diff --git a/crates/aldabra-dao/src/builder/escrow_veto.rs b/crates/aldabra-dao/src/builder/escrow_veto.rs index 770d246..9a7317e 100644 --- a/crates/aldabra-dao/src/builder/escrow_veto.rs +++ b/crates/aldabra-dao/src/builder/escrow_veto.rs @@ -298,8 +298,16 @@ pub fn build_unsigned_escrow_veto(args: EscrowVetoArgs) -> DaoResult u64::MAX)" + )) + })?; out = out - .add_asset(policy_hash, name, qty as u64) + .add_asset(policy_hash, name, qty_u64) .map_err(|e| DaoError::Backend(format!("refund add_asset: {e}")))?; } staging = staging.output(out); diff --git a/crates/aldabra-mcp/src/tools.rs b/crates/aldabra-mcp/src/tools.rs index 289ea24..0388970 100644 --- a/crates/aldabra-mcp/src/tools.rs +++ b/crates/aldabra-mcp/src/tools.rs @@ -3584,11 +3584,8 @@ impl WalletService { lock_period_ms, initial_contributor_pkh_hex, initial_lovelace, - fee_lovelace, }: EscrowOpenUnsignedArgs, ) -> Result { - let _ = fee_lovelace; // accepted for forward compat; payment builder is fee-estimating - let party_a = decode_pkh28(&party_a_pkh_hex, "party_a_pkh_hex")?; let party_b = decode_pkh28(&party_b_pkh_hex, "party_b_pkh_hex")?; let recipient = decode_pkh28(&recipient_pkh_hex, "recipient_pkh_hex")?; @@ -3906,13 +3903,17 @@ impl WalletService { let cfg = self.dao_cfg_for_escrow()?; let wallet_utxos = pull_wallet_utxos(&self.inner.chain, &self.inner.address).await?; - let (tip_slot, tip_ms) = fetch_tip_slot_ms(self).await?; + let (tip_slot, _tip_ms) = fetch_tip_slot_ms(self).await?; - // lower bound: caller-driven from tip; we sanity-check it satisfies - // the lock-window elapsed gate. Validator extracts `lower` from - // valid_from_slot anyway, so we anchor lower at tip_slot. + // MED-2/3 fix (2026-05-09 audit): derive `validity_lower_ms` + // from the slot via the Shelley constants, NOT from Koios's + // `block_time*1000`. The chain reconstructs `lower` from + // `valid_from_slot(slot)` via slot↔ms math; using Koios's + // block_time can drift up to ~1s, which at the strict-`>` + // validator boundary makes the off-chain preflight pass while + // the chain rejects → fees + collateral burned. let validity_lower_slot = tip_slot; - let validity_lower_ms = tip_ms; + let validity_lower_ms = slot_to_posix_ms(cfg.network, validity_lower_slot)?; let validity_upper_slot = tip_slot + validity_window_seconds.unwrap_or(1800); @@ -3977,9 +3978,10 @@ impl WalletService { let cfg = self.dao_cfg_for_escrow()?; let wallet_utxos = pull_wallet_utxos(&self.inner.chain, &self.inner.address).await?; - let (tip_slot, tip_ms) = fetch_tip_slot_ms(self).await?; + let (tip_slot, _tip_ms) = fetch_tip_slot_ms(self).await?; + // MED-2/3 fix: same slot-derived ms as Settle (see escrow_settle_unsigned). let validity_lower_slot = tip_slot; - let validity_lower_ms = tip_ms; + let validity_lower_ms = slot_to_posix_ms(cfg.network, validity_lower_slot)?; let validity_upper_slot = tip_slot + validity_window_seconds.unwrap_or(1800); let unsigned = build_unsigned_escrow_refund_timeout(EscrowRefundTimeoutArgs { @@ -4286,13 +4288,16 @@ pub struct EscrowOpenUnsignedArgs { /// Veto-window length after Agree, in ms. pub lock_period_ms: i64, /// Optional pkh of the initial contributor (must equal party_a or party_b). - /// If unset, opens with empty deposits — both parties top up later. + /// **HIGH-2 fix 2026-05-09:** The builder now REJECTS `None` here — every + /// escrow must have at least one initial contributor at open time. + /// Sending `null` returns an error. Field stays `Option` for + /// schema-stability. #[serde(default)] pub initial_contributor_pkh_hex: Option, - /// Lovelace to lock at the escrow output. Must clear min-utxo floor (~1 ADA). + /// Lovelace to lock at the escrow output. **MED-5 fix:** must clear + /// 2_000_000 (≥2 ADA) — Conway-era inline-datum + script-address + /// outputs need ~1.4-1.7 ADA min-utxo, with headroom. pub initial_lovelace: u64, - /// Estimated total fee in lovelace. ~2_500_000 reasonable for v1. - pub fee_lovelace: u64, } // ─── escrow_wip spend-tool args (deposit / agree / veto / settle / refund) ──