From a7175ff79ea0d57f85bee28b1faee6578243edf5 Mon Sep 17 00:00:00 2001 From: Samuel Dahunsi Date: Tue, 15 Sep 2026 07:28:02 +0100 Subject: [PATCH 1/4] Add test snapshots for escrow preflight rejection scenarios and implement state recovery tests - Introduced new JSON test snapshots for various escrow preflight rejection cases: - `escrow_preflight_propagates_verifier_rejection.1.json` - `escrow_preflight_rejects_malformed_payload.1.json` - `escrow_preflight_rejects_noncanonical_public_inputs.1.json` - Implemented a state recovery test in `state-recovery.mjs` to validate the handling of outages, incomplete backfills, and merging logic in the state engine. --- README.md | 24 +- contracts/Cargo.lock | 1 + contracts/Cargo.toml | 6 +- contracts/escrow-factory/src/test.rs | 26 +- ...e_escrow_deploys_a_working_instance.1.json | 111 +++- .../testdata/private_escrow_instance.wasm | Bin 8840 -> 9486 bytes contracts/escrow-instance/src/instance.rs | 111 ++-- contracts/escrow-instance/src/lib.rs | 26 +- contracts/escrow-instance/src/test.rs | 196 ++++++- .../test/cannot_fund_twice.1.json | 115 ++++- ...ared_inputs_or_proofs_after_funding.1.json | 425 +++++++++++++++ ...ter_window_blocked_when_arbiter_set.1.json | 117 ++++- .../test/claim_after_window_no_arbiter.1.json | 134 ++++- .../test/claim_before_window_blocked.1.json | 117 ++++- .../dispute_then_resolve_to_depositor.1.json | 136 ++++- .../dispute_then_resolve_to_recipient.1.json | 136 ++++- .../dispute_without_arbiter_blocked.1.json | 117 ++++- .../test/early_release_from_funded.1.json | 130 ++++- .../test/fund_moves_to_funded.1.json | 115 ++++- ..._refund_proof_cannot_enable_funding.1.json | 301 +++++++++++ ...release_proof_cannot_enable_funding.1.json | 448 ++++++++++++++++ .../test/normal_release_pays_recipient.1.json | 132 ++++- ...yout_proof_requires_prepared_inputs.1.json | 165 ++++++ ...ain_invalidates_both_payout_proofs.1.json} | 122 +++-- .../stranger_cannot_mark_completed.1.json | 115 ++++- .../timeout_blocked_after_completed.1.json | 117 ++++- .../test/timeout_refunds_depositor.1.json | 130 ++++- .../test/timeout_too_early.1.json | 115 ++++- ...icited_credit_does_not_block_refund.1.json | 485 ++++++++++++++++++ ...cited_credit_does_not_block_release.1.json | 485 ++++++++++++++++++ contracts/token/Cargo.toml | 1 + contracts/token/src/escrow.rs | 76 +++ contracts/token/src/lib.rs | 5 + contracts/token/src/test.rs | 208 ++++++++ ..._public_inputs_without_moving_funds.1.json | 365 +++++++++++++ ...light_propagates_verifier_rejection.1.json | 316 ++++++++++++ ...preflight_rejects_malformed_payload.1.json | 307 +++++++++++ ..._rejects_noncanonical_public_inputs.1.json | 307 +++++++++++ packages/app/app/docs/page.tsx | 20 +- packages/app/app/escrow/page.tsx | 4 +- packages/app/lib/wallet.ts | 22 +- .../sdk/contracts/confidential_auditor.wasm | Bin 19522 -> 19530 bytes .../sdk/contracts/confidential_policy.wasm | Bin 2091 -> 2099 bytes .../sdk/contracts/confidential_token.wasm | Bin 62553 -> 63722 bytes .../sdk/contracts/confidential_verifier.wasm | Bin 37584 -> 37592 bytes packages/sdk/contracts/payroll_vault.wasm | Bin 9179 -> 9187 bytes .../sdk/contracts/private_escrow_factory.wasm | Bin 3404 -> 3412 bytes .../contracts/private_escrow_instance.wasm | Bin 8840 -> 9486 bytes packages/sdk/package.json | 4 +- packages/sdk/src/chain/escrow.ts | 55 +- packages/sdk/src/chain/event-source.ts | 28 +- packages/sdk/src/crypto/field.ts | 8 +- packages/sdk/src/state/engine.ts | 8 +- packages/sdk/test/state-recovery.mjs | 77 +++ scripts/build-contracts.sh | 8 +- 55 files changed, 6174 insertions(+), 303 deletions(-) create mode 100644 contracts/escrow-instance/test_snapshots/test/cannot_replace_prepared_inputs_or_proofs_after_funding.1.json create mode 100644 contracts/escrow-instance/test_snapshots/test/invalid_refund_proof_cannot_enable_funding.1.json create mode 100644 contracts/escrow-instance/test_snapshots/test/invalid_release_proof_cannot_enable_funding.1.json create mode 100644 contracts/escrow-instance/test_snapshots/test/payout_proof_requires_prepared_inputs.1.json rename contracts/escrow-instance/test_snapshots/test/{store_payout_proofs_can_be_overwritten_before_funding.1.json => preparing_again_invalidates_both_payout_proofs.1.json} (85%) create mode 100644 contracts/escrow-instance/test_snapshots/test/unsolicited_credit_does_not_block_refund.1.json create mode 100644 contracts/escrow-instance/test_snapshots/test/unsolicited_credit_does_not_block_release.1.json create mode 100644 contracts/token/src/escrow.rs create mode 100644 contracts/token/src/test.rs create mode 100644 contracts/token/test_snapshots/test/escrow_preflight_matches_real_token_transfer_public_inputs_without_moving_funds.1.json create mode 100644 contracts/token/test_snapshots/test/escrow_preflight_propagates_verifier_rejection.1.json create mode 100644 contracts/token/test_snapshots/test/escrow_preflight_rejects_malformed_payload.1.json create mode 100644 contracts/token/test_snapshots/test/escrow_preflight_rejects_noncanonical_public_inputs.1.json create mode 100644 packages/sdk/test/state-recovery.mjs diff --git a/README.md b/README.md index 54a841e..f1f444a 100644 --- a/README.md +++ b/README.md @@ -140,13 +140,16 @@ salary stays decryptable to them and opaque to everyone else. **PrivateEscrow** is custodial: each escrow deploys its own **instance contract**, giving it its own isolated confidential account (a confidential balance is keyed by contract address, so custody requires a dedicated address -per escrow). Funding an instance is two on-chain calls, not one — -`store_payout_proofs` stores the two pre-generated payout proofs -(instance→recipient, instance→depositor), then `fund` registers the instance -and transfers the amount in, refusing to run until the payout proofs are -already stored. They're split because all four proofs together (register + -transfer-in + both payout proofs, each a ~14KB UltraHonk proof) exceed what -fits in one Soroban transaction. +per escrow). Funding takes four on-chain calls: + +1. `prepare_funding` stores the exact registration and transfer-in inputs. +2. `store_payout_proof(true, …)` verifies the recipient payout against the future funded commitment. +3. `store_payout_proof(false, …)` verifies the depositor refund against the same commitment. +4. `fund()` atomically registers the instance, transfers the funds in, and merges once. + +No funds move until both proofs pass. Re-preparing clears both validated proofs. +Separate calls keep the proof payloads within Soroban's transaction size limit. +Settlement spends the fixed commitment without merging unsolicited later credits. At settlement, the instance's own state machine (created → funded → completed → released / disputed / refunded / cancelled) submits exactly the @@ -224,9 +227,10 @@ cargo test --manifest-path contracts/Cargo.toml | Crate | Coverage | Tests | |---|---|---| +| `contracts/token` | Escrow preflight PI parity with upstream transfer, malformed inputs and verifier rejection | 4 | | `contracts/payroll` | State machine, employer auth, atomic batch payout, cancel paths | 10 | -| `contracts/escrow-instance` | Every state transition, release-window timing, arbiter vs. no-arbiter branches, auth, the two-step `store_payout_proofs` → `fund` guard | 18 | -| `contracts/escrow-factory` | Deploys a real instance and drives it through `store_payout_proofs` → `fund` → `mark_completed` → `release` | 1 | +| `contracts/escrow-instance` | Every state transition, release-window timing, arbiter vs. no-arbiter branches, auth, pre-funding proof validation and unsolicited-credit regressions | 24 | +| `contracts/escrow-factory` | Deploys a real instance and drives it through preparation → proof validation → funding → release | 1 | | `contracts/policy` | Allowlist add/remove/is_authorized round-trip, admin auth rejection | 3 | ## Deploying @@ -262,7 +266,7 @@ A full end-to-end walkthrough, real proofs on testnet: 2. **Send** — confidential transfer to a second registered account. 3. **Payroll** — create a template of employees, open + confirm a run, enter salaries, execute; then **Auditor** decrypts every salary amount. -4. **Escrow** — deploy + fund an escrow (two wallet confirmations); walk it +4. **Escrow** — deploy + fund an escrow (four funding confirmations); walk it through mark-completed → release (or dispute → resolve). 5. **Selective disclosure** — mint a request on the Verify screen, disclose the matching transfer from Home's activity feed, verify the returned diff --git a/contracts/Cargo.lock b/contracts/Cargo.lock index 745af6b..c83a306 100644 --- a/contracts/Cargo.lock +++ b/contracts/Cargo.lock @@ -311,6 +311,7 @@ version = "0.1.0" dependencies = [ "soroban-sdk", "stellar-access", + "stellar-contract-utils", "stellar-macros", "stellar-tokens", ] diff --git a/contracts/Cargo.toml b/contracts/Cargo.toml index 658f3f7..883e4a5 100644 --- a/contracts/Cargo.toml +++ b/contracts/Cargo.toml @@ -10,8 +10,9 @@ license = "MIT" # The confidential token, access-control, and proc-macro crates are consumed as # git dependencies from the `feat/confidential-verifier-ultrahonk` branch of # OpenZeppelin/stellar-contracts (they are NOT published to crates.io). Cargo.lock -# pins the exact resolved commit; this branch was validated at rev 539968f. Run -# `cargo update -p stellar-tokens` to move to the branch tip. +# pins the exact resolved commit; this branch was validated at rev 539968f. +# Do not update independently of SDK/circuits/VKs: newer branch revisions change +# the proof protocol. See ../UPSTREAM_RECONCILIATION.md. # # Transitive deps (soroban-poseidon, stellar-contract-utils, stellar-governance, # and the pinned `ultrahonk-soroban-verifier` git rev) are resolved through that @@ -25,6 +26,7 @@ soroban-sdk = { version = "26.0.0" } stellar-access = { git = "https://github.com/OpenZeppelin/stellar-contracts", branch = "feat/confidential-verifier-ultrahonk" } stellar-macros = { git = "https://github.com/OpenZeppelin/stellar-contracts", branch = "feat/confidential-verifier-ultrahonk" } stellar-tokens = { git = "https://github.com/OpenZeppelin/stellar-contracts", branch = "feat/confidential-verifier-ultrahonk" } +stellar-contract-utils = { git = "https://github.com/OpenZeppelin/stellar-contracts", branch = "feat/confidential-verifier-ultrahonk" } # Soroban release profile: optimize for wasm code size and determinism. [profile.release] diff --git a/contracts/escrow-factory/src/test.rs b/contracts/escrow-factory/src/test.rs index fad4255..fca152f 100644 --- a/contracts/escrow-factory/src/test.rs +++ b/contracts/escrow-factory/src/test.rs @@ -23,11 +23,24 @@ impl MockToken { } pub fn confidential_transfer(e: &Env, from: Address, to: Address, _data: Bytes) { from.require_auth(); - let mut log: Vec<(Address, Address)> = - e.storage().instance().get(&symbol_short!("xfers")).unwrap_or(Vec::new(e)); + let mut log: Vec<(Address, Address)> = e + .storage() + .instance() + .get(&symbol_short!("xfers")) + .unwrap_or(Vec::new(e)); log.push_back((from, to)); e.storage().instance().set(&symbol_short!("xfers"), &log); } + pub fn verify_escrow_payout( + _e: &Env, + _register_data: Bytes, + _auditor_id: u32, + transfer_in: Bytes, + _to: Address, + data: Bytes, + ) -> bool { + !data.is_empty() && data == transfer_in + } pub fn merge(_e: &Env, account: Address) { account.require_auth(); } @@ -59,14 +72,17 @@ fn create_escrow_deploys_a_working_instance() { // through fund -> mark_completed -> release. let escrow = instance::Client::new(&e, &addr); let blob = Bytes::from_array(&e, &[7u8; 8]); - escrow.store_payout_proofs(&blob, &blob); - escrow.fund(&blob, &0u32, &blob); + escrow.prepare_funding(&blob, &0u32, &blob); + escrow.store_payout_proof(&true, &blob); + escrow.store_payout_proof(&false, &blob); + escrow.fund(); escrow.mark_completed(&String::from_str(&e, "ipfs://x")); escrow.release(); assert_eq!(escrow.get_escrow().state, instance::EscrowState::Released); // Second escrow gets a distinct address. - let (id2, addr2) = factory.create_escrow(&depositor, &recipient, &Some(recipient.clone()), &10u64); + let (id2, addr2) = + factory.create_escrow(&depositor, &recipient, &Some(recipient.clone()), &10u64); assert_eq!(id2, 2); assert_ne!(addr, addr2); } diff --git a/contracts/escrow-factory/test_snapshots/test/create_escrow_deploys_a_working_instance.1.json b/contracts/escrow-factory/test_snapshots/test/create_escrow_deploys_a_working_instance.1.json index 5ca74fa..45901fa 100644 --- a/contracts/escrow-factory/test_snapshots/test/create_escrow_deploys_a_working_instance.1.json +++ b/contracts/escrow-factory/test_snapshots/test/create_escrow_deploys_a_working_instance.1.json @@ -42,11 +42,14 @@ "function": { "contract_fn": { "contract_address": "CDDMUEDPF7Z22WY7BL24MYJZWHJK7OPKG5UN4MDPDIRROZZUBU6H3OPS", - "function_name": "store_payout_proofs", + "function_name": "prepare_funding", "args": [ { "bytes": "0707070707070707" }, + { + "u32": 0 + }, { "bytes": "0707070707070707" } @@ -64,13 +67,32 @@ "function": { "contract_fn": { "contract_address": "CDDMUEDPF7Z22WY7BL24MYJZWHJK7OPKG5UN4MDPDIRROZZUBU6H3OPS", - "function_name": "fund", + "function_name": "store_payout_proof", "args": [ { - "bytes": "0707070707070707" + "bool": true }, { - "u32": 0 + "bytes": "0707070707070707" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + { + "function": { + "contract_fn": { + "contract_address": "CDDMUEDPF7Z22WY7BL24MYJZWHJK7OPKG5UN4MDPDIRROZZUBU6H3OPS", + "function_name": "store_payout_proof", + "args": [ + { + "bool": false }, { "bytes": "0707070707070707" @@ -78,6 +100,21 @@ ] } }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + { + "function": { + "contract_fn": { + "contract_address": "CDDMUEDPF7Z22WY7BL24MYJZWHJK7OPKG5UN4MDPDIRROZZUBU6H3OPS", + "function_name": "fund", + "args": [] + } + }, "sub_invocations": [ { "function": { @@ -320,7 +357,7 @@ ] }, "val": { - "bytes": "44c5852692374c24c5fe2cc6c9e7fcfa936418365ae352266182743794501306" + "bytes": "6136c5350ce537fb404ae1c9e4a37b4a5156b62601fcbca01060210025b1bc1a" } }, { @@ -413,7 +450,7 @@ "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", "key": { "ledger_key_nonce": { - "nonce": "4270020994084947596" + "nonce": "4837995959683129791" } }, "durability": "temporary", @@ -444,6 +481,46 @@ }, "live_until": 6311999 }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "ledger_key_nonce": { + "nonce": "6277191135259896685" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", + "key": { + "ledger_key_nonce": { + "nonce": "8370022561469687789" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, { "entry": { "last_modified_ledger_seq": 0, @@ -453,7 +530,7 @@ "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", "key": { "ledger_key_nonce": { - "nonce": "4837995959683129791" + "nonce": "4270020994084947596" } }, "durability": "temporary", @@ -476,7 +553,7 @@ "val": { "contract_instance": { "executable": { - "wasm": "44c5852692374c24c5fe2cc6c9e7fcfa936418365ae352266182743794501306" + "wasm": "6136c5350ce537fb404ae1c9e4a37b4a5156b62601fcbca01060210025b1bc1a" }, "storage": [ { @@ -581,7 +658,7 @@ "val": { "contract_instance": { "executable": { - "wasm": "44c5852692374c24c5fe2cc6c9e7fcfa936418365ae352266182743794501306" + "wasm": "6136c5350ce537fb404ae1c9e4a37b4a5156b62601fcbca01060210025b1bc1a" }, "storage": [ { @@ -706,21 +783,21 @@ "ext": "v0", "cost_inputs": { "ext": "v0", - "n_instructions": 1731, - "n_functions": 36, + "n_instructions": 2081, + "n_functions": 42, "n_globals": 4, "n_table_entries": 0, - "n_types": 17, + "n_types": 20, "n_data_segments": 1, "n_elem_segments": 0, - "n_imports": 14, - "n_exports": 17, - "n_data_segment_bytes": 341 + "n_imports": 15, + "n_exports": 18, + "n_data_segment_bytes": 413 } } }, - "hash": "44c5852692374c24c5fe2cc6c9e7fcfa936418365ae352266182743794501306", - "code": "0061736d010000000166116000017e60017e017e60027e7e017e60037e7e7e017e60027f7e0060017f017e60017f0060027e7e0060037f7f7f0060047e7e7e7e017e60017e017f60017f017f60047e7e7e7e0060027f7f017e60037e7e7e0060047f7f7f7f017e60057e7e7e7e7e017e02550e016901300001016d016100090178013700000178013100020169015f00010161013000010162016a00020164015f0003017801340000016c01310002016c01300002016c015f0003017601670002016d0139000303252404050a010b06050704040c080d0e060007050f080410000000010300010000000200050605030100110621047f01418080c0000b7f0041d882c0000b7f0041d882c0000b7f0041e082c0000b07f10111066d656d6f727902000d5f5f636f6e7374727563746f7200230663616e63656c002512636c61696d5f61667465725f77696e646f77002612646973707574655f776974685f70726f6f6600270466756e6400280a6765745f657363726f7700290e6d61726b5f636f6d706c65746564002a0772656c65617365002b147265736f6c76655f746f5f6465706f7369746f72002c147265736f6c76655f746f5f726563697069656e74002d1373746f72655f7061796f75745f70726f6f6673002e0774696d656f7574002f05746f6b656e001d015f03010a5f5f646174615f656e6403020b5f5f686561705f6261736503030c01010aea1b244902017f017e027e2001a741ff0171220241c0004704402002410647044042012103428390808080010c020b20014208880c010b200110000b210120002003370300200020013703080bbb0102017f017e230041106b2201240002400240024002400240200041ff017141016b0e03010203000b200141bd81c000410510210c030b200141c281c000410610210c020b200141c881c000410c10210c010b200141d481c000410b10210b0240200128020045044020012903082102230041106b2200240020002002370308200041086a4101101a21022001420037030020012002370308200041106a2400200129030821022001290300500d010b000b200141106a240020020b0b0020004202100a4201510b08002000420210090b08002000100f10100b0c004101100f2000101410150bd80102027f077e230041d0006b220124002000290308210320002903002104200141406b2202200029033010220240024020012802400d002001290348210520022000290320102220012802400d002001290348210620003100382107200029031821082000290310210920022000290328102220012802404101470d010b000b2001200129034837033820012008370328200120093703202001200637031820012005370310200120074220864204843703302001200342022004a71b37030841f080c0004107200141086a41071020200141d0006a24000b0b00200020014202100b1a0b0a002000100f200110150b350020014202520440200142ff018342cd00520440200042023703000f0b20002001370308200042013703000f0b200042003703000bab0102027f017e230041306b22042400200441186a41a881c00041151019200428021841014704402004290320210620042003370310200420023703082004200137030003402005411846044041002105034020054118470440200441186a20056a200420056a290300370300200541086a21050c010b0b20002006200441186a4103101a101b200441306a24000f05200441186a20056a4202370300200541086a21050c010b000b000b000bc40102037f017e027e0240200241094b0d00200221042001210503402006420886420e842004450d021a027f410120052d0000220341df00460d001a0240200341306b41ff0171410a4f0440200341c1006b41ff0171411a490d01200341e1006b41ff0171411a4f0d042003413b6b0c020b2003412e6b0c010b200341356b0bad42ff01832006420686842106200441016b2104200541016a21050c000b000b2001ad4220864204842002ad42208642048410060b210620004200370300200020063703080b16002000ad4220864204842001ad422086420484100c0b1500200020012002100742ff01834202520440000b0be00202027f087e230041d0006b2201240002404101100f220310100440200310112103034020024138470440200141086a20026a4202370300200241086a21020c010b0b0240200342ff018342cc00520d0020034284808080808e8008200141086aad4220864204844284808080f00010011a200141406b220220012903081017200129034022044202510d002001290348210520022001290310100e20012802400d002001290348210620022001290318100e20012802400d002001290320220742ff018342cd00520d002001290328220842ff018342cd00520d002001290330220342ff0183420452200342ffffffffef0056720d002001290348210920022001290338100e20012802404101470d020b000b000b2001290348210a200020063703302000200a3703282000200937032020002008370318200020073703102000200537030820002004370300200020034220883c0038200141d0006a24000b5a02017f017e230041106b220024000240024020004100100f22011010047e20011011220142ff018342cd00520d012000200137030842010542000b3703000c010b000b2000280200450440000b2000290308200041106a24000b6502027f037e230041106b22022400101d21042002100222053703004202210641012103034020030440200341016b2103200521060c010b0b200220063703082004428ed4ecdbaa06200241086a4101101a101b20042005200120001018200241106a24000b4f02017f027e230041106b220124002001200029030022033703004202210241012100034020000440200041016b2100200321020c010b0b20012002370308200141086a4101101a200141106a24000b280020012003470440000b2000ad4220864204842002ad4220864204842001ad422086420484100d0b3801017f230041106b22032400200320012002101920002003280200047e4201052000200329030837030842000b370300200341106a24000b2f00200142ffffffffffffffff0058047e200142088642068405200110040b210120004200370300200020013703080bc70102017f027e230041406a2205240002400240200042ff018342cd0052200142ff018342cd005272200242ff018342cd0052720d00200520031017200529030022064202510d002005290308210720052004100e20052802004101460d0020052903082104102421034100100f20001015200320047c22002003540d012005200237031820052001370310200541003a0038200520073703082005200637030020054200370330200520003703282005200337032020051013200541406b240042020f0b000b000b2b02017e017f10082200a741ff017122014106470440200141c000460440200010000f0b000b20004208880b6102027f017e230041d0006b22002400200041086a2201101c200029031810051a20002d0040047f410405200041063a004020011013418080c000101f41044100200041c8006a4100102010031a41000b4103742903808240200041d0006a24000b870102017f037e230041406a220024002000101c2000290318220110051a027f410420002d00384102470d001a1024210202402000290330220342a77b5804402002200342d8047c5a0d0141050c020b000b410720002802000d001a200041033a003820001013410210302001101e41f881c000103141000b4103742903808240200041406b24000bb20102017f037e230041d0006b22012400200042ff018342c9005104402001101c2001290318220310051a027f410420012d00384102470d001a1024210202402001290330220442a77b5804402002200442d8047c5a0d0141050c020b000b41062001290300500d001a200141043a00382001101341e881c000101f2001200037034820012003370340419480c0004102200141406b4102102010031a41000b4103742903808240200141d0006a24000f0b000bb90202037f037e230041f0006b220424000240200042ff018342c80052200142ff018342045272200242ff018342c80052724504402004101c2004290310220810051a4104210320042d00380d01410a210341021012450d0141031012450d01101d210610022107200420003703502004200142848080807083370348200420073703404100210303402003411846044041002103034020034118470440200441d8006a20036a200441406b20036a290300370300200341086a21030c010b0b2006428eeeea9ceee5aaef00200441d8006a22054103101a101b20062008200720021018200441013a0038200410134100210341e081c000101f4104410020054100102010031a0c0305200441d8006a20036a4202370300200341086a21030c010b000b000b000b20034103742903808240200441f0006a24000b1e02017f017e230041406a220024002000101c20001014200041406b24000b870102017f027e230041d0006b22012400200042ff018342c9005104402001101c2001290318220210051a20012d0038410146047f200141023a0038200110243703302001101341a880c000101f2001200037034820012002370340419480c0004102200141406b4102102010031a41000541040b4103742903808240200141d0006a24000f0b000b5e02017f017e230041406a220024002000101c200029031010051a20002d003841016b41ff017141014d047f200041033a003820001013410210302000290318101e41f881c000103141000541040b4103742903808240200041406b24000b6602017f017e230041406a220024002000101c027f410620002802004101470d001a200029030810051a410420002d00384104470d001a200041053a003820001013410310302000290310101e41f081c000103141000b4103742903808240200041406b24000b6602017f017e230041406a220024002000101c027f410620002802004101470d001a200029030810051a410420002d00384104470d001a200041033a003820001013410210302000290318101e41f881c000103141000b4103742903808240200041406b24000b5c01017f230041406a22022400200042ff018342c80052200142ff018342c80052724504402002101c200229031010051a20022d0038047f41040541022000101641032001101641000b4103742903808240200241406b24000f0b000b6502017f017e230041406a220024002000101c2000290310220110051a027f410420002d00384101470d001a410810242000290328540d001a200041053a003820001013410310302001101e41f081c000103141000b4103742903808240200041406b24000b5a02017f017e230041106b220124000240024020012000100f22021010047e20021011220242ff018342c800520d012001200237030842010542000b3703000c010b000b2001280200450440000b2001290308200141106a24000b2801017f230041106b220124002000101f41044100200141086a4100102010031a200141106a24000b0bdf020100418080c0000bd5020ea91ac72a3a9b28627970726f6f665f7572690008001000020000000a00100009000000000000000ea99aab712dd32861726269746572636f6d706c657465645f6174637265617465645f61746465706f7369746f72726563697069656e74737461746574696d656f75745f617400003000100007000000370010000c000000430010000a0000004d0010000900000056001000090000005f00100005000000640010000a000000636f6e666964656e7469616c5f7472616e73666572546f6b656e457363726f7752656c6561736550726f6f66526566756e6450726f6f66000ea99acefa0a00000ea99aeb35eea6000ea99acefaaade000ea98a9b6aacde000200000000000000030000000100000003000000020000000300000003000000030000000400000003000000050000000300000006000000030000000700000003000000080000000300000009000000030000000a00c3200e636f6e7472616374737065637630000000040000000000000000000000054572726f720000000000000a000000000000000c4e6f744465706f7369746f7200000001000000000000000c4e6f74526563697069656e7400000002000000000000000a4e6f74417262697465720000000000030000000000000008426164537461746500000004000000000000001352656c6561736557696e646f77416374697665000000000500000000000000094e6f4172626974657200000000000006000000000000000a417262697465725365740000000000070000000000000008546f6f4561726c790000000800000000000000084e6f74466f756e6400000009000000436066756e6460207761732063616c6c6564206265666f7265206073746f72655f7061796f75745f70726f6f66736020e280942073656520696e7374616e63652e72732e00000000135061796f757450726f6f66734d697373696e67000000000a000000010000002152656164206d6f64656c206f6620616e20657363726f7720696e7374616e63652e0000000000000000000006457363726f7700000000000700000000000000076172626974657200000003e800000013000000000000000c636f6d706c657465645f617400000006000000000000000a637265617465645f617400000000000600000000000000096465706f7369746f72000000000000130000000000000009726563697069656e740000000000001300000000000000057374617465000000000007d00000000b457363726f77537461746500000000000000000a74696d656f75745f617400000000000600000003000000414c6966656379636c65206f6620616e20657363726f772c206d6972726f72696e672074686520536f6c6964697479207265666572656e63652065786163746c792e000000000000000000000b457363726f77537461746500000000070000001e5368656c6c20637265617465642c206e6f74207965742066756e6465642e000000000007437265617465640000000000000000274465706f7369746f72206c6f636b65642066756e64733b2074696d656f7574206163746976652e000000000646756e64656400000000000100000042526563697069656e74206d61726b65642064656c69766572793b2072656c656173652077696e646f77206163746976653b2074696d656f757420626c6f636b65642e000000000009436f6d706c65746564000000000000020000001846756e64732073656e7420746f20726563697069656e742e0000000852656c65617365640000000300000012417262697465722063616c6c656420696e2e0000000000084469737075746564000000040000001c46756e64732072657475726e656420746f206465706f7369746f722e00000008526566756e646564000000050000001943616e63656c6c6564206265666f72652066756e64696e672e0000000000000943616e63656c6c6564000000000000060000000500000000000000000000000646756e6465640000000000010000000666756e6465640000000000000000000200000005000000000000000000000008446973707574656400000001000000086469737075746564000000020000000000000002627900000000001300000000000000000000000970726f6f665f75726900000000000010000000000000000200000005000000000000000000000008526566756e6465640000000100000008726566756e64656400000000000000020000000500000000000000000000000852656c6561736564000000010000000872656c656173656400000000000000020000000500000000000000000000000943616e63656c6c6564000000000000010000000963616e63656c6c6564000000000000000000000200000005000000000000000000000009436f6d706c657465640000000000000100000009636f6d706c65746564000000000000020000000000000002627900000000001300000000000000000000000970726f6f665f75726900000000000010000000000000000200000000000001ca4c6f636b2066756e647320696e746f207468697320657363726f772e20546865206465706f7369746f723a0a2a20726567697374657273207468697320696e7374616e6365206173206120636f6e666964656e7469616c206163636f756e7420286072656769737465725f64617461600a6973207468652072656769737465722070726f6f6620666f722074686520696e7374616e63652773204772756d706b696e206964656e74697479292c20616e640a2a2060636f6e666964656e7469616c5f7472616e7366657260732074686520616d6f756e7420696e2028607472616e736665725f696e60292e0a5265717569726573206073746f72655f7061796f75745f70726f6f66736020746f206861766520616c7265616479206265656e2063616c6c656420e28094206046756e646564602069730a6f6e6c79206576657220726561636865642077697468206120636f6d706c6574652c20776f726b696e67207061796f75742d70726f6f662073657420616c726561647920696e0a706c6163652c20736f207468657265206973206e6f20726561636861626c652068616c662d66756e6465642073746174652e2053746174653a2043726561746564202d3e2046756e6465642e00000000000466756e6400000003000000000000000d72656769737465725f646174610000000000000e000000000000000a61756469746f725f6964000000000004000000000000000b7472616e736665725f696e000000000e00000001000003e90000000200000003000000000000000000000005746f6b656e000000000000000000000100000013000000000000003643616e63656c20616e20756e66756e646564207368656c6c2e2053746174653a2043726561746564202d3e2043616e63656c6c65642e00000000000663616e63656c00000000000000000001000003e90000000200000003000000000000006c4465706f7369746f722072656c656173657320746f2074686520726563697069656e742e2043616c6c61626c652066726f6d2046756e64656420286561726c7929206f720a436f6d706c6574656420286e6f726d616c292e2053746174653a202d3e2052656c65617365642e0000000772656c65617365000000000000000001000003e9000000020000000300000000000000804465706f7369746f72207265636c61696d732061207374696c6c2d6046756e6465646020657363726f772061667465722074696d656f75742e20426c6f636b6564206f6e6365207468650a726563697069656e74206d61726b7320636f6d706c657465642e2053746174653a2046756e646564202d3e20526566756e6465642e0000000774696d656f7574000000000000000001000003e9000000020000000300000000000000000000000a6765745f657363726f7700000000000000000001000007d000000006457363726f77000000000000000000794465706c6f7965642062792074686520666163746f72792e206074696d656f75745f7365636f6e64736020636f756e74732066726f6d206e6f773b2061667465722069742c207468650a6465706f7369746f72206d61792073656c662d726566756e64207768696c65207374696c6c206046756e646564602e0000000000000d5f5f636f6e7374727563746f72000000000000050000000000000005746f6b656e0000000000001300000000000000096465706f7369746f72000000000000130000000000000009726563697069656e740000000000001300000000000000076172626974657200000003e800000013000000000000000f74696d656f75745f7365636f6e64730000000006000000000000000000000060526563697069656e74206d61726b732064656c69766572793b20737461727473207468652072656c656173652077696e646f772c20626c6f636b732074696d656f75742e0a53746174653a2046756e646564202d3e20436f6d706c657465642e0000000e6d61726b5f636f6d706c65746564000000000001000000000000000970726f6f665f7572690000000000001000000001000003e900000002000000030000000000000070526563697069656e74206175746f2d636c61696d73207768656e207468657265206973206e6f206172626974657220616e64207468652072656c656173652077696e646f77206861730a657870697265642e2053746174653a20436f6d706c65746564202d3e2052656c65617365642e00000012636c61696d5f61667465725f77696e646f7700000000000000000001000003e90000000200000003000000000000006f526563697069656e7420657363616c6174657320746f207468652061726269746572206166746572207468652072656c656173652077696e646f772e20526571756972657320616e0a617262697465722e2053746174653a20436f6d706c65746564202d3e2044697370757465642e0000000012646973707574655f776974685f70726f6f66000000000001000000000000000970726f6f665f7572690000000000001000000001000003e9000000020000000300000000000001c753746f7265207468652074776f207072652d67656e657261746564207061796f75742070726f6f66732028696e7374616e636520e2869220726563697069656e742c0a696e7374616e636520e28692206465706f7369746f722920746865207374617465206d616368696e652077696c6c206c617465722073656c656374206265747765656e2e0a53706c6974206f75742066726f6d206066756e646020626563617573652062756e646c696e6720626f74682070726f6f667320616c6f6e6773696465207468650a726567697374657220616e64207472616e736665722d696e2070726f6f667320696e206f6e65207472616e73616374696f6e206578636565647320536f726f62616e27730a7065722d7472616e73616374696f6e2073697a65206365696c696e6720e2809420666f7572207e31344b4220556c747261486f6e6b2070726f6f667320697320746f6f206d7563680a666f7220612073696e676c652063616c6c2e204d7573742062652063616c6c6564206265666f7265206066756e64603b206861726d6c65737320746f2063616c6c20616761696e0a7768696c65207374696c6c2060437265617465646020286c6173742077726974652077696e73292e000000001373746f72655f7061796f75745f70726f6f66730000000002000000000000000d72656c656173655f70726f6f660000000000000e000000000000000c726566756e645f70726f6f660000000e00000001000003e900000002000000030000000000000049417262697465722072657475726e732074686520657363726f7720746f20746865206465706f7369746f722e2053746174653a204469737075746564202d3e20526566756e6465642e000000000000147265736f6c76655f746f5f6465706f7369746f720000000000000001000003e90000000200000003000000000000004841726269746572206177617264732074686520657363726f7720746f2074686520726563697069656e742e2053746174653a204469737075746564202d3e2052656c65617365642e000000147265736f6c76655f746f5f726563697069656e740000000000000001000003e90000000200000003001e11636f6e7472616374656e766d6574617630000000000000001a00000000006f0e636f6e74726163746d65746176300000000000000005727376657200000000000006312e39312e3100000000000000000008727373646b7665720000002f32362e312e3023313735616134313330366633383330353761386364666338346236386439333136363466633334650000530e636f6e74726163746d65746176300000000000000006636c6976657200000000002f32372e302e30233561376335666537363533306266343234383437376163383132666337353731343662393863633400" + "hash": "6136c5350ce537fb404ae1c9e4a37b4a5156b62601fcbca01060210025b1bc1a", + "code": "0061736d010000000179146000017e60027e7e017e60017e017e60037e7e7e017e60027f7e0060017f0060017f017e60027e7e0060027f7f017e60037f7f7f0060047e7e7e7e017e60017e017f60027f7f0060017f017f60067e7e7f7e7e7e017f60047e7e7e7e0060037e7e7e0060047f7f7f7f017e60057e7e7e7e7e017e60017e00025b0f0169013000020164015f0003016d0161000a0178013700000178013100010169015f00020161013000020162016a0001017801340000016c01310001016c01300001016c01320001016c015f0003017601670001016d01390003032b2a0405060b020c0d04070506040e08080f100500070611090412000000020013000203000000010009060505030100110621047f01418080c0000b7f0041a083c0000b7f0041a083c0000b7f0041a083c0000b07820212066d656d6f727902000d5f5f636f6e7374727563746f7200270663616e63656c002912636c61696d5f61667465725f77696e646f77002a12646973707574655f776974685f70726f6f66002b0466756e64002c0a6765745f657363726f77002e0e6d61726b5f636f6d706c65746564002f0f707265706172655f66756e64696e6700300772656c656173650031147265736f6c76655f746f5f6465706f7369746f720032147265736f6c76655f746f5f726563697069656e7400331273746f72655f7061796f75745f70726f6f6600340774696d656f7574003505746f6b656e0021015f03010a5f5f646174615f656e6403020b5f5f686561705f6261736503030c01010aa8212a4902017f017e027e2001a741ff0171220241c0004704402002410647044042012103428390808080010c020b20014208880c010b200110000b210120002003370300200020013703080b4202017e027f02404105101122011012047f20011013220142ff01834204520d012001422088a7210241010541000b210320002002360204200020033602000f0b000bee0102017f017e230041106b2201240002400240024002400240024002400240200041ff017141016b0e06010203040506000b200141d181c000410510250c060b200141d681c000410610250c050b200141dc81c000410c10250c040b200141e881c000410b10250c030b200141f381c000410c10250c020b200141ff81c000410910250c010b2001418882c000410a10250b0240200128020045044020012903082102230041106b2200240020002002370308200041086a4101101d21022001420037030020012002370308200041106a2400200129030821022001290300500d010b000b200141106a240020020b0b0020004202100a4201510b08002000420210090b3501017e024020002001101122021012047e20021013220242ff018342c800520d012000200237030842010542000b3703000f0b000b08002000101110120b0a0020001011200110170b0b00200020014202100c1a0b0c00410110112000101910170bd80102027f077e230041d0006b220124002000290308210320002903002104200141406b2202200029033010260240024020012802400d002001290348210520022000290320102620012802400d002001290348210620003100382107200029031821082000290310210920022000290328102620012802404101470d010b000b2001200129034837033820012008370328200120093703202001200637031820012005370310200120074220864204843703302001200342022004a71b37030841f080c0004107200141086a41071024200141d0006a24000b350020014202520440200142ff018342cd00520440200042023703000f0b20002001370308200042013703000f0b200042003703000bcb0102017f017e230041d0006b2206240041a881c0004114101c21072006200537032020062004370318200620033703102006200137030020062002ad42208642048437030841002102037f2002412846047f41002102034020024128470440200641286a20026a200220066a290300370300200241086a21020c010b0b4101210202400240024020002007200641286a4105101d1001a741ff01710e020102000b000b410021020b200641d0006a2400200205200641286a20026a4202370300200241086a21020c010b0b0b2f02017f017e230041106b22022400200220002001103620022802004101460440000b2002290308200241106a24000b16002000ad4220864204842001ad422086420484100d0b920102027f017e230041306b2205240041bc81c0004115101c210620052003370310200520023703082005200137030003402004411846044041002104034020044118470440200541186a20046a200420056a290300370300200441086a21040c010b0b20002006200541186a4103101d101f200541306a240005200541186a20046a4202370300200441086a21040c010b0b0b1500200020012002100142ff01834202520440000b0be00202027f087e230041d0006b22012400024041011011220310120440200310132103034020024138470440200141086a20026a4202370300200241086a21020c010b0b0240200342ff018342cc00520d0020034284808080808e8008200141086aad4220864204844284808080f00010021a200141406b22022001290308101a200129034022044202510d002001290348210520022001290310100f20012802400d002001290348210620022001290318100f20012802400d002001290320220742ff018342cd00520d002001290328220842ff018342cd00520d002001290330220342ff0183420452200342ffffffffef0056720d002001290348210920022001290338100f20012802404101470d020b000b000b2001290348210a200020063703302000200a3703282000200937032020002008370318200020073703102000200537030820002004370300200020034220883c0038200141d0006a24000b5a02017f017e230041106b220024000240024020004100101122011012047e20011013220142ff018342cd00520d012000200137030842010542000b3703000c010b000b2000280200450440000b2000290308200041106a24000b0c001021100320012000101e0b4f02017f027e230041106b220124002001200029030022033703004202210241012100034020000440200041016b2100200321020c010b0b20012002370308200141086a4101101d200141106a24000b280020012003470440000b2000ad4220864204842002ad4220864204842001ad422086420484100e0b3801017f230041106b22032400200320012002103620002003280200047e4201052000200329030837030842000b370300200341106a24000b2f00200142ffffffffffffffff0058047e200142088642068405200110050b210120004200370300200020013703080bc70102017f027e230041406a2205240002400240200042ff018342cd0052200142ff018342cd005272200242ff018342cd0052720d0020052003101a200529030022064202510d002005290308210720052004100f20052802004101460d0020052903082104102821034100101120001017200320047c22002003540d012005200237031820052001370310200541003a0038200520073703082005200637030020054200370330200520003703282005200337032020051018200541406b240042020f0b000b000b2b02017e017f10082200a741ff017122014106470440200141c000460440200010000f0b000b20004208880b6102027f017e230041d0006b22002400200041086a22011020200029031810061a20002d0040047f410405200041063a004020011018418080c000102341044100200041c8006a4100102410041a41000b4103742903b88240200041d0006a24000b870102017f037e230041406a22002400200010202000290318220110061a027f410420002d00384102470d001a1028210202402000290330220342a77b5804402002200342d8047c5a0d0141050c020b000b410720002802000d001a200041033a003820001018410210372001102241b082c000103841000b4103742903b88240200041406b24000bb20102017f037e230041d0006b22012400200042ff018342c900510440200110202001290318220310061a027f410420012d00384102470d001a1028210202402001290330220442a77b5804402002200442d8047c5a0d0141050c020b000b41062001290300500d001a200141043a00382001101841a082c00010232001200037034820012003370340419480c0004102200141406b4102102410041a41000b4103742903b88240200141d0006a24000f0b000bbb0302037f057e23004180016b22002400200041106a10202000290320220410061a41042101024020002d00480d00410a210141021015450d0041031015450d00200041e8006a22014104101402402000280268450d0020002903702106200041086a10102000280208410171450d00200028020c21022001410610142000280268450d00200029037021071021210510032103200020063703602000200337035020002002ad4220864204843703584100210103402001411846044041002101034020014118470440200041e8006a20016a200041d0006a20016a290300370300200141086a21010c010b0b2005428eeeea9ceee5aaef00200041e8006a4103101d101f2005200420032007101e200020033703504202210441012101034020010440200141016b2101200321040c010b0b200020043703682005428ed4ecdbaa06200041e8006a22024101101d101f41041011102d41061011102d41051011102d200041013a0048200041106a101841002101419882c00010234104410020024100102410041a0c0305200041e8006a20016a4202370300200141086a21010c010b000b000b000b20014103742903b8824020004180016a24000b090020004202100b1a0b1e02017f017e230041406a220024002000102020001019200041406b24000b870102017f027e230041d0006b22012400200042ff018342c900510440200110202001290318220210061a20012d0038410146047f200141023a0038200110283703302001101841a880c00010232001200037034820012002370340419480c0004102200141406b4102102410041a41000541040b4103742903b88240200141d0006a24000f0b000b810101017f230041406a22032400200042ff018342c80052200142ff018342045272200242ff018342c800527245044020031020200329031010061a20032d0038047f41040541042000101641051011200142848080807083101741062002101641021011102d41031011102d41000b4103742903b88240200341406b24000f0b000b5e02017f017e230041406a2200240020001020200029031010061a20002d003841016b41ff017141014d047f200041033a003820001018410210372000290318102241b082c000103841000541040b4103742903b88240200041406b24000b6602017f017e230041406a2200240020001020027f410620002802004101470d001a200029030810061a410420002d00384104470d001a200041053a003820001018410310372000290310102241a882c000103841000b4103742903b88240200041406b24000b6602017f017e230041406a2200240020001020027f410620002802004101470d001a200029030810061a410420002d00384104470d001a200041033a003820001018410210372000290318102241b082c000103841000b4103742903b88240200041406b24000b820202047f027e230041e0006b2202240002404101410241002000a741ff017122031b20034101461b2204410246200142ff018342c8005272450440200241106a10202002290320220710061a027f410420022d00480d001a200241d0006a220541041014410b20022802504101470d001a20022903582100200241086a10102002280208410171450d02200228020c21032005410610142002280250450d0220022903582106027f024002402004410171450440102120002003200620072001101b450d0141030c030b102120002003200620022903282001101b0d010b410c0c020b41020b2001101641000b4103742903b88240200241e0006a24000f0b000b000b6502017f017e230041406a22002400200010202000290310220110061a027f410420002d00384101470d001a410810282000290328540d001a200041053a003820001018410310372001102241a882c000103841000b4103742903b88240200041406b24000bc40102037f017e027e0240200241094b0d00200221042001210503402006420886420e842004450d021a027f410120052d0000220341df00460d001a0240200341306b41ff0171410a4f0440200341c1006b41ff0171411a490d01200341e1006b41ff0171411a4f0d042003413b6b0c020b2003412e6b0c010b200341356b0bad42ff01832006420686842106200441016b2104200541016a21050c000b000b2001ad4220864204842002ad42208642048410070b210620004200370300200020063703080b2b02017f017e230041106b220124002001200010142001280200450440000b2001290308200141106a24000b2801017f230041106b220124002000102341044100200141086a4100102410041a200141106a24000b0ba7030100418080c0000b9d030ea91ac72a3a9b28627970726f6f665f7572690008001000020000000a00100009000000000000000ea99aab712dd32861726269746572636f6d706c657465645f6174637265617465645f61746465706f7369746f72726563697069656e74737461746574696d656f75745f617400003000100007000000370010000c000000430010000a0000004d0010000900000056001000090000005f00100005000000640010000a0000007665726966795f657363726f775f7061796f7574636f6e666964656e7469616c5f7472616e73666572546f6b656e457363726f7752656c6561736550726f6f66526566756e6450726f6f6652656769737465724461746141756469746f7249645472616e73666572496e0000000000000ea99acefa0a00000ea99aeb35eea6000ea99acefaaade000ea98a9b6aacde000200000000000000030000000100000003000000020000000300000003000000030000000400000003000000050000000300000006000000030000000700000003000000080000000300000009000000030000000a000000030000000b000000030000000c008b1f0e636f6e7472616374737065637630000000040000000000000000000000054572726f720000000000000c000000000000000c4e6f744465706f7369746f7200000001000000000000000c4e6f74526563697069656e7400000002000000000000000a4e6f74417262697465720000000000030000000000000008426164537461746500000004000000000000001352656c6561736557696e646f77416374697665000000000500000000000000094e6f4172626974657200000000000006000000000000000a417262697465725365740000000000070000000000000008546f6f4561726c790000000800000000000000084e6f74466f756e640000000900000034426f7468207061796f7574206272616e63686573206d757374206265207665726966696564206265666f7265206066756e64602e000000135061796f757450726f6f66734d697373696e67000000000a000000000000001246756e64696e674e6f74507265706172656400000000000b0000000000000012496e76616c69645061796f757450726f6f6600000000000c000000010000002152656164206d6f64656c206f6620616e20657363726f7720696e7374616e63652e0000000000000000000006457363726f7700000000000700000000000000076172626974657200000003e800000013000000000000000c636f6d706c657465645f617400000006000000000000000a637265617465645f617400000000000600000000000000096465706f7369746f72000000000000130000000000000009726563697069656e740000000000001300000000000000057374617465000000000007d00000000b457363726f77537461746500000000000000000a74696d656f75745f617400000000000600000003000000414c6966656379636c65206f6620616e20657363726f772c206d6972726f72696e672074686520536f6c6964697479207265666572656e63652065786163746c792e000000000000000000000b457363726f77537461746500000000070000001e5368656c6c20637265617465642c206e6f74207965742066756e6465642e000000000007437265617465640000000000000000274465706f7369746f72206c6f636b65642066756e64733b2074696d656f7574206163746976652e000000000646756e64656400000000000100000042526563697069656e74206d61726b65642064656c69766572793b2072656c656173652077696e646f77206163746976653b2074696d656f757420626c6f636b65642e000000000009436f6d706c65746564000000000000020000001846756e64732073656e7420746f20726563697069656e742e0000000852656c65617365640000000300000012417262697465722063616c6c656420696e2e0000000000084469737075746564000000040000001c46756e64732072657475726e656420746f206465706f7369746f722e00000008526566756e646564000000050000001943616e63656c6c6564206265666f72652066756e64696e672e0000000000000943616e63656c6c6564000000000000060000000500000000000000000000000646756e6465640000000000010000000666756e6465640000000000000000000200000005000000000000000000000008446973707574656400000001000000086469737075746564000000020000000000000002627900000000001300000000000000000000000970726f6f665f75726900000000000010000000000000000200000005000000000000000000000008526566756e6465640000000100000008726566756e64656400000000000000020000000500000000000000000000000852656c6561736564000000010000000872656c656173656400000000000000020000000500000000000000000000000943616e63656c6c6564000000000000010000000963616e63656c6c6564000000000000000000000200000005000000000000000000000009436f6d706c657465640000000000000100000009636f6d706c65746564000000000000020000000000000002627900000000001300000000000000000000000970726f6f665f757269000000000000100000000000000002000000000000011d45786563757465207468652070726570617265642066756e64696e67206f6e6c7920616674657220424f5448207061796f75742070726f6f6673207061737365642e0a526567697374726174696f6e2c207472616e7366657220616e64206d65726765206172652061746f6d69633a206e6f626f64792063616e20696e6a6563742061206372656469740a6265747765656e20726567697374726174696f6e20616e642074686973206f6e65206d657267652e204c617465722063726564697473207374617920696e20726563656976696e670a616e642063616e6e6f7420696e76616c6964617465207468652066726f7a656e207370656e6461626c6520636f6d6d69746d656e74207573656420617420736574746c656d656e742e0000000000000466756e640000000000000001000003e90000000200000003000000000000000000000005746f6b656e000000000000000000000100000013000000000000003643616e63656c20616e20756e66756e646564207368656c6c2e2053746174653a2043726561746564202d3e2043616e63656c6c65642e00000000000663616e63656c00000000000000000001000003e90000000200000003000000000000006c4465706f7369746f722072656c656173657320746f2074686520726563697069656e742e2043616c6c61626c652066726f6d2046756e64656420286561726c7929206f720a436f6d706c6574656420286e6f726d616c292e2053746174653a202d3e2052656c65617365642e0000000772656c65617365000000000000000001000003e9000000020000000300000000000000804465706f7369746f72207265636c61696d732061207374696c6c2d6046756e6465646020657363726f772061667465722074696d656f75742e20426c6f636b6564206f6e6365207468650a726563697069656e74206d61726b7320636f6d706c657465642e2053746174653a2046756e646564202d3e20526566756e6465642e0000000774696d656f7574000000000000000001000003e9000000020000000300000000000000000000000a6765745f657363726f7700000000000000000001000007d000000006457363726f77000000000000000000794465706c6f7965642062792074686520666163746f72792e206074696d656f75745f7365636f6e64736020636f756e74732066726f6d206e6f773b2061667465722069742c207468650a6465706f7369746f72206d61792073656c662d726566756e64207768696c65207374696c6c206046756e646564602e0000000000000d5f5f636f6e7374727563746f72000000000000050000000000000005746f6b656e0000000000001300000000000000096465706f7369746f72000000000000130000000000000009726563697069656e740000000000001300000000000000076172626974657200000003e800000013000000000000000f74696d656f75745f7365636f6e64730000000006000000000000000000000060526563697069656e74206d61726b732064656c69766572793b20737461727473207468652072656c656173652077696e646f772c20626c6f636b732074696d656f75742e0a53746174653a2046756e646564202d3e20436f6d706c657465642e0000000e6d61726b5f636f6d706c65746564000000000001000000000000000970726f6f665f7572690000000000001000000001000003e9000000020000000300000000000000915072657061726520696d6d757461626c6520696e7075747320666f72207061796f75742076616c69646174696f6e2e2052652d707265706172696e6720696e76616c6964617465730a626f74682070726576696f75736c7920636865636b65642070726f6f66732e204e6f20746f6b656e20726567697374726174696f6e206f722066756e6473206d6f7665207965742e0000000000000f707265706172655f66756e64696e670000000003000000000000000d72656769737465725f646174610000000000000e000000000000000a61756469746f725f6964000000000004000000000000000b7472616e736665725f696e000000000e00000001000003e900000002000000030000000000000070526563697069656e74206175746f2d636c61696d73207768656e207468657265206973206e6f206172626974657220616e64207468652072656c656173652077696e646f77206861730a657870697265642e2053746174653a20436f6d706c65746564202d3e2052656c65617365642e00000012636c61696d5f61667465725f77696e646f7700000000000000000001000003e90000000200000003000000000000006f526563697069656e7420657363616c6174657320746f207468652061726269746572206166746572207468652072656c656173652077696e646f772e20526571756972657320616e0a617262697465722e2053746174653a20436f6d706c65746564202d3e2044697370757465642e0000000012646973707574655f776974685f70726f6f66000000000001000000000000000970726f6f665f7572690000000000001000000001000003e9000000020000000300000000000000d2566572696679206f6e6520736574746c656d656e74206272616e636820616761696e7374207468652045584143542070726570617265642066756e64696e6720696e707574730a6265666f72652073746f72696e672069742e204f6e652070726f6f66207065722063616c6c206b65657073207472616e73616374696f6e2073697a6520616e642070726f76696e670a766572696669636174696f6e20636f737420626f756e6465642e20412072656a65637465642070726f6f66206e6576657220656e61626c65732066756e64696e672e00000000001273746f72655f7061796f75745f70726f6f66000000000002000000000000000772656c656173650000000001000000000000000570726f6f660000000000000e00000001000003e900000002000000030000000000000049417262697465722072657475726e732074686520657363726f7720746f20746865206465706f7369746f722e2053746174653a204469737075746564202d3e20526566756e6465642e000000000000147265736f6c76655f746f5f6465706f7369746f720000000000000001000003e90000000200000003000000000000004841726269746572206177617264732074686520657363726f7720746f2074686520726563697069656e742e2053746174653a204469737075746564202d3e2052656c65617365642e000000147265736f6c76655f746f5f726563697069656e740000000000000001000003e90000000200000003001e11636f6e7472616374656e766d6574617630000000000000001a0000000000770e636f6e74726163746d6574617630000000000000000572737665720000000000000e312e39312e302d6e696768746c7900000000000000000008727373646b7665720000002f32362e312e3023313735616134313330366633383330353761386364666338346236386439333136363466633334650000530e636f6e74726163746d65746176300000000000000006636c6976657200000000002f32372e302e30233561376335666537363533306266343234383437376163383132666337353731343662393863633400" } }, "ext": "v0" diff --git a/contracts/escrow-factory/testdata/private_escrow_instance.wasm b/contracts/escrow-factory/testdata/private_escrow_instance.wasm index 7278934870f334025a6a61693c1b24263038cf87..9bdbc6e42be82711da1abd1e86325472bd9ec857 100644 GIT binary patch delta 4079 zcmZu!U2GiH6}~?+yKB#`eQg}FapL6eCcxTGOadeuB30el;t(i>08xbm)q1^qZLht5 z?2et72agG;LPY}6QKd?4C7w!zidre^k4jb1st;6sp;gsZq7QwcLj9o+ed$X}zjJ3d z4gvqn+~0H0`ObIFJ@eAyD-VaP+HY~j7~h^+Vti*w?Cjvl=^=M)TZB7oiHGzb&$A^F zQd5Q@MjfmgYzb+?t_znEJ3Apwgz*AqrC~Mp&|a5zVOxl!n0R`eH~2{=c%4_6H;`cKt=jR+Z;fZv{ zNxBJVER`BpE=wjRMx05;zQP2%jR{Ezu#tr8O3o${IVa@)?(RFx3z`4=3!m{$UKNvx zmT7f*+k#~(m0G9W4|*>RA_Ody~<7|d!}iseZx*o^-RCh+%lD*Q>mM7 zr{AE%?zwrmXKIaZ!?Xi-?_?jdrqZo$cQ%7cH{0uUR@i;XpwTiIV5i-nvtimS7yX?d zmDh4}(S&&TfwJH`A`~UxRTFuxCY?}obz7d7Kjtr#ohLF}^Rj;Fjhyhg>oYGWHPhmZ zaPX361RM95_fhnWH~>U~VT5zKMwy>u15QFVuhLwP|&zYs_HO!R@c5T52R37Wu= ziM)VGJ6gabVNH6Mkxj6nC{tzbmYG+S)`}FV>tBRc1WVBWIsr8%ydY&KhoESPx<3KEie`XYagWNYJxL|NB zN%Syj)z-ot3M~V?o5gu|4~yql1^S0B{jII z4oAmR7eMCC)ZP2XytAB#;0d6WfR z+T|O0Mv)25DXX5&JCN@?IW9`1;Drn_NRC6XeT!&H`@;GU*?OM)j+&xn1+j)nLZ}Nz zGVn-+iiY8UXYEWuq;qgEQrgrfmnT&&=PGG)W}+yUG~8E|7xCJQ;io`d4(jqDj|Uy% zvDHNLbuIBTAC$0$S6kY~AIQ8b)9S60SGx9Udl?(t7Mia-uqbmC=9F zcP!|bF@k7o*@8TSyUQ2n*jdo5P?RSvd#~Y62W`HXnK>TQ#`T>6adGTT%z2*2frjG{ zXwi?nqmLl%YB?(vogu+U8yZAzbvprptKr4n-QDgBYQK*d$DptnN&6gz2TqYl5YcWX zn}P*aT=aV8(2+PIZ0PL;#h!N2`%K3Zb@)feLtlN1Z&|E!99mcXNWiXi!$CV&H^JW*wH@s zhlQj^X{Bs$Xk1OW)xG)Q;mG+M8H~euQ_)Yy@47S2!W2b=5Cehjjq1IDDmJcPzayih zx;C|CdX1IsLESkh3Zw6<;;|>pYNH>R-UHR3>TlMmqN zWvY=q{L?$lUOp04CgylL`r5=FPv2MW1Zz63HT5!f*Vas5w>JBMUN+hu-Y|8vS5TAc zB`R*07NYM?9{C((vB~psvHNHzxEPnebsDyZ(R=ct_Expos9&_T>_uD2(s=s%FDLs> zIJ0=g)HVa7gEgZE^>bYh3TWMFH@9_l1t#k9W0x)rmF$v~K6?GWsV|JiF!ZWHqtiaF zgMt0J+OF%C>8%=#np{_dPODKnr`w(7PJLUW$k&bbdT45auIgIP0KL&=6I?c?t$P;N zSfCXXtTp;j#>Da#^dnVLDc;rB{h+!HVc1qPjV%=ZqjWS*Xm{}EBg|s7 z_>}*JOP?k~Y$BXwc}QPK)|y~JKL*cOjdhpYQf)T%hB4iK%!O(V#0Y_T<2ld(p21S< zrI^|^%Nw|X_}+n4pp^Du@H)6LghICsR%_EHumN+-`Pe(Re5~DIxQKnn>_^}s`U=Dk v9}K!y-?%dtwWs%Ae@oxa`Q_+Wx%~LpsfGJbEu1{jZmg~a&F$!)xo`a+@2++K delta 3412 zcmZ`*O>7)j9e?l5%hxS0%2jeU>q}SKfh6ZfeHnP}b=eHP=Bn&@fukbL9vt>%+vz#7816z-wltO_g76aO zW`S6gm(UsIWAT^txv2`Pv$~+utUg2poza%chG2rsXo6SbUHu%b#CP>;Lcs4|$Yzz8 zCR_>HVBDNE^NCwQ;j3gUMn9p9K}V;EHNRESt3>G5#HMver8CBl3VoVQSoDfs7dqUR zGeQ^IqQ>!Ii&_pJx~LJYE(~kpvR=1H*+@Id3V0I6CX9^D8I8aYX1UF>fs#!m1ZUPP zf@yq`A47W{sg{f+0jy{sz<~wCBxd}_;djnwOk_bCi97f}7Unog`dLHVYUpnW+HdfJ zIhIr{7|+I^XDVi?qH&HwG(H@k&R(6Rlfb9GRbdLk96zEy^@`qL-#mya201UrZ)eA8 zF@86@jQ>K;hcgOiyMS>x{$B2alt58aC~`Qg5`Mf4ggC1hD5Am28H<)RAfu`HkVsh* zMmdw*q--njk#r+>ej5eyK4?*tNI2nyaOFvtN;{HNR!#4*&{>d1xlkdo(9%5 z7&3k|zIMo>di>)z($XzpYCRyE@F2K0X%W-X!WnHZ{%`)oRO$oB z7?TVRl&1?8yD~&3c{TpBxp;KMVtgL{PFSBqV0_`x@>}LvEC<*VV5z^H9$fyOc_BAq z{ZlPF85au2YmbG04OymIFF_~2U`$Kdct{davwHlS;;BgIQ%c6Xl0yhf2MIbt3{fi& zNEknS2~92efWHi9k+VJDiO-7i<;tZ#JYn+9z@(I9-l~wFf6?>Edl%T#N+(i#M+scZ?-RC0SF z-lHr5z!nb2Yw1P;7}&TtS-zmJHy)6ez<9sqU&5|s0Ewwg01Sg_k{x2<)aB8*h26); z_r(kVSmIh~Q9cc9rNPH{300X}IbK!iPQRR%VGPPpFsNPg1O^C%8kSTM-x`F$`9rHD zy&#ZWslt+Tit*tJ8x%A|)oFo~vq6mpF>ypek~m)P96s|*y2q(Hgwibz^3~a6njbPs z(#!p?EdI~oJMqs)7URO`4*Q*me>i%U=HvULf4lU2OWn^cv113KZM&{q6)SQLm#Szz zkN18c0x5-qXMno=Ykp88@q1$@@0}a(>Cqp);kCDfav8uR^hCJf1R}lnYvSb% zDfTb*i}|y{m+MY|H$#xx4V(%jV+%Yr)|^$`^N#HbyWRG-yP=qF4c0VQ?a*%J;XZ`h zbaYYrB6$S}l#q-MT%HNU6@RKDC zHN0t@ZfmBNe@VW&?cjm(f3QKh8}@Z6Y}c3e>P-MCy8}=aZmr9}MFMOm$a`J)rjXZ> zFKpWzfIZrA!i}Wt^jS13c03>Hu8Z_}GnWyDeu$ppcee4RCb5)Th1T zN+jg2%_%+*0gQ#RCYIIbqIe#G@%R#RUlmDSh1D8SzvRIdpBL-*K0NkQ?cQ6WiR0(@ z%j%((AR6v?z*x?$%dYej4{3fW@PU{fKrTMM^?hX0f2_^s9~~`pQT@lF}Z7Ct?WzY9k?CzN$-;@5_L6gAw zwiIpYB*7KgYu>gmb{Ecny&+z4VY%dWxAsFoX`UxK+wG0K5~?i%UUfjC?AQ5u-9!UVQ0gEhagngwff|?#I$R}*^cjo3f68glaTz> zcQd$Wi2?{2>c7X+CpDQ&hKv2lf-hAj>D)bjYJpNOZd5DT%tGzCh1x depositor. RefundProof, + RegisterData, + AuditorId, + TransferIn, } #[contractevent] @@ -79,37 +82,69 @@ impl PrivateEscrowInstance { ); } - /// Store the two pre-generated payout proofs (instance → recipient, - /// instance → depositor) the state machine will later select between. - /// Split out from `fund` because bundling both proofs alongside the - /// register and transfer-in proofs in one transaction exceeds Soroban's - /// per-transaction size ceiling — four ~14KB UltraHonk proofs is too much - /// for a single call. Must be called before `fund`; harmless to call again - /// while still `Created` (last write wins). - pub fn store_payout_proofs(e: &Env, release_proof: Bytes, refund_proof: Bytes) -> Result<(), Error> { + /// Prepare immutable inputs for payout validation. Re-preparing invalidates + /// both previously checked proofs. No token registration or funds move yet. + pub fn prepare_funding( + e: &Env, + register_data: Bytes, + auditor_id: u32, + transfer_in: Bytes, + ) -> Result<(), Error> { let esc = get(e); esc.depositor.require_auth(); if esc.state != EscrowState::Created { return Err(Error::BadState); } - e.storage().instance().set(&DataKey::ReleaseProof, &release_proof); - e.storage().instance().set(&DataKey::RefundProof, &refund_proof); + e.storage() + .instance() + .set(&DataKey::RegisterData, ®ister_data); + e.storage().instance().set(&DataKey::AuditorId, &auditor_id); + e.storage() + .instance() + .set(&DataKey::TransferIn, &transfer_in); + e.storage().instance().remove(&DataKey::ReleaseProof); + e.storage().instance().remove(&DataKey::RefundProof); Ok(()) } - /// Lock funds into this escrow. The depositor: - /// * registers this instance as a confidential account (`register_data` - /// is the register proof for the instance's Grumpkin identity), and - /// * `confidential_transfer`s the amount in (`transfer_in`). - /// Requires `store_payout_proofs` to have already been called — `Funded` is - /// only ever reached with a complete, working payout-proof set already in - /// place, so there is no reachable half-funded state. State: Created -> Funded. - pub fn fund( - e: &Env, - register_data: Bytes, - auditor_id: u32, - transfer_in: Bytes, - ) -> Result<(), Error> { + /// Verify one settlement branch against the EXACT prepared funding inputs + /// before storing it. One proof per call keeps transaction size and proving + /// verification cost bounded. A rejected proof never enables funding. + pub fn store_payout_proof(e: &Env, release: bool, proof: Bytes) -> Result<(), Error> { + let esc = get(e); + esc.depositor.require_auth(); + if esc.state != EscrowState::Created { + return Err(Error::BadState); + } + let register_data: Bytes = e + .storage() + .instance() + .get(&DataKey::RegisterData) + .ok_or(Error::FundingNotPrepared)?; + let auditor_id: u32 = e.storage().instance().get(&DataKey::AuditorId).unwrap(); + let transfer_in: Bytes = e.storage().instance().get(&DataKey::TransferIn).unwrap(); + let to = if release { + &esc.recipient + } else { + &esc.depositor + }; + if !token(e).verify_escrow_payout(®ister_data, &auditor_id, &transfer_in, to, &proof) { + return Err(Error::InvalidPayoutProof); + } + let key = if release { + DataKey::ReleaseProof + } else { + DataKey::RefundProof + }; + e.storage().instance().set(&key, &proof); + Ok(()) + } + + /// Execute the prepared funding only after BOTH payout proofs passed. + /// Registration, transfer and merge are atomic: nobody can inject a credit + /// between registration and this one merge. Later credits stay in receiving + /// and cannot invalidate the frozen spendable commitment used at settlement. + pub fn fund(e: &Env) -> Result<(), Error> { let mut esc = get(e); esc.depositor.require_auth(); if esc.state != EscrowState::Created { @@ -120,14 +155,18 @@ impl PrivateEscrowInstance { { return Err(Error::PayoutProofsMissing); } - + let register_data: Bytes = e.storage().instance().get(&DataKey::RegisterData).unwrap(); + let auditor_id: u32 = e.storage().instance().get(&DataKey::AuditorId).unwrap(); + let transfer_in: Bytes = e.storage().instance().get(&DataKey::TransferIn).unwrap(); let token = token(e); let this = e.current_contract_address(); - // The instance authorizes its own registration by invocation. token.register(&this, &auditor_id, ®ister_data); - // from = depositor (the transaction source authorizes this). token.confidential_transfer(&esc.depositor, &this, &transfer_in); + token.merge(&this); + e.storage().instance().remove(&DataKey::RegisterData); + e.storage().instance().remove(&DataKey::TransferIn); + e.storage().instance().remove(&DataKey::AuditorId); esc.state = EscrowState::Funded; put(e, &esc); Funded {}.publish(e); @@ -145,7 +184,11 @@ impl PrivateEscrowInstance { esc.state = EscrowState::Completed; esc.completed_at = e.ledger().timestamp(); put(e, &esc); - Completed { by: esc.recipient, proof_uri }.publish(e); + Completed { + by: esc.recipient, + proof_uri, + } + .publish(e); Ok(()) } @@ -180,7 +223,11 @@ impl PrivateEscrowInstance { } esc.state = EscrowState::Disputed; put(e, &esc); - Disputed { by: esc.recipient, proof_uri }.publish(e); + Disputed { + by: esc.recipient, + proof_uri, + } + .publish(e); Ok(()) } @@ -299,11 +346,11 @@ fn depositor_proof(e: &Env) -> Bytes { e.storage().instance().get(&DataKey::RefundProof).unwrap() } -/// Fold received funds into spendable, then send them out with the selected -/// pre-generated proof. `from` is this contract, which authorizes by invocation. +/// Spend only the commitment fixed during funding, using the selected +/// pre-verified proof. Unsolicited credits remain isolated in receiving. +/// `from` is this contract, which authorizes by invocation. fn payout(e: &Env, proof: &Bytes, to: &Address) { let token = token(e); let this = e.current_contract_address(); - token.merge(&this); token.confidential_transfer(&this, to, proof); } diff --git a/contracts/escrow-instance/src/lib.rs b/contracts/escrow-instance/src/lib.rs index f5a3046..6bb5ff4 100644 --- a/contracts/escrow-instance/src/lib.rs +++ b/contracts/escrow-instance/src/lib.rs @@ -11,15 +11,11 @@ //! and pays out with a `confidential_transfer` where `from` is the instance //! itself — a contract authorizes its own outgoing transfer by invocation, so //! the recipient or arbiter can trigger a payout without holding any key. -//! * Because a contract cannot prove on-chain, the depositor pre-generates the -//! two possible payout proofs (instance → recipient, instance → depositor) -//! and stores them via `store_payout_proofs` *before* calling `fund` — the -//! instance submits exactly the one the state machine selects, later. This -//! is two transactions, not one: four ~14KB UltraHonk proofs bundled into a -//! single `fund` call (register + transfer-in + both payout proofs) exceeds -//! Soroban's per-transaction size ceiling. `fund` refuses to run until the -//! payout proofs are already in place, so `Funded` is only ever reached with -//! a complete, working proof set — there's no reachable half-funded state. +//! * The depositor prepares registration + funding inputs, then submits each +//! payout proof for on-chain verification against that future commitment. +//! Only after both branches validate can `fund` atomically register, receive +//! and merge the exact prepared transfer. Settlement never merges later credits. +//! Four transactions keep proof payloads within the transaction size limit. //! //! # Trust caveat //! @@ -45,6 +41,14 @@ pub trait ConfidentialTokenInterface { fn register(env: Env, account: Address, auditor_id: u32, data: Bytes); fn confidential_transfer(env: Env, from: Address, to: Address, data: Bytes); fn merge(env: Env, account: Address); + fn verify_escrow_payout( + env: Env, + register_data: Bytes, + auditor_id: u32, + transfer_in: Bytes, + to: Address, + data: Bytes, + ) -> bool; } #[contracterror] @@ -60,8 +64,10 @@ pub enum Error { ArbiterSet = 7, TooEarly = 8, NotFound = 9, - /// `fund` was called before `store_payout_proofs` — see instance.rs. + /// Both payout branches must be verified before `fund`. PayoutProofsMissing = 10, + FundingNotPrepared = 11, + InvalidPayoutProof = 12, } /// Lifecycle of an escrow, mirroring the Solidity reference exactly. diff --git a/contracts/escrow-instance/src/test.rs b/contracts/escrow-instance/src/test.rs index b55264b..e945d1d 100644 --- a/contracts/escrow-instance/src/test.rs +++ b/contracts/escrow-instance/src/test.rs @@ -16,12 +16,43 @@ pub struct MockToken; #[contractimpl] impl MockToken { - pub fn register(_e: &Env, account: Address, _auditor_id: u32, _data: Bytes) { + pub fn register(e: &Env, account: Address, _auditor_id: u32, _data: Bytes) { account.require_auth(); + e.storage() + .instance() + .set(&(symbol_short!("spend"), account.clone()), &0u32); + e.storage() + .instance() + .set(&(symbol_short!("receive"), account), &0u32); + } + + pub fn verify_escrow_payout( + _e: &Env, + _register_data: Bytes, + _auditor_id: u32, + transfer_in: Bytes, + _to: Address, + data: Bytes, + ) -> bool { + !data.is_empty() && data == transfer_in + } + + pub fn credit(e: &Env, account: Address, amount: u32) { + let key = (symbol_short!("receive"), account); + let prior: u32 = e.storage().instance().get(&key).unwrap_or(0); + e.storage().instance().set(&key, &(prior + amount)); } - pub fn confidential_transfer(e: &Env, from: Address, to: Address, _data: Bytes) { + pub fn confidential_transfer(e: &Env, from: Address, to: Address, data: Bytes) { from.require_auth(); + // Model a proof bound to the sender's original commitment. Any later + // merge of unsolicited credits makes this check fail. + let key = (symbol_short!("spend"), from.clone()); + if let Some(spend) = e.storage().instance().get::<_, u32>(&key) { + assert_eq!(spend, data.get(0).unwrap() as u32); + e.storage().instance().set(&key, &0u32); + } + Self::credit(e, to.clone(), data.get(0).unwrap() as u32); let mut log: Vec<(Address, Address)> = e .storage() .instance() @@ -31,12 +62,21 @@ impl MockToken { e.storage().instance().set(&symbol_short!("xfers"), &log); } - pub fn merge(_e: &Env, account: Address) { + pub fn merge(e: &Env, account: Address) { account.require_auth(); + let spend_key = (symbol_short!("spend"), account.clone()); + let receive_key = (symbol_short!("receive"), account); + let spend: u32 = e.storage().instance().get(&spend_key).unwrap_or(0); + let receive: u32 = e.storage().instance().get(&receive_key).unwrap_or(0); + e.storage().instance().set(&spend_key, &(spend + receive)); + e.storage().instance().set(&receive_key, &0u32); } pub fn xfers(e: &Env) -> Vec<(Address, Address)> { - e.storage().instance().get(&symbol_short!("xfers")).unwrap_or(Vec::new(e)) + e.storage() + .instance() + .get(&symbol_short!("xfers")) + .unwrap_or(Vec::new(e)) } } @@ -59,13 +99,30 @@ fn setup(with_arbiter: bool) -> Fixture { let token = e.register(MockToken, ()); let depositor = Address::generate(&e); let recipient = Address::generate(&e); - let arbiter = if with_arbiter { Some(Address::generate(&e)) } else { None }; + let arbiter = if with_arbiter { + Some(Address::generate(&e)) + } else { + None + }; let id = e.register( PrivateEscrowInstance, - (token.clone(), depositor.clone(), recipient.clone(), arbiter.clone(), TIMEOUT), + ( + token.clone(), + depositor.clone(), + recipient.clone(), + arbiter.clone(), + TIMEOUT, + ), ); let escrow = PrivateEscrowInstanceClient::new(&e, &id); - Fixture { e, token, escrow, depositor, recipient, arbiter } + Fixture { + e, + token, + escrow, + depositor, + recipient, + arbiter, + } } fn b(f: &Fixture) -> Bytes { @@ -73,12 +130,15 @@ fn b(f: &Fixture) -> Bytes { } fn fund(f: &Fixture) { - f.escrow.store_payout_proofs(&b(f), &b(f)); - f.escrow.fund(&b(f), &0u32, &b(f)); + f.escrow.prepare_funding(&b(f), &0u32, &b(f)); + f.escrow.store_payout_proof(&true, &b(f)); + f.escrow.store_payout_proof(&false, &b(f)); + f.escrow.fund(); } fn advance_past_window(f: &Fixture, completed_at: u64) { - f.e.ledger().set_timestamp(completed_at + RELEASE_WINDOW + 1); + f.e.ledger() + .set_timestamp(completed_at + RELEASE_WINDOW + 1); } fn last_payout_to(f: &Fixture) -> Address { @@ -105,7 +165,8 @@ fn fund_moves_to_funded() { fn normal_release_pays_recipient() { let f = setup(false); fund(&f); - f.escrow.mark_completed(&String::from_str(&f.e, "ipfs://proof")); + f.escrow + .mark_completed(&String::from_str(&f.e, "ipfs://proof")); assert_eq!(f.escrow.get_escrow().state, EscrowState::Completed); f.escrow.release(); assert_eq!(f.escrow.get_escrow().state, EscrowState::Released); @@ -140,7 +201,8 @@ fn dispute_then_resolve_to_recipient() { f.escrow.mark_completed(&String::from_str(&f.e, "x")); let completed_at = f.escrow.get_escrow().completed_at; advance_past_window(&f, completed_at); - f.escrow.dispute_with_proof(&String::from_str(&f.e, "evidence")); + f.escrow + .dispute_with_proof(&String::from_str(&f.e, "evidence")); assert_eq!(f.escrow.get_escrow().state, EscrowState::Disputed); f.escrow.resolve_to_recipient(); assert_eq!(f.escrow.get_escrow().state, EscrowState::Released); @@ -154,7 +216,8 @@ fn dispute_then_resolve_to_depositor() { f.escrow.mark_completed(&String::from_str(&f.e, "x")); let completed_at = f.escrow.get_escrow().completed_at; advance_past_window(&f, completed_at); - f.escrow.dispute_with_proof(&String::from_str(&f.e, "evidence")); + f.escrow + .dispute_with_proof(&String::from_str(&f.e, "evidence")); f.escrow.resolve_to_depositor(); assert_eq!(f.escrow.get_escrow().state, EscrowState::Refunded); assert_eq!(last_payout_to(&f), f.depositor); @@ -183,25 +246,25 @@ fn cancel_unfunded() { fn cannot_fund_twice() { let f = setup(false); fund(&f); - let res = f.escrow.try_fund(&b(&f), &0u32, &b(&f)); + let res = f.escrow.try_fund(); assert_eq!(res, Err(Ok(Error::BadState))); } #[test] fn fund_before_payout_proofs_blocked() { let f = setup(false); - let res = f.escrow.try_fund(&b(&f), &0u32, &b(&f)); + let res = f.escrow.try_fund(); assert_eq!(res, Err(Ok(Error::PayoutProofsMissing))); } #[test] -fn store_payout_proofs_can_be_overwritten_before_funding() { +fn preparing_again_invalidates_both_payout_proofs() { let f = setup(false); - f.escrow.store_payout_proofs(&b(&f), &b(&f)); - // Last write wins; still Created, so this is allowed. - f.escrow.store_payout_proofs(&b(&f), &b(&f)); - f.escrow.fund(&b(&f), &0u32, &b(&f)); - assert_eq!(f.escrow.get_escrow().state, EscrowState::Funded); + f.escrow.prepare_funding(&b(&f), &0u32, &b(&f)); + f.escrow.store_payout_proof(&true, &b(&f)); + f.escrow.store_payout_proof(&false, &b(&f)); + f.escrow.prepare_funding(&b(&f), &1u32, &b(&f)); + assert_eq!(f.escrow.try_fund(), Err(Ok(Error::PayoutProofsMissing))); } #[test] @@ -238,7 +301,9 @@ fn dispute_without_arbiter_blocked() { f.escrow.mark_completed(&String::from_str(&f.e, "x")); let completed_at = f.escrow.get_escrow().completed_at; advance_past_window(&f, completed_at); - let res = f.escrow.try_dispute_with_proof(&String::from_str(&f.e, "x")); + let res = f + .escrow + .try_dispute_with_proof(&String::from_str(&f.e, "x")); assert_eq!(res, Err(Ok(Error::NoArbiter))); } @@ -273,15 +338,96 @@ fn stranger_cannot_mark_completed() { let recipient = Address::generate(&e); let id = e.register( PrivateEscrowInstance, - (token, depositor.clone(), recipient, None::
, TIMEOUT), + ( + token, + depositor.clone(), + recipient, + None::
, + TIMEOUT, + ), ); let escrow = PrivateEscrowInstanceClient::new(&e, &id); e.mock_all_auths(); - escrow.store_payout_proofs(&Bytes::from_array(&e, &[1]), &Bytes::from_array(&e, &[1])); - escrow.fund(&Bytes::from_array(&e, &[1]), &0u32, &Bytes::from_array(&e, &[1])); + let blob = Bytes::from_array(&e, &[1]); + escrow.prepare_funding(&blob, &0u32, &blob); + escrow.store_payout_proof(&true, &blob); + escrow.store_payout_proof(&false, &blob); + escrow.fund(); // Real auth required now: nobody authorized as the recipient. e.set_auths(&[]); escrow.mark_completed(&String::from_str(&e, "x")); } + +#[test] +fn invalid_release_proof_cannot_enable_funding() { + let f = setup(false); + f.escrow.prepare_funding(&b(&f), &0u32, &b(&f)); + f.escrow.store_payout_proof(&false, &b(&f)); + assert_eq!( + f.escrow.try_store_payout_proof(&true, &Bytes::new(&f.e)), + Err(Ok(Error::InvalidPayoutProof)) + ); + assert_eq!(f.escrow.try_fund(), Err(Ok(Error::PayoutProofsMissing))); + assert_eq!(f.escrow.get_escrow().state, EscrowState::Created); + assert!(MockTokenClient::new(&f.e, &f.token).xfers().is_empty()); + // A corrected proof can be submitted before funding, with no funds at risk. + f.escrow.store_payout_proof(&true, &b(&f)); + f.escrow.fund(); +} + +#[test] +fn invalid_refund_proof_cannot_enable_funding() { + let f = setup(false); + f.escrow.prepare_funding(&b(&f), &0u32, &b(&f)); + f.escrow.store_payout_proof(&true, &b(&f)); + assert_eq!( + f.escrow + .try_store_payout_proof(&false, &Bytes::from_array(&f.e, &[1])), + Err(Ok(Error::InvalidPayoutProof)) + ); + assert_eq!(f.escrow.try_fund(), Err(Ok(Error::PayoutProofsMissing))); +} + +#[test] +fn payout_proof_requires_prepared_inputs() { + let f = setup(false); + assert_eq!( + f.escrow.try_store_payout_proof(&true, &b(&f)), + Err(Ok(Error::FundingNotPrepared)) + ); +} + +#[test] +fn unsolicited_credit_does_not_block_release() { + let f = setup(false); + fund(&f); + MockTokenClient::new(&f.e, &f.token).credit(&f.escrow.address, &1); + f.escrow.release(); + assert_eq!(last_payout_to(&f), f.recipient); +} + +#[test] +fn unsolicited_credit_does_not_block_refund() { + let f = setup(false); + fund(&f); + MockTokenClient::new(&f.e, &f.token).credit(&f.escrow.address, &1); + f.e.ledger().with_mut(|li| li.timestamp = TIMEOUT + 1); + f.escrow.timeout(); + assert_eq!(last_payout_to(&f), f.depositor); +} + +#[test] +fn cannot_replace_prepared_inputs_or_proofs_after_funding() { + let f = setup(false); + fund(&f); + assert_eq!( + f.escrow.try_prepare_funding(&b(&f), &0, &b(&f)), + Err(Ok(Error::BadState)) + ); + assert_eq!( + f.escrow.try_store_payout_proof(&true, &b(&f)), + Err(Ok(Error::BadState)) + ); +} diff --git a/contracts/escrow-instance/test_snapshots/test/cannot_fund_twice.1.json b/contracts/escrow-instance/test_snapshots/test/cannot_fund_twice.1.json index 5643cc3..3c21317 100644 --- a/contracts/escrow-instance/test_snapshots/test/cannot_fund_twice.1.json +++ b/contracts/escrow-instance/test_snapshots/test/cannot_fund_twice.1.json @@ -14,11 +14,14 @@ "function": { "contract_fn": { "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", - "function_name": "store_payout_proofs", + "function_name": "prepare_funding", "args": [ { "bytes": "0909090909090909" }, + { + "u32": 0 + }, { "bytes": "0909090909090909" } @@ -36,13 +39,32 @@ "function": { "contract_fn": { "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", - "function_name": "fund", + "function_name": "store_payout_proof", "args": [ { - "bytes": "0909090909090909" + "bool": true }, { - "u32": 0 + "bytes": "0909090909090909" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "store_payout_proof", + "args": [ + { + "bool": false }, { "bytes": "0909090909090909" @@ -50,6 +72,21 @@ ] } }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "fund", + "args": [] + } + }, "sub_invocations": [ { "function": { @@ -120,6 +157,36 @@ } ] } + }, + { + "key": { + "vec": [ + { + "symbol": "receive" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4" + } + ] + }, + "val": { + "u32": 0 + } + }, + { + "key": { + "vec": [ + { + "symbol": "spend" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4" + } + ] + }, + "val": { + "u32": 9 + } } ] } @@ -150,6 +217,46 @@ }, "live_until": 6311999 }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": "1033654523790656264" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": "4837995959683129791" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, { "entry": { "last_modified_ledger_seq": 0, diff --git a/contracts/escrow-instance/test_snapshots/test/cannot_replace_prepared_inputs_or_proofs_after_funding.1.json b/contracts/escrow-instance/test_snapshots/test/cannot_replace_prepared_inputs_or_proofs_after_funding.1.json new file mode 100644 index 0000000..7b3c26c --- /dev/null +++ b/contracts/escrow-instance/test_snapshots/test/cannot_replace_prepared_inputs_or_proofs_after_funding.1.json @@ -0,0 +1,425 @@ +{ + "generators": { + "address": 4, + "nonce": 0, + "mux_id": 0 + }, + "auth": [ + [], + [], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "prepare_funding", + "args": [ + { + "bytes": "0909090909090909" + }, + { + "u32": 0 + }, + { + "bytes": "0909090909090909" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "store_payout_proof", + "args": [ + { + "bool": true + }, + { + "bytes": "0909090909090909" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "store_payout_proof", + "args": [ + { + "bool": false + }, + { + "bytes": "0909090909090909" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "fund", + "args": [] + } + }, + "sub_invocations": [ + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "function_name": "confidential_transfer", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4" + }, + { + "bytes": "0909090909090909" + } + ] + } + }, + "sub_invocations": [] + } + ] + } + ] + ], + [], + [] + ], + "ledger": { + "protocol_version": 26, + "sequence_number": 0, + "timestamp": 0, + "network_id": "0000000000000000000000000000000000000000000000000000000000000000", + "base_reserve": 0, + "min_persistent_entry_ttl": 4096, + "min_temp_entry_ttl": 16, + "max_entry_ttl": 6312000, + "ledger_entries": [ + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": { + "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "storage": [ + { + "key": { + "symbol": "xfers" + }, + "val": { + "vec": [ + { + "vec": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4" + } + ] + } + ] + } + }, + { + "key": { + "vec": [ + { + "symbol": "receive" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4" + } + ] + }, + "val": { + "u32": 0 + } + }, + { + "key": { + "vec": [ + { + "symbol": "spend" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4" + } + ] + }, + "val": { + "u32": 9 + } + } + ] + } + } + } + }, + "ext": "v0" + }, + "live_until": 4095 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": "801925984706572462" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": "1033654523790656264" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": "4837995959683129791" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": "5541220902715666415" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": { + "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "storage": [ + { + "key": { + "vec": [ + { + "symbol": "Escrow" + } + ] + }, + "val": { + "map": [ + { + "key": { + "symbol": "arbiter" + }, + "val": "void" + }, + { + "key": { + "symbol": "completed_at" + }, + "val": { + "u64": "0" + } + }, + { + "key": { + "symbol": "created_at" + }, + "val": { + "u64": "0" + } + }, + { + "key": { + "symbol": "depositor" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + }, + { + "key": { + "symbol": "recipient" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + }, + { + "key": { + "symbol": "state" + }, + "val": { + "u32": 1 + } + }, + { + "key": { + "symbol": "timeout_at" + }, + "val": { + "u64": "3600" + } + } + ] + } + }, + { + "key": { + "vec": [ + { + "symbol": "RefundProof" + } + ] + }, + "val": { + "bytes": "0909090909090909" + } + }, + { + "key": { + "vec": [ + { + "symbol": "ReleaseProof" + } + ] + }, + "val": { + "bytes": "0909090909090909" + } + }, + { + "key": { + "vec": [ + { + "symbol": "Token" + } + ] + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + } + ] + } + } + } + }, + "ext": "v0" + }, + "live_until": 4095 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_code": { + "ext": "v0", + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "code": "" + } + }, + "ext": "v0" + }, + "live_until": 4095 + } + ] + }, + "events": [] +} \ No newline at end of file diff --git a/contracts/escrow-instance/test_snapshots/test/claim_after_window_blocked_when_arbiter_set.1.json b/contracts/escrow-instance/test_snapshots/test/claim_after_window_blocked_when_arbiter_set.1.json index d85e0d5..c8668d1 100644 --- a/contracts/escrow-instance/test_snapshots/test/claim_after_window_blocked_when_arbiter_set.1.json +++ b/contracts/escrow-instance/test_snapshots/test/claim_after_window_blocked_when_arbiter_set.1.json @@ -14,11 +14,14 @@ "function": { "contract_fn": { "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", - "function_name": "store_payout_proofs", + "function_name": "prepare_funding", "args": [ { "bytes": "0909090909090909" }, + { + "u32": 0 + }, { "bytes": "0909090909090909" } @@ -36,13 +39,32 @@ "function": { "contract_fn": { "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", - "function_name": "fund", + "function_name": "store_payout_proof", "args": [ { - "bytes": "0909090909090909" + "bool": true }, { - "u32": 0 + "bytes": "0909090909090909" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", + "function_name": "store_payout_proof", + "args": [ + { + "bool": false }, { "bytes": "0909090909090909" @@ -50,6 +72,21 @@ ] } }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", + "function_name": "fund", + "args": [] + } + }, "sub_invocations": [ { "function": { @@ -140,6 +177,36 @@ } ] } + }, + { + "key": { + "vec": [ + { + "symbol": "receive" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM" + } + ] + }, + "val": { + "u32": 0 + } + }, + { + "key": { + "vec": [ + { + "symbol": "spend" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM" + } + ] + }, + "val": { + "u32": 9 + } } ] } @@ -170,6 +237,46 @@ }, "live_until": 6311999 }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": "1033654523790656264" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": "4837995959683129791" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, { "entry": { "last_modified_ledger_seq": 0, @@ -199,7 +306,7 @@ "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", "key": { "ledger_key_nonce": { - "nonce": "1033654523790656264" + "nonce": "2032731177588607455" } }, "durability": "temporary", diff --git a/contracts/escrow-instance/test_snapshots/test/claim_after_window_no_arbiter.1.json b/contracts/escrow-instance/test_snapshots/test/claim_after_window_no_arbiter.1.json index 0d5e445..1a0b589 100644 --- a/contracts/escrow-instance/test_snapshots/test/claim_after_window_no_arbiter.1.json +++ b/contracts/escrow-instance/test_snapshots/test/claim_after_window_no_arbiter.1.json @@ -14,11 +14,14 @@ "function": { "contract_fn": { "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", - "function_name": "store_payout_proofs", + "function_name": "prepare_funding", "args": [ { "bytes": "0909090909090909" }, + { + "u32": 0 + }, { "bytes": "0909090909090909" } @@ -36,13 +39,32 @@ "function": { "contract_fn": { "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", - "function_name": "fund", + "function_name": "store_payout_proof", "args": [ { - "bytes": "0909090909090909" + "bool": true }, { - "u32": 0 + "bytes": "0909090909090909" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "store_payout_proof", + "args": [ + { + "bool": false }, { "bytes": "0909090909090909" @@ -50,6 +72,21 @@ ] } }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "fund", + "args": [] + } + }, "sub_invocations": [ { "function": { @@ -166,6 +203,51 @@ } ] } + }, + { + "key": { + "vec": [ + { + "symbol": "receive" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + ] + }, + "val": { + "u32": 9 + } + }, + { + "key": { + "vec": [ + { + "symbol": "receive" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4" + } + ] + }, + "val": { + "u32": 0 + } + }, + { + "key": { + "vec": [ + { + "symbol": "spend" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4" + } + ] + }, + "val": { + "u32": 0 + } } ] } @@ -196,6 +278,46 @@ }, "live_until": 6311999 }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": "1033654523790656264" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": "4837995959683129791" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, { "entry": { "last_modified_ledger_seq": 0, @@ -225,7 +347,7 @@ "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", "key": { "ledger_key_nonce": { - "nonce": "1033654523790656264" + "nonce": "2032731177588607455" } }, "durability": "temporary", @@ -245,7 +367,7 @@ "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", "key": { "ledger_key_nonce": { - "nonce": "4837995959683129791" + "nonce": "4270020994084947596" } }, "durability": "temporary", diff --git a/contracts/escrow-instance/test_snapshots/test/claim_before_window_blocked.1.json b/contracts/escrow-instance/test_snapshots/test/claim_before_window_blocked.1.json index dad52d5..9aa4cbe 100644 --- a/contracts/escrow-instance/test_snapshots/test/claim_before_window_blocked.1.json +++ b/contracts/escrow-instance/test_snapshots/test/claim_before_window_blocked.1.json @@ -14,11 +14,14 @@ "function": { "contract_fn": { "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", - "function_name": "store_payout_proofs", + "function_name": "prepare_funding", "args": [ { "bytes": "0909090909090909" }, + { + "u32": 0 + }, { "bytes": "0909090909090909" } @@ -36,13 +39,32 @@ "function": { "contract_fn": { "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", - "function_name": "fund", + "function_name": "store_payout_proof", "args": [ { - "bytes": "0909090909090909" + "bool": true }, { - "u32": 0 + "bytes": "0909090909090909" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "store_payout_proof", + "args": [ + { + "bool": false }, { "bytes": "0909090909090909" @@ -50,6 +72,21 @@ ] } }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "fund", + "args": [] + } + }, "sub_invocations": [ { "function": { @@ -139,6 +176,36 @@ } ] } + }, + { + "key": { + "vec": [ + { + "symbol": "receive" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4" + } + ] + }, + "val": { + "u32": 0 + } + }, + { + "key": { + "vec": [ + { + "symbol": "spend" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4" + } + ] + }, + "val": { + "u32": 9 + } } ] } @@ -169,6 +236,46 @@ }, "live_until": 6311999 }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": "1033654523790656264" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": "4837995959683129791" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, { "entry": { "last_modified_ledger_seq": 0, @@ -198,7 +305,7 @@ "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", "key": { "ledger_key_nonce": { - "nonce": "1033654523790656264" + "nonce": "2032731177588607455" } }, "durability": "temporary", diff --git a/contracts/escrow-instance/test_snapshots/test/dispute_then_resolve_to_depositor.1.json b/contracts/escrow-instance/test_snapshots/test/dispute_then_resolve_to_depositor.1.json index 23ce429..ddb859c 100644 --- a/contracts/escrow-instance/test_snapshots/test/dispute_then_resolve_to_depositor.1.json +++ b/contracts/escrow-instance/test_snapshots/test/dispute_then_resolve_to_depositor.1.json @@ -14,11 +14,14 @@ "function": { "contract_fn": { "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", - "function_name": "store_payout_proofs", + "function_name": "prepare_funding", "args": [ { "bytes": "0909090909090909" }, + { + "u32": 0 + }, { "bytes": "0909090909090909" } @@ -36,13 +39,32 @@ "function": { "contract_fn": { "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", - "function_name": "fund", + "function_name": "store_payout_proof", "args": [ { - "bytes": "0909090909090909" + "bool": true }, { - "u32": 0 + "bytes": "0909090909090909" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", + "function_name": "store_payout_proof", + "args": [ + { + "bool": false }, { "bytes": "0909090909090909" @@ -50,6 +72,21 @@ ] } }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", + "function_name": "fund", + "args": [] + } + }, "sub_invocations": [ { "function": { @@ -185,6 +222,51 @@ } ] } + }, + { + "key": { + "vec": [ + { + "symbol": "receive" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + ] + }, + "val": { + "u32": 9 + } + }, + { + "key": { + "vec": [ + { + "symbol": "receive" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM" + } + ] + }, + "val": { + "u32": 0 + } + }, + { + "key": { + "vec": [ + { + "symbol": "spend" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM" + } + ] + }, + "val": { + "u32": 0 + } } ] } @@ -215,6 +297,46 @@ }, "live_until": 6311999 }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": "1033654523790656264" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": "4837995959683129791" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, { "entry": { "last_modified_ledger_seq": 0, @@ -244,7 +366,7 @@ "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", "key": { "ledger_key_nonce": { - "nonce": "1033654523790656264" + "nonce": "2032731177588607455" } }, "durability": "temporary", @@ -264,7 +386,7 @@ "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", "key": { "ledger_key_nonce": { - "nonce": "4837995959683129791" + "nonce": "4270020994084947596" } }, "durability": "temporary", @@ -284,7 +406,7 @@ "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", "key": { "ledger_key_nonce": { - "nonce": "2032731177588607455" + "nonce": "8370022561469687789" } }, "durability": "temporary", diff --git a/contracts/escrow-instance/test_snapshots/test/dispute_then_resolve_to_recipient.1.json b/contracts/escrow-instance/test_snapshots/test/dispute_then_resolve_to_recipient.1.json index db627c2..f43643c 100644 --- a/contracts/escrow-instance/test_snapshots/test/dispute_then_resolve_to_recipient.1.json +++ b/contracts/escrow-instance/test_snapshots/test/dispute_then_resolve_to_recipient.1.json @@ -14,11 +14,14 @@ "function": { "contract_fn": { "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", - "function_name": "store_payout_proofs", + "function_name": "prepare_funding", "args": [ { "bytes": "0909090909090909" }, + { + "u32": 0 + }, { "bytes": "0909090909090909" } @@ -36,13 +39,32 @@ "function": { "contract_fn": { "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", - "function_name": "fund", + "function_name": "store_payout_proof", "args": [ { - "bytes": "0909090909090909" + "bool": true }, { - "u32": 0 + "bytes": "0909090909090909" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", + "function_name": "store_payout_proof", + "args": [ + { + "bool": false }, { "bytes": "0909090909090909" @@ -50,6 +72,21 @@ ] } }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", + "function_name": "fund", + "args": [] + } + }, "sub_invocations": [ { "function": { @@ -186,6 +223,51 @@ } ] } + }, + { + "key": { + "vec": [ + { + "symbol": "receive" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + ] + }, + "val": { + "u32": 9 + } + }, + { + "key": { + "vec": [ + { + "symbol": "receive" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM" + } + ] + }, + "val": { + "u32": 0 + } + }, + { + "key": { + "vec": [ + { + "symbol": "spend" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM" + } + ] + }, + "val": { + "u32": 0 + } } ] } @@ -216,6 +298,46 @@ }, "live_until": 6311999 }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": "1033654523790656264" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": "4837995959683129791" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, { "entry": { "last_modified_ledger_seq": 0, @@ -245,7 +367,7 @@ "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", "key": { "ledger_key_nonce": { - "nonce": "1033654523790656264" + "nonce": "2032731177588607455" } }, "durability": "temporary", @@ -265,7 +387,7 @@ "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", "key": { "ledger_key_nonce": { - "nonce": "4837995959683129791" + "nonce": "4270020994084947596" } }, "durability": "temporary", @@ -285,7 +407,7 @@ "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", "key": { "ledger_key_nonce": { - "nonce": "2032731177588607455" + "nonce": "8370022561469687789" } }, "durability": "temporary", diff --git a/contracts/escrow-instance/test_snapshots/test/dispute_without_arbiter_blocked.1.json b/contracts/escrow-instance/test_snapshots/test/dispute_without_arbiter_blocked.1.json index 59c46d6..032a4d4 100644 --- a/contracts/escrow-instance/test_snapshots/test/dispute_without_arbiter_blocked.1.json +++ b/contracts/escrow-instance/test_snapshots/test/dispute_without_arbiter_blocked.1.json @@ -14,11 +14,14 @@ "function": { "contract_fn": { "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", - "function_name": "store_payout_proofs", + "function_name": "prepare_funding", "args": [ { "bytes": "0909090909090909" }, + { + "u32": 0 + }, { "bytes": "0909090909090909" } @@ -36,13 +39,32 @@ "function": { "contract_fn": { "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", - "function_name": "fund", + "function_name": "store_payout_proof", "args": [ { - "bytes": "0909090909090909" + "bool": true }, { - "u32": 0 + "bytes": "0909090909090909" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "store_payout_proof", + "args": [ + { + "bool": false }, { "bytes": "0909090909090909" @@ -50,6 +72,21 @@ ] } }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "fund", + "args": [] + } + }, "sub_invocations": [ { "function": { @@ -140,6 +177,36 @@ } ] } + }, + { + "key": { + "vec": [ + { + "symbol": "receive" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4" + } + ] + }, + "val": { + "u32": 0 + } + }, + { + "key": { + "vec": [ + { + "symbol": "spend" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4" + } + ] + }, + "val": { + "u32": 9 + } } ] } @@ -170,6 +237,46 @@ }, "live_until": 6311999 }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": "1033654523790656264" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": "4837995959683129791" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, { "entry": { "last_modified_ledger_seq": 0, @@ -199,7 +306,7 @@ "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", "key": { "ledger_key_nonce": { - "nonce": "1033654523790656264" + "nonce": "2032731177588607455" } }, "durability": "temporary", diff --git a/contracts/escrow-instance/test_snapshots/test/early_release_from_funded.1.json b/contracts/escrow-instance/test_snapshots/test/early_release_from_funded.1.json index 64016d9..7575243 100644 --- a/contracts/escrow-instance/test_snapshots/test/early_release_from_funded.1.json +++ b/contracts/escrow-instance/test_snapshots/test/early_release_from_funded.1.json @@ -14,11 +14,14 @@ "function": { "contract_fn": { "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", - "function_name": "store_payout_proofs", + "function_name": "prepare_funding", "args": [ { "bytes": "0909090909090909" }, + { + "u32": 0 + }, { "bytes": "0909090909090909" } @@ -36,13 +39,32 @@ "function": { "contract_fn": { "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", - "function_name": "fund", + "function_name": "store_payout_proof", "args": [ { - "bytes": "0909090909090909" + "bool": true }, { - "u32": 0 + "bytes": "0909090909090909" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "store_payout_proof", + "args": [ + { + "bool": false }, { "bytes": "0909090909090909" @@ -50,6 +72,21 @@ ] } }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "fund", + "args": [] + } + }, "sub_invocations": [ { "function": { @@ -146,6 +183,51 @@ } ] } + }, + { + "key": { + "vec": [ + { + "symbol": "receive" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + ] + }, + "val": { + "u32": 9 + } + }, + { + "key": { + "vec": [ + { + "symbol": "receive" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4" + } + ] + }, + "val": { + "u32": 0 + } + }, + { + "key": { + "vec": [ + { + "symbol": "spend" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4" + } + ] + }, + "val": { + "u32": 0 + } } ] } @@ -196,6 +278,46 @@ }, "live_until": 6311999 }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": "2032731177588607455" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": "4837995959683129791" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, { "entry": { "last_modified_ledger_seq": 0, diff --git a/contracts/escrow-instance/test_snapshots/test/fund_moves_to_funded.1.json b/contracts/escrow-instance/test_snapshots/test/fund_moves_to_funded.1.json index a6913f7..7b3c26c 100644 --- a/contracts/escrow-instance/test_snapshots/test/fund_moves_to_funded.1.json +++ b/contracts/escrow-instance/test_snapshots/test/fund_moves_to_funded.1.json @@ -14,11 +14,14 @@ "function": { "contract_fn": { "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", - "function_name": "store_payout_proofs", + "function_name": "prepare_funding", "args": [ { "bytes": "0909090909090909" }, + { + "u32": 0 + }, { "bytes": "0909090909090909" } @@ -36,13 +39,32 @@ "function": { "contract_fn": { "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", - "function_name": "fund", + "function_name": "store_payout_proof", "args": [ { - "bytes": "0909090909090909" + "bool": true }, { - "u32": 0 + "bytes": "0909090909090909" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "store_payout_proof", + "args": [ + { + "bool": false }, { "bytes": "0909090909090909" @@ -50,6 +72,21 @@ ] } }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "fund", + "args": [] + } + }, "sub_invocations": [ { "function": { @@ -121,6 +158,36 @@ } ] } + }, + { + "key": { + "vec": [ + { + "symbol": "receive" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4" + } + ] + }, + "val": { + "u32": 0 + } + }, + { + "key": { + "vec": [ + { + "symbol": "spend" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4" + } + ] + }, + "val": { + "u32": 9 + } } ] } @@ -151,6 +218,46 @@ }, "live_until": 6311999 }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": "1033654523790656264" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": "4837995959683129791" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, { "entry": { "last_modified_ledger_seq": 0, diff --git a/contracts/escrow-instance/test_snapshots/test/invalid_refund_proof_cannot_enable_funding.1.json b/contracts/escrow-instance/test_snapshots/test/invalid_refund_proof_cannot_enable_funding.1.json new file mode 100644 index 0000000..1c009a6 --- /dev/null +++ b/contracts/escrow-instance/test_snapshots/test/invalid_refund_proof_cannot_enable_funding.1.json @@ -0,0 +1,301 @@ +{ + "generators": { + "address": 4, + "nonce": 0, + "mux_id": 0 + }, + "auth": [ + [], + [], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "prepare_funding", + "args": [ + { + "bytes": "0909090909090909" + }, + { + "u32": 0 + }, + { + "bytes": "0909090909090909" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "store_payout_proof", + "args": [ + { + "bool": true + }, + { + "bytes": "0909090909090909" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [], + [] + ], + "ledger": { + "protocol_version": 26, + "sequence_number": 0, + "timestamp": 0, + "network_id": "0000000000000000000000000000000000000000000000000000000000000000", + "base_reserve": 0, + "min_persistent_entry_ttl": 4096, + "min_temp_entry_ttl": 16, + "max_entry_ttl": 6312000, + "ledger_entries": [ + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": { + "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "storage": null + } + } + } + }, + "ext": "v0" + }, + "live_until": 4095 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": "801925984706572462" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": "5541220902715666415" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": { + "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "storage": [ + { + "key": { + "vec": [ + { + "symbol": "AuditorId" + } + ] + }, + "val": { + "u32": 0 + } + }, + { + "key": { + "vec": [ + { + "symbol": "Escrow" + } + ] + }, + "val": { + "map": [ + { + "key": { + "symbol": "arbiter" + }, + "val": "void" + }, + { + "key": { + "symbol": "completed_at" + }, + "val": { + "u64": "0" + } + }, + { + "key": { + "symbol": "created_at" + }, + "val": { + "u64": "0" + } + }, + { + "key": { + "symbol": "depositor" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + }, + { + "key": { + "symbol": "recipient" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + }, + { + "key": { + "symbol": "state" + }, + "val": { + "u32": 0 + } + }, + { + "key": { + "symbol": "timeout_at" + }, + "val": { + "u64": "3600" + } + } + ] + } + }, + { + "key": { + "vec": [ + { + "symbol": "RegisterData" + } + ] + }, + "val": { + "bytes": "0909090909090909" + } + }, + { + "key": { + "vec": [ + { + "symbol": "ReleaseProof" + } + ] + }, + "val": { + "bytes": "0909090909090909" + } + }, + { + "key": { + "vec": [ + { + "symbol": "Token" + } + ] + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + }, + { + "key": { + "vec": [ + { + "symbol": "TransferIn" + } + ] + }, + "val": { + "bytes": "0909090909090909" + } + } + ] + } + } + } + }, + "ext": "v0" + }, + "live_until": 4095 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_code": { + "ext": "v0", + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "code": "" + } + }, + "ext": "v0" + }, + "live_until": 4095 + } + ] + }, + "events": [] +} \ No newline at end of file diff --git a/contracts/escrow-instance/test_snapshots/test/invalid_release_proof_cannot_enable_funding.1.json b/contracts/escrow-instance/test_snapshots/test/invalid_release_proof_cannot_enable_funding.1.json new file mode 100644 index 0000000..6357521 --- /dev/null +++ b/contracts/escrow-instance/test_snapshots/test/invalid_release_proof_cannot_enable_funding.1.json @@ -0,0 +1,448 @@ +{ + "generators": { + "address": 4, + "nonce": 0, + "mux_id": 0 + }, + "auth": [ + [], + [], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "prepare_funding", + "args": [ + { + "bytes": "0909090909090909" + }, + { + "u32": 0 + }, + { + "bytes": "0909090909090909" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "store_payout_proof", + "args": [ + { + "bool": false + }, + { + "bytes": "0909090909090909" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [], + [], + [], + [], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "store_payout_proof", + "args": [ + { + "bool": true + }, + { + "bytes": "0909090909090909" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "fund", + "args": [] + } + }, + "sub_invocations": [ + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "function_name": "confidential_transfer", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4" + }, + { + "bytes": "0909090909090909" + } + ] + } + }, + "sub_invocations": [] + } + ] + } + ] + ] + ], + "ledger": { + "protocol_version": 26, + "sequence_number": 0, + "timestamp": 0, + "network_id": "0000000000000000000000000000000000000000000000000000000000000000", + "base_reserve": 0, + "min_persistent_entry_ttl": 4096, + "min_temp_entry_ttl": 16, + "max_entry_ttl": 6312000, + "ledger_entries": [ + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": { + "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "storage": [ + { + "key": { + "symbol": "xfers" + }, + "val": { + "vec": [ + { + "vec": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4" + } + ] + } + ] + } + }, + { + "key": { + "vec": [ + { + "symbol": "receive" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4" + } + ] + }, + "val": { + "u32": 0 + } + }, + { + "key": { + "vec": [ + { + "symbol": "spend" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4" + } + ] + }, + "val": { + "u32": 9 + } + } + ] + } + } + } + }, + "ext": "v0" + }, + "live_until": 4095 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": "801925984706572462" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": "2032731177588607455" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": "4270020994084947596" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": "5541220902715666415" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": { + "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "storage": [ + { + "key": { + "vec": [ + { + "symbol": "Escrow" + } + ] + }, + "val": { + "map": [ + { + "key": { + "symbol": "arbiter" + }, + "val": "void" + }, + { + "key": { + "symbol": "completed_at" + }, + "val": { + "u64": "0" + } + }, + { + "key": { + "symbol": "created_at" + }, + "val": { + "u64": "0" + } + }, + { + "key": { + "symbol": "depositor" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + }, + { + "key": { + "symbol": "recipient" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + }, + { + "key": { + "symbol": "state" + }, + "val": { + "u32": 1 + } + }, + { + "key": { + "symbol": "timeout_at" + }, + "val": { + "u64": "3600" + } + } + ] + } + }, + { + "key": { + "vec": [ + { + "symbol": "RefundProof" + } + ] + }, + "val": { + "bytes": "0909090909090909" + } + }, + { + "key": { + "vec": [ + { + "symbol": "ReleaseProof" + } + ] + }, + "val": { + "bytes": "0909090909090909" + } + }, + { + "key": { + "vec": [ + { + "symbol": "Token" + } + ] + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + } + ] + } + } + } + }, + "ext": "v0" + }, + "live_until": 4095 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_code": { + "ext": "v0", + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "code": "" + } + }, + "ext": "v0" + }, + "live_until": 4095 + } + ] + }, + "events": [ + { + "event": { + "ext": "v0", + "contract_id": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "type_": "contract", + "body": { + "v0": { + "topics": [ + { + "symbol": "funded" + } + ], + "data": { + "map": [] + } + } + } + }, + "failed_call": false + } + ] +} \ No newline at end of file diff --git a/contracts/escrow-instance/test_snapshots/test/normal_release_pays_recipient.1.json b/contracts/escrow-instance/test_snapshots/test/normal_release_pays_recipient.1.json index 2c39487..88221c8 100644 --- a/contracts/escrow-instance/test_snapshots/test/normal_release_pays_recipient.1.json +++ b/contracts/escrow-instance/test_snapshots/test/normal_release_pays_recipient.1.json @@ -14,11 +14,14 @@ "function": { "contract_fn": { "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", - "function_name": "store_payout_proofs", + "function_name": "prepare_funding", "args": [ { "bytes": "0909090909090909" }, + { + "u32": 0 + }, { "bytes": "0909090909090909" } @@ -36,13 +39,32 @@ "function": { "contract_fn": { "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", - "function_name": "fund", + "function_name": "store_payout_proof", "args": [ { - "bytes": "0909090909090909" + "bool": true }, { - "u32": 0 + "bytes": "0909090909090909" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "store_payout_proof", + "args": [ + { + "bool": false }, { "bytes": "0909090909090909" @@ -50,6 +72,21 @@ ] } }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "fund", + "args": [] + } + }, "sub_invocations": [ { "function": { @@ -166,6 +203,51 @@ } ] } + }, + { + "key": { + "vec": [ + { + "symbol": "receive" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + ] + }, + "val": { + "u32": 9 + } + }, + { + "key": { + "vec": [ + { + "symbol": "receive" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4" + } + ] + }, + "val": { + "u32": 0 + } + }, + { + "key": { + "vec": [ + { + "symbol": "spend" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4" + } + ] + }, + "val": { + "u32": 0 + } } ] } @@ -196,6 +278,46 @@ }, "live_until": 6311999 }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": "1033654523790656264" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": "4270020994084947596" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, { "entry": { "last_modified_ledger_seq": 0, @@ -245,7 +367,7 @@ "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", "key": { "ledger_key_nonce": { - "nonce": "1033654523790656264" + "nonce": "2032731177588607455" } }, "durability": "temporary", diff --git a/contracts/escrow-instance/test_snapshots/test/payout_proof_requires_prepared_inputs.1.json b/contracts/escrow-instance/test_snapshots/test/payout_proof_requires_prepared_inputs.1.json new file mode 100644 index 0000000..75e5eb1 --- /dev/null +++ b/contracts/escrow-instance/test_snapshots/test/payout_proof_requires_prepared_inputs.1.json @@ -0,0 +1,165 @@ +{ + "generators": { + "address": 4, + "nonce": 0, + "mux_id": 0 + }, + "auth": [ + [], + [], + [] + ], + "ledger": { + "protocol_version": 26, + "sequence_number": 0, + "timestamp": 0, + "network_id": "0000000000000000000000000000000000000000000000000000000000000000", + "base_reserve": 0, + "min_persistent_entry_ttl": 4096, + "min_temp_entry_ttl": 16, + "max_entry_ttl": 6312000, + "ledger_entries": [ + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": { + "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "storage": null + } + } + } + }, + "ext": "v0" + }, + "live_until": 4095 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": { + "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "storage": [ + { + "key": { + "vec": [ + { + "symbol": "Escrow" + } + ] + }, + "val": { + "map": [ + { + "key": { + "symbol": "arbiter" + }, + "val": "void" + }, + { + "key": { + "symbol": "completed_at" + }, + "val": { + "u64": "0" + } + }, + { + "key": { + "symbol": "created_at" + }, + "val": { + "u64": "0" + } + }, + { + "key": { + "symbol": "depositor" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + }, + { + "key": { + "symbol": "recipient" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + }, + { + "key": { + "symbol": "state" + }, + "val": { + "u32": 0 + } + }, + { + "key": { + "symbol": "timeout_at" + }, + "val": { + "u64": "3600" + } + } + ] + } + }, + { + "key": { + "vec": [ + { + "symbol": "Token" + } + ] + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + } + ] + } + } + } + }, + "ext": "v0" + }, + "live_until": 4095 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_code": { + "ext": "v0", + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "code": "" + } + }, + "ext": "v0" + }, + "live_until": 4095 + } + ] + }, + "events": [] +} \ No newline at end of file diff --git a/contracts/escrow-instance/test_snapshots/test/store_payout_proofs_can_be_overwritten_before_funding.1.json b/contracts/escrow-instance/test_snapshots/test/preparing_again_invalidates_both_payout_proofs.1.json similarity index 85% rename from contracts/escrow-instance/test_snapshots/test/store_payout_proofs_can_be_overwritten_before_funding.1.json rename to contracts/escrow-instance/test_snapshots/test/preparing_again_invalidates_both_payout_proofs.1.json index 3374ce8..46b5e39 100644 --- a/contracts/escrow-instance/test_snapshots/test/store_payout_proofs_can_be_overwritten_before_funding.1.json +++ b/contracts/escrow-instance/test_snapshots/test/preparing_again_invalidates_both_payout_proofs.1.json @@ -14,11 +14,14 @@ "function": { "contract_fn": { "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", - "function_name": "store_payout_proofs", + "function_name": "prepare_funding", "args": [ { "bytes": "0909090909090909" }, + { + "u32": 0 + }, { "bytes": "0909090909090909" } @@ -36,10 +39,32 @@ "function": { "contract_fn": { "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", - "function_name": "store_payout_proofs", + "function_name": "store_payout_proof", "args": [ + { + "bool": true + }, { "bytes": "0909090909090909" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "store_payout_proof", + "args": [ + { + "bool": false }, { "bytes": "0909090909090909" @@ -58,13 +83,13 @@ "function": { "contract_fn": { "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", - "function_name": "fund", + "function_name": "prepare_funding", "args": [ { "bytes": "0909090909090909" }, { - "u32": 0 + "u32": 1 }, { "bytes": "0909090909090909" @@ -72,28 +97,7 @@ ] } }, - "sub_invocations": [ - { - "function": { - "contract_fn": { - "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", - "function_name": "confidential_transfer", - "args": [ - { - "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" - }, - { - "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4" - }, - { - "bytes": "0909090909090909" - } - ] - } - }, - "sub_invocations": [] - } - ] + "sub_invocations": [] } ] ], @@ -123,27 +127,7 @@ "executable": { "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" }, - "storage": [ - { - "key": { - "symbol": "xfers" - }, - "val": { - "vec": [ - { - "vec": [ - { - "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" - }, - { - "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4" - } - ] - } - ] - } - } - ] + "storage": null } } } @@ -192,6 +176,26 @@ }, "live_until": 6311999 }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": "4837995959683129791" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, { "entry": { "last_modified_ledger_seq": 0, @@ -227,6 +231,18 @@ "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" }, "storage": [ + { + "key": { + "vec": [ + { + "symbol": "AuditorId" + } + ] + }, + "val": { + "u32": 1 + } + }, { "key": { "vec": [ @@ -280,7 +296,7 @@ "symbol": "state" }, "val": { - "u32": 1 + "u32": 0 } }, { @@ -298,7 +314,7 @@ "key": { "vec": [ { - "symbol": "RefundProof" + "symbol": "RegisterData" } ] }, @@ -310,24 +326,24 @@ "key": { "vec": [ { - "symbol": "ReleaseProof" + "symbol": "Token" } ] }, "val": { - "bytes": "0909090909090909" + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" } }, { "key": { "vec": [ { - "symbol": "Token" + "symbol": "TransferIn" } ] }, "val": { - "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + "bytes": "0909090909090909" } } ] diff --git a/contracts/escrow-instance/test_snapshots/test/stranger_cannot_mark_completed.1.json b/contracts/escrow-instance/test_snapshots/test/stranger_cannot_mark_completed.1.json index 0c9cc8f..62286f8 100644 --- a/contracts/escrow-instance/test_snapshots/test/stranger_cannot_mark_completed.1.json +++ b/contracts/escrow-instance/test_snapshots/test/stranger_cannot_mark_completed.1.json @@ -14,11 +14,14 @@ "function": { "contract_fn": { "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", - "function_name": "store_payout_proofs", + "function_name": "prepare_funding", "args": [ { "bytes": "01" }, + { + "u32": 0 + }, { "bytes": "01" } @@ -36,13 +39,32 @@ "function": { "contract_fn": { "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", - "function_name": "fund", + "function_name": "store_payout_proof", "args": [ { - "bytes": "01" + "bool": true }, { - "u32": 0 + "bytes": "01" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "store_payout_proof", + "args": [ + { + "bool": false }, { "bytes": "01" @@ -50,6 +72,21 @@ ] } }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "fund", + "args": [] + } + }, "sub_invocations": [ { "function": { @@ -120,6 +157,36 @@ } ] } + }, + { + "key": { + "vec": [ + { + "symbol": "receive" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4" + } + ] + }, + "val": { + "u32": 0 + } + }, + { + "key": { + "vec": [ + { + "symbol": "spend" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4" + } + ] + }, + "val": { + "u32": 1 + } } ] } @@ -150,6 +217,46 @@ }, "live_until": 6311999 }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": "1033654523790656264" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": "4837995959683129791" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, { "entry": { "last_modified_ledger_seq": 0, diff --git a/contracts/escrow-instance/test_snapshots/test/timeout_blocked_after_completed.1.json b/contracts/escrow-instance/test_snapshots/test/timeout_blocked_after_completed.1.json index 15302b4..a29074a 100644 --- a/contracts/escrow-instance/test_snapshots/test/timeout_blocked_after_completed.1.json +++ b/contracts/escrow-instance/test_snapshots/test/timeout_blocked_after_completed.1.json @@ -14,11 +14,14 @@ "function": { "contract_fn": { "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", - "function_name": "store_payout_proofs", + "function_name": "prepare_funding", "args": [ { "bytes": "0909090909090909" }, + { + "u32": 0 + }, { "bytes": "0909090909090909" } @@ -36,13 +39,32 @@ "function": { "contract_fn": { "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", - "function_name": "fund", + "function_name": "store_payout_proof", "args": [ { - "bytes": "0909090909090909" + "bool": true }, { - "u32": 0 + "bytes": "0909090909090909" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "store_payout_proof", + "args": [ + { + "bool": false }, { "bytes": "0909090909090909" @@ -50,6 +72,21 @@ ] } }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "fund", + "args": [] + } + }, "sub_invocations": [ { "function": { @@ -139,6 +176,36 @@ } ] } + }, + { + "key": { + "vec": [ + { + "symbol": "receive" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4" + } + ] + }, + "val": { + "u32": 0 + } + }, + { + "key": { + "vec": [ + { + "symbol": "spend" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4" + } + ] + }, + "val": { + "u32": 9 + } } ] } @@ -169,6 +236,46 @@ }, "live_until": 6311999 }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": "1033654523790656264" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": "4837995959683129791" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, { "entry": { "last_modified_ledger_seq": 0, @@ -198,7 +305,7 @@ "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M", "key": { "ledger_key_nonce": { - "nonce": "1033654523790656264" + "nonce": "2032731177588607455" } }, "durability": "temporary", diff --git a/contracts/escrow-instance/test_snapshots/test/timeout_refunds_depositor.1.json b/contracts/escrow-instance/test_snapshots/test/timeout_refunds_depositor.1.json index bbe8c62..848e277 100644 --- a/contracts/escrow-instance/test_snapshots/test/timeout_refunds_depositor.1.json +++ b/contracts/escrow-instance/test_snapshots/test/timeout_refunds_depositor.1.json @@ -14,11 +14,14 @@ "function": { "contract_fn": { "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", - "function_name": "store_payout_proofs", + "function_name": "prepare_funding", "args": [ { "bytes": "0909090909090909" }, + { + "u32": 0 + }, { "bytes": "0909090909090909" } @@ -36,13 +39,32 @@ "function": { "contract_fn": { "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", - "function_name": "fund", + "function_name": "store_payout_proof", "args": [ { - "bytes": "0909090909090909" + "bool": true }, { - "u32": 0 + "bytes": "0909090909090909" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "store_payout_proof", + "args": [ + { + "bool": false }, { "bytes": "0909090909090909" @@ -50,6 +72,21 @@ ] } }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "fund", + "args": [] + } + }, "sub_invocations": [ { "function": { @@ -146,6 +183,51 @@ } ] } + }, + { + "key": { + "vec": [ + { + "symbol": "receive" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + ] + }, + "val": { + "u32": 9 + } + }, + { + "key": { + "vec": [ + { + "symbol": "receive" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4" + } + ] + }, + "val": { + "u32": 0 + } + }, + { + "key": { + "vec": [ + { + "symbol": "spend" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4" + } + ] + }, + "val": { + "u32": 0 + } } ] } @@ -196,6 +278,46 @@ }, "live_until": 6311999 }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": "2032731177588607455" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": "4837995959683129791" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, { "entry": { "last_modified_ledger_seq": 0, diff --git a/contracts/escrow-instance/test_snapshots/test/timeout_too_early.1.json b/contracts/escrow-instance/test_snapshots/test/timeout_too_early.1.json index 5643cc3..3c21317 100644 --- a/contracts/escrow-instance/test_snapshots/test/timeout_too_early.1.json +++ b/contracts/escrow-instance/test_snapshots/test/timeout_too_early.1.json @@ -14,11 +14,14 @@ "function": { "contract_fn": { "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", - "function_name": "store_payout_proofs", + "function_name": "prepare_funding", "args": [ { "bytes": "0909090909090909" }, + { + "u32": 0 + }, { "bytes": "0909090909090909" } @@ -36,13 +39,32 @@ "function": { "contract_fn": { "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", - "function_name": "fund", + "function_name": "store_payout_proof", "args": [ { - "bytes": "0909090909090909" + "bool": true }, { - "u32": 0 + "bytes": "0909090909090909" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "store_payout_proof", + "args": [ + { + "bool": false }, { "bytes": "0909090909090909" @@ -50,6 +72,21 @@ ] } }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "fund", + "args": [] + } + }, "sub_invocations": [ { "function": { @@ -120,6 +157,36 @@ } ] } + }, + { + "key": { + "vec": [ + { + "symbol": "receive" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4" + } + ] + }, + "val": { + "u32": 0 + } + }, + { + "key": { + "vec": [ + { + "symbol": "spend" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4" + } + ] + }, + "val": { + "u32": 9 + } } ] } @@ -150,6 +217,46 @@ }, "live_until": 6311999 }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": "1033654523790656264" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": "4837995959683129791" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, { "entry": { "last_modified_ledger_seq": 0, diff --git a/contracts/escrow-instance/test_snapshots/test/unsolicited_credit_does_not_block_refund.1.json b/contracts/escrow-instance/test_snapshots/test/unsolicited_credit_does_not_block_refund.1.json new file mode 100644 index 0000000..a4a5c57 --- /dev/null +++ b/contracts/escrow-instance/test_snapshots/test/unsolicited_credit_does_not_block_refund.1.json @@ -0,0 +1,485 @@ +{ + "generators": { + "address": 4, + "nonce": 0, + "mux_id": 0 + }, + "auth": [ + [], + [], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "prepare_funding", + "args": [ + { + "bytes": "0909090909090909" + }, + { + "u32": 0 + }, + { + "bytes": "0909090909090909" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "store_payout_proof", + "args": [ + { + "bool": true + }, + { + "bytes": "0909090909090909" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "store_payout_proof", + "args": [ + { + "bool": false + }, + { + "bytes": "0909090909090909" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "fund", + "args": [] + } + }, + "sub_invocations": [ + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "function_name": "confidential_transfer", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4" + }, + { + "bytes": "0909090909090909" + } + ] + } + }, + "sub_invocations": [] + } + ] + } + ] + ], + [], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "timeout", + "args": [] + } + }, + "sub_invocations": [] + } + ] + ], + [] + ], + "ledger": { + "protocol_version": 26, + "sequence_number": 0, + "timestamp": 3601, + "network_id": "0000000000000000000000000000000000000000000000000000000000000000", + "base_reserve": 0, + "min_persistent_entry_ttl": 4096, + "min_temp_entry_ttl": 16, + "max_entry_ttl": 6312000, + "ledger_entries": [ + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": { + "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "storage": [ + { + "key": { + "symbol": "xfers" + }, + "val": { + "vec": [ + { + "vec": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4" + } + ] + }, + { + "vec": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + ] + } + ] + } + }, + { + "key": { + "vec": [ + { + "symbol": "receive" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + ] + }, + "val": { + "u32": 9 + } + }, + { + "key": { + "vec": [ + { + "symbol": "receive" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4" + } + ] + }, + "val": { + "u32": 1 + } + }, + { + "key": { + "vec": [ + { + "symbol": "spend" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4" + } + ] + }, + "val": { + "u32": 0 + } + } + ] + } + } + } + }, + "ext": "v0" + }, + "live_until": 4095 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": "801925984706572462" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": "1033654523790656264" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": "2032731177588607455" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": "4837995959683129791" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": "5541220902715666415" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": { + "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "storage": [ + { + "key": { + "vec": [ + { + "symbol": "Escrow" + } + ] + }, + "val": { + "map": [ + { + "key": { + "symbol": "arbiter" + }, + "val": "void" + }, + { + "key": { + "symbol": "completed_at" + }, + "val": { + "u64": "0" + } + }, + { + "key": { + "symbol": "created_at" + }, + "val": { + "u64": "0" + } + }, + { + "key": { + "symbol": "depositor" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + }, + { + "key": { + "symbol": "recipient" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + }, + { + "key": { + "symbol": "state" + }, + "val": { + "u32": 5 + } + }, + { + "key": { + "symbol": "timeout_at" + }, + "val": { + "u64": "3600" + } + } + ] + } + }, + { + "key": { + "vec": [ + { + "symbol": "RefundProof" + } + ] + }, + "val": { + "bytes": "0909090909090909" + } + }, + { + "key": { + "vec": [ + { + "symbol": "ReleaseProof" + } + ] + }, + "val": { + "bytes": "0909090909090909" + } + }, + { + "key": { + "vec": [ + { + "symbol": "Token" + } + ] + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + } + ] + } + } + } + }, + "ext": "v0" + }, + "live_until": 4095 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_code": { + "ext": "v0", + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "code": "" + } + }, + "ext": "v0" + }, + "live_until": 4095 + } + ] + }, + "events": [] +} \ No newline at end of file diff --git a/contracts/escrow-instance/test_snapshots/test/unsolicited_credit_does_not_block_release.1.json b/contracts/escrow-instance/test_snapshots/test/unsolicited_credit_does_not_block_release.1.json new file mode 100644 index 0000000..019ac8c --- /dev/null +++ b/contracts/escrow-instance/test_snapshots/test/unsolicited_credit_does_not_block_release.1.json @@ -0,0 +1,485 @@ +{ + "generators": { + "address": 4, + "nonce": 0, + "mux_id": 0 + }, + "auth": [ + [], + [], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "prepare_funding", + "args": [ + { + "bytes": "0909090909090909" + }, + { + "u32": 0 + }, + { + "bytes": "0909090909090909" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "store_payout_proof", + "args": [ + { + "bool": true + }, + { + "bytes": "0909090909090909" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "store_payout_proof", + "args": [ + { + "bool": false + }, + { + "bytes": "0909090909090909" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "fund", + "args": [] + } + }, + "sub_invocations": [ + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "function_name": "confidential_transfer", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4" + }, + { + "bytes": "0909090909090909" + } + ] + } + }, + "sub_invocations": [] + } + ] + } + ] + ], + [], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "function_name": "release", + "args": [] + } + }, + "sub_invocations": [] + } + ] + ], + [] + ], + "ledger": { + "protocol_version": 26, + "sequence_number": 0, + "timestamp": 0, + "network_id": "0000000000000000000000000000000000000000000000000000000000000000", + "base_reserve": 0, + "min_persistent_entry_ttl": 4096, + "min_temp_entry_ttl": 16, + "max_entry_ttl": 6312000, + "ledger_entries": [ + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": { + "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "storage": [ + { + "key": { + "symbol": "xfers" + }, + "val": { + "vec": [ + { + "vec": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4" + } + ] + }, + { + "vec": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + ] + } + ] + } + }, + { + "key": { + "vec": [ + { + "symbol": "receive" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + ] + }, + "val": { + "u32": 9 + } + }, + { + "key": { + "vec": [ + { + "symbol": "receive" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4" + } + ] + }, + "val": { + "u32": 1 + } + }, + { + "key": { + "vec": [ + { + "symbol": "spend" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4" + } + ] + }, + "val": { + "u32": 0 + } + } + ] + } + } + } + }, + "ext": "v0" + }, + "live_until": 4095 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": "801925984706572462" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": "1033654523790656264" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": "2032731177588607455" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": "4837995959683129791" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": { + "ledger_key_nonce": { + "nonce": "5541220902715666415" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": { + "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "storage": [ + { + "key": { + "vec": [ + { + "symbol": "Escrow" + } + ] + }, + "val": { + "map": [ + { + "key": { + "symbol": "arbiter" + }, + "val": "void" + }, + { + "key": { + "symbol": "completed_at" + }, + "val": { + "u64": "0" + } + }, + { + "key": { + "symbol": "created_at" + }, + "val": { + "u64": "0" + } + }, + { + "key": { + "symbol": "depositor" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + }, + { + "key": { + "symbol": "recipient" + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + }, + { + "key": { + "symbol": "state" + }, + "val": { + "u32": 3 + } + }, + { + "key": { + "symbol": "timeout_at" + }, + "val": { + "u64": "3600" + } + } + ] + } + }, + { + "key": { + "vec": [ + { + "symbol": "RefundProof" + } + ] + }, + "val": { + "bytes": "0909090909090909" + } + }, + { + "key": { + "vec": [ + { + "symbol": "ReleaseProof" + } + ] + }, + "val": { + "bytes": "0909090909090909" + } + }, + { + "key": { + "vec": [ + { + "symbol": "Token" + } + ] + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + } + ] + } + } + } + }, + "ext": "v0" + }, + "live_until": 4095 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_code": { + "ext": "v0", + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "code": "" + } + }, + "ext": "v0" + }, + "live_until": 4095 + } + ] + }, + "events": [] +} \ No newline at end of file diff --git a/contracts/token/Cargo.toml b/contracts/token/Cargo.toml index ed0c029..e9a7cfc 100644 --- a/contracts/token/Cargo.toml +++ b/contracts/token/Cargo.toml @@ -14,6 +14,7 @@ soroban-sdk = { workspace = true } stellar-access = { workspace = true } stellar-macros = { workspace = true } stellar-tokens = { workspace = true } +stellar-contract-utils = { workspace = true } [dev-dependencies] soroban-sdk = { workspace = true, features = ["testutils"] } diff --git a/contracts/token/src/escrow.rs b/contracts/token/src/escrow.rs new file mode 100644 index 0000000..f83a806 --- /dev/null +++ b/contracts/token/src/escrow.rs @@ -0,0 +1,76 @@ +//! Read-only preflight for an escrow's future outgoing transfer. This does not +//! authorize a transfer, register an account, or move funds. The escrow must +//! later execute exactly the register_data / transfer_in it validated here. +//! PI order and canonical checks mirror stellar-tokens 539968f storage.rs. + +use soroban_sdk::{contractimpl, panic_with_error, Address, Bytes, BytesN, Env}; +use stellar_contract_utils::crypto::grumpkin::{Grumpkin, Point}; +use stellar_tokens::confidential::{ + auditor::ConfidentialAuditorClient, + storage::{self, RegisterData, TransferData}, + verifier::{CircuitType, ConfidentialVerifierClient}, + ConfidentialTokenError, +}; + +use crate::{ + ConfidentialTokenContract, ConfidentialTokenContractArgs, ConfidentialTokenContractClient, +}; + +#[contractimpl] +impl ConfidentialTokenContract { + /// Validate a payout against the account and spendable commitment that + /// atomic register -> transfer-in -> merge will produce. Account keys and + /// auditor keys for the recipient are read from this token, never supplied + /// by the depositor. The funding call independently verifies registration + /// and transfer-in before committing either of them. + pub fn verify_escrow_payout( + e: &Env, + register_data: Bytes, + auditor_id: u32, + transfer_in: Bytes, + to: Address, + data: Bytes, + ) -> bool { + let registration: RegisterData = storage::decode_data(e, ®ister_data); + let funding: TransferData = storage::decode_data(e, &transfer_in); + let payout: TransferData = storage::decode_data(e, &data); + let recipient = storage::get_account(e, &to); + let auditor = ConfidentialAuditorClient::new(e, &storage::get_auditor(e)); + let p = &payout.payload; + + let mut pi = Bytes::new(e); + append_point(&mut pi, &funding.payload.c_tx); + append_point(&mut pi, ®istration.payload.y); + append_point(&mut pi, &recipient.viewing_public_key); + append_field(&mut pi, &storage::get_address_as_field_element(e)); + append_point(&mut pi, &auditor.get_key(&recipient.auditor_id)); + append_point(&mut pi, &auditor.get_key(&auditor_id)); + append_point(&mut pi, &p.c_spend_new); + append_point(&mut pi, &p.c_tx); + append_point(&mut pi, &p.r_e); + for field in [ + &p.v_tilde, &p.b_tilde, &p.sigma, &p.v_aud_r, &p.r_aud_r, &p.v_aud_s, &p.b_aud_s, + ] { + append_field(&mut pi, field); + } + ConfidentialVerifierClient::new(e, &storage::get_verifier(e)).verify_proof( + &CircuitType::Transfer, + &pi, + &payout.proof, + ) + } +} + +fn append_point(pi: &mut Bytes, point: &Point) { + if !Grumpkin::is_canonical_point(point) { + panic_with_error!(pi.env(), ConfidentialTokenError::NonCanonicalEncoding); + } + pi.append(&Bytes::from(point)); +} + +fn append_field(pi: &mut Bytes, field: &BytesN<32>) { + if !Grumpkin::is_canonical_field(field) { + panic_with_error!(pi.env(), ConfidentialTokenError::NonCanonicalEncoding); + } + pi.append(&Bytes::from(field)); +} diff --git a/contracts/token/src/lib.rs b/contracts/token/src/lib.rs index 615ee0c..9a014d1 100644 --- a/contracts/token/src/lib.rs +++ b/contracts/token/src/lib.rs @@ -36,6 +36,11 @@ use stellar_tokens::confidential::{ storage as token_storage, ConfidentialAccount, ConfidentialToken, SpenderDelegation, }; +mod escrow; + +#[cfg(test)] +mod test; + #[contract] pub struct ConfidentialTokenContract; diff --git a/contracts/token/src/test.rs b/contracts/token/src/test.rs new file mode 100644 index 0000000..8022e42 --- /dev/null +++ b/contracts/token/src/test.rs @@ -0,0 +1,208 @@ +extern crate std; + +use crate::{ConfidentialTokenContract, ConfidentialTokenContractClient}; +use soroban_sdk::{ + contract, contractimpl, symbol_short, testutils::Address as _, xdr::ToXdr, Address, Bytes, + BytesN, Env, +}; +use stellar_contract_utils::crypto::grumpkin::{Grumpkin, Point}; +use stellar_tokens::confidential::{ + storage::{ + self, ConfidentialTokenStorageKey, RegisterData, RegisterPayload, TransferData, + TransferPayload, + }, + verifier::CircuitType, + ConfidentialAccount, +}; + +#[contract] +struct Verifier; +#[contractimpl] +impl Verifier { + pub fn verify_proof( + e: &Env, + circuit_type: CircuitType, + public_inputs: Bytes, + proof: Bytes, + ) -> bool { + assert_eq!(circuit_type, CircuitType::Transfer); + e.storage() + .instance() + .set(&symbol_short!("pi"), &public_inputs); + proof == Bytes::from_array(e, &[42]) + } + pub fn inputs(e: &Env) -> Bytes { + e.storage().instance().get(&symbol_short!("pi")).unwrap() + } +} + +#[contract] +struct Auditor; +#[contractimpl] +impl Auditor { + pub fn get_key(e: &Env, auditor_id: u32) -> Point { + Grumpkin::mul(e, &Grumpkin::generator(e), u128::from(auditor_id) + 1) + } +} + +fn point(e: &Env, n: u128) -> Point { + Grumpkin::mul(e, &Grumpkin::generator(e), n) +} +fn field(e: &Env, n: u8) -> BytesN<32> { + let mut bytes = [0; 32]; + bytes[31] = n; + BytesN::from_array(e, &bytes) +} +fn transfer(e: &Env) -> TransferData { + TransferData { + proof: Bytes::from_array(e, &[42]), + payload: TransferPayload { + c_spend_new: point(e, 4), + c_tx: point(e, 5), + r_e: point(e, 6), + v_tilde: field(e, 7), + b_tilde: field(e, 8), + sigma: field(e, 9), + v_aud_r: field(e, 10), + r_aud_r: field(e, 11), + v_aud_s: field(e, 12), + b_aud_s: field(e, 13), + }, + } +} + +struct Fixture { + e: Env, + token: Address, + verifier: Address, + from: Address, + to: Address, + registration: RegisterData, + funding: TransferData, + payout: TransferData, +} +fn setup() -> Fixture { + let e = Env::default(); + e.mock_all_auths(); + let verifier = e.register(Verifier, ()); + let auditor = e.register(Auditor, ()); + let token = e.register( + ConfidentialTokenContract, + ( + Address::generate(&e), + verifier.clone(), + auditor, + Address::generate(&e), + ), + ); + let from = Address::generate(&e); + let to = Address::generate(&e); + let registration = RegisterData { + payload: RegisterPayload { + y: point(&e, 2), + pvk: point(&e, 3), + }, + proof: Bytes::new(&e), + }; + let funding = transfer(&e); + let payout = transfer(&e); + e.as_contract(&token, || { + e.storage().persistent().set( + &ConfidentialTokenStorageKey::Account(from.clone()), + &ConfidentialAccount { + spending_key: registration.payload.y.clone(), + viewing_public_key: registration.payload.pvk.clone(), + spendable_balance: funding.payload.c_tx.clone(), + receiving_balance: Grumpkin::identity(&e), + auditor_id: 1, + }, + ); + e.storage().persistent().set( + &ConfidentialTokenStorageKey::Account(to.clone()), + &ConfidentialAccount { + spending_key: point(&e, 14), + viewing_public_key: point(&e, 15), + spendable_balance: Grumpkin::identity(&e), + receiving_balance: Grumpkin::identity(&e), + auditor_id: 2, + }, + ); + }); + Fixture { + e, + token, + verifier, + from, + to, + registration, + funding, + payout, + } +} + +#[test] +fn escrow_preflight_matches_real_token_transfer_public_inputs_without_moving_funds() { + let f = setup(); + let client = ConfidentialTokenContractClient::new(&f.e, &f.token); + let before = + f.e.as_contract(&f.token, || storage::get_account(&f.e, &f.from)); + assert!(client.verify_escrow_payout( + &f.registration.to_xdr(&f.e), + &1, + &f.funding.to_xdr(&f.e), + &f.to, + &f.payout.clone().to_xdr(&f.e) + )); + let expected = VerifierClient::new(&f.e, &f.verifier).inputs(); + assert_eq!( + before, + f.e.as_contract(&f.token, || storage::get_account(&f.e, &f.from)) + ); + // Exercise the actual pinned upstream transfer code, not another PI builder. + client.confidential_transfer(&f.from, &f.to, &f.payout.to_xdr(&f.e)); + assert_eq!(expected, VerifierClient::new(&f.e, &f.verifier).inputs()); +} + +#[test] +fn escrow_preflight_propagates_verifier_rejection() { + let mut f = setup(); + f.payout.proof = Bytes::from_array(&f.e, &[0]); + assert!( + !ConfidentialTokenContractClient::new(&f.e, &f.token).verify_escrow_payout( + &f.registration.to_xdr(&f.e), + &1, + &f.funding.to_xdr(&f.e), + &f.to, + &f.payout.to_xdr(&f.e) + ) + ); +} + +#[test] +fn escrow_preflight_rejects_malformed_payload() { + let f = setup(); + assert!(ConfidentialTokenContractClient::new(&f.e, &f.token) + .try_verify_escrow_payout( + &f.registration.to_xdr(&f.e), + &1, + &f.funding.to_xdr(&f.e), + &f.to, + &Bytes::new(&f.e) + ) + .is_err()); +} + +#[test] +fn escrow_preflight_rejects_noncanonical_public_inputs() { + let mut f = setup(); + f.payout.payload.sigma = BytesN::from_array(&f.e, &[255; 32]); + assert!(ConfidentialTokenContractClient::new(&f.e, &f.token) + .try_verify_escrow_payout( + &f.registration.to_xdr(&f.e), + &1, + &f.funding.to_xdr(&f.e), + &f.to, + &f.payout.to_xdr(&f.e) + ) + .is_err()); +} diff --git a/contracts/token/test_snapshots/test/escrow_preflight_matches_real_token_transfer_public_inputs_without_moving_funds.1.json b/contracts/token/test_snapshots/test/escrow_preflight_matches_real_token_transfer_public_inputs_without_moving_funds.1.json new file mode 100644 index 0000000..ea2f48e --- /dev/null +++ b/contracts/token/test_snapshots/test/escrow_preflight_matches_real_token_transfer_public_inputs_without_moving_funds.1.json @@ -0,0 +1,365 @@ +{ + "generators": { + "address": 7, + "nonce": 0, + "mux_id": 0 + }, + "auth": [ + [], + [], + [], + [], + [], + [], + [], + [], + [ + [ + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMDR4", + { + "function": { + "contract_fn": { + "contract_address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", + "function_name": "confidential_transfer", + "args": [ + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMDR4" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOLZM" + }, + { + "bytes": "0000001100000001000000020000000f000000077061796c6f61640000000011000000010000000a0000000f00000007625f6175645f73000000000d00000020000000000000000000000000000000000000000000000000000000000000000d0000000f00000007625f74696c6465000000000d0000002000000000000000000000000000000000000000000000000000000000000000080000000f0000000b635f7370656e645f6e6577000000000d000000400213cb9d1f32d90df15ecef40edfd4b4013726c52d0583416f13b031c8f24648091b5252177dd98cbaf3fb47cf994413a7e1144f6f604c46a5bead567b51a6ec0000000f00000004635f74780000000d000000402d0a8556b15580b949b5104b0c0b527ad61dac372081ec532fbccd2da8e263361725e2dd632b098eba49a7e9d310aba4843a67e4f40e2b98df1ca6fe4c57c49c0000000f00000007725f6175645f72000000000d00000020000000000000000000000000000000000000000000000000000000000000000b0000000f00000003725f65000000000d000000402639fb5afa37f916f0abdd25fd442bc53a8f51ad105ef675d535afca07b7cd741ae7198c38ecf03a73a7b2d98df7241c46a8bd5ba45ec44dd57f8dd994a2b2760000000f000000057369676d610000000000000d0000002000000000000000000000000000000000000000000000000000000000000000090000000f00000007765f6175645f72000000000d00000020000000000000000000000000000000000000000000000000000000000000000a0000000f00000007765f6175645f73000000000d00000020000000000000000000000000000000000000000000000000000000000000000c0000000f00000007765f74696c6465000000000d0000002000000000000000000000000000000000000000000000000000000000000000070000000f0000000570726f6f660000000000000d000000012a000000" + } + ] + } + }, + "sub_invocations": [] + } + ] + ], + [] + ], + "ledger": { + "protocol_version": 26, + "sequence_number": 0, + "timestamp": 0, + "network_id": "0000000000000000000000000000000000000000000000000000000000000000", + "base_reserve": 0, + "min_persistent_entry_ttl": 4096, + "min_temp_entry_ttl": 16, + "max_entry_ttl": 6312000, + "ledger_entries": [ + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": { + "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "storage": [ + { + "key": { + "symbol": "pi" + }, + "val": { + "bytes": "2d0a8556b15580b949b5104b0c0b527ad61dac372081ec532fbccd2da8e263361725e2dd632b098eba49a7e9d310aba4843a67e4f40e2b98df1ca6fe4c57c49c2eff510e43fa25f29efbfd646b7ef62f11ff77a27df704e249eb061e8b1e89291495f4d469ff1a7ac1a42fef25b7e63d19862fcaf2b7cfde3a88418ebbc02d070f704f3760742131a62723bdaf8e9e49722a7ea0e221e2065e55a826ace71b63295c5ef57658847a467fd0bdb0182040919ea3be6242aa395c1b249e9d857dd32a69fbcbb6bf5fbe3c8d5a06237f8ce6c49d26bc26aebc0a94b3df5613263e45004be015a410fcd86f09c2cdbc243b54a6e3d7bbf9990e03a2c4868ab2a11b4a19f36003498da6ca6ea600ad31e9bda3a8f7c007b2777618f064c0bf95b9cac92eff510e43fa25f29efbfd646b7ef62f11ff77a27df704e249eb061e8b1e89291495f4d469ff1a7ac1a42fef25b7e63d19862fcaf2b7cfde3a88418ebbc02d070213cb9d1f32d90df15ecef40edfd4b4013726c52d0583416f13b031c8f24648091b5252177dd98cbaf3fb47cf994413a7e1144f6f604c46a5bead567b51a6ec2d0a8556b15580b949b5104b0c0b527ad61dac372081ec532fbccd2da8e263361725e2dd632b098eba49a7e9d310aba4843a67e4f40e2b98df1ca6fe4c57c49c2639fb5afa37f916f0abdd25fd442bc53a8f51ad105ef675d535afca07b7cd741ae7198c38ecf03a73a7b2d98df7241c46a8bd5ba45ec44dd57f8dd994a2b276000000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000d" + } + } + ] + } + } + } + }, + "ext": "v0" + }, + "live_until": 4095 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": { + "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "storage": null + } + } + } + }, + "ext": "v0" + }, + "live_until": 4095 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", + "key": { + "vec": [ + { + "symbol": "Account" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMDR4" + } + ] + }, + "durability": "persistent", + "val": { + "map": [ + { + "key": { + "symbol": "auditor_id" + }, + "val": { + "u32": 1 + } + }, + { + "key": { + "symbol": "receiving_balance" + }, + "val": { + "bytes": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + } + }, + { + "key": { + "symbol": "spendable_balance" + }, + "val": { + "bytes": "0213cb9d1f32d90df15ecef40edfd4b4013726c52d0583416f13b031c8f24648091b5252177dd98cbaf3fb47cf994413a7e1144f6f604c46a5bead567b51a6ec" + } + }, + { + "key": { + "symbol": "spending_key" + }, + "val": { + "bytes": "2eff510e43fa25f29efbfd646b7ef62f11ff77a27df704e249eb061e8b1e89291495f4d469ff1a7ac1a42fef25b7e63d19862fcaf2b7cfde3a88418ebbc02d07" + } + }, + { + "key": { + "symbol": "viewing_public_key" + }, + "val": { + "bytes": "004be015a410fcd86f09c2cdbc243b54a6e3d7bbf9990e03a2c4868ab2a11b4a19f36003498da6ca6ea600ad31e9bda3a8f7c007b2777618f064c0bf95b9cac9" + } + } + ] + } + } + }, + "ext": "v0" + }, + "live_until": 518400 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", + "key": { + "vec": [ + { + "symbol": "Account" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOLZM" + } + ] + }, + "durability": "persistent", + "val": { + "map": [ + { + "key": { + "symbol": "auditor_id" + }, + "val": { + "u32": 2 + } + }, + { + "key": { + "symbol": "receiving_balance" + }, + "val": { + "bytes": "2d0a8556b15580b949b5104b0c0b527ad61dac372081ec532fbccd2da8e263361725e2dd632b098eba49a7e9d310aba4843a67e4f40e2b98df1ca6fe4c57c49c" + } + }, + { + "key": { + "symbol": "spendable_balance" + }, + "val": { + "bytes": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + } + }, + { + "key": { + "symbol": "spending_key" + }, + "val": { + "bytes": "0228011f2cbbd22dad3b9d335a55232bc439b6150d2411fe06b31e912125b2132cd113f3d0cbc3ff264558c0e8a89341ac983ed52d359e9f6eff12723b3f2c25" + } + }, + { + "key": { + "symbol": "viewing_public_key" + }, + "val": { + "bytes": "0f704f3760742131a62723bdaf8e9e49722a7ea0e221e2065e55a826ace71b63295c5ef57658847a467fd0bdb0182040919ea3be6242aa395c1b249e9d857dd3" + } + } + ] + } + } + }, + "ext": "v0" + }, + "live_until": 518400 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": { + "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "storage": [ + { + "key": { + "vec": [ + { + "symbol": "AddressAsField" + } + ] + }, + "val": { + "bytes": "2a69fbcbb6bf5fbe3c8d5a06237f8ce6c49d26bc26aebc0a94b3df5613263e45" + } + }, + { + "key": { + "vec": [ + { + "symbol": "Admin" + } + ] + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4" + } + }, + { + "key": { + "vec": [ + { + "symbol": "Auditor" + } + ] + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + }, + { + "key": { + "vec": [ + { + "symbol": "UnderlyingAsset" + } + ] + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + }, + { + "key": { + "vec": [ + { + "symbol": "Verifier" + } + ] + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + } + ] + } + } + } + }, + "ext": "v0" + }, + "live_until": 4095 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMDR4", + "key": { + "ledger_key_nonce": { + "nonce": "801925984706572462" + } + }, + "durability": "temporary", + "val": "void" + } + }, + "ext": "v0" + }, + "live_until": 6311999 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_code": { + "ext": "v0", + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "code": "" + } + }, + "ext": "v0" + }, + "live_until": 4095 + } + ] + }, + "events": [] +} \ No newline at end of file diff --git a/contracts/token/test_snapshots/test/escrow_preflight_propagates_verifier_rejection.1.json b/contracts/token/test_snapshots/test/escrow_preflight_propagates_verifier_rejection.1.json new file mode 100644 index 0000000..4dc8cdf --- /dev/null +++ b/contracts/token/test_snapshots/test/escrow_preflight_propagates_verifier_rejection.1.json @@ -0,0 +1,316 @@ +{ + "generators": { + "address": 7, + "nonce": 0, + "mux_id": 0 + }, + "auth": [ + [], + [], + [], + [], + [] + ], + "ledger": { + "protocol_version": 26, + "sequence_number": 0, + "timestamp": 0, + "network_id": "0000000000000000000000000000000000000000000000000000000000000000", + "base_reserve": 0, + "min_persistent_entry_ttl": 4096, + "min_temp_entry_ttl": 16, + "max_entry_ttl": 6312000, + "ledger_entries": [ + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": { + "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "storage": [ + { + "key": { + "symbol": "pi" + }, + "val": { + "bytes": "2d0a8556b15580b949b5104b0c0b527ad61dac372081ec532fbccd2da8e263361725e2dd632b098eba49a7e9d310aba4843a67e4f40e2b98df1ca6fe4c57c49c2eff510e43fa25f29efbfd646b7ef62f11ff77a27df704e249eb061e8b1e89291495f4d469ff1a7ac1a42fef25b7e63d19862fcaf2b7cfde3a88418ebbc02d070f704f3760742131a62723bdaf8e9e49722a7ea0e221e2065e55a826ace71b63295c5ef57658847a467fd0bdb0182040919ea3be6242aa395c1b249e9d857dd32a69fbcbb6bf5fbe3c8d5a06237f8ce6c49d26bc26aebc0a94b3df5613263e45004be015a410fcd86f09c2cdbc243b54a6e3d7bbf9990e03a2c4868ab2a11b4a19f36003498da6ca6ea600ad31e9bda3a8f7c007b2777618f064c0bf95b9cac92eff510e43fa25f29efbfd646b7ef62f11ff77a27df704e249eb061e8b1e89291495f4d469ff1a7ac1a42fef25b7e63d19862fcaf2b7cfde3a88418ebbc02d070213cb9d1f32d90df15ecef40edfd4b4013726c52d0583416f13b031c8f24648091b5252177dd98cbaf3fb47cf994413a7e1144f6f604c46a5bead567b51a6ec2d0a8556b15580b949b5104b0c0b527ad61dac372081ec532fbccd2da8e263361725e2dd632b098eba49a7e9d310aba4843a67e4f40e2b98df1ca6fe4c57c49c2639fb5afa37f916f0abdd25fd442bc53a8f51ad105ef675d535afca07b7cd741ae7198c38ecf03a73a7b2d98df7241c46a8bd5ba45ec44dd57f8dd994a2b276000000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000d" + } + } + ] + } + } + } + }, + "ext": "v0" + }, + "live_until": 4095 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": { + "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "storage": null + } + } + } + }, + "ext": "v0" + }, + "live_until": 4095 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", + "key": { + "vec": [ + { + "symbol": "Account" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMDR4" + } + ] + }, + "durability": "persistent", + "val": { + "map": [ + { + "key": { + "symbol": "auditor_id" + }, + "val": { + "u32": 1 + } + }, + { + "key": { + "symbol": "receiving_balance" + }, + "val": { + "bytes": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + } + }, + { + "key": { + "symbol": "spendable_balance" + }, + "val": { + "bytes": "2d0a8556b15580b949b5104b0c0b527ad61dac372081ec532fbccd2da8e263361725e2dd632b098eba49a7e9d310aba4843a67e4f40e2b98df1ca6fe4c57c49c" + } + }, + { + "key": { + "symbol": "spending_key" + }, + "val": { + "bytes": "2eff510e43fa25f29efbfd646b7ef62f11ff77a27df704e249eb061e8b1e89291495f4d469ff1a7ac1a42fef25b7e63d19862fcaf2b7cfde3a88418ebbc02d07" + } + }, + { + "key": { + "symbol": "viewing_public_key" + }, + "val": { + "bytes": "004be015a410fcd86f09c2cdbc243b54a6e3d7bbf9990e03a2c4868ab2a11b4a19f36003498da6ca6ea600ad31e9bda3a8f7c007b2777618f064c0bf95b9cac9" + } + } + ] + } + } + }, + "ext": "v0" + }, + "live_until": 4095 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", + "key": { + "vec": [ + { + "symbol": "Account" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOLZM" + } + ] + }, + "durability": "persistent", + "val": { + "map": [ + { + "key": { + "symbol": "auditor_id" + }, + "val": { + "u32": 2 + } + }, + { + "key": { + "symbol": "receiving_balance" + }, + "val": { + "bytes": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + } + }, + { + "key": { + "symbol": "spendable_balance" + }, + "val": { + "bytes": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + } + }, + { + "key": { + "symbol": "spending_key" + }, + "val": { + "bytes": "0228011f2cbbd22dad3b9d335a55232bc439b6150d2411fe06b31e912125b2132cd113f3d0cbc3ff264558c0e8a89341ac983ed52d359e9f6eff12723b3f2c25" + } + }, + { + "key": { + "symbol": "viewing_public_key" + }, + "val": { + "bytes": "0f704f3760742131a62723bdaf8e9e49722a7ea0e221e2065e55a826ace71b63295c5ef57658847a467fd0bdb0182040919ea3be6242aa395c1b249e9d857dd3" + } + } + ] + } + } + }, + "ext": "v0" + }, + "live_until": 518400 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": { + "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "storage": [ + { + "key": { + "vec": [ + { + "symbol": "AddressAsField" + } + ] + }, + "val": { + "bytes": "2a69fbcbb6bf5fbe3c8d5a06237f8ce6c49d26bc26aebc0a94b3df5613263e45" + } + }, + { + "key": { + "vec": [ + { + "symbol": "Admin" + } + ] + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4" + } + }, + { + "key": { + "vec": [ + { + "symbol": "Auditor" + } + ] + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + }, + { + "key": { + "vec": [ + { + "symbol": "UnderlyingAsset" + } + ] + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + }, + { + "key": { + "vec": [ + { + "symbol": "Verifier" + } + ] + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + } + ] + } + } + } + }, + "ext": "v0" + }, + "live_until": 4095 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_code": { + "ext": "v0", + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "code": "" + } + }, + "ext": "v0" + }, + "live_until": 4095 + } + ] + }, + "events": [] +} \ No newline at end of file diff --git a/contracts/token/test_snapshots/test/escrow_preflight_rejects_malformed_payload.1.json b/contracts/token/test_snapshots/test/escrow_preflight_rejects_malformed_payload.1.json new file mode 100644 index 0000000..4d53780 --- /dev/null +++ b/contracts/token/test_snapshots/test/escrow_preflight_rejects_malformed_payload.1.json @@ -0,0 +1,307 @@ +{ + "generators": { + "address": 7, + "nonce": 0, + "mux_id": 0 + }, + "auth": [ + [], + [], + [], + [], + [] + ], + "ledger": { + "protocol_version": 26, + "sequence_number": 0, + "timestamp": 0, + "network_id": "0000000000000000000000000000000000000000000000000000000000000000", + "base_reserve": 0, + "min_persistent_entry_ttl": 4096, + "min_temp_entry_ttl": 16, + "max_entry_ttl": 6312000, + "ledger_entries": [ + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": { + "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "storage": null + } + } + } + }, + "ext": "v0" + }, + "live_until": 4095 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": { + "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "storage": null + } + } + } + }, + "ext": "v0" + }, + "live_until": 4095 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", + "key": { + "vec": [ + { + "symbol": "Account" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMDR4" + } + ] + }, + "durability": "persistent", + "val": { + "map": [ + { + "key": { + "symbol": "auditor_id" + }, + "val": { + "u32": 1 + } + }, + { + "key": { + "symbol": "receiving_balance" + }, + "val": { + "bytes": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + } + }, + { + "key": { + "symbol": "spendable_balance" + }, + "val": { + "bytes": "2d0a8556b15580b949b5104b0c0b527ad61dac372081ec532fbccd2da8e263361725e2dd632b098eba49a7e9d310aba4843a67e4f40e2b98df1ca6fe4c57c49c" + } + }, + { + "key": { + "symbol": "spending_key" + }, + "val": { + "bytes": "2eff510e43fa25f29efbfd646b7ef62f11ff77a27df704e249eb061e8b1e89291495f4d469ff1a7ac1a42fef25b7e63d19862fcaf2b7cfde3a88418ebbc02d07" + } + }, + { + "key": { + "symbol": "viewing_public_key" + }, + "val": { + "bytes": "004be015a410fcd86f09c2cdbc243b54a6e3d7bbf9990e03a2c4868ab2a11b4a19f36003498da6ca6ea600ad31e9bda3a8f7c007b2777618f064c0bf95b9cac9" + } + } + ] + } + } + }, + "ext": "v0" + }, + "live_until": 4095 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", + "key": { + "vec": [ + { + "symbol": "Account" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOLZM" + } + ] + }, + "durability": "persistent", + "val": { + "map": [ + { + "key": { + "symbol": "auditor_id" + }, + "val": { + "u32": 2 + } + }, + { + "key": { + "symbol": "receiving_balance" + }, + "val": { + "bytes": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + } + }, + { + "key": { + "symbol": "spendable_balance" + }, + "val": { + "bytes": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + } + }, + { + "key": { + "symbol": "spending_key" + }, + "val": { + "bytes": "0228011f2cbbd22dad3b9d335a55232bc439b6150d2411fe06b31e912125b2132cd113f3d0cbc3ff264558c0e8a89341ac983ed52d359e9f6eff12723b3f2c25" + } + }, + { + "key": { + "symbol": "viewing_public_key" + }, + "val": { + "bytes": "0f704f3760742131a62723bdaf8e9e49722a7ea0e221e2065e55a826ace71b63295c5ef57658847a467fd0bdb0182040919ea3be6242aa395c1b249e9d857dd3" + } + } + ] + } + } + }, + "ext": "v0" + }, + "live_until": 4095 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": { + "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "storage": [ + { + "key": { + "vec": [ + { + "symbol": "AddressAsField" + } + ] + }, + "val": { + "bytes": "2a69fbcbb6bf5fbe3c8d5a06237f8ce6c49d26bc26aebc0a94b3df5613263e45" + } + }, + { + "key": { + "vec": [ + { + "symbol": "Admin" + } + ] + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4" + } + }, + { + "key": { + "vec": [ + { + "symbol": "Auditor" + } + ] + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + }, + { + "key": { + "vec": [ + { + "symbol": "UnderlyingAsset" + } + ] + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + }, + { + "key": { + "vec": [ + { + "symbol": "Verifier" + } + ] + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + } + ] + } + } + } + }, + "ext": "v0" + }, + "live_until": 4095 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_code": { + "ext": "v0", + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "code": "" + } + }, + "ext": "v0" + }, + "live_until": 4095 + } + ] + }, + "events": [] +} \ No newline at end of file diff --git a/contracts/token/test_snapshots/test/escrow_preflight_rejects_noncanonical_public_inputs.1.json b/contracts/token/test_snapshots/test/escrow_preflight_rejects_noncanonical_public_inputs.1.json new file mode 100644 index 0000000..4d53780 --- /dev/null +++ b/contracts/token/test_snapshots/test/escrow_preflight_rejects_noncanonical_public_inputs.1.json @@ -0,0 +1,307 @@ +{ + "generators": { + "address": 7, + "nonce": 0, + "mux_id": 0 + }, + "auth": [ + [], + [], + [], + [], + [] + ], + "ledger": { + "protocol_version": 26, + "sequence_number": 0, + "timestamp": 0, + "network_id": "0000000000000000000000000000000000000000000000000000000000000000", + "base_reserve": 0, + "min_persistent_entry_ttl": 4096, + "min_temp_entry_ttl": 16, + "max_entry_ttl": 6312000, + "ledger_entries": [ + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": { + "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "storage": null + } + } + } + }, + "ext": "v0" + }, + "live_until": 4095 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": { + "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "storage": null + } + } + } + }, + "ext": "v0" + }, + "live_until": 4095 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", + "key": { + "vec": [ + { + "symbol": "Account" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMDR4" + } + ] + }, + "durability": "persistent", + "val": { + "map": [ + { + "key": { + "symbol": "auditor_id" + }, + "val": { + "u32": 1 + } + }, + { + "key": { + "symbol": "receiving_balance" + }, + "val": { + "bytes": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + } + }, + { + "key": { + "symbol": "spendable_balance" + }, + "val": { + "bytes": "2d0a8556b15580b949b5104b0c0b527ad61dac372081ec532fbccd2da8e263361725e2dd632b098eba49a7e9d310aba4843a67e4f40e2b98df1ca6fe4c57c49c" + } + }, + { + "key": { + "symbol": "spending_key" + }, + "val": { + "bytes": "2eff510e43fa25f29efbfd646b7ef62f11ff77a27df704e249eb061e8b1e89291495f4d469ff1a7ac1a42fef25b7e63d19862fcaf2b7cfde3a88418ebbc02d07" + } + }, + { + "key": { + "symbol": "viewing_public_key" + }, + "val": { + "bytes": "004be015a410fcd86f09c2cdbc243b54a6e3d7bbf9990e03a2c4868ab2a11b4a19f36003498da6ca6ea600ad31e9bda3a8f7c007b2777618f064c0bf95b9cac9" + } + } + ] + } + } + }, + "ext": "v0" + }, + "live_until": 4095 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", + "key": { + "vec": [ + { + "symbol": "Account" + }, + { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOLZM" + } + ] + }, + "durability": "persistent", + "val": { + "map": [ + { + "key": { + "symbol": "auditor_id" + }, + "val": { + "u32": 2 + } + }, + { + "key": { + "symbol": "receiving_balance" + }, + "val": { + "bytes": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + } + }, + { + "key": { + "symbol": "spendable_balance" + }, + "val": { + "bytes": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + } + }, + { + "key": { + "symbol": "spending_key" + }, + "val": { + "bytes": "0228011f2cbbd22dad3b9d335a55232bc439b6150d2411fe06b31e912125b2132cd113f3d0cbc3ff264558c0e8a89341ac983ed52d359e9f6eff12723b3f2c25" + } + }, + { + "key": { + "symbol": "viewing_public_key" + }, + "val": { + "bytes": "0f704f3760742131a62723bdaf8e9e49722a7ea0e221e2065e55a826ace71b63295c5ef57658847a467fd0bdb0182040919ea3be6242aa395c1b249e9d857dd3" + } + } + ] + } + } + }, + "ext": "v0" + }, + "live_until": 4095 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_data": { + "ext": "v0", + "contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAK3IM", + "key": "ledger_key_contract_instance", + "durability": "persistent", + "val": { + "contract_instance": { + "executable": { + "wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + "storage": [ + { + "key": { + "vec": [ + { + "symbol": "AddressAsField" + } + ] + }, + "val": { + "bytes": "2a69fbcbb6bf5fbe3c8d5a06237f8ce6c49d26bc26aebc0a94b3df5613263e45" + } + }, + { + "key": { + "vec": [ + { + "symbol": "Admin" + } + ] + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAITA4" + } + }, + { + "key": { + "vec": [ + { + "symbol": "Auditor" + } + ] + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4" + } + }, + { + "key": { + "vec": [ + { + "symbol": "UnderlyingAsset" + } + ] + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M" + } + }, + { + "key": { + "vec": [ + { + "symbol": "Verifier" + } + ] + }, + "val": { + "address": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM" + } + } + ] + } + } + } + }, + "ext": "v0" + }, + "live_until": 4095 + }, + { + "entry": { + "last_modified_ledger_seq": 0, + "data": { + "contract_code": { + "ext": "v0", + "hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "code": "" + } + }, + "ext": "v0" + }, + "live_until": 4095 + } + ] + }, + "events": [] +} \ No newline at end of file diff --git a/packages/app/app/docs/page.tsx b/packages/app/app/docs/page.tsx index 7f05a35..646173d 100644 --- a/packages/app/app/docs/page.tsx +++ b/packages/app/app/docs/page.tsx @@ -384,27 +384,31 @@ No delivery -> depositor waits for timeout -> reclaims (REFUNDED)`} (Timeout Refund / Claim / Dispute) until it actually opens, so there's no guessing at when a call will succeed.

-

Funding: two calls, not one

+

Funding and payout validation

Funding is the expensive step, proof-wise — the depositor derives a one-time Grumpkin identity for the instance itself and builds four proofs: a register proof for that identity, a transfer-in proof (depositor → instance), and — because the instance can never generate a proof on its own later — both possible payout proofs up front, instance → recipient and instance → depositor. At roughly 14KB each, all four together exceed what fits in one - Soroban transaction, so funding is two calls (two wallet confirmations, back to back): + Soroban transaction. Four wallet confirmations prepare the inputs, verify each payout, and fund:

-
{`store_payout_proofs(release_proof, refund_proof)   // stored first
-fund(register_data, auditor_id, transfer_in)       // then this moves the money`}
+
{`prepare_funding(register_data, auditor_id, transfer_in)
+store_payout_proof(true, release_proof)    // verifies recipient payout
+store_payout_proof(false, refund_proof)    // verifies depositor refund
+fund()                                   // atomically registers, transfers and merges`}

- fund checks the payout proofs are already stored before it will run, so the - escrow can never end up Funded without a working settlement path already in - place. Once funding completes, the depositor discards the instance's one-time secret — + fund requires both payout proofs to have passed verification against the exact + prepared funding commitment. Replacing the funding inputs clears both approvals. Funds + move only in the last call; a rejected proof leaves the escrow unfunded. Once funding completes, the depositor discards the instance's one-time secret — see the trust caveat below.

Settlement

Every payout proof was generated once, at funding time, against a fixed opening. That's - what lets the instance submit one of them unattended, whenever the state machine says so: no + what lets the instance submit one of them unattended, whenever the state machine says so. + Funding merges once, atomically; settlement never merges later deposits, so unsolicited + credits cannot change that fixed opening. No one needs to be online or hold a key at settlement time. On the happy path the recipient marks delivery, a 10-minute release window opens, and the depositor releases. If the depositor stalls, the recipient either self-serves after the window (no arbiter) or escalates diff --git a/packages/app/app/escrow/page.tsx b/packages/app/app/escrow/page.tsx index 4620a9d..279f558 100644 --- a/packages/app/app/escrow/page.tsx +++ b/packages/app/app/escrow/page.tsx @@ -278,8 +278,8 @@ export default function EscrowPage() { />

Funding generates a register proof for the escrow's confidential account, plus the - transfer-in and two payout proofs — all in your browser. This needs two wallet - confirmations, submitted one after the other. + transfer-in and two payout proofs — all in your browser. Four wallet confirmations + prepare funding, verify both payouts, and finally move the funds.

+ + + ); + } + if (!registered) { return ( diff --git a/packages/app/app/send/page.tsx b/packages/app/app/send/page.tsx index 7c5c36f..e6c81d3 100644 --- a/packages/app/app/send/page.tsx +++ b/packages/app/app/send/page.tsx @@ -2,6 +2,7 @@ import { useEffect, useState } from "react"; import { motion } from "framer-motion"; +import { StrKey } from "@stellar/stellar-sdk"; import { CheckCircle, ExternalLink, Lock } from "lucide-react"; import { AppShell } from "@/components/layout/AppShell"; import { PageHeader } from "@/components/layout/PageHeader"; @@ -20,30 +21,53 @@ import { ConnectPrompt } from "@/components/ui/ConnectPrompt"; import { ErrorBanner } from "@/components/ui/ErrorBanner"; import { useAction } from "@/lib/use-action"; import { toBaseUnits, formatAmount, DECIMALS } from "@/lib/amount"; -import { errMsg } from "@/lib/err"; type Step = "recipient" | "amount" | "confirm"; +type RecipientCheck = { + address: string; + wallet: object; + status: "checking" | "registered" | "unregistered" | "error"; +}; export default function SendPage() { const wallet = useRequireWallet(); const { view, error, setError } = useWallet(); const { run, busy, phase } = useAction(); const [step, setStep] = useState("recipient"); - const [recipients, setRecipients] = useState(null); const [to, setTo] = useState(""); + const [recipientCheck, setRecipientCheck] = useState(null); + const [checkAttempt, setCheckAttempt] = useState(0); const [amount, setAmount] = useState(""); const [txHash, setTxHash] = useState(null); useEffect(() => { - if (!wallet) return; - wallet - .registeredRecipients() - .then(setRecipients) - .catch((e) => { - setError(errMsg(e)); - setRecipients([]); - }); - }, [wallet, setError]); + const address = to.trim(); + if (!wallet || !StrKey.isValidEd25519PublicKey(address)) return; + let cancelled = false; + setRecipientCheck({ address, wallet, status: "checking" }); + const timer = setTimeout(async () => { + try { + const registered = await wallet.isRecipientRegistered(address); + if (!cancelled) setRecipientCheck({ address, wallet, status: registered ? "registered" : "unregistered" }); + } catch { + if (!cancelled) setRecipientCheck({ address, wallet, status: "error" }); + } + }, 350); + return () => { cancelled = true; clearTimeout(timer); }; + }, [wallet, to, checkAttempt]); + + const recipientAddress = to.trim(); + const validAddress = StrKey.isValidEd25519PublicKey(recipientAddress); + const recipientStatus = recipientCheck?.wallet === wallet && recipientCheck.address === recipientAddress + ? recipientCheck.status : null; + const recipientReady = validAddress && recipientStatus === "registered"; + const recipientError = recipientAddress && !validAddress + ? "Enter a valid Stellar public address beginning with G." + : recipientStatus === "unregistered" + ? "This address is not registered with Lucent on Testnet. Ask the recipient to connect and register first." + : recipientStatus === "error" + ? "Could not check registration. Retry to continue." + : undefined; if (!wallet) { return ( @@ -55,6 +79,7 @@ export default function SendPage() { } async function submit() { + if (!recipientReady) { setStep("recipient"); return; } setTxHash(null); await run("send", async (sp) => { const r = await wallet!.transfer(to.trim(), toBaseUnits(amount || "0"), sp); @@ -138,26 +163,22 @@ export default function SendPage() { placeholder="G…" value={to} onChange={(e) => setTo(e.target.value)} - className="font-mono" + className={`font-mono ${recipientError ? "border-error/50" : ""}`} + autoComplete="off" + spellCheck={false} + aria-invalid={!!recipientError} + aria-describedby="recipient-status" /> +
+ {recipientError ?

{recipientError}

: + recipientReady ?

Registered with Lucent on Testnet.

: + validAddress ?

Checking registration…

: +

Paste the recipient’s Stellar public address. We’ll check their Lucent registration before you continue.

} + {recipientStatus === "error" && } +
- {recipients && recipients.length > 0 && ( - <> - Registered accounts -
- {recipients.map((a) => ( - - ))} -
- - )} - - @@ -186,7 +207,7 @@ export default function SendPage() { - @@ -224,7 +245,7 @@ export default function SendPage() { - diff --git a/packages/app/lib/wallet-context.tsx b/packages/app/lib/wallet-context.tsx index 8205e23..3e46227 100644 --- a/packages/app/lib/wallet-context.tsx +++ b/packages/app/lib/wallet-context.tsx @@ -82,6 +82,8 @@ export function WalletProvider({ children }: { children: ReactNode }) { setConnecting(true); try { const w = await ConfidentialWallet.connect(log); + setView(null); + setLastSync(null); setWallet(w); const v = await w.refresh(); setView(v); @@ -111,15 +113,15 @@ export function WalletProvider({ children }: { children: ReactNode }) { if (localStorage.getItem(MANUALLY_DISCONNECTED_KEY)) return; freighterIsAllowed().then(async (allowed) => { if (!allowed) return; - const w = await connect(); - // Unprompted attempt — if it failed, clear the error connect() set - // rather than surfacing it for something the user didn't initiate. - if (!w) setError(null); + await connect(); + // Preserve account-read/recovery errors so a connected wallet never + // silently falls into the registration screen after a failed refresh. }); }, [connect]); const refresh = useCallback(async () => { if (!wallet) return; + setError(null); try { const v = await wallet.refresh(); setView(v); diff --git a/packages/app/lib/wallet.ts b/packages/app/lib/wallet.ts index 35135b3..58b24ab 100644 --- a/packages/app/lib/wallet.ts +++ b/packages/app/lib/wallet.ts @@ -231,7 +231,20 @@ export class ConfidentialWallet { return this.client.confidentialBalance(this.address); } + /** Direct lookup, independent of event-history retention or local caches. */ + async isRecipientRegistered(address: string): Promise { + return this.client.isRegistered(address); + } + async register(onPhase?: (p: TxPhase) => void): Promise { + const existing = await this.account(); + if (existing) { + if (!existing.spendingKey.equals(this.keys.Y) || !existing.viewingPublicKey.equals(this.keys.PVK)) { + throw new Error("This account is already registered, but its confidential keys do not match this wallet. Restore the original confidential keys before transacting."); + } + this.log("already registered on-chain; refreshing account state"); + return; + } const w = buildRegisterWitness(this.keys); onPhase?.("proving"); this.log("proving register…"); @@ -831,8 +844,11 @@ export class ConfidentialWallet { /** Sync from RPC events, verify against chain, and return a UI view. */ async refresh(): Promise { - const state: AccountState = await this.engine.sync(); const onchain = await this.account(); + if (onchain && (!onchain.spendingKey.equals(this.keys.Y) || !onchain.viewingPublicKey.equals(this.keys.PVK))) { + throw new Error("This account is already registered, but its confidential keys do not match this wallet. Restore the original confidential keys before transacting."); + } + const state: AccountState = await this.engine.sync(); let matchesChain: boolean | null = null; if (onchain) { matchesChain = (await this.engine.verifyAgainstChain()).ok; diff --git a/packages/sdk/contracts/confidential_auditor.wasm b/packages/sdk/contracts/confidential_auditor.wasm index 86ba043a5c915f2f13a27751eb6ce16faf79ba4d..972a6e3bf376fd079fad6bd70b1b673b15261d39 100644 GIT binary patch delta 174 zcmX>#gYnP|#tjvWtgM{;VqBYR8GkY}MolhfRbY(VJcHGiOEp%3L4ipigvmjH5lF`= zF*;sqIl$m}fI%RJ1t{kDfFVmDcJeQN9md$r>H-nWKz$9uxr~fao8O7tW!K?i0P1IS zViZu}7GQ8(&!gYnc1#tjvWtemX;TwH-nWKz$9uxr~gFo8O7tW!Dj4a9q#~ zR4k*w;KV4vAjQqa05p&h$X4MN05TmnflN~nh;@`N+iWeH$2j?ijLYVga*k|Fvl%Bh ks)|Xo78RGJ7BPSUpP`}-a5mWFzUo0C{BG6Mi(AO`{f delta 34 qcmZ22uvuV(J`3aQ$p$RS{CtLbmWFx;x_O!D86`QDo1<7RG6Mjrt_nQ> diff --git a/packages/sdk/contracts/confidential_token.wasm b/packages/sdk/contracts/confidential_token.wasm index b7ddddb9411882e6d8be259e3bd045767dc1aa1d..f6a0a26691b814bae0cfaa231e5eed315912e5d2 100644 GIT binary patch delta 1914 zcmZuyT}&KR7@d3X%O#+!N??la?ZrMGJZr+*|~gD7d2t_9?gvc3AerP=ZsdpZ{sp z@)OoBzSGR`yZTjiD5fqF-MC1cUpC~FFN`PnIco>JUA0zFLcHfKAovLT$^!|_XJ5Z? zOM6PwLa8(Pe12&a(S&IA1?#MYW-wys5x48Ni>ZB6Wb5czIhsG39EDYdNj6-g7ee+2OsiXlqA) z=!-ED#a;4VHDmyM13jsRSa7(_FzhQ~O5-lrR50Yp1$z|CAV+ma11Kh%kN$?7fV=FM zmkt*PhWEo!#M#jTdd!K*B%B38nwP>mafQS1@UhBbc2k(Mz&dH&nCn$@qhQ*?R@SFj zh%*0Z>&okShS-YbW371imf+k|!TBCzlEX5Rj30kFz=y|5?R6ia)W7gk)&)kArm*jT zF{!<72P~~c!9265$xjrwKc!JKR0>YXj|DN<`_fnnpGUlUyrsr|e{&bjb1a?g2In1+ zFOO~aC&1)hjcJf9UkAT9zKef4ein+|as|lze{(7SYi4)V%k`m(Po1GP?PHel>)&C#4X_q(v delta 1960 zcmZuyT}&KR6rOu$c6OHCk=s&WyBN8Pq*;{iPbCVZ)tRmAA_Q40%1=Ysg0`@mh99FP z#;{AEOYa*sMl5zu2k7CXaom*{2)GuT@U8*Da1~=ulU0hhcGo2iks9>5K&b; z_(_r4_3%{io}?u*Ps~d*F_hn^bxkhUC+)Kb?|n@*gz3}$up1O zCFtE%6H&bOwF@_uy^0cuFXZ$2)kla#c(>OdGa?G~VdoLETdMfn{yBAf_L9hEJFP5K zowEWeRQ>Sabrj{jFV13kxs`Yeh1vdO9PX1#J^_)7$$gOfWAYJ#(DyI-12L+F@LdGF zYE9}g3c9IFJc&8{18}$uu8?pD+KhJj-z6jRq?%GB9p@Az&ppOPb2ufvgW6aHs! z0wo-MMWrTNgPN28P$#5X3>Rca%fbcOfk^rMD|f`SQhf=S%?EwAu?9!9v9)X+Tj-CV zCC>W~BW)dH%yteAVH2~-!RB@ok%GI3r08{`6) zXEz4x*veqNNi{M{H9MEkEXB+8p_ZI#M>Egj6bSE@l4;P$tD>jp)K2@ak8Ub9f@DP6 z2@ZH6V^zsCDsk-1BZPB6I?XoVMzFI@G6ZN0VPYewOp!G9Srk;g4oVf0#TE=?GY8v7 z1`?~C74Wt=G=z;A6G0DDWotwAz|4-r2`slpk=p|01mrk5TqAcx5iBqa#Pd&vPb1XK z_l&d&=cUua9-_-l?{5ZvEmpO3b%`=ife&0=)yeBhxlTDe#A zf=>R!Si2Zr#nGR@Q9mCQmrz4^z=Va?q^5&#ig+O4r^;hBk#Gs@o|dfLZgvtaOV3MC?6YTaIoq^)R50Yd633$ZtW3 z?EUSiSE68Pc4K?xg0I28{K4^V{FET6#4rz~VeVn9=CH7)REguvs#@*P4ET|Z1zn&9 zD#zBt&3;x^+t~F)YRbVlp!JGANVSj$k@W=bs1xft^JiCYIQN zxI***dwjaP0=t31f1SCLkQmoRPGAul-%#5*s(cRvX_amWAbn5P9WJTGapE*%H9W(ta80Tatw@d=gm7JD;YPJL@(fEoIF`HRhga5P|wm(&v3JQ>O@@tY|}Xu delta 205 zcmcbxlLkQmoRPGAul-%#6&kn?;%8Ss2SEm$E4^mT#WM_JA8m zl?&xEGL~(AD%{S>*uFVevX_amee!SVP9WJTGapE*%H9W(ta80Ta*n8)m5h^jL^^LSiC)0TID4{asxm*Hp`N9oo`G&&W_m_RPUU9%)QP$Pak4!S diff --git a/packages/sdk/contracts/payroll_vault.wasm b/packages/sdk/contracts/payroll_vault.wasm index 7ad011c64659da54aedc19c66c8bf32d28e4fec6..c5864d93cfd8832d6887c186dc53d46ce506092b 100644 GIT binary patch delta 29 lcmaFte%pP6m@;GjFgWrENboR$coRW9Rv?cN#G3}0_qzxpOFd0uaW47VuW>8>IU=-kWVho&ojVWYu5wjgHFHppZNr7RxBV(cT zLT{xs=_D5h!thLl&s? l9)~8Q&}I(KdS=G_$&9>Wljrg9u(KKJSsLmYPTt8g8vw~KE-wH8 delta 203 zcmX>jbwz5zCT4bShK*a(7`4TDn7I|099tU>FgWrEi1RRkcoRW9Rv?cN#G3}qzxpOFd0vlXAb7(W>8>IU=-kWVho&ojmdU$5wqRoear#8yg*SWCIyD& zj*NxUn|WE-7#W2oi?Av%icB_TJLTY6x_F)yTtoQc9Wc!90(gxh!Q2DHdZ-7qCrF~M8U#JFj&M+P;wFNL{L{0 zi(o5ua(_Uuv9q)Yu~7?ufSrZ!A~v(bd-G;yyR~lZY@rXD5Ny&QAm=MLhGv3p*|E5; zJ$$zze5M>sF$g>z3ncK2dS_$((*R9ckpu@~km9N-DX#9QEG38}T=2AM^av_)rioO- zEakRmTExdA)Ob9nhGU)3)da-=hAtJ!cqW{Tum2}Dqr~t!aS2*G!Vax z3&aES3Nd4yfTM0LH=mWHNE1Hn&e@n+q*j4S@OAE}7wdIE@Nwi3Y7t5-GehR_;dP!@ zPxcOYs+?Rx#~^ts-AIMSk6W!)c9lz=Nv}eG$P^DBP-A`>Jex|k%7y12^9P-1n|P9qu(bk_%um#LHd_3(qYWN-BFV9!zJyH9ID+N%0$s*bE~q;(R5X}m=waTnSx6&vsGzSV zGA|{IDiWqRI)P<&x@gExN}9*XBFHi+1s0N#?CQTZO0~(QaSmE)@>ShzKw0gWE#jwn zM%=S5hHnFT8 zoh_)SdiMeub zVh9a~1yb~jl`4}WG@4jU3xDZ&y0xnrsdv&1xXTczeRqu{Z|)Dc$&2^y!iak4yZ!~G C{ZIG+ diff --git a/packages/sdk/package.json b/packages/sdk/package.json index 558ea12..527ec31 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -24,8 +24,8 @@ "scripts": { "build": "tsc -p tsconfig.json", "typecheck": "tsc -p tsconfig.json --noEmit", - "test": "tsx test/smoke.mjs && tsx test/parity.mjs && tsx test/payload.mjs && tsx test/auditor.mjs && tsx test/ephemeral.mjs && tsx test/dedup.mjs && tsx test/event-pagination.mjs && tsx test/state-recovery.mjs && tsx test/state-namespace.mjs && tsx test/indexer-parity.mjs && tsx test/prove.mjs && tsx test/disclosure.mjs", - "test:fast": "tsx test/smoke.mjs && tsx test/parity.mjs && tsx test/payload.mjs && tsx test/auditor.mjs && tsx test/ephemeral.mjs && tsx test/dedup.mjs && tsx test/event-pagination.mjs && tsx test/state-recovery.mjs && tsx test/state-namespace.mjs && tsx test/indexer-parity.mjs" + "test": "tsx test/restore.mjs && tsx test/account-status.mjs && tsx test/smoke.mjs && tsx test/parity.mjs && tsx test/payload.mjs && tsx test/auditor.mjs && tsx test/ephemeral.mjs && tsx test/dedup.mjs && tsx test/event-pagination.mjs && tsx test/state-recovery.mjs && tsx test/state-namespace.mjs && tsx test/indexer-parity.mjs && tsx test/prove.mjs && tsx test/disclosure.mjs", + "test:fast": "tsx test/restore.mjs && tsx test/account-status.mjs && tsx test/smoke.mjs && tsx test/parity.mjs && tsx test/payload.mjs && tsx test/auditor.mjs && tsx test/ephemeral.mjs && tsx test/dedup.mjs && tsx test/event-pagination.mjs && tsx test/state-recovery.mjs && tsx test/state-namespace.mjs && tsx test/indexer-parity.mjs" }, "dependencies": { "@aztec/bb.js": "0.87.0", diff --git a/packages/sdk/src/chain/client.ts b/packages/sdk/src/chain/client.ts index 1c5a64e..c332c68 100644 --- a/packages/sdk/src/chain/client.ts +++ b/packages/sdk/src/chain/client.ts @@ -16,6 +16,10 @@ import { TransactionBuilder, BASE_FEE, rpc, + scValToNative, + Operation, + SorobanDataBuilder, + type Transaction, } from "@stellar/stellar-sdk"; import { pointFromBytes, type Point } from "../crypto/grumpkin.js"; @@ -123,8 +127,14 @@ export class ChainClient { new Address(address).toScVal(), ]); return parseAccount(retval); - } catch { - return null; + } catch (error) { + // Only the token's explicit AccountNotRegistered error means absence. + // RPC outages, archived entries and malformed responses must stay errors. + if (error instanceof Error && + /^simulate confidential_balance failed: HostError: Error\(Contract, #3501\)/.test(error.message)) { + return null; + } + throw error; } } @@ -156,6 +166,7 @@ export class ChainClient { method: string, args: xdr.ScVal[], signer: Signer, + restored = false, ): Promise { const source = await this.server.getAccount(signer.publicKey); const tx = new TransactionBuilder(source, { @@ -170,14 +181,56 @@ export class ChainClient { if (rpc.Api.isSimulationError(sim)) { throw new Error(`simulate ${method} failed: ${sim.error}`); } + const data = sim.transactionData.build(); + const archived = data.ext().switch() === 1 + ? data.ext().resourceExt().archivedSorobanEntries() + : []; + if (archived.length) { + if (restored) throw new Error(`${method}: ledger entries are still archived after restoration; retry the account operation`); + // Auto-restoration plus the invocation can exceed the network write + // limit even when each operation fits separately. Restore first, then + // rebuild from a fresh sequence number and fresh simulation. + const footprint = data.resources().footprint().readWrite(); + const restoreTx = new TransactionBuilder(await this.server.getAccount(signer.publicKey), { + fee: BASE_FEE, + networkPassphrase: this.cfg.networkPassphrase, + }) + .setSorobanData(new SorobanDataBuilder().setReadWrite(archived.map(index => { + const key = footprint[index]; + if (!key) throw new Error("Simulation returned an invalid archived entry index"); + return key; + })).build()) + .addOperation(Operation.restoreFootprint({})) + .setTimeout(180) + .build(); + const restoreSim = await this.server.simulateTransaction(restoreTx); + if (rpc.Api.isSimulationError(restoreSim)) { + throw new Error(`simulate restore for ${method} failed: ${restoreSim.error}`); + } + await this.submit(rpc.assembleTransaction(restoreTx, restoreSim).build(), signer, `restore for ${method}`); + return this.invoke(contractId, method, args, signer, true); + } const assembled = rpc.assembleTransaction(tx, sim).build(); + return this.submit(assembled, signer, method); + } + private async submit(assembled: Transaction, signer: Signer, method: string): Promise { const signedXdr = await signer.sign(assembled.toXDR()); const signedTx = TransactionBuilder.fromXDR(signedXdr, this.cfg.networkPassphrase); const send = await this.server.sendTransaction(signedTx); if (send.status === "ERROR") { - throw new Error(`send ${method} rejected: ${JSON.stringify(send.errorResult)}`); + const diagnostics = (send.diagnosticEvents ?? []).map((diagnostic) => { + const event = diagnostic.event().body().v0(); + return JSON.stringify({ + topics: event.topics().map((topic) => scValToNative(topic)), + data: scValToNative(event.data()), + }, (_, value) => typeof value === "bigint" ? value.toString() : value); + }); + throw new Error( + `send ${method} rejected (${send.errorResult?.result().switch().name ?? "unknown"}, tx ${send.hash})` + + (diagnostics.length ? `: ${diagnostics.join("; ")}` : `: ${JSON.stringify(send.errorResult)}`), + ); } for (let i = 0; i < MAX_POLL_ATTEMPTS; i++) { diff --git a/packages/sdk/test/account-status.mjs b/packages/sdk/test/account-status.mjs new file mode 100644 index 0000000..e437ea8 --- /dev/null +++ b/packages/sdk/test/account-status.mjs @@ -0,0 +1,27 @@ +import assert from "node:assert/strict"; +import { ChainClient } from "../src/chain/client.ts"; +import { G, pointToBytes } from "../src/crypto/grumpkin.ts"; +import { xdr, nativeToScVal } from "@stellar/stellar-sdk"; + +const client = new ChainClient({ rpcUrl: "https://example.com", networkPassphrase: "test", contracts: { token: "token" } }); +const address = "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWHF"; +const absent = new Error("simulate confidential_balance failed: HostError: Error(Contract, #3501)\nEvent log"); +client.simulate = async () => { throw absent; }; +assert.equal(await client.confidentialBalance(address), null); +assert.equal(await client.isRegistered(address), false); + +for (const error of [new Error("network unavailable"), new Error("simulate confidential_balance failed: HostError: Error(Storage, MissingValue)"), { code: -32603, message: "RPC unavailable" }]) { + client.simulate = async () => { throw error; }; + await assert.rejects(client.confidentialBalance(address), e => e === error); +} +client.simulate = async () => xdr.ScVal.scvVoid(); +await assert.rejects(client.confidentialBalance(address)); + +const point = () => nativeToScVal(Buffer.from(pointToBytes(G)), { type: "bytes" }); +client.simulate = async () => xdr.ScVal.scvMap([ + ...["spending_key", "viewing_public_key", "spendable_balance", "receiving_balance"].map(key => new xdr.ScMapEntry({ key: xdr.ScVal.scvSymbol(key), val: point() })), + new xdr.ScMapEntry({ key: xdr.ScVal.scvSymbol("auditor_id"), val: xdr.ScVal.scvU32(0) }), +]); +assert.equal(await client.isRegistered(address), true); +assert((await client.confidentialBalance(address)).spendingKey.equals(G)); +console.log("account-status: registered, absent, RPC failure, archived data, and malformed response passed"); diff --git a/packages/sdk/test/restore.mjs b/packages/sdk/test/restore.mjs new file mode 100644 index 0000000..ce91bb9 --- /dev/null +++ b/packages/sdk/test/restore.mjs @@ -0,0 +1,29 @@ +import assert from 'node:assert/strict'; +import {Account, Contract, SorobanDataBuilder, xdr} from '@stellar/stellar-sdk'; +import {ChainClient} from '../src/chain/client.ts'; +const address='GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWHF'; +const contract='CACKEFUKVPBGDJM6Z4NOTY3H44MUMJDYIRNBLH6MDFN3QUSFWENXAABF'; +const key=new Contract(contract).getFootprint(); +const client=new ChainClient({rpcUrl:'https://example.com',networkPassphrase:'test',contracts:{token:contract}}); +let simulations=0, accounts=0; +const submissions=[]; +client.server.getAccount=async()=>new Account(address,String(++accounts)); +client.server.simulateTransaction=async tx=>{ + simulations++; + const data=new SorobanDataBuilder().setReadWrite([key]).build(); + if(simulations===1) data.ext(new xdr.SorobanTransactionDataExt(1,new xdr.SorobanResourcesExtV0({archivedSorobanEntries:[0]}))); + if(simulations===2) { + assert.equal(tx.operations[0].type,'restoreFootprint'); + assert.equal(tx.toEnvelope().v1().tx().ext().value().resources().footprint().readWrite().length,1); + } + return {_parsed:true, latestLedger:1,events:[],transactionData:new SorobanDataBuilder(data),minResourceFee:'0',result:{auth:[],retval:xdr.ScVal.scvVoid()}}; +}; +client.submit=async(tx,signer,method)=>{ + submissions.push({method,sequence:tx.sequence}); + return {hash:'test',status:'SUCCESS'}; +}; +await client.invoke(contract,'register',[],{publicKey:address}); +assert.equal(simulations,3); +assert.deepEqual(submissions.map(x=>x.method),['restore for register','register']); +assert.notEqual(submissions[0].sequence,submissions[1].sequence); +console.log('restore: separate restoration, fresh simulation, fresh sequence, then invocation passed');