diff --git a/README.md b/README.md index ac4bce7..a4bd142 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,7 @@ notarization command of the verification layer, and the agents' x402 wallet (EIP | [`control-plane/`](control-plane/) | from findings to a finished migration: a prioritized plan from the inventory and the scanner, its execution through the gateway, KMS and PKI with consent per action and a measured proof afterwards, recipes for the servers the products do not touch and a rescan that judges them, a compliance report against NIST IR 8547, the EU roadmap and optionally CNSA 2.0, and a console that checks it all again | | [`agents/`](agents/) | limits an AI agent cannot break unseen: a post-quantum identity (ML-DSA-65), a policy (spending per time window, allowed tools and recipients, which actions need human approval), a signed ledger of every action judged against the policy, approvals and revocation signed by people, and a verifier that re-runs the policy over the whole ledger without trusting the agent; two branches of one ledger are a proof of equivocation anyone can check; and a wallet that pays over x402 only what the agent's ledger records and its policy allows, either holding the payment key for the owner or co-signing from a 2-of-2 contract wallet that neither the agent nor the owner can spend alone; both run on the public testnet with their evidence; and the chain as the witness of a ledger: a notarized head, read through the AIP-23 verifier under a post-quantum certified anchor, bounds entry times from below (a backdated entry is caught) | | [`proof-of-ai/`](proof-of-ai/) | the AIP-23 envelope of an AI agent's action: model, version, weights digest, prompt, input, output, tools, agent, requester, as digests; verified by the same AIP-23 verifier as every other proof | +| [`market-settlement/`](market-settlement/) | the dispute and settlement rail of a verifiable infrastructure market, measured end to end on testnet 28001: an order with its reward in escrow and a provider bond, the result committed on chain with its execution envelope notarized under a post-quantum certified anchor, a challenge window in which anyone disputes with a recomputed result and a bond, an arbiter that can only route the escrow (with a permissionless 14-day timeout), deadline reclaims, and an AIP-23 settlement receipt; a pure judge over the job's timeline that checks deadlines, the window, who resolved, the payout, the replay and the proof | | [`verifiable-data/`](verifiable-data/) | a dataset whose every answer is checkable against a short commitment without the data: RFC 9162 commitments per version (append-only, consistency proofs), equality and range queries proven correct AND complete (contiguous run of a sorted index plus its two neighbours), hash-based selective disclosure of fields, availability sampling against the serving endpoint, and the version's AIP-23 envelope notarized and read back under a post-quantum certified anchor; not zero knowledge, and says so | | [`ai-trust/`](ai-trust/) | the trust chain of an AI result: the agent's identity (agents/), the model artifact's attestation, the host's runtime record (verify-layer/), the policy and signed ledger, the Proof of AI envelope and the chain as witness, joined in one bundle whose verifier checks only the links between them | | [`identity/`](identity/) | post-quantum credentials: an issuer signs claims (hybrid Ed25519 + ML-DSA-65, both required), the holder shows only the claims it picks (selective disclosure in the manner of SD-JWT, RFC 9901, in a format of its own), bound to the verifier's audience and nonce; delegation to a phone, an agent or a ten-minute session key that can only narrow; revocation and an issuer status list in the manner of W3C Bitstring Status List; all checked offline from the files; and compliance without surveillance: a verifier's policy (issuers, required claims) judged on a presentation, recorded as an AIP-23 envelope that carries no personal data; and the Travel Rule between VASPs, the IVMS101 data sealed for the receiving VASP with a hybrid X25519 + ML-KEM-768 key encapsulation, signed, bound to the transfer and acknowledged; and the same credentials as standard SD-JWT (IETF RFC 9901): issued with the issuer's Ed25519 key (EdDSA) or its ML-DSA-65 key, presented with a key binding JWT, and verified against the RFC's own example vectors (`identity-cli.mjs verify-sdjwt`, behind Aere Cloud's POST /v1/identity/sd-jwt/verify) | @@ -41,6 +42,7 @@ test, counts as a failure of the control. Results measured on 2026-09-29 (Node.j | identity | 44/44 (`node proba-identity.mjs`, with the AIP-23 verifier for its envelope test; without it that test is reported as skipped and the exit code is 2), compliance 15/15 (`node proba-conformitate.mjs`), Travel Rule 19/19 (`node proba-travel-rule.mjs`), SD-JWT 23/23 (`node proba-sdjwt.mjs`, the RFC 9901 vectors included), measured 2026-09-30 | 49/49 (`node control-negativ-identity.mjs`); compliance 14/14 (`node control-negativ-conformitate.mjs`); Travel Rule 19/19 (`node control-negativ-travel-rule.mjs`); SD-JWT 28/28 (`node control-negativ-sdjwt.mjs`) | | agents | policy 27/27 with the AIP-23 verifier (without it 25 run, 2 are reported as skipped and the exit code is 2), ledger 51/51, approval and revocation 39/39, the chain as witness 26/26 without a network and 7/7 on testnet 28001 on 2026-09-30 (`proba-agent-ancora-testnet.mjs`, needs a funded testnet key and the AIP-23 verifier), command line 23/23 through files and processes only (on Linux and macOS one more test checks the key file mode; not measured here); x402 wallet 25/25, 2-of-2 co-signing 16/16 and payment verifier 14/14 without a network; on the public testnet 28001, 9/9 with the wallet key and 13/13 with the 2-of-2 contract wallet (`x402/proba-x402-testnet.mjs`, `x402/proba-cosign-testnet.mjs`, each needs a funded testnet key); the contract's artifact recompiles byte for byte with solc 0.8.23 (`node x402/recompileaza-contract.mjs --solc `) | 26/26 (`node control-negativ-aprobare.mjs`); the chain as witness 11/11 (`node control-negativ-ancora.mjs`); x402 30/30 (`node x402/control-negativ-wallet.mjs`); the contract's own tests (7) and their negative control (4/4) run in the Aere Network contracts project, not in this repository | | proof-of-ai | 6/6 with the AIP-23 verifier (`AERE_VERIFY_PROOF=... node proba-proof-of-ai.mjs`); without it the probe reports NEMASURAT and exits 2 | one negative control inside the test (an envelope touched after its hash: INVALID) | +| market-settlement | 20/20 on testnet 28001 on 2026-10-02 (`AERE_TESTNET_KEY_FILE=... AERE_ETHERS_DIR=... node proba-piata-28001.mjs`: five scenarios on AereComputeMarketV3 deployed from the committed artifact, every refusal by its named custom error, the provider's notarized envelope read back under a post-quantum certified anchor); the judge on the recorded timelines 16/16 without a chain (`node proba-judecata.mjs`: five honest timelines VALID, ten forged ones INVALID for their named reason, the settlement receipt) | 7/7 (`node proba-judecata.mjs --control-negativ`: deadline, window, arbiter, payout, result bytes, replay, proof, each planted out on a copy and each forged fixture then accepted) | | verifiable-data | 22/22 with the AIP-23 verifier (`AERE_VERIFY_PROOF=... node proba-verifiable-data.mjs`: honest answers VALID, nine forged ones INVALID for their named reason, availability sampling on a local server; the envelope row is NEMASURAT without the verifier, exit 2); 24/24 with `--viu` on testnet 28001 on 2026-10-02 (a version notarized with a test key and read back under a post-quantum certified anchor; evidence in `dovezi/`) | 5/5 (`node proba-verifiable-data.mjs --control-negativ`: field commitment, index order, completeness, consistency, sampling, each planted out on a copy and each forged fixture then accepted) | | ai-trust | 13/13 with the AIP-23 verifier (`AERE_VERIFY_PROOF=... node proba-lant-de-incredere.mjs`: the whole chain on a committed fixture, then ten links broken on purpose, each refused for its named reason); without the verifier it exits 2 | 8/8 (`node proba-lant-de-incredere.mjs --control-negativ`) | @@ -51,4 +53,4 @@ interface, command line and data (`definePolicy`, `verifyLedger`, `approve`, ... ## Licence -MIT, see [LICENSE](LICENSE). Files: 174 (pq-gateway 6, pq-kms 10, pq-pki 6, crypto-inventory 42, verify-layer 12, proof-kinds 3, control-plane 19, agents 39, identity 15, proof-of-ai 3, ai-trust 6, verifiable-data 7, readiness 4). +MIT, see [LICENSE](LICENSE). Files: 183 (pq-gateway 6, pq-kms 10, pq-pki 6, crypto-inventory 42, verify-layer 12, proof-kinds 3, control-plane 19, agents 39, identity 15, proof-of-ai 3, ai-trust 6, verifiable-data 7, market-settlement 9, readiness 4). diff --git a/market-settlement/AereComputeMarketV3.json b/market-settlement/AereComputeMarketV3.json new file mode 100644 index 0000000..7d083e7 --- /dev/null +++ b/market-settlement/AereComputeMarketV3.json @@ -0,0 +1,1458 @@ +{ + "kind": "aere-compute-market-v3-artifact", + "contract": "AereComputeMarketV3", + "source": "contracts/depin/AereComputeMarketV3.sol", + "sourceSha256": "0x6db4d53dffb0afd79cfb41f973ac4d2ca82589ab7bdd206296b66b4c72dd4fe4", + "solc": "0.8.23+commit.f704f362", + "optimizer": { + "enabled": true, + "runs": 1 + }, + "evmVersion": "paris", + "abi": [ + { + "inputs": [ + { + "internalType": "address", + "name": "zkVerifier", + "type": "address" + }, + { + "internalType": "address", + "name": "arbiter", + "type": "address" + }, + { + "internalType": "address", + "name": "governance", + "type": "address" + }, + { + "internalType": "bytes4", + "name": "pinnedProofSelector", + "type": "bytes4" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "ArbitrationTimeoutNotPassed", + "type": "error" + }, + { + "inputs": [], + "name": "BadBond", + "type": "error" + }, + { + "inputs": [], + "name": "BadDeadline", + "type": "error" + }, + { + "inputs": [], + "name": "BadFalconKey", + "type": "error" + }, + { + "inputs": [], + "name": "BadPublicValues", + "type": "error" + }, + { + "inputs": [], + "name": "BadResult", + "type": "error" + }, + { + "inputs": [], + "name": "BadReward", + "type": "error" + }, + { + "inputs": [], + "name": "BadSpec", + "type": "error" + }, + { + "inputs": [], + "name": "BadVKey", + "type": "error" + }, + { + "inputs": [], + "name": "BadValue", + "type": "error" + }, + { + "inputs": [], + "name": "BadWindow", + "type": "error" + }, + { + "inputs": [], + "name": "DeadlineNotPassed", + "type": "error" + }, + { + "inputs": [], + "name": "DeadlinePassed", + "type": "error" + }, + { + "inputs": [], + "name": "InlineResultNotAllowed", + "type": "error" + }, + { + "inputs": [], + "name": "NotArbiter", + "type": "error" + }, + { + "inputs": [], + "name": "NotGovernance", + "type": "error" + }, + { + "inputs": [], + "name": "NotJobProvider", + "type": "error" + }, + { + "inputs": [], + "name": "NotPQCAuthorized", + "type": "error" + }, + { + "inputs": [], + "name": "NotPQCJob", + "type": "error" + }, + { + "inputs": [], + "name": "NotRequester", + "type": "error" + }, + { + "inputs": [], + "name": "OffchainResultNotAllowed", + "type": "error" + }, + { + "inputs": [], + "name": "PQCSigNotAllowed", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "length", + "type": "uint256" + } + ], + "name": "ProofTooShort", + "type": "error" + }, + { + "inputs": [], + "name": "ResultMismatch", + "type": "error" + }, + { + "inputs": [], + "name": "SettlementGraceOpen", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + } + ], + "name": "TokenNotAllowed", + "type": "error" + }, + { + "inputs": [], + "name": "TransferFailed", + "type": "error" + }, + { + "inputs": [], + "name": "VerifierHasNoCode", + "type": "error" + }, + { + "inputs": [], + "name": "WindowClosed", + "type": "error" + }, + { + "inputs": [], + "name": "WindowOpen", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "got", + "type": "bytes4" + }, + { + "internalType": "bytes4", + "name": "expected", + "type": "bytes4" + } + ], + "name": "WrongProofSelector", + "type": "error" + }, + { + "inputs": [], + "name": "WrongStatus", + "type": "error" + }, + { + "inputs": [], + "name": "ZeroAddress", + "type": "error" + }, + { + "inputs": [], + "name": "ZeroProofSelector", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bool", + "name": "providerWon", + "type": "bool" + } + ], + "name": "DisputeResolved", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "requester", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "reward", + "type": "uint256" + } + ], + "name": "DisputeTimedOut", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "provider", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "providerBond", + "type": "uint256" + } + ], + "name": "JobClaimed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "challenger", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "bond", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "recomputedResultHash", + "type": "bytes32" + } + ], + "name": "JobDisputed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "provider", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "reward", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "bondReturned", + "type": "uint256" + } + ], + "name": "JobPaid", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "requester", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "reward", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "enum AereComputeMarketV3.Mode", + "name": "mode", + "type": "uint8" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "specHash", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "uint64", + "name": "deadline", + "type": "uint64" + }, + { + "indexed": false, + "internalType": "bool", + "name": "pqcSettlement", + "type": "bool" + } + ], + "name": "JobPosted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "requester", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "reward", + "type": "uint256" + } + ], + "name": "JobRefunded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "challenger", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "slashedProviderBond", + "type": "uint256" + } + ], + "name": "JobSlashed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "settlementDigest", + "type": "bytes32" + } + ], + "name": "PQCSettlementAuthorized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "resultHash", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "string", + "name": "uri", + "type": "string" + } + ], + "name": "ResultReferenced", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "resultHash", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "result", + "type": "bytes" + } + ], + "name": "ResultSubmitted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "resultHash", + "type": "bytes32" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "zkProgramVKey", + "type": "bytes32" + } + ], + "name": "ResultVerifiedZK", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "indexed": false, + "internalType": "bool", + "name": "allowed", + "type": "bool" + } + ], + "name": "TokenAllowed", + "type": "event" + }, + { + "inputs": [], + "name": "ARBITER", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "ARBITRATION_TIMEOUT", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "FALCON512_PRECOMPILE", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "GOVERNANCE", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "PINNED_PROOF_SELECTOR", + "outputs": [ + { + "internalType": "bytes4", + "name": "", + "type": "bytes4" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "PQC_SETTLEMENT_GRACE", + "outputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "SETTLEMENT_DOMAIN", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "ZK_VERIFIER", + "outputs": [ + { + "internalType": "contract ISP1Verifier", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "pqcSig", + "type": "bytes" + } + ], + "name": "acceptResult", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + } + ], + "name": "cancelJob", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "challengeResultHashOf", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "challengerBondOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "challengerOf", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "falconPubKey", + "type": "bytes" + } + ], + "name": "claimJob", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "recomputedResultHash", + "type": "bytes32" + } + ], + "name": "dispute", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "falconPubKeyOf", + "outputs": [ + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "pqcSig", + "type": "bytes" + } + ], + "name": "finalize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + } + ], + "name": "getJob", + "outputs": [ + { + "components": [ + { + "internalType": "address", + "name": "requester", + "type": "address" + }, + { + "internalType": "address", + "name": "provider", + "type": "address" + }, + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "reward", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "providerBond", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "specHash", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "resultHash", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "zkProgramVKey", + "type": "bytes32" + }, + { + "internalType": "enum AereComputeMarketV3.Mode", + "name": "mode", + "type": "uint8" + }, + { + "internalType": "enum AereComputeMarketV3.Status", + "name": "status", + "type": "uint8" + }, + { + "internalType": "bool", + "name": "pqcSettlement", + "type": "bool" + }, + { + "internalType": "bool", + "name": "offchainResult", + "type": "bool" + }, + { + "internalType": "uint64", + "name": "deadline", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "challengeWindow", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "submittedAt", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "disputedAt", + "type": "uint64" + } + ], + "internalType": "struct AereComputeMarketV3.Job", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + } + ], + "name": "isSolvent", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "jobCount", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "jobs", + "outputs": [ + { + "internalType": "address", + "name": "requester", + "type": "address" + }, + { + "internalType": "address", + "name": "provider", + "type": "address" + }, + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "reward", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "providerBond", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "specHash", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "resultHash", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "zkProgramVKey", + "type": "bytes32" + }, + { + "internalType": "enum AereComputeMarketV3.Mode", + "name": "mode", + "type": "uint8" + }, + { + "internalType": "enum AereComputeMarketV3.Status", + "name": "status", + "type": "uint8" + }, + { + "internalType": "bool", + "name": "pqcSettlement", + "type": "bool" + }, + { + "internalType": "bool", + "name": "offchainResult", + "type": "bool" + }, + { + "internalType": "uint64", + "name": "deadline", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "challengeWindow", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "submittedAt", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "disputedAt", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "reward", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "providerBond", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "specHash", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "zkProgramVKey", + "type": "bytes32" + }, + { + "internalType": "enum AereComputeMarketV3.Mode", + "name": "mode", + "type": "uint8" + }, + { + "internalType": "uint64", + "name": "deadline", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "challengeWindow", + "type": "uint64" + }, + { + "internalType": "bool", + "name": "pqcSettlement", + "type": "bool" + }, + { + "internalType": "bool", + "name": "offchainResult", + "type": "bool" + } + ], + "internalType": "struct AereComputeMarketV3.JobParams", + "name": "p", + "type": "tuple" + } + ], + "name": "postJob", + "outputs": [ + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + } + ], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + } + ], + "name": "reclaimExpired", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + } + ], + "name": "reclaimUnsettled", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "requiredBondOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + } + ], + "name": "resolveByTimeout", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "providerWon", + "type": "bool" + } + ], + "name": "resolveDispute", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "bool", + "name": "allowed", + "type": "bool" + } + ], + "name": "setTokenAllowed", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "internalType": "address", + "name": "provider", + "type": "address" + }, + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "resultHash", + "type": "bytes32" + } + ], + "name": "settlementDigest", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "result", + "type": "bytes" + } + ], + "name": "submitResult", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "resultHash", + "type": "bytes32" + }, + { + "internalType": "string", + "name": "uri", + "type": "string" + } + ], + "name": "submitResultRef", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "publicValues", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "proofBytes", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "pqcSig", + "type": "bytes" + } + ], + "name": "submitResultZK", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "tokenAllowed", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "totalLiabilities", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + } + ], + "bytecode": "0x610100346200016c57601f62002e7438819003918201601f191683019291906001600160401b03841183851017620001715781608092849260409687528339810103126200016c57620000528162000187565b90620000616020820162000187565b60606200007085840162000187565b920151926001600160e01b03198416908185036200016c5760016000556001600160a01b038181169290831590811562000160575b811562000154575b5062000143571562000132573b15620001215760805260c05260e05260a05251612cd790816200019d8239608051818181611060015281816117f50152611864015260a05181818161101a01526117c0015260c0518181816113700152611b1d015260e051818181611fa8015261205b0152f35b84516362d4176d60e11b8152600490fd5b855163689b914560e11b8152600490fd5b865163d92e233d60e01b8152600490fd5b905085161538620000ad565b858116159150620000a5565b600080fd5b634e487b7160e01b600052604160045260246000fd5b51906001600160a01b03821682036200016c5756fe6080604052600436101561001257600080fd5b6000803560e01c806301bb9baa146120d257806305b93aa8146120a857806309c71c031461208a578063146278341461204557806315f6901214611f7a578063180aedf314611e755780631cbd0a8814611e585780631d5ca2a614611e2f5780631dffa3dc14611d6f57806334b25ee214611b0157806338b51ce114611a4e57806349875db2146119625780634b4ed009146116955780634c5d8a0f1461167757806355219d5a14611638578063582e05791461160e5780636138cc34146114995780636f1df0ad1461141b57806371641548146113d85780637d2224dd1461139f578063904cae5c1461135a57806390cd6e4c146113305780639d3625301461108f5780639ded39521461104a578063bbde791c14611004578063bf22c45714610d76578063cbe5a82014610754578063d8170f6a146106fe578063d905812714610537578063de847ff8146103e9578063e2e27d0d1461027e578063e4358a071461024b578063e9bd8333146101b35763f103e5ac1461019357600080fd5b346101b057806003193601126101b057602060405162093a808152f35b80fd5b50346101b0576101c23661226a565b906101cb6125a4565b82845260016020526040842080546001600160a01b031633036102395760ff600882015460081c166008811015610225576003036102135761020c936126d4565b6001815580f35b604051638e78f0cb60e01b8152600490fd5b634e487b7160e01b86526021600452602486fd5b6040516371ced2cf60e11b8152600490fd5b50346101b05760203660031901126101b057602090600435815260048252604060018060a01b0391205416604051908152f35b50346101b05760603660031901126101b0576004356001600160401b036024356044358281116103e5576102b690369060040161223d565b91908486526001602052604086209060018060a01b0360018301541633036103d3576008820180549060ff8260081c1660088110156103bf576002036102135760ff821660038110156103bf576001146102135760ff8260181c16156103ad57868260201c16421161039b578415610389577fc9fba5916f7698c486c0e394045ebcf81f5c5b9afdc147e75fbe0345daeaa4bc9661030061036a9387600661038398015561ff00191617825542169061248a565b60405193849384526040602085015260408401916124b3565b0390a280f35b604051632acfffb560e21b8152600490fd5b60405163387b2e5560e11b8152600490fd5b60405163225d57bd60e11b8152600490fd5b634e487b7160e01b8a52602160045260248afd5b60405163c226996b60e01b8152600490fd5b8480fd5b5060403660031901126101b0576024356004356104046125a4565b8083526020916001835260408420600881019081549060ff8260081c16600881101561052357600303610213576001600160401b0392610450606084901c851660a085901c861661242b565b42101561051157600482015434036104ff5761040060099361ff0019161790550190421660018060401b031982541617905581845260048352604084203360018060a01b0319825416179055600583523460408520556006835280604085205583805260098352604084206104c634825461242b565b9055604051923484528301527febb63c39fa23825a2b6693e874eb75decb0654826ca930034c7ec8ed3a98fb2c60403393a36001815580f35b604051630bba69fb60e01b8152600490fd5b604051632f23cfcd60e01b8152600490fd5b634e487b7160e01b88526021600452602488fd5b50346101b0576020806003193601126106fa57600435906105566125a4565b8183526001815260408320916008830180549260ff8460081c1660088110156106e6576004036102135760018060401b036009860154166212750081018091116106d05742106106be57600080516020612c42833981519152918387526004825260018060a01b0395866040892054169060058452604089205490888a60038301958187549760048601926106008454966002890154169f8060018a0154169854169e61ff0019161790555555878b52600586528a6040812055898b526009865260408b2061062686825461241e565b9055610632838261242b565b8b80526009875261064860408d2091825461241e565b9055610655858a8c61265f565b806106ae575b50508061069e575b505084847f71283df932d260173eb1200efe17661526933e57f46bdc5d3a1029b9e8eb880a84604051858152a3604051908152a46001815580f35b6106a79161262a565b3880610663565b6106b79161262a565b388061065b565b604051636771cb5f60e01b8152600490fd5b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b87526021600452602487fd5b5080fd5b50346101b05760a03660031901126101b0576001600160a01b03602435818116810361074f57604435918216820361074f57602091610747916084359160643591600435612532565b604051908152f35b600080fd5b506101403660031901126101b05761076a6125a4565b60243515610c1e5760643515610d64576107826124e0565b426001600160401b039091161115610d5257600360a43510156101b05760a435600103610d115760843515610cff57604435610ced575b6001600160a01b036107c961250c565b16610b045760243534036104ff575b6007546000198114610af057600181016007556107f361250c565b6107fb612522565b610124351515610124350361074f576108126124e0565b61081a6124f6565b9160405193610828856122d7565b338552602085018790526001600160a01b0316604085015260243560608501526080840186905260643560a085015260c0840186905260843560e085015261087660a43561010086016124d4565b600161012085018190529015156101408501526101243515156101608501526001600160401b0391821661018085015291166101a08301526101c082018490526101e0820184905282845260208181526040808620845181546001600160a01b03199081166001600160a01b0392831617835593860151948201805485169582169590951790945590840151600282018054909316931692909217905560608201516003808301919091556080830151600483015560a0830151600583015560c0830151600683015560e0830151600783015561010083015190811015610adc57600882015461012084015160088110156106e6579284926009926020989562ff00006101406001990151151560101b1663ff000000610160880151151560181b169161ff008a8d1b8b60601b036101808a01518e1b169460ff8c60601b8d60a01b036101a08c015160601b169716908c8060a01b031916179160081b16171717171760088201556109f7858060401b036101c0850151166008830161248a565b01906101e0848060401b0391015116838060401b0319825416179055818060a01b03610a2161250c565b1681526009845260408120610a39602435825461242b565b90558160a43503610ac8575b610a4d61250c565b610a556124e0565b90610a5e612522565b604051926024358452610a7588850160a435612223565b6064356040850152858060401b0316606084015215156080830152838060a01b031690847f7fed077780cd3b25ffef7cf7803445684b9a3a8bfabe02fee03ff0b0119573b360a03393a455604051908152f35b828152600384526044356040822055610a45565b634e487b7160e01b85526021600452602485fd5b634e487b7160e01b82526011600452602482fd5b6001600160a01b03610b1461250c565b168152600860205260ff60408220541615610cc457346104ff57602460206001600160a01b03610b4261250c565b16604051928380926370a0823160e01b82523060048301525afa908115610cb9578291610c87575b506001600160a01b03610b7b61250c565b1690604051916323b872dd60e01b60208401523360248401523060448401526024356064840152606483528260a081011060018060401b0360a085011117610c715782610bd09160a060249501604052612aaf565b60206001600160a01b03610be261250c565b16604051938480926370a0823160e01b82523060048301525afa918215610c66578392610c30575b50610c18906024359261241e565b146107d8575b604051630e4567b160e31b8152600490fd5b9091506020813d602011610c5e575b81610c4c6020938361230e565b8101031261074f575190610c18610c0a565b3d9150610c3f565b6040513d85823e3d90fd5b634e487b7160e01b600052604160045260246000fd5b90506020813d602011610cb1575b81610ca26020938361230e565b8101031261074f575138610b6a565b3d9150610c95565b6040513d84823e3d90fd5b6024610cce61250c565b60405163094403b760e41b81526001600160a01b039091166004820152fd5b60405163c2fb134f60e01b8152600490fd5b60405163e2aad27160e01b8152600490fd5b6001600160401b03610d216124f6565b1615610d40576044356107b95760405163c2fb134f60e01b8152600490fd5b604051632a0c9bb560e11b8152600490fd5b60405163710e1ce560e01b8152600490fd5b60405163bc6a309f60e01b8152600490fd5b50346101b05760203660031901126101b057806040916101e08351610d9a816122d7565b82815282602082015282858201528260608201528260808201528260a08201528260c08201528260e08201528261010082015282610120820152826101408201528261016082015282610180820152826101a0820152826101c082015201526004358152600160205220604051610e10816122d7565b81546001600160a01b03908116825260018301548116602083015260028301541660408201526003820154606082015260048201546080820152600582015460a0820152600682015460c0820152600782015460e0820152600882015491610e7f60ff841661010084016124d4565b600860ff84821c161015610fee578260ff6102009460081c1661012084015260ff8160101c16151561014084015260ff8160181c16151561016084015260018060401b038160201c1661018084015260018060401b038160601c166101a084015260018060401b039060a01c166101c0830152600960018060401b03910154166101e08201526040519060018060a01b03815116825260018060a01b03602082015116602083015260018060a01b036040820151166040830152606081015160608301526080810151608083015260a081015160a083015260c081015160c083015260e081015160e0830152610f7f610100820151610100840190612223565b610f93610120820151610120840190612230565b6101408181015115159083015261016080820151151590830152610180808201516001600160401b03908116918401919091526101a0808301518216908401526101c0808301518216908401526101e0918201511690820152f35b634e487b7160e01b600052602160045260246000fd5b50346101b057806003193601126101b0576040517f00000000000000000000000000000000000000000000000000000000000000006001600160e01b0319168152602090f35b50346101b057806003193601126101b0576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b506110993661226a565b916110a26125a4565b8084526001926020928484526040862090600882019283549160ff8360081c1660088110156103bf578803610213576001600160401b039280881c8416421161039b5760ff8116600381101561131c57890361130b57895b34036104ff5760101c60ff16156112f15761038182148015906112c8575b6112b65785895260028752604089209282116112a257819061113a845461229d565b601f8111611252575b508990601f83116001146111f3578a926111e8575b5050600019600383901b1c191690871b1790555b80850180546001600160a01b03191633179055346004909101819055815461ff001916610200179091556111cb575b7f76fd1071bb2e8e5da7695a00bf50a2ba73ff07ba5f83b6a36729fdb0d290587e604051923484523393a3815580f35b83805260098252604084206111e134825461242b565b905561119b565b013590503880611158565b848b52888b208a945091601f1984168c5b8b82821061123c5750508411611222575b505050811b01905561116c565b0135600019600384901b60f8161c19169055388080611215565b8385013586558d97909501949283019201611204565b909150838a52878a20601f840160051c810191898510611298575b84939291601f8c920160051c01915b82811061128a575050611143565b8c81558594508b910161127c565b909150819061126d565b634e487b7160e01b89526041600452602489fd5b604051633347f13160e11b8152600490fd5b5081156112dd576009813560f81c1415611118565b634e487b7160e01b89526032600452602489fd5b5090501561116c57604051633347f13160e11b8152600490fd5b868a526003885260408a20546110fa565b634e487b7160e01b8b52602160045260248bfd5b50346101b05760203660031901126101b05760406020916004358152600683522054604051908152f35b50346101b057806003193601126101b0576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b50346101b05760203660031901126101b0576020906040906001600160a01b036113c76121fe565b168152600983522054604051908152f35b50346101b05760203660031901126101b0576114036040611417926004358152600260205220612331565b6040519182916020835260208301906123f9565b0390f35b50346101b05761142a3661226a565b906114336125a4565b828452600160205260408420600881015460ff8160081c1660088110156106e65760030361021357611478906001600160401b03606082901c81169160a01c1661242b565b42106114875761020c936126d4565b60405163a4229fab60e01b8152600490fd5b50346101b05760203660031901126101b0576004356114b66125a4565b80825260016020526040822080546001600160a01b0390811633036102395760088201805460ff8160081c1660088110156106e6576003036102135760ff8160101c16156115fc5761151c6001600160401b03606083901c81169060a084901c1661242b565b62093a8081018091116106d05742106115e7576106009061ff001916179055600382019182549260026004830192878454948187600185015416955555019183835416875260096020526040872061157586825461241e565b9055801515806115c9575b61158e86338787541661265f565b6115b9575b5050541691604051918252600080516020612c4283398151915260203393a46001815580f35b6115c29161262a565b3880611593565b8780526009602052604088206115e083825461241e565b9055611580565b60405160016205e19f60e41b03198152600490fd5b604051637bd63fd560e11b8152600490fd5b50346101b05760203660031901126101b05760406020916004358152600383522054604051908152f35b50346101b05760203660031901126101b05760209060ff906040906001600160a01b036116636121fe565b168152600884522054166040519015158152f35b50346101b057806003193601126101b0576020600754604051908152f35b50346101b05760803660031901126101b0576024356001600160401b0381116106fa576116c690369060040161223d565b906044356001600160401b03811161190d576116e690369060040161223d565b906064356001600160401b03811161195e5761170690369060040161223d565b9390926117116125a4565b60043587526001602052604087209260018060a01b038060018601541633036103d357600885015460ff8160081c16600881101561131c576002036102135760ff8116600381101561131c576001036102135760201c6001600160401b0316421161039b576040880361194c57604084898101031261192f57600585015484350361194c576020840135600686015560048310611933578260041161192f576001600160e01b031982358116907f000000000000000000000000000000000000000000000000000000000000000016808203611911575050908891600786015498817f0000000000000000000000000000000000000000000000000000000000000000163b1561190d578961186061184e946040519788968795869563020a49e360e51b875260048701526060602487015260648601908c6124b3565b848103600319016044860152916124b3565b03917f0000000000000000000000000000000000000000000000000000000000000000165afa8015611902576118d5575b5061020c946020604051920135825260208201527f2e1b996230923d7501d3a4c54ba05b52dd0e74b208c3fa9c0f2e0ae3e1902973604060043592a26004356126d4565b6001600160401b0381116118ee5760405261020c611891565b634e487b7160e01b87526041600452602487fd5b6040513d89823e3d90fd5b8380fd5b6044925060405191632b1b430160e01b835260048301526024820152fd5b8880fd5b60405163422e17ef60e01b815260048101849052602490fd5b604051633060511b60e11b8152600490fd5b8580fd5b50346101b0576119713661226a565b8284526001602052604084209160018060a01b0360018401541633036103d357600883019283549160ff8360081c166008811015610523576002036102135760ff83166003811015610523576001146102135760ff8360181c16611a3c576001600160401b0392602081901c8416421161039b577ff65712e4997e89efb84614c500905f156904ca98e8ef172ccce8525b91d505999560069461030061036a9361038396611a20368b89612453565b60208151910120988991015561ff00191617825542169061248a565b60405163bbd10e7160e01b8152600490fd5b50346101b057602090816003193601126101b0576001600160a01b03611a726121fe565b169081611a915760409047925b81526009845220541115604051908152f35b6040516370a0823160e01b8152306004820152908382602481865afa8015611af4578190611ac4575b6040925092611a7f565b50908381813d8311611aed575b611adb818361230e565b810103126106fa579060409151611aba565b503d611ad1565b50604051903d90823e3d90fd5b50346101b05760403660031901126101b057611b1b612214565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03163303611d5d57611b536125a4565b600435825260016020526040822060ff600882015460081c166008811015611d4957600403610213576004358352600460205260018060a01b03604084205416906005602052604084209081549060038101549160048201549160018060a01b036002820154169560018060a01b03600183015416958960018060a01b038454169181600386015581600486015555878a52600960205260408a20611bf987825461241e565b9055611c05848661242b565b8a80526009602052611c1c60408c2091825461241e565b90558815611cc6575050600801805461ff001916610500179055611c4183858761265f565b81611cb7575b80611ca7575b506040519182526020820152600080516020612c82833981519152604060043592a45b60405190151581527f5a87909bff68caaaaf0b3fd9c74eeccc928832f879315e5c6fb7a73612f26c0c602060043592a26001815580f35b611cb1908461262a565b38611c4d565b611cc1828561262a565b611c47565b6008909201805461ff001916610700179055959294509092611cea9290919061265f565b80611d39575b5080611d2a575b6040519081527fd55e4bfec83a785390aded3a9bfcc350dcb5a67382a1f71f1aeecabf07fa2a94602060043592a3611c70565b611d34818361262a565b611cf7565b611d43908361262a565b38611cf0565b634e487b7160e01b84526021600452602484fd5b60405163665b32d360e11b8152600490fd5b50346101b05760203660031901126101b057600435611d8c6125a4565b80825260016020526040822080546001600160a01b0390811633036102395760088201805460ff8160081c1660088110156106e657600103610213576106009061ff00191617905560026003830192858454945501818154168552600960205260408520611dfb84825461241e565b9055611e0b83338484541661265f565b541691604051918252600080516020612c4283398151915260203393a46001815580f35b50346101b057806003193601126101b0576020604051600080516020612c628339815191528152f35b50346101b057806003193601126101b0576020604051610ae18152f35b50346101b05760203660031901126101b057604061020091600435815260016020522060018060a01b036009818354169282600182015416926002820154166003820154600483015460058401549060068501549260078601549460088701549660018060401b03988991015416986040519a8b5260208b015260408a01526060890152608088015260a087015260c086015260e0850152611f1e610100850160ff8316612223565b611f32610120850160ff8360081c16612230565b60ff8160101c16151561014085015260ff8160181c161515610160850152818160201c16610180850152818160601c166101a085015260a01c166101c08301526101e0820152f35b50346101b05760403660031901126101b057611f946121fe565b611f9c612214565b906001600160a01b03907f00000000000000000000000000000000000000000000000000000000000000008216330361203357169081156120215760207f9a8e30a8658b96ab3f034ce4bac6806278b4aee5880ccdd1ac35e4ed5bb31d239183855260088252604085209015159060ff1981541660ff8316179055604051908152a280f35b60405163d92e233d60e01b8152600490fd5b604051632d5be4cb60e21b8152600490fd5b50346101b057806003193601126101b0576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b50346101b057806003193601126101b0576020604051621275008152f35b50346101b05760203660031901126101b05760406020916004358152600583522054604051908152f35b50346101b0576020806003193601126106fa576004356120f06125a4565b808352600182526040832080549091906001600160a01b03908116330361023957600883019081549160ff8360081c166008811015610523576002036102135782861c6001600160401b03164211156121ec57610600600080516020612c428339815191529361ff00191617905560038401600281549588600482018181549555550190828254168852600987526040882061218d87825461241e565b9055801515806121cf575b6121a687338686541661265f565b6121bf575b505416936040519384523393a46001815580f35b6121c9903361262a565b386121ab565b88805260098852604089206121e583825461241e565b9055612198565b6040516302eb354360e41b8152600490fd5b600435906001600160a01b038216820361074f57565b60243590811515820361074f57565b906003821015610fee5752565b906008821015610fee5752565b9181601f8401121561074f578235916001600160401b03831161074f576020838186019501011161074f57565b90604060031983011261074f5760043591602435906001600160401b03821161074f576122999160040161223d565b9091565b90600182811c921680156122cd575b60208310146122b757565b634e487b7160e01b600052602260045260246000fd5b91607f16916122ac565b61020081019081106001600160401b03821117610c7157604052565b604081019081106001600160401b03821117610c7157604052565b601f909101601f19168101906001600160401b03821190821017610c7157604052565b906040519182600082546123448161229d565b908184526020946001916001811690816000146123b45750600114612375575b5050506123739250038361230e565b565b600090815285812095935091905b81831061239c5750506123739350820101388080612364565b85548884018501529485019487945091830191612383565b9250505061237394925060ff191682840152151560051b820101388080612364565b60005b8381106123e95750506000910152565b81810151838201526020016123d9565b90602091612412815180928185528580860191016123d6565b601f01601f1916010190565b919082039182116106d057565b919082018092116106d057565b6001600160401b038111610c7157601f01601f191660200190565b92919261245f82612438565b9161246d604051938461230e565b82948184528183011161074f578281602093846000960137010152565b8054600160a01b600160e01b03191660a09290921b600160a01b600160e01b0316919091179055565b908060209392818452848401376000828201840152601f01601f1916010190565b6003821015610fee5752565b60c4356001600160401b038116810361074f5790565b60e4356001600160401b038116810361074f5790565b6004356001600160a01b038116810361074f5790565b61010435801515810361074f5790565b93919290604051936020850195600080516020612c628339815191528752466040870152306060870152608086015260018060a01b0380921660a08601521660c084015260e083015261010090818301528152610120810181811060018060401b03821117610c715760405251902090565b6002600054146125b5576002600055565b60405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606490fd5b3d15612625573d9061260b82612438565b91612619604051938461230e565b82523d6000602084013e565b606090565b811561265b57600080809381935af16126416125fa565b501561264957565b6040516312171d8360e31b8152600490fd5b5050565b82156126cf576001600160a01b039081169081612689575050600080809381935af16126416125fa565b60405163a9059cbb60e01b60208201529216602483015260448083019390935291815260808101916001600160401b03831182841017610c715761237392604052612aaf565b505050565b909160018060a01b0392836001820154169360028201541694600382019081549160048401908154926008860196888b8b8a549960ff8b60101c1660001461282c57928961275895936127319360066127529f9997015493612532565b998a918c600052600260205261274a6040600020612331565b933691612453565b91612889565b1561281b57610500604096897ffa098250c8076c215e57e37e1daacbd822ef0c9d9e2dd35b12aa849327a35ef16020600080516020612c828339815191529b8b51908152a25b61ff001916179055600091828092555587815260096020528381206127c484825461241e565b905581151590816127fd575b506127dc83888a61265f565b6127ee575b82519182526020820152a4565b6127f8818761262a565b6127e1565b808086925260096020522061281383825461241e565b9055386127d0565b604051628f3e5b60e61b8152600490fd5b505050505061285057600080516020612c828339815191529561050060409661279e565b60405163187b766d60e21b8152600490fd5b908151811015612873570160200190565b634e487b7160e01b600052603260045260246000fd5b92919092610381815103612aa75781516028946028821115612a9d5760271982019182116106d05761ffff8211612a9d5760408051606081016001600160401b03811182821017610c7157825260288152602095868201938336863760005b8a8110612a7157506128f986612438565b906129068551928361230e565b86825261291287612438565b828a019390601f190136853760005b888110612a3957505088999a50849896979851878101918252878152612946816122f3565b85519687958987019a61ffff60f01b9060f01b168b525190816022880161296c926123d6565b8501905191826022830161297f926123d6565b019051918260228301612991926123d6565b01036002810183526022016129a6908361230e565b51928391838084018781985192839101916129c0926123d6565b8301905191828583016129d2926123d6565b0103808352016129e2908261230e565b51905a9160009291610ae18493fa906129f96125fa565b9082612a2d575b5081612a0a575090565b80915051601f101561287357603f01516001600160f81b031916600160f81b1490565b81511015915038612a00565b8c810190818e116106d0576001916001600160f81b031990612a5b9085612862565b511660001a612a6a8287612862565b5301612921565b6001906001600160f81b0319612a878286612862565b511660001a612a968287612862565b53016128e8565b5060009450505050565b506000925050565b60018060a01b031690612b0e604051612ac7816122f3565b6020938482527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564858301526000808587829751910182855af1612b086125fa565b91612ba4565b805191821591848315612b80575b505050905015612b295750565b6084906040519062461bcd60e51b82526004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152fd5b9193818094500103126106fa578201519081151582036101b0575080388084612b1c565b91929015612c065750815115612bb8575090565b3b15612bc15790565b60405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606490fd5b825190915015612c195750805190602001fd5b60405162461bcd60e51b815260206004820152908190612c3d9060248301906123f9565b0390fdfee257c770e48715cd6ce3834146a7d7b04bd626423802ecde7a2346d3c0b985ddd7b83be88f1aae552e9a9057ff5cd5e79aeeaef816dc27cc937777c9cc00ec9ccfb74f7ba842154e916641e0845c97af0df986b664065dd84c41603c75bdd3ada2646970667358221220feb6e6bddf943e06df7a1310f42db4a158b9a4dbc1d623fce6a11f9cec873fca64736f6c63430008170033", + "deployedBytecode": "0x6080604052600436101561001257600080fd5b6000803560e01c806301bb9baa146120d257806305b93aa8146120a857806309c71c031461208a578063146278341461204557806315f6901214611f7a578063180aedf314611e755780631cbd0a8814611e585780631d5ca2a614611e2f5780631dffa3dc14611d6f57806334b25ee214611b0157806338b51ce114611a4e57806349875db2146119625780634b4ed009146116955780634c5d8a0f1461167757806355219d5a14611638578063582e05791461160e5780636138cc34146114995780636f1df0ad1461141b57806371641548146113d85780637d2224dd1461139f578063904cae5c1461135a57806390cd6e4c146113305780639d3625301461108f5780639ded39521461104a578063bbde791c14611004578063bf22c45714610d76578063cbe5a82014610754578063d8170f6a146106fe578063d905812714610537578063de847ff8146103e9578063e2e27d0d1461027e578063e4358a071461024b578063e9bd8333146101b35763f103e5ac1461019357600080fd5b346101b057806003193601126101b057602060405162093a808152f35b80fd5b50346101b0576101c23661226a565b906101cb6125a4565b82845260016020526040842080546001600160a01b031633036102395760ff600882015460081c166008811015610225576003036102135761020c936126d4565b6001815580f35b604051638e78f0cb60e01b8152600490fd5b634e487b7160e01b86526021600452602486fd5b6040516371ced2cf60e11b8152600490fd5b50346101b05760203660031901126101b057602090600435815260048252604060018060a01b0391205416604051908152f35b50346101b05760603660031901126101b0576004356001600160401b036024356044358281116103e5576102b690369060040161223d565b91908486526001602052604086209060018060a01b0360018301541633036103d3576008820180549060ff8260081c1660088110156103bf576002036102135760ff821660038110156103bf576001146102135760ff8260181c16156103ad57868260201c16421161039b578415610389577fc9fba5916f7698c486c0e394045ebcf81f5c5b9afdc147e75fbe0345daeaa4bc9661030061036a9387600661038398015561ff00191617825542169061248a565b60405193849384526040602085015260408401916124b3565b0390a280f35b604051632acfffb560e21b8152600490fd5b60405163387b2e5560e11b8152600490fd5b60405163225d57bd60e11b8152600490fd5b634e487b7160e01b8a52602160045260248afd5b60405163c226996b60e01b8152600490fd5b8480fd5b5060403660031901126101b0576024356004356104046125a4565b8083526020916001835260408420600881019081549060ff8260081c16600881101561052357600303610213576001600160401b0392610450606084901c851660a085901c861661242b565b42101561051157600482015434036104ff5761040060099361ff0019161790550190421660018060401b031982541617905581845260048352604084203360018060a01b0319825416179055600583523460408520556006835280604085205583805260098352604084206104c634825461242b565b9055604051923484528301527febb63c39fa23825a2b6693e874eb75decb0654826ca930034c7ec8ed3a98fb2c60403393a36001815580f35b604051630bba69fb60e01b8152600490fd5b604051632f23cfcd60e01b8152600490fd5b634e487b7160e01b88526021600452602488fd5b50346101b0576020806003193601126106fa57600435906105566125a4565b8183526001815260408320916008830180549260ff8460081c1660088110156106e6576004036102135760018060401b036009860154166212750081018091116106d05742106106be57600080516020612c42833981519152918387526004825260018060a01b0395866040892054169060058452604089205490888a60038301958187549760048601926106008454966002890154169f8060018a0154169854169e61ff0019161790555555878b52600586528a6040812055898b526009865260408b2061062686825461241e565b9055610632838261242b565b8b80526009875261064860408d2091825461241e565b9055610655858a8c61265f565b806106ae575b50508061069e575b505084847f71283df932d260173eb1200efe17661526933e57f46bdc5d3a1029b9e8eb880a84604051858152a3604051908152a46001815580f35b6106a79161262a565b3880610663565b6106b79161262a565b388061065b565b604051636771cb5f60e01b8152600490fd5b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b87526021600452602487fd5b5080fd5b50346101b05760a03660031901126101b0576001600160a01b03602435818116810361074f57604435918216820361074f57602091610747916084359160643591600435612532565b604051908152f35b600080fd5b506101403660031901126101b05761076a6125a4565b60243515610c1e5760643515610d64576107826124e0565b426001600160401b039091161115610d5257600360a43510156101b05760a435600103610d115760843515610cff57604435610ced575b6001600160a01b036107c961250c565b16610b045760243534036104ff575b6007546000198114610af057600181016007556107f361250c565b6107fb612522565b610124351515610124350361074f576108126124e0565b61081a6124f6565b9160405193610828856122d7565b338552602085018790526001600160a01b0316604085015260243560608501526080840186905260643560a085015260c0840186905260843560e085015261087660a43561010086016124d4565b600161012085018190529015156101408501526101243515156101608501526001600160401b0391821661018085015291166101a08301526101c082018490526101e0820184905282845260208181526040808620845181546001600160a01b03199081166001600160a01b0392831617835593860151948201805485169582169590951790945590840151600282018054909316931692909217905560608201516003808301919091556080830151600483015560a0830151600583015560c0830151600683015560e0830151600783015561010083015190811015610adc57600882015461012084015160088110156106e6579284926009926020989562ff00006101406001990151151560101b1663ff000000610160880151151560181b169161ff008a8d1b8b60601b036101808a01518e1b169460ff8c60601b8d60a01b036101a08c015160601b169716908c8060a01b031916179160081b16171717171760088201556109f7858060401b036101c0850151166008830161248a565b01906101e0848060401b0391015116838060401b0319825416179055818060a01b03610a2161250c565b1681526009845260408120610a39602435825461242b565b90558160a43503610ac8575b610a4d61250c565b610a556124e0565b90610a5e612522565b604051926024358452610a7588850160a435612223565b6064356040850152858060401b0316606084015215156080830152838060a01b031690847f7fed077780cd3b25ffef7cf7803445684b9a3a8bfabe02fee03ff0b0119573b360a03393a455604051908152f35b828152600384526044356040822055610a45565b634e487b7160e01b85526021600452602485fd5b634e487b7160e01b82526011600452602482fd5b6001600160a01b03610b1461250c565b168152600860205260ff60408220541615610cc457346104ff57602460206001600160a01b03610b4261250c565b16604051928380926370a0823160e01b82523060048301525afa908115610cb9578291610c87575b506001600160a01b03610b7b61250c565b1690604051916323b872dd60e01b60208401523360248401523060448401526024356064840152606483528260a081011060018060401b0360a085011117610c715782610bd09160a060249501604052612aaf565b60206001600160a01b03610be261250c565b16604051938480926370a0823160e01b82523060048301525afa918215610c66578392610c30575b50610c18906024359261241e565b146107d8575b604051630e4567b160e31b8152600490fd5b9091506020813d602011610c5e575b81610c4c6020938361230e565b8101031261074f575190610c18610c0a565b3d9150610c3f565b6040513d85823e3d90fd5b634e487b7160e01b600052604160045260246000fd5b90506020813d602011610cb1575b81610ca26020938361230e565b8101031261074f575138610b6a565b3d9150610c95565b6040513d84823e3d90fd5b6024610cce61250c565b60405163094403b760e41b81526001600160a01b039091166004820152fd5b60405163c2fb134f60e01b8152600490fd5b60405163e2aad27160e01b8152600490fd5b6001600160401b03610d216124f6565b1615610d40576044356107b95760405163c2fb134f60e01b8152600490fd5b604051632a0c9bb560e11b8152600490fd5b60405163710e1ce560e01b8152600490fd5b60405163bc6a309f60e01b8152600490fd5b50346101b05760203660031901126101b057806040916101e08351610d9a816122d7565b82815282602082015282858201528260608201528260808201528260a08201528260c08201528260e08201528261010082015282610120820152826101408201528261016082015282610180820152826101a0820152826101c082015201526004358152600160205220604051610e10816122d7565b81546001600160a01b03908116825260018301548116602083015260028301541660408201526003820154606082015260048201546080820152600582015460a0820152600682015460c0820152600782015460e0820152600882015491610e7f60ff841661010084016124d4565b600860ff84821c161015610fee578260ff6102009460081c1661012084015260ff8160101c16151561014084015260ff8160181c16151561016084015260018060401b038160201c1661018084015260018060401b038160601c166101a084015260018060401b039060a01c166101c0830152600960018060401b03910154166101e08201526040519060018060a01b03815116825260018060a01b03602082015116602083015260018060a01b036040820151166040830152606081015160608301526080810151608083015260a081015160a083015260c081015160c083015260e081015160e0830152610f7f610100820151610100840190612223565b610f93610120820151610120840190612230565b6101408181015115159083015261016080820151151590830152610180808201516001600160401b03908116918401919091526101a0808301518216908401526101c0808301518216908401526101e0918201511690820152f35b634e487b7160e01b600052602160045260246000fd5b50346101b057806003193601126101b0576040517f00000000000000000000000000000000000000000000000000000000000000006001600160e01b0319168152602090f35b50346101b057806003193601126101b0576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b506110993661226a565b916110a26125a4565b8084526001926020928484526040862090600882019283549160ff8360081c1660088110156103bf578803610213576001600160401b039280881c8416421161039b5760ff8116600381101561131c57890361130b57895b34036104ff5760101c60ff16156112f15761038182148015906112c8575b6112b65785895260028752604089209282116112a257819061113a845461229d565b601f8111611252575b508990601f83116001146111f3578a926111e8575b5050600019600383901b1c191690871b1790555b80850180546001600160a01b03191633179055346004909101819055815461ff001916610200179091556111cb575b7f76fd1071bb2e8e5da7695a00bf50a2ba73ff07ba5f83b6a36729fdb0d290587e604051923484523393a3815580f35b83805260098252604084206111e134825461242b565b905561119b565b013590503880611158565b848b52888b208a945091601f1984168c5b8b82821061123c5750508411611222575b505050811b01905561116c565b0135600019600384901b60f8161c19169055388080611215565b8385013586558d97909501949283019201611204565b909150838a52878a20601f840160051c810191898510611298575b84939291601f8c920160051c01915b82811061128a575050611143565b8c81558594508b910161127c565b909150819061126d565b634e487b7160e01b89526041600452602489fd5b604051633347f13160e11b8152600490fd5b5081156112dd576009813560f81c1415611118565b634e487b7160e01b89526032600452602489fd5b5090501561116c57604051633347f13160e11b8152600490fd5b868a526003885260408a20546110fa565b634e487b7160e01b8b52602160045260248bfd5b50346101b05760203660031901126101b05760406020916004358152600683522054604051908152f35b50346101b057806003193601126101b0576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b50346101b05760203660031901126101b0576020906040906001600160a01b036113c76121fe565b168152600983522054604051908152f35b50346101b05760203660031901126101b0576114036040611417926004358152600260205220612331565b6040519182916020835260208301906123f9565b0390f35b50346101b05761142a3661226a565b906114336125a4565b828452600160205260408420600881015460ff8160081c1660088110156106e65760030361021357611478906001600160401b03606082901c81169160a01c1661242b565b42106114875761020c936126d4565b60405163a4229fab60e01b8152600490fd5b50346101b05760203660031901126101b0576004356114b66125a4565b80825260016020526040822080546001600160a01b0390811633036102395760088201805460ff8160081c1660088110156106e6576003036102135760ff8160101c16156115fc5761151c6001600160401b03606083901c81169060a084901c1661242b565b62093a8081018091116106d05742106115e7576106009061ff001916179055600382019182549260026004830192878454948187600185015416955555019183835416875260096020526040872061157586825461241e565b9055801515806115c9575b61158e86338787541661265f565b6115b9575b5050541691604051918252600080516020612c4283398151915260203393a46001815580f35b6115c29161262a565b3880611593565b8780526009602052604088206115e083825461241e565b9055611580565b60405160016205e19f60e41b03198152600490fd5b604051637bd63fd560e11b8152600490fd5b50346101b05760203660031901126101b05760406020916004358152600383522054604051908152f35b50346101b05760203660031901126101b05760209060ff906040906001600160a01b036116636121fe565b168152600884522054166040519015158152f35b50346101b057806003193601126101b0576020600754604051908152f35b50346101b05760803660031901126101b0576024356001600160401b0381116106fa576116c690369060040161223d565b906044356001600160401b03811161190d576116e690369060040161223d565b906064356001600160401b03811161195e5761170690369060040161223d565b9390926117116125a4565b60043587526001602052604087209260018060a01b038060018601541633036103d357600885015460ff8160081c16600881101561131c576002036102135760ff8116600381101561131c576001036102135760201c6001600160401b0316421161039b576040880361194c57604084898101031261192f57600585015484350361194c576020840135600686015560048310611933578260041161192f576001600160e01b031982358116907f000000000000000000000000000000000000000000000000000000000000000016808203611911575050908891600786015498817f0000000000000000000000000000000000000000000000000000000000000000163b1561190d578961186061184e946040519788968795869563020a49e360e51b875260048701526060602487015260648601908c6124b3565b848103600319016044860152916124b3565b03917f0000000000000000000000000000000000000000000000000000000000000000165afa8015611902576118d5575b5061020c946020604051920135825260208201527f2e1b996230923d7501d3a4c54ba05b52dd0e74b208c3fa9c0f2e0ae3e1902973604060043592a26004356126d4565b6001600160401b0381116118ee5760405261020c611891565b634e487b7160e01b87526041600452602487fd5b6040513d89823e3d90fd5b8380fd5b6044925060405191632b1b430160e01b835260048301526024820152fd5b8880fd5b60405163422e17ef60e01b815260048101849052602490fd5b604051633060511b60e11b8152600490fd5b8580fd5b50346101b0576119713661226a565b8284526001602052604084209160018060a01b0360018401541633036103d357600883019283549160ff8360081c166008811015610523576002036102135760ff83166003811015610523576001146102135760ff8360181c16611a3c576001600160401b0392602081901c8416421161039b577ff65712e4997e89efb84614c500905f156904ca98e8ef172ccce8525b91d505999560069461030061036a9361038396611a20368b89612453565b60208151910120988991015561ff00191617825542169061248a565b60405163bbd10e7160e01b8152600490fd5b50346101b057602090816003193601126101b0576001600160a01b03611a726121fe565b169081611a915760409047925b81526009845220541115604051908152f35b6040516370a0823160e01b8152306004820152908382602481865afa8015611af4578190611ac4575b6040925092611a7f565b50908381813d8311611aed575b611adb818361230e565b810103126106fa579060409151611aba565b503d611ad1565b50604051903d90823e3d90fd5b50346101b05760403660031901126101b057611b1b612214565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03163303611d5d57611b536125a4565b600435825260016020526040822060ff600882015460081c166008811015611d4957600403610213576004358352600460205260018060a01b03604084205416906005602052604084209081549060038101549160048201549160018060a01b036002820154169560018060a01b03600183015416958960018060a01b038454169181600386015581600486015555878a52600960205260408a20611bf987825461241e565b9055611c05848661242b565b8a80526009602052611c1c60408c2091825461241e565b90558815611cc6575050600801805461ff001916610500179055611c4183858761265f565b81611cb7575b80611ca7575b506040519182526020820152600080516020612c82833981519152604060043592a45b60405190151581527f5a87909bff68caaaaf0b3fd9c74eeccc928832f879315e5c6fb7a73612f26c0c602060043592a26001815580f35b611cb1908461262a565b38611c4d565b611cc1828561262a565b611c47565b6008909201805461ff001916610700179055959294509092611cea9290919061265f565b80611d39575b5080611d2a575b6040519081527fd55e4bfec83a785390aded3a9bfcc350dcb5a67382a1f71f1aeecabf07fa2a94602060043592a3611c70565b611d34818361262a565b611cf7565b611d43908361262a565b38611cf0565b634e487b7160e01b84526021600452602484fd5b60405163665b32d360e11b8152600490fd5b50346101b05760203660031901126101b057600435611d8c6125a4565b80825260016020526040822080546001600160a01b0390811633036102395760088201805460ff8160081c1660088110156106e657600103610213576106009061ff00191617905560026003830192858454945501818154168552600960205260408520611dfb84825461241e565b9055611e0b83338484541661265f565b541691604051918252600080516020612c4283398151915260203393a46001815580f35b50346101b057806003193601126101b0576020604051600080516020612c628339815191528152f35b50346101b057806003193601126101b0576020604051610ae18152f35b50346101b05760203660031901126101b057604061020091600435815260016020522060018060a01b036009818354169282600182015416926002820154166003820154600483015460058401549060068501549260078601549460088701549660018060401b03988991015416986040519a8b5260208b015260408a01526060890152608088015260a087015260c086015260e0850152611f1e610100850160ff8316612223565b611f32610120850160ff8360081c16612230565b60ff8160101c16151561014085015260ff8160181c161515610160850152818160201c16610180850152818160601c166101a085015260a01c166101c08301526101e0820152f35b50346101b05760403660031901126101b057611f946121fe565b611f9c612214565b906001600160a01b03907f00000000000000000000000000000000000000000000000000000000000000008216330361203357169081156120215760207f9a8e30a8658b96ab3f034ce4bac6806278b4aee5880ccdd1ac35e4ed5bb31d239183855260088252604085209015159060ff1981541660ff8316179055604051908152a280f35b60405163d92e233d60e01b8152600490fd5b604051632d5be4cb60e21b8152600490fd5b50346101b057806003193601126101b0576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b50346101b057806003193601126101b0576020604051621275008152f35b50346101b05760203660031901126101b05760406020916004358152600583522054604051908152f35b50346101b0576020806003193601126106fa576004356120f06125a4565b808352600182526040832080549091906001600160a01b03908116330361023957600883019081549160ff8360081c166008811015610523576002036102135782861c6001600160401b03164211156121ec57610600600080516020612c428339815191529361ff00191617905560038401600281549588600482018181549555550190828254168852600987526040882061218d87825461241e565b9055801515806121cf575b6121a687338686541661265f565b6121bf575b505416936040519384523393a46001815580f35b6121c9903361262a565b386121ab565b88805260098852604089206121e583825461241e565b9055612198565b6040516302eb354360e41b8152600490fd5b600435906001600160a01b038216820361074f57565b60243590811515820361074f57565b906003821015610fee5752565b906008821015610fee5752565b9181601f8401121561074f578235916001600160401b03831161074f576020838186019501011161074f57565b90604060031983011261074f5760043591602435906001600160401b03821161074f576122999160040161223d565b9091565b90600182811c921680156122cd575b60208310146122b757565b634e487b7160e01b600052602260045260246000fd5b91607f16916122ac565b61020081019081106001600160401b03821117610c7157604052565b604081019081106001600160401b03821117610c7157604052565b601f909101601f19168101906001600160401b03821190821017610c7157604052565b906040519182600082546123448161229d565b908184526020946001916001811690816000146123b45750600114612375575b5050506123739250038361230e565b565b600090815285812095935091905b81831061239c5750506123739350820101388080612364565b85548884018501529485019487945091830191612383565b9250505061237394925060ff191682840152151560051b820101388080612364565b60005b8381106123e95750506000910152565b81810151838201526020016123d9565b90602091612412815180928185528580860191016123d6565b601f01601f1916010190565b919082039182116106d057565b919082018092116106d057565b6001600160401b038111610c7157601f01601f191660200190565b92919261245f82612438565b9161246d604051938461230e565b82948184528183011161074f578281602093846000960137010152565b8054600160a01b600160e01b03191660a09290921b600160a01b600160e01b0316919091179055565b908060209392818452848401376000828201840152601f01601f1916010190565b6003821015610fee5752565b60c4356001600160401b038116810361074f5790565b60e4356001600160401b038116810361074f5790565b6004356001600160a01b038116810361074f5790565b61010435801515810361074f5790565b93919290604051936020850195600080516020612c628339815191528752466040870152306060870152608086015260018060a01b0380921660a08601521660c084015260e083015261010090818301528152610120810181811060018060401b03821117610c715760405251902090565b6002600054146125b5576002600055565b60405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606490fd5b3d15612625573d9061260b82612438565b91612619604051938461230e565b82523d6000602084013e565b606090565b811561265b57600080809381935af16126416125fa565b501561264957565b6040516312171d8360e31b8152600490fd5b5050565b82156126cf576001600160a01b039081169081612689575050600080809381935af16126416125fa565b60405163a9059cbb60e01b60208201529216602483015260448083019390935291815260808101916001600160401b03831182841017610c715761237392604052612aaf565b505050565b909160018060a01b0392836001820154169360028201541694600382019081549160048401908154926008860196888b8b8a549960ff8b60101c1660001461282c57928961275895936127319360066127529f9997015493612532565b998a918c600052600260205261274a6040600020612331565b933691612453565b91612889565b1561281b57610500604096897ffa098250c8076c215e57e37e1daacbd822ef0c9d9e2dd35b12aa849327a35ef16020600080516020612c828339815191529b8b51908152a25b61ff001916179055600091828092555587815260096020528381206127c484825461241e565b905581151590816127fd575b506127dc83888a61265f565b6127ee575b82519182526020820152a4565b6127f8818761262a565b6127e1565b808086925260096020522061281383825461241e565b9055386127d0565b604051628f3e5b60e61b8152600490fd5b505050505061285057600080516020612c828339815191529561050060409661279e565b60405163187b766d60e21b8152600490fd5b908151811015612873570160200190565b634e487b7160e01b600052603260045260246000fd5b92919092610381815103612aa75781516028946028821115612a9d5760271982019182116106d05761ffff8211612a9d5760408051606081016001600160401b03811182821017610c7157825260288152602095868201938336863760005b8a8110612a7157506128f986612438565b906129068551928361230e565b86825261291287612438565b828a019390601f190136853760005b888110612a3957505088999a50849896979851878101918252878152612946816122f3565b85519687958987019a61ffff60f01b9060f01b168b525190816022880161296c926123d6565b8501905191826022830161297f926123d6565b019051918260228301612991926123d6565b01036002810183526022016129a6908361230e565b51928391838084018781985192839101916129c0926123d6565b8301905191828583016129d2926123d6565b0103808352016129e2908261230e565b51905a9160009291610ae18493fa906129f96125fa565b9082612a2d575b5081612a0a575090565b80915051601f101561287357603f01516001600160f81b031916600160f81b1490565b81511015915038612a00565b8c810190818e116106d0576001916001600160f81b031990612a5b9085612862565b511660001a612a6a8287612862565b5301612921565b6001906001600160f81b0319612a878286612862565b511660001a612a968287612862565b53016128e8565b5060009450505050565b506000925050565b60018060a01b031690612b0e604051612ac7816122f3565b6020938482527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564858301526000808587829751910182855af1612b086125fa565b91612ba4565b805191821591848315612b80575b505050905015612b295750565b6084906040519062461bcd60e51b82526004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152fd5b9193818094500103126106fa578201519081151582036101b0575080388084612b1c565b91929015612c065750815115612bb8575090565b3b15612bc15790565b60405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606490fd5b825190915015612c195750805190602001fd5b60405162461bcd60e51b815260206004820152908190612c3d9060248301906123f9565b0390fdfee257c770e48715cd6ce3834146a7d7b04bd626423802ecde7a2346d3c0b985ddd7b83be88f1aae552e9a9057ff5cd5e79aeeaef816dc27cc937777c9cc00ec9ccfb74f7ba842154e916641e0845c97af0df986b664065dd84c41603c75bdd3ada2646970667358221220feb6e6bddf943e06df7a1310f42db4a158b9a4dbc1d623fce6a11f9cec873fca64736f6c63430008170033", + "immutables": { + "ZK_VERIFIER": { + "type": "contract ISP1Verifier", + "positions": [ + { + "length": 32, + "start": 4192 + }, + { + "length": 32, + "start": 6133 + }, + { + "length": 32, + "start": 6244 + } + ] + }, + "PINNED_PROOF_SELECTOR": { + "type": "bytes4", + "positions": [ + { + "length": 32, + "start": 4122 + }, + { + "length": 32, + "start": 6080 + } + ] + }, + "ARBITER": { + "type": "address", + "positions": [ + { + "length": 32, + "start": 4976 + }, + { + "length": 32, + "start": 6941 + } + ] + }, + "GOVERNANCE": { + "type": "address", + "positions": [ + { + "length": 32, + "start": 8104 + }, + { + "length": 32, + "start": 8283 + } + ] + } + }, + "note": "runtime code of a deployment = deployedBytecode with each immutable written at its positions as a 32-byte word (addresses right-aligned, bytes4 left-aligned); compare with eth_getCode" +} diff --git a/market-settlement/README.md b/market-settlement/README.md new file mode 100644 index 0000000..5ea84a9 --- /dev/null +++ b/market-settlement/README.md @@ -0,0 +1,50 @@ +# AERE Market Settlement + +The dispute and settlement rail of a verifiable infrastructure market, measured end to end on testnet 28001: an order with its reward in +escrow, a provider bond, the provider's result committed on chain and its proof notarized under a post-quantum certified anchor, a +challenge window in which anyone can dispute with a recomputed result and a matching bond, an arbiter who can only route the escrow +between the three parties (and a permissionless timeout if the arbiter never answers), a deadline after which an undelivered order is +reclaimed, and an AIP-23 settlement receipt of the payout. Built from what already exists: `AereComputeMarketV3` (the contract, here +as a committed artifact), `proof-kinds/` (the execution envelope and the settlement receipt), `agents/agent-ancora.mjs` (the one +notarization call of the house) and the AIP-23 reference verifier. + +| step | on chain | off chain, checkable by anyone | +|---|---|---| +| order | `postJob`: reward escrowed, `specHash` of the public workload, deadline, challenge window, required provider bond | the spec itself (`sarcina.mjs`: a keccak chain anyone recomputes) | +| claim | `claimJob` with the bond, only before the deadline | | +| proof | `submitResult`: `keccak256(result)` recorded, the bytes emitted; the window starts | the provider's `aere-proof-of-execution` envelope (program, `inputHash` = specHash, `outputHash` = resultHash) notarized on AereNotary: its `firstSeen` is the chain's time, read back under a post-quantum certified anchor by `verify-proof.mjs` | +| dispute | `dispute(recomputedHash)` with a bond equal to the provider's, only inside the window | the judge replays the spec and says which side the arbiter should take | +| settlement | `finalize` by anyone after the window (Paid); `resolveDispute` by the ARBITER (Paid or Slashed); `resolveByTimeout` by anyone after 14 days (Refunded, bonds returned); `reclaimExpired` by the requester after the deadline (Refunded, bond slashed); `cancelJob` on an open order | `piata.mjs judeca`: the timeline against the rules; `chitanta`: the AIP-23 `settlement` envelope of the payout tx | + +`piata.mjs` has the three pieces a reader needs: `codulAsteptat` rebuilds the runtime code a market must have from the committed +artifact and the four constructor arguments (so `eth_getCode` is compared before any event is believed), `cronologie` reads a job's +state and every event with its block time and sender, and `judeca` is a pure function over that timeline: claim and submission before +the deadline, dispute strictly inside the window, finalize only after it (unless the requester accepts early), resolution only by the +arbiter or after `ARBITRATION_TIMEOUT`, the terminal payout matching the state, the result bytes hashing to the commitment, the replay of +the public spec agreeing with whoever won, and the notarized envelope naming this job's spec and result before the window closed. + +``` +AERE_TESTNET_KEY_FILE= AERE_ETHERS_DIR= node proba-piata-28001.mjs # the flow on 28001 (five scenarios) +node proba-judecata.mjs # the judge on the recorded timelines: 5 honest VALID, 10 forged INVALID, the receipt +node proba-judecata.mjs --control-negativ # 7 plantings on a copy of piata.mjs; each forged fixture must then be accepted +node extrage-artefact.mjs # regenerate AereComputeMarketV3.json from the contracts build (refuses a changed source) +``` + +## What it is not, and what is not measured + +- **Not a marketplace.** No discovery, no pricing, no reputation, no real GPU, storage or inference behind the workload; the task is a + keccak chain chosen because anyone can replay it. The rail settles; it does not find providers. +- **The arbiter is one key.** A dispute is decided by `ARBITER`, who can only route the escrow between requester, provider and + challenger, never elsewhere, and whose silence is unwound by anyone after 14 days. That is a trust assumption, named, not a proof; + the judge checks the arbiter's decision against the replay afterwards, which makes a wrong ruling visible, not impossible. +- **REPLAY mode only.** `ZK_VERIFIED` (pay only on an SP1 proof) cannot be exercised on this deployment: 28001 has no SP1 gateway, so the + market was built with a contract that has code but no `verifyProof` (the notary), and a ZK job reverts, fail-closed. `pqcSettlement` + (a Falcon-512 payout authorization) is not exercised either. The 14-day arbitration timeout and the 7-day PQC grace are not waited for: + the probe shows they refuse early (`ArbitrationTimeoutNotPassed`), not that they unwind. +- **Native tAERE only.** An allowlisted ERC-20 reward and the 2-of-2 agent wallet as requester are not measured: the contract wallet has + no function that calls `postJob`, so an agent that orders through this rail does it from its EOA, under its ledger and policy. +- **Chain 2800: nothing.** `AereComputeMarketV3` is held back from mainnet until an external audit of fund-flow contracts; everything here + ran on testnet 28001 with test keys (the provider's and the arbiter's derived from the requester's test key, never printed). +- The replay uses a dependency-free keccak-256 (BigInt): about 7 s for the 20,000 iterations of the laboratory task on a laptop, against well under a second with a native or WebAssembly keccak; the cost is the price of a component with nothing to install, and it is measured, not hidden. +- The judge trusts the RPC for the timeline (events and block times), like every reader of a chain through an endpoint; the notarized + envelope's time is checked under a post-quantum certified anchor by the reference verifier, the rest is not. diff --git a/market-settlement/desfasurare-28001.json b/market-settlement/desfasurare-28001.json new file mode 100644 index 0000000..2dad3b3 --- /dev/null +++ b/market-settlement/desfasurare-28001.json @@ -0,0 +1,14 @@ +{ + "chainId": 28001, + "market": "0x4145d6f639436d840957F2D4B9f2e73f34F56B5D", + "deployTx": "0x8f45502e40a71d45550756fdcb3e4ed3af0532134212704f161fd2c4004d8ae2", + "block": 4445446, + "args": { + "ZK_VERIFIER": "0x70099E62735500AA2F85B60C518551a57B202d54", + "PINNED_PROOF_SELECTOR": "0x4388a21c", + "ARBITER": "0x5521aC7371Afdbf6BE986B46Da4116fb256d9e58", + "GOVERNANCE": "0x86D6C68408DDb2CC0d1cf4dFd6e07d3830600fAF" + }, + "artifactSourceSha256": "0x6db4d53dffb0afd79cfb41f973ac4d2ca82589ab7bdd206296b66b4c72dd4fe4", + "at": "2026-10-02T16:40:39.149Z" +} \ No newline at end of file diff --git a/market-settlement/dovezi/piata-28001-2026-10-02T1652Z.json b/market-settlement/dovezi/piata-28001-2026-10-02T1652Z.json new file mode 100644 index 0000000..e4bc94a --- /dev/null +++ b/market-settlement/dovezi/piata-28001-2026-10-02T1652Z.json @@ -0,0 +1,815 @@ +{ + "la": "2026-10-02T16:46:56.361Z", + "chainId": 28001, + "rpc": "https://testnet-rpc.aere.network", + "fereastra": 90, + "scenarii": { + "S1": { + "spec": { + "task": "keccak-chain", + "seed": "0xbfcf8dae6e6f105b4e7ead898a4fdb0319745deb3d38042e3815d75805e1060d", + "iters": 20000 + }, + "pasi": [], + "jobId": 5, + "computeMs": 597, + "envelope": { + "v": 1, + "kind": "aere-proof-of-execution-attestation", + "statement": { + "v": 1, + "kind": "aere-proof-of-execution", + "inputHash": "0xf2a0d3e03521234fd6be921e346817e6f77e20db038ff5325318a2a5a47cfd25", + "outputHash": "0xeba5b6ff363f15d358926ab16bc4c7c8c979ec2d217868134810488304dde0be", + "programSha256": "0x1824b9e133c368fab195cb2f33e35bee78abdb4de7b03f0c377ac5af951eb9e0", + "program": "keccak-chain", + "exitCode": 0, + "createdAt": "2026-10-02T16:47:11.789Z" + }, + "statementHash": "0xfffa43d50b6222a17f915d528f0f636b16882f736f357b8418d30dfec2f88200", + "notarization": { + "chainId": 28001, + "notary": "0x70099E62735500AA2F85B60C518551a57B202d54", + "firstSeen": 1790959633, + "txHash": "0x86f094ae0ba1030b97060792344eda1b6018367dbf14088c6c2de1e5a4e2fc6e", + "block": 4446125 + } + }, + "date": { + "chainId": 28001, + "market": "0x4145d6f639436d840957F2D4B9f2e73f34F56B5D", + "jobId": "5", + "constants": { + "arbiter": "0x5521aC7371Afdbf6BE986B46Da4116fb256d9e58", + "governance": "0x86D6C68408DDb2CC0d1cf4dFd6e07d3830600fAF", + "arbitrationTimeout": 1209600, + "zkVerifier": "0x70099E62735500AA2F85B60C518551a57B202d54", + "pinnedProofSelector": "0x4388a21c" + }, + "job": { + "requester": "0x86D6C68408DDb2CC0d1cf4dFd6e07d3830600fAF", + "provider": "0xeC2261CECBB06768F6db095822b429AF5c861E2e", + "token": "0x0000000000000000000000000000000000000000", + "reward": "0", + "providerBond": "0", + "specHash": "0xf2a0d3e03521234fd6be921e346817e6f77e20db038ff5325318a2a5a47cfd25", + "resultHash": "0xeba5b6ff363f15d358926ab16bc4c7c8c979ec2d217868134810488304dde0be", + "zkProgramVKey": "0x0000000000000000000000000000000000000000000000000000000000000000", + "mode": 0, + "status": 5, + "pqcSettlement": false, + "offchainResult": false, + "deadline": 1790960218, + "challengeWindow": 90, + "submittedAt": 1790959639, + "disputedAt": 0 + }, + "events": [ + { + "name": "JobPosted", + "args": { + "id": "5", + "requester": "0x86D6C68408DDb2CC0d1cf4dFd6e07d3830600fAF", + "token": "0x0000000000000000000000000000000000000000", + "reward": "10000000000000000", + "mode": "0", + "specHash": "0xf2a0d3e03521234fd6be921e346817e6f77e20db038ff5325318a2a5a47cfd25", + "deadline": "1790960218", + "pqcSettlement": false + }, + "blockNumber": 4446103, + "blockHash": "0xfc22d0155293bef0b5349507a2a45495de7d3baa37b1f9e5e482585d93ecdc3e", + "timestamp": 1790959620, + "txHash": "0x5178c7b523d9ad5516f5e649f50bc98c44aacd6c4564403ac6b7528a9e63791e", + "from": "0x86D6C68408DDb2CC0d1cf4dFd6e07d3830600fAF", + "logIndex": 0 + }, + { + "name": "JobClaimed", + "args": { + "id": "5", + "provider": "0xeC2261CECBB06768F6db095822b429AF5c861E2e", + "providerBond": "4000000000000000" + }, + "blockNumber": 4446113, + "blockHash": "0xd59b44a60e225a952c0ef940a62f6ebe7325dc4d75627161c329aa6f48bc9ce4", + "timestamp": 1790959626, + "txHash": "0xf46a947200113d014c3e8b0282267feb2882f0d8895ae4b13a72f1db20fa7ee3", + "from": "0xeC2261CECBB06768F6db095822b429AF5c861E2e", + "logIndex": 0 + }, + { + "name": "ResultSubmitted", + "args": { + "id": "5", + "resultHash": "0xeba5b6ff363f15d358926ab16bc4c7c8c979ec2d217868134810488304dde0be", + "result": "0x7b22646967657374223a22307864346139306165303264396364623232353863373239633532636166613662613263623164306539323532326135313739313733383362366535386131323535222c226974657273223a32303030302c2273656564223a22307862666366386461653665366631303562346537656164383938613466646230333139373435646562336433383034326533383135643735383035653130363064222c227461736b223a226b656363616b2d636861696e227d" + }, + "blockNumber": 4446136, + "blockHash": "0x7cedaf1f5da474b94c41fd0925f181459ff642fa449843886d94226daaf2650f", + "timestamp": 1790959639, + "txHash": "0xea128ff1992e39f6690ebfbfbd9896ff27bcea0db4b0070c32062d2de599d446", + "from": "0xeC2261CECBB06768F6db095822b429AF5c861E2e", + "logIndex": 0 + }, + { + "name": "JobPaid", + "args": { + "id": "5", + "provider": "0xeC2261CECBB06768F6db095822b429AF5c861E2e", + "token": "0x0000000000000000000000000000000000000000", + "reward": "10000000000000000", + "bondReturned": "4000000000000000" + }, + "blockNumber": 4446295, + "blockHash": "0x736c818d1833f0c88ccda5ec5101d392fd842af32a6b152018a085c7a75a7c5c", + "timestamp": 1790959733, + "txHash": "0x5e4bfedda879e4e016b7f4434f75da4a8af63ccc4cce285d714b9e56e453e65f", + "from": "0x5521aC7371Afdbf6BE986B46Da4116fb256d9e58", + "logIndex": 0 + } + ], + "result": "0x7b22646967657374223a22307864346139306165303264396364623232353863373239633532636166613662613263623164306539323532326135313739313733383362366535386131323535222c226974657273223a32303030302c2273656564223a22307862666366386461653665366631303562346537656164383938613466646230333139373435646562336433383034326533383135643735383035653130363064222c227461736b223a226b656363616b2d636861696e227d", + "spec": { + "task": "keccak-chain", + "seed": "0xbfcf8dae6e6f105b4e7ead898a4fdb0319745deb3d38042e3815d75805e1060d", + "iters": 20000 + }, + "envelope": { + "v": 1, + "kind": "aere-proof-of-execution-attestation", + "statement": { + "v": 1, + "kind": "aere-proof-of-execution", + "inputHash": "0xf2a0d3e03521234fd6be921e346817e6f77e20db038ff5325318a2a5a47cfd25", + "outputHash": "0xeba5b6ff363f15d358926ab16bc4c7c8c979ec2d217868134810488304dde0be", + "programSha256": "0x1824b9e133c368fab195cb2f33e35bee78abdb4de7b03f0c377ac5af951eb9e0", + "program": "keccak-chain", + "exitCode": 0, + "createdAt": "2026-10-02T16:47:11.789Z" + }, + "statementHash": "0xfffa43d50b6222a17f915d528f0f636b16882f736f357b8418d30dfec2f88200", + "notarization": { + "chainId": 28001, + "notary": "0x70099E62735500AA2F85B60C518551a57B202d54", + "firstSeen": 1790959633, + "txHash": "0x86f094ae0ba1030b97060792344eda1b6018367dbf14088c6c2de1e5a4e2fc6e", + "block": 4446125 + } + } + }, + "judecata": { + "verdict": "VALID", + "motive": [], + "randuri": [ + "2026-10-02T16:47:00.000Z #4446103 JobPosted by 0x86D6C684.. id=5 requester=0x86D6C684.. token=0x00000000.. reward=10000000000000000 mode=0 specHash=0xf2a0d3e0.. deadline=1790960218 pqcSettlement=false", + "2026-10-02T16:47:06.000Z #4446113 JobClaimed by 0xeC2261CE.. id=5 provider=0xeC2261CE.. providerBond=4000000000000000", + "2026-10-02T16:47:19.000Z #4446136 ResultSubmitted by 0xeC2261CE.. id=5 resultHash=0xeba5b6ff..", + "2026-10-02T16:48:53.000Z #4446295 JobPaid by 0x5521aC73.. id=5 provider=0xeC2261CE.. token=0x00000000.. reward=10000000000000000 bondReturned=4000000000000000" + ], + "status": "Paid", + "terminal": { + "status": "Paid", + "payee": "0xeC2261CECBB06768F6db095822b429AF5c861E2e", + "amount": "10000000000000000", + "txHash": "0x5e4bfedda879e4e016b7f4434f75da4a8af63ccc4cce285d714b9e56e453e65f", + "blockHash": "0x736c818d1833f0c88ccda5ec5101d392fd842af32a6b152018a085c7a75a7c5c" + }, + "replay": { + "recomputedHash": "0xeba5b6ff363f15d358926ab16bc4c7c8c979ec2d217868134810488304dde0be", + "providerRight": true + } + }, + "verifyProof": { + "verdict": "VALID", + "statementHash": "0xfffa43d50b6222a17f915d528f0f636b16882f736f357b8418d30dfec2f88200", + "levels": [ + { + "level": "form", + "state": "PASSED", + "detail": "kind=aere-proof-of-execution-attestation" + }, + { + "level": "integrity", + "state": "PASSED", + "detail": "sha256(statement) == statementHash (0xfffa43d50b6222a1..)" + }, + { + "level": "signature", + "state": "ABSENT", + "detail": "the envelope carries no signature" + }, + { + "level": "finality", + "state": "PASSED", + "detail": "post-quantum: the state of block 4446303, the parent of anchor 4446304 whose post-quantum certificate verified here records this statementHash in AereNotary 0x70099e62735500aa2f85b60c518551a57b202d54 as first seen at 2026-10-02T16:47:13.000Z (1790959633); first seen in block 4446125, transaction 0x86f094ae0ba1030b.. (located through the endpoint's logs, not part of what is certified)" + } + ] + }, + "chitanta": { + "v": 1, + "kind": "aere-proof-of-settlement-attestation", + "statement": { + "v": 1, + "kind": "aere-proof-of-settlement", + "instructionHash": "0xacad5a190c81f60a3051a56f2a7fad505abbbe86da6ffd130fc7f2f8964eceb9", + "txHash": "0x5e4bfedda879e4e016b7f4434f75da4a8af63ccc4cce285d714b9e56e453e65f", + "blockHash": "0x736c818d1833f0c88ccda5ec5101d392fd842af32a6b152018a085c7a75a7c5c", + "chainId": 28001, + "from": "0x4145d6f639436d840957F2D4B9f2e73f34F56B5D", + "to": "0xeC2261CECBB06768F6db095822b429AF5c861E2e", + "amount": "10000000000000000", + "asset": "native", + "createdAt": "2026-10-02T16:49:13.443Z" + }, + "statementHash": "0xab6c8e8876816ff3fbaef7b3fc364ad3b4e94b98116ede3fdb982bff3b886786" + }, + "chitantaVerdict": { + "verdict": "VALID", + "statementHash": "0xab6c8e8876816ff3fbaef7b3fc364ad3b4e94b98116ede3fdb982bff3b886786", + "levels": [ + { + "level": "form", + "state": "PASSED", + "detail": "kind=aere-proof-of-settlement-attestation" + }, + { + "level": "integrity", + "state": "PASSED", + "detail": "sha256(statement) == statementHash (0xab6c8e8876816ff3..)" + }, + { + "level": "signature", + "state": "ABSENT", + "detail": "the envelope carries no signature" + }, + { + "level": "finality", + "state": "ABSENT", + "detail": "no notarization claimed and no --rpc given" + } + ] + } + }, + "S2": { + "spec": { + "task": "keccak-chain", + "seed": "0x5de2558627fcce6d953b1a70358f167c9b364fc944a45fe0741abc0c0b8d42ce", + "iters": 20000 + }, + "pasi": [], + "jobId": 6, + "date": { + "chainId": 28001, + "market": "0x4145d6f639436d840957F2D4B9f2e73f34F56B5D", + "jobId": "6", + "constants": { + "arbiter": "0x5521aC7371Afdbf6BE986B46Da4116fb256d9e58", + "governance": "0x86D6C68408DDb2CC0d1cf4dFd6e07d3830600fAF", + "arbitrationTimeout": 1209600, + "zkVerifier": "0x70099E62735500AA2F85B60C518551a57B202d54", + "pinnedProofSelector": "0x4388a21c" + }, + "job": { + "requester": "0x86D6C68408DDb2CC0d1cf4dFd6e07d3830600fAF", + "provider": "0xeC2261CECBB06768F6db095822b429AF5c861E2e", + "token": "0x0000000000000000000000000000000000000000", + "reward": "0", + "providerBond": "0", + "specHash": "0x307e7d75c2de86416fd1df625fd5c00a12a4ff6257bea57871de8c7d47cf5a89", + "resultHash": "0x2dea74737284c05166223abbb28b3eaf367e8964a5a12bffa0ab4bd1e2b300ae", + "zkProgramVKey": "0x0000000000000000000000000000000000000000000000000000000000000000", + "mode": 0, + "status": 7, + "pqcSettlement": false, + "offchainResult": false, + "deadline": 1790960353, + "challengeWindow": 90, + "submittedAt": 1790959767, + "disputedAt": 1790959773 + }, + "events": [ + { + "name": "JobPosted", + "args": { + "id": "6", + "requester": "0x86D6C68408DDb2CC0d1cf4dFd6e07d3830600fAF", + "token": "0x0000000000000000000000000000000000000000", + "reward": "10000000000000000", + "mode": "0", + "specHash": "0x307e7d75c2de86416fd1df625fd5c00a12a4ff6257bea57871de8c7d47cf5a89", + "deadline": "1790960353", + "pqcSettlement": false + }, + "blockNumber": 4446332, + "blockHash": "0x373ef4cd4095e1db711ba4748c2a5bd2d78a26dd7892a98c14929aeb0b62cf1f", + "timestamp": 1790959755, + "txHash": "0xdf242547d54507d84bb9ac8d91ce24b65529d17940bd95504f5267ee74bdd92a", + "from": "0x86D6C68408DDb2CC0d1cf4dFd6e07d3830600fAF", + "logIndex": 0 + }, + { + "name": "JobClaimed", + "args": { + "id": "6", + "provider": "0xeC2261CECBB06768F6db095822b429AF5c861E2e", + "providerBond": "4000000000000000" + }, + "blockNumber": 4446342, + "blockHash": "0xa81e65065cd3c472cc571c64035031c66e975906a92e5b88acba4a6e08c9d7a1", + "timestamp": 1790959761, + "txHash": "0xfcfc913a260d29b519276a484199d372ed39aac81005166e5231025bf948d35b", + "from": "0xeC2261CECBB06768F6db095822b429AF5c861E2e", + "logIndex": 0 + }, + { + "name": "ResultSubmitted", + "args": { + "id": "6", + "resultHash": "0x2dea74737284c05166223abbb28b3eaf367e8964a5a12bffa0ab4bd1e2b300ae", + "result": "0x7b22646967657374223a22307865656565656565656565656565656565656565656565656565656565656565656565656565656565656565656565656565656565656565656565656565656565222c226974657273223a32303030302c2273656564223a22307835646532353538363237666363653664393533623161373033353866313637633962333634666339343461343566653037343161626330633062386434326365222c227461736b223a226b656363616b2d636861696e227d" + }, + "blockNumber": 4446353, + "blockHash": "0xd4d23bd3f6d3883330ff25de0a81696c0e9ba473c5457b918c5aa82e55601777", + "timestamp": 1790959767, + "txHash": "0x5f921a8d67de79bfcfd4d77085fa220d5ecc4191631a7e4dc050e003e612c6c6", + "from": "0xeC2261CECBB06768F6db095822b429AF5c861E2e", + "logIndex": 0 + }, + { + "name": "JobDisputed", + "args": { + "id": "6", + "challenger": "0x86D6C68408DDb2CC0d1cf4dFd6e07d3830600fAF", + "bond": "4000000000000000", + "recomputedResultHash": "0xb37eb93d1b69a562f94bb2de482a0a4dd3e04493d3020cb29eeef8df82c713c3" + }, + "blockNumber": 4446364, + "blockHash": "0xf6a3e7e6f51312f624cbed5251b0c5abe05f9bd2b1d255ec8fe65114d408311c", + "timestamp": 1790959773, + "txHash": "0x72c54a067ebf1341a588db66f61223a28d7f6977bc60ab8eff5e59e008ddf8de", + "from": "0x86D6C68408DDb2CC0d1cf4dFd6e07d3830600fAF", + "logIndex": 0 + }, + { + "name": "JobSlashed", + "args": { + "id": "6", + "challenger": "0x86D6C68408DDb2CC0d1cf4dFd6e07d3830600fAF", + "slashedProviderBond": "4000000000000000" + }, + "blockNumber": 4446375, + "blockHash": "0xf5aa67bf1e48b8fc8a8ff44b794b0f9cd501f45d10b7979b7b5fdc37e9d70a9a", + "timestamp": 1790959780, + "txHash": "0x7b1916485981fef836d5f43c3d8c4528678931f78d4b3110859198c630e5e69f", + "from": "0x5521aC7371Afdbf6BE986B46Da4116fb256d9e58", + "logIndex": 0 + }, + { + "name": "DisputeResolved", + "args": { + "id": "6", + "providerWon": false + }, + "blockNumber": 4446375, + "blockHash": "0xf5aa67bf1e48b8fc8a8ff44b794b0f9cd501f45d10b7979b7b5fdc37e9d70a9a", + "timestamp": 1790959780, + "txHash": "0x7b1916485981fef836d5f43c3d8c4528678931f78d4b3110859198c630e5e69f", + "from": "0x5521aC7371Afdbf6BE986B46Da4116fb256d9e58", + "logIndex": 1 + } + ], + "result": "0x7b22646967657374223a22307865656565656565656565656565656565656565656565656565656565656565656565656565656565656565656565656565656565656565656565656565656565222c226974657273223a32303030302c2273656564223a22307835646532353538363237666363653664393533623161373033353866313637633962333634666339343461343566653037343161626330633062386434326365222c227461736b223a226b656363616b2d636861696e227d", + "spec": { + "task": "keccak-chain", + "seed": "0x5de2558627fcce6d953b1a70358f167c9b364fc944a45fe0741abc0c0b8d42ce", + "iters": 20000 + }, + "envelope": null + }, + "judecata": { + "verdict": "VALID", + "motive": [], + "randuri": [ + "2026-10-02T16:49:15.000Z #4446332 JobPosted by 0x86D6C684.. id=6 requester=0x86D6C684.. token=0x00000000.. reward=10000000000000000 mode=0 specHash=0x307e7d75.. deadline=1790960353 pqcSettlement=false", + "2026-10-02T16:49:21.000Z #4446342 JobClaimed by 0xeC2261CE.. id=6 provider=0xeC2261CE.. providerBond=4000000000000000", + "2026-10-02T16:49:27.000Z #4446353 ResultSubmitted by 0xeC2261CE.. id=6 resultHash=0x2dea7473..", + "2026-10-02T16:49:33.000Z #4446364 JobDisputed by 0x86D6C684.. id=6 challenger=0x86D6C684.. bond=4000000000000000 recomputedResultHash=0xb37eb93d..", + "2026-10-02T16:49:40.000Z #4446375 JobSlashed by 0x5521aC73.. id=6 challenger=0x86D6C684.. slashedProviderBond=4000000000000000", + "2026-10-02T16:49:40.000Z #4446375 DisputeResolved by 0x5521aC73.. id=6 providerWon=false" + ], + "status": "Slashed", + "terminal": { + "status": "Slashed", + "payee": "0x86D6C68408DDb2CC0d1cf4dFd6e07d3830600fAF", + "amount": "4000000000000000", + "refundedTo": "0x86D6C68408DDb2CC0d1cf4dFd6e07d3830600fAF", + "txHash": "0x7b1916485981fef836d5f43c3d8c4528678931f78d4b3110859198c630e5e69f", + "blockHash": "0xf5aa67bf1e48b8fc8a8ff44b794b0f9cd501f45d10b7979b7b5fdc37e9d70a9a" + }, + "replay": { + "recomputedHash": "0xb37eb93d1b69a562f94bb2de482a0a4dd3e04493d3020cb29eeef8df82c713c3", + "providerRight": false, + "challengerRecomputedRight": true + } + }, + "gasResolve": "70471" + }, + "S3": { + "spec": { + "task": "keccak-chain", + "seed": "0x53c2cdb3e3e6a740c9fd8800cca9d50ec84681b76f5547c2536090db7624b09d", + "iters": 20000 + }, + "pasi": [], + "jobId": 7, + "date": { + "chainId": 28001, + "market": "0x4145d6f639436d840957F2D4B9f2e73f34F56B5D", + "jobId": "7", + "constants": { + "arbiter": "0x5521aC7371Afdbf6BE986B46Da4116fb256d9e58", + "governance": "0x86D6C68408DDb2CC0d1cf4dFd6e07d3830600fAF", + "arbitrationTimeout": 1209600, + "zkVerifier": "0x70099E62735500AA2F85B60C518551a57B202d54", + "pinnedProofSelector": "0x4388a21c" + }, + "job": { + "requester": "0x86D6C68408DDb2CC0d1cf4dFd6e07d3830600fAF", + "provider": "0xeC2261CECBB06768F6db095822b429AF5c861E2e", + "token": "0x0000000000000000000000000000000000000000", + "reward": "0", + "providerBond": "0", + "specHash": "0x33d4d459ac50fbf9089cfbbdf51416f7f9d8fd8794f03f4788bef4b679be0e06", + "resultHash": "0x20595189a5aae95406d466972f780d5b04408146e30afdcc66449836a67b240a", + "zkProgramVKey": "0x0000000000000000000000000000000000000000000000000000000000000000", + "mode": 0, + "status": 5, + "pqcSettlement": false, + "offchainResult": false, + "deadline": 1790960390, + "challengeWindow": 90, + "submittedAt": 1790959804, + "disputedAt": 1790959809 + }, + "events": [ + { + "name": "JobPosted", + "args": { + "id": "7", + "requester": "0x86D6C68408DDb2CC0d1cf4dFd6e07d3830600fAF", + "token": "0x0000000000000000000000000000000000000000", + "reward": "10000000000000000", + "mode": "0", + "specHash": "0x33d4d459ac50fbf9089cfbbdf51416f7f9d8fd8794f03f4788bef4b679be0e06", + "deadline": "1790960390", + "pqcSettlement": false + }, + "blockNumber": 4446395, + "blockHash": "0xdaec8217b35341244eb65c7a06bc6d817c44888c0e2c673d2278091e7c308a83", + "timestamp": 1790959791, + "txHash": "0x8c0ab87432b8e3e4b8a53f9ef3fd9d217e214f106ff637368ab75f0ed68c300d", + "from": "0x86D6C68408DDb2CC0d1cf4dFd6e07d3830600fAF", + "logIndex": 0 + }, + { + "name": "JobClaimed", + "args": { + "id": "7", + "provider": "0xeC2261CECBB06768F6db095822b429AF5c861E2e", + "providerBond": "4000000000000000" + }, + "blockNumber": 4446404, + "blockHash": "0x31141aeb86c3bc3f7f3e0b493aa69a2a4d2e1952c09181f2ed3bc8e32b062c97", + "timestamp": 1790959797, + "txHash": "0x78e05e10e9b9aca97b0e26ce9e868dd017b57fcce4248bf65701b06ed44d1d1a", + "from": "0xeC2261CECBB06768F6db095822b429AF5c861E2e", + "logIndex": 0 + }, + { + "name": "ResultSubmitted", + "args": { + "id": "7", + "resultHash": "0x20595189a5aae95406d466972f780d5b04408146e30afdcc66449836a67b240a", + "result": "0x7b22646967657374223a22307838613832333664613464396231373164613863643538643832373738376535656539323739316533643262353665313537383163313938336363326464396531222c226974657273223a32303030302c2273656564223a22307835336332636462336533653661373430633966643838303063636139643530656338343638316237366635353437633235333630393064623736323462303964222c227461736b223a226b656363616b2d636861696e227d" + }, + "blockNumber": 4446415, + "blockHash": "0x27d0fdbd6383be65aa8549cae7f87436255111ccb57597f92f0eb78a8c568d20", + "timestamp": 1790959804, + "txHash": "0xf4b8f42fa5cad3827bbe234348b687dfec24d0b3e55f5ae162d66891239353e8", + "from": "0xeC2261CECBB06768F6db095822b429AF5c861E2e", + "logIndex": 0 + }, + { + "name": "JobDisputed", + "args": { + "id": "7", + "challenger": "0x86D6C68408DDb2CC0d1cf4dFd6e07d3830600fAF", + "bond": "4000000000000000", + "recomputedResultHash": "0xdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd" + }, + "blockNumber": 4446425, + "blockHash": "0x42ff0ad6b3187d212824c078f5cbb09cae1f67e5d762b1500053d34188da73e4", + "timestamp": 1790959809, + "txHash": "0x8595234a75d21301720a71505d4aff1046b8a73171da9bf24d245b5512911cd2", + "from": "0x86D6C68408DDb2CC0d1cf4dFd6e07d3830600fAF", + "logIndex": 0 + }, + { + "name": "JobPaid", + "args": { + "id": "7", + "provider": "0xeC2261CECBB06768F6db095822b429AF5c861E2e", + "token": "0x0000000000000000000000000000000000000000", + "reward": "10000000000000000", + "bondReturned": "4000000000000000" + }, + "blockNumber": 4446436, + "blockHash": "0x0e01a68f00de85f42a89054e785755699653ca065746982b153565be3051c2fd", + "timestamp": 1790959815, + "txHash": "0x7eb96d3a9703668a275d233daeb829435e6eb08fdb30f9179f0ed806b2926e8e", + "from": "0x5521aC7371Afdbf6BE986B46Da4116fb256d9e58", + "logIndex": 0 + }, + { + "name": "DisputeResolved", + "args": { + "id": "7", + "providerWon": true + }, + "blockNumber": 4446436, + "blockHash": "0x0e01a68f00de85f42a89054e785755699653ca065746982b153565be3051c2fd", + "timestamp": 1790959815, + "txHash": "0x7eb96d3a9703668a275d233daeb829435e6eb08fdb30f9179f0ed806b2926e8e", + "from": "0x5521aC7371Afdbf6BE986B46Da4116fb256d9e58", + "logIndex": 1 + } + ], + "result": "0x7b22646967657374223a22307838613832333664613464396231373164613863643538643832373738376535656539323739316533643262353665313537383163313938336363326464396531222c226974657273223a32303030302c2273656564223a22307835336332636462336533653661373430633966643838303063636139643530656338343638316237366635353437633235333630393064623736323462303964222c227461736b223a226b656363616b2d636861696e227d", + "spec": { + "task": "keccak-chain", + "seed": "0x53c2cdb3e3e6a740c9fd8800cca9d50ec84681b76f5547c2536090db7624b09d", + "iters": 20000 + }, + "envelope": null + }, + "judecata": { + "verdict": "VALID", + "motive": [], + "randuri": [ + "2026-10-02T16:49:51.000Z #4446395 JobPosted by 0x86D6C684.. id=7 requester=0x86D6C684.. token=0x00000000.. reward=10000000000000000 mode=0 specHash=0x33d4d459.. deadline=1790960390 pqcSettlement=false", + "2026-10-02T16:49:57.000Z #4446404 JobClaimed by 0xeC2261CE.. id=7 provider=0xeC2261CE.. providerBond=4000000000000000", + "2026-10-02T16:50:04.000Z #4446415 ResultSubmitted by 0xeC2261CE.. id=7 resultHash=0x20595189..", + "2026-10-02T16:50:09.000Z #4446425 JobDisputed by 0x86D6C684.. id=7 challenger=0x86D6C684.. bond=4000000000000000 recomputedResultHash=0xdddddddd..", + "2026-10-02T16:50:15.000Z #4446436 JobPaid by 0x5521aC73.. id=7 provider=0xeC2261CE.. token=0x00000000.. reward=10000000000000000 bondReturned=4000000000000000", + "2026-10-02T16:50:15.000Z #4446436 DisputeResolved by 0x5521aC73.. id=7 providerWon=true" + ], + "status": "Paid", + "terminal": { + "status": "Paid", + "payee": "0xeC2261CECBB06768F6db095822b429AF5c861E2e", + "amount": "10000000000000000", + "txHash": "0x7eb96d3a9703668a275d233daeb829435e6eb08fdb30f9179f0ed806b2926e8e", + "blockHash": "0x0e01a68f00de85f42a89054e785755699653ca065746982b153565be3051c2fd" + }, + "replay": { + "recomputedHash": "0x20595189a5aae95406d466972f780d5b04408146e30afdcc66449836a67b240a", + "providerRight": true, + "challengerRecomputedRight": false + } + } + }, + "S4": { + "spec": { + "task": "keccak-chain", + "seed": "0xd2356607ad7de44861e4098fc8de3628ab454527539afeb302e6cbc03450d500", + "iters": 20000 + }, + "pasi": [], + "jobId": 8, + "date": { + "chainId": 28001, + "market": "0x4145d6f639436d840957F2D4B9f2e73f34F56B5D", + "jobId": "8", + "constants": { + "arbiter": "0x5521aC7371Afdbf6BE986B46Da4116fb256d9e58", + "governance": "0x86D6C68408DDb2CC0d1cf4dFd6e07d3830600fAF", + "arbitrationTimeout": 1209600, + "zkVerifier": "0x70099E62735500AA2F85B60C518551a57B202d54", + "pinnedProofSelector": "0x4388a21c" + }, + "job": { + "requester": "0x86D6C68408DDb2CC0d1cf4dFd6e07d3830600fAF", + "provider": "0xeC2261CECBB06768F6db095822b429AF5c861E2e", + "token": "0x0000000000000000000000000000000000000000", + "reward": "0", + "providerBond": "0", + "specHash": "0xe39172c8a9a6c56862bc48d25c2b20f56c585d165d8140b9cd18da9784f1f5cd", + "resultHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "zkProgramVKey": "0x0000000000000000000000000000000000000000000000000000000000000000", + "mode": 0, + "status": 6, + "pqcSettlement": false, + "offchainResult": false, + "deadline": 1790959871, + "challengeWindow": 90, + "submittedAt": 0, + "disputedAt": 0 + }, + "events": [ + { + "name": "JobPosted", + "args": { + "id": "8", + "requester": "0x86D6C68408DDb2CC0d1cf4dFd6e07d3830600fAF", + "token": "0x0000000000000000000000000000000000000000", + "reward": "10000000000000000", + "mode": "0", + "specHash": "0xe39172c8a9a6c56862bc48d25c2b20f56c585d165d8140b9cd18da9784f1f5cd", + "deadline": "1790959871", + "pqcSettlement": false + }, + "blockNumber": 4446456, + "blockHash": "0x4f912d1702c83e1c6fdd864b75471c8f30a69f37d8decdbf121415285c94492f", + "timestamp": 1790959827, + "txHash": "0x2129c617c59cf4fce4f0bb03cfd4d1d97ff2ea256be637f553dd63093dc2cee9", + "from": "0x86D6C68408DDb2CC0d1cf4dFd6e07d3830600fAF", + "logIndex": 0 + }, + { + "name": "JobClaimed", + "args": { + "id": "8", + "provider": "0xeC2261CECBB06768F6db095822b429AF5c861E2e", + "providerBond": "4000000000000000" + }, + "blockNumber": 4446459, + "blockHash": "0x5e3fb425890cf5d8e65b0992db0b872cb06b62df2d3dbe404b1e73b805891df6", + "timestamp": 1790959829, + "txHash": "0x351e7248fc153fd6f46f1d5fd2480ec6428b1ce351b35232b9099d5e1cd6aec3", + "from": "0xeC2261CECBB06768F6db095822b429AF5c861E2e", + "logIndex": 0 + }, + { + "name": "JobRefunded", + "args": { + "id": "8", + "requester": "0x86D6C68408DDb2CC0d1cf4dFd6e07d3830600fAF", + "token": "0x0000000000000000000000000000000000000000", + "reward": "10000000000000000" + }, + "blockNumber": 4446540, + "blockHash": "0x269e3df7ecdcc85db01e702814eb766d235233eee90c0182179ddf7307c32cab", + "timestamp": 1790959877, + "txHash": "0xf041b9338843a0727acca19c794d940ec7d13df17dd17d88cc1c48da740c0a03", + "from": "0x86D6C68408DDb2CC0d1cf4dFd6e07d3830600fAF", + "logIndex": 0 + } + ], + "result": null, + "spec": { + "task": "keccak-chain", + "seed": "0xd2356607ad7de44861e4098fc8de3628ab454527539afeb302e6cbc03450d500", + "iters": 20000 + }, + "envelope": null + }, + "judecata": { + "verdict": "VALID", + "motive": [], + "randuri": [ + "2026-10-02T16:50:27.000Z #4446456 JobPosted by 0x86D6C684.. id=8 requester=0x86D6C684.. token=0x00000000.. reward=10000000000000000 mode=0 specHash=0xe39172c8.. deadline=1790959871 pqcSettlement=false", + "2026-10-02T16:50:29.000Z #4446459 JobClaimed by 0xeC2261CE.. id=8 provider=0xeC2261CE.. providerBond=4000000000000000", + "2026-10-02T16:51:17.000Z #4446540 JobRefunded by 0x86D6C684.. id=8 requester=0x86D6C684.. token=0x00000000.. reward=10000000000000000" + ], + "status": "Refunded", + "terminal": { + "status": "Refunded", + "payee": "0x86D6C68408DDb2CC0d1cf4dFd6e07d3830600fAF", + "amount": "10000000000000000", + "txHash": "0xf041b9338843a0727acca19c794d940ec7d13df17dd17d88cc1c48da740c0a03", + "blockHash": "0x269e3df7ecdcc85db01e702814eb766d235233eee90c0182179ddf7307c32cab" + }, + "replay": null + } + }, + "S5": { + "spec": { + "task": "keccak-chain", + "seed": "0x7fbe35a5bee832d3c35f100c82ebcc863a4d17ee1be045b5dfaba46aa4b93322", + "iters": 20000 + }, + "pasi": [], + "jobId": 9, + "date": { + "chainId": 28001, + "market": "0x4145d6f639436d840957F2D4B9f2e73f34F56B5D", + "jobId": "9", + "constants": { + "arbiter": "0x5521aC7371Afdbf6BE986B46Da4116fb256d9e58", + "governance": "0x86D6C68408DDb2CC0d1cf4dFd6e07d3830600fAF", + "arbitrationTimeout": 1209600, + "zkVerifier": "0x70099E62735500AA2F85B60C518551a57B202d54", + "pinnedProofSelector": "0x4388a21c" + }, + "job": { + "requester": "0x86D6C68408DDb2CC0d1cf4dFd6e07d3830600fAF", + "provider": "0x0000000000000000000000000000000000000000", + "token": "0x0000000000000000000000000000000000000000", + "reward": "0", + "providerBond": "0", + "specHash": "0xac9d0a395f1ae6e8ca7adebdd44e4454000c349e80feba2c16dc3e0749c9a9b7", + "resultHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "zkProgramVKey": "0x0000000000000000000000000000000000000000000000000000000000000000", + "mode": 0, + "status": 6, + "pqcSettlement": false, + "offchainResult": false, + "deadline": 1790959916, + "challengeWindow": 90, + "submittedAt": 0, + "disputedAt": 0 + }, + "events": [ + { + "name": "JobPosted", + "args": { + "id": "9", + "requester": "0x86D6C68408DDb2CC0d1cf4dFd6e07d3830600fAF", + "token": "0x0000000000000000000000000000000000000000", + "reward": "10000000000000000", + "mode": "0", + "specHash": "0xac9d0a395f1ae6e8ca7adebdd44e4454000c349e80feba2c16dc3e0749c9a9b7", + "deadline": "1790959916", + "pqcSettlement": false + }, + "blockNumber": 4446558, + "blockHash": "0xb3512a658a8969ec6e6516d19c9bd9d2c99134cc3d654ba5afac6da85ffe363f", + "timestamp": 1790959888, + "txHash": "0x5aba1b174fd5948b8ff555f0b4d4584607145914eec3ed1bdde00072d31ee1af", + "from": "0x86D6C68408DDb2CC0d1cf4dFd6e07d3830600fAF", + "logIndex": 0 + }, + { + "name": "JobRefunded", + "args": { + "id": "9", + "requester": "0x86D6C68408DDb2CC0d1cf4dFd6e07d3830600fAF", + "token": "0x0000000000000000000000000000000000000000", + "reward": "10000000000000000" + }, + "blockNumber": 4446614, + "blockHash": "0x6cb797489059f864e1e57a687cde487c0f8765945688cd673879c36e8be7e0e3", + "timestamp": 1790959920, + "txHash": "0xe13b6cdbb7bb49c2d74235eb3c014f793a9d62df079235a19adbe9c66020de21", + "from": "0x86D6C68408DDb2CC0d1cf4dFd6e07d3830600fAF", + "logIndex": 0 + } + ], + "result": null, + "spec": { + "task": "keccak-chain", + "seed": "0x7fbe35a5bee832d3c35f100c82ebcc863a4d17ee1be045b5dfaba46aa4b93322", + "iters": 20000 + }, + "envelope": null + }, + "judecata": { + "verdict": "VALID", + "motive": [], + "randuri": [ + "2026-10-02T16:51:28.000Z #4446558 JobPosted by 0x86D6C684.. id=9 requester=0x86D6C684.. token=0x00000000.. reward=10000000000000000 mode=0 specHash=0xac9d0a39.. deadline=1790959916 pqcSettlement=false", + "2026-10-02T16:52:00.000Z #4446614 JobRefunded by 0x86D6C684.. id=9 requester=0x86D6C684.. token=0x00000000.. reward=10000000000000000" + ], + "status": "Refunded", + "terminal": { + "status": "Refunded", + "payee": "0x86D6C68408DDb2CC0d1cf4dFd6e07d3830600fAF", + "amount": "10000000000000000", + "txHash": "0xe13b6cdbb7bb49c2d74235eb3c014f793a9d62df079235a19adbe9c66020de21", + "blockHash": "0x6cb797489059f864e1e57a687cde487c0f8765945688cd673879c36e8be7e0e3" + }, + "replay": null + } + } + }, + "desfasurare": { + "chainId": 28001, + "market": "0x4145d6f639436d840957F2D4B9f2e73f34F56B5D", + "deployTx": "0x8f45502e40a71d45550756fdcb3e4ed3af0532134212704f161fd2c4004d8ae2", + "block": 4445446, + "args": { + "ZK_VERIFIER": "0x70099E62735500AA2F85B60C518551a57B202d54", + "PINNED_PROOF_SELECTOR": "0x4388a21c", + "ARBITER": "0x5521aC7371Afdbf6BE986B46Da4116fb256d9e58", + "GOVERNANCE": "0x86D6C68408DDb2CC0d1cf4dFd6e07d3830600fAF" + }, + "artifactSourceSha256": "0x6db4d53dffb0afd79cfb41f973ac4d2ca82589ab7bdd206296b66b4c72dd4fe4", + "at": "2026-10-02T16:40:39.149Z", + "codeOk": true + }, + "rezumat": { + "verzi": 20, + "rosii": 0 + } +} \ No newline at end of file diff --git a/market-settlement/extrage-artefact.mjs b/market-settlement/extrage-artefact.mjs new file mode 100644 index 0000000..157b04c --- /dev/null +++ b/market-settlement/extrage-artefact.mjs @@ -0,0 +1,32 @@ +#!/usr/bin/env node +// extrage-artefact.mjs: the compiled AereComputeMarketV3 as ONE file beside this component, taken from the hardhat build-info of the +// contracts project (roadmap point 28, 2026-10-02): abi, creation and runtime bytecode, the immutable references WITH their names (so a +// reader can rebuild the exact runtime code of a deployment from its constructor arguments and compare it with eth_getCode), the +// compiler and its settings, and the SHA-256 of the Solidity source the build-info holds (checked equal to the source in the tree). +// Deterministic: the same build-info gives the same file. Refuses a build-info whose source differs from the tree. +// node extrage-artefact.mjs writes AereComputeMarketV3.json +import fs from 'node:fs'; +import path from 'node:path'; +import crypto from 'node:crypto'; +import { fileURLToPath } from 'node:url'; + +const AICI = path.dirname(fileURLToPath(import.meta.url)); +const RAD = path.resolve(AICI, '..', '..'); +const SOL = 'contracts/depin/AereComputeMarketV3.sol'; +const dbg = JSON.parse(fs.readFileSync(path.join(RAD, 'contracts', 'artifacts', SOL, 'AereComputeMarketV3.dbg.json'), 'utf8')); +const bi = JSON.parse(fs.readFileSync(path.resolve(path.join(RAD, 'contracts', 'artifacts', SOL), dbg.buildInfo.replace(/\\/g, '/')), 'utf8')); +const o = bi.output.contracts[SOL].AereComputeMarketV3; +const src = bi.input.sources[SOL].content.replace(/\r\n/g, '\n'); +const tree = fs.readFileSync(path.join(RAD, 'contracts', SOL), 'utf8').replace(/\r\n/g, '\n'); +if (src !== tree) { console.log('REFUZ: the source in the build-info differs from contracts/' + SOL + ' (recompile first)'); process.exit(1); } +const nume = {}; (function walk(x) { if (x && typeof x === 'object') { if (x.nodeType === 'VariableDeclaration' && x.mutability === 'immutable') nume[x.id] = { name: x.name, type: x.typeDescriptions.typeString }; for (const k in x) walk(x[k]); } })(bi.output.sources[SOL].ast); +const refs = o.evm.deployedBytecode.immutableReferences || {}; +const immutables = Object.fromEntries(Object.entries(refs).map(([id, pos]) => [nume[id].name, { type: nume[id].type, positions: pos }])); +const art = { + kind: 'aere-compute-market-v3-artifact', contract: 'AereComputeMarketV3', source: SOL, sourceSha256: '0x' + crypto.createHash('sha256').update(src).digest('hex'), + solc: bi.solcLongVersion, optimizer: bi.input.settings.optimizer, evmVersion: bi.input.settings.evmVersion || 'default', + abi: o.abi, bytecode: '0x' + o.evm.bytecode.object, deployedBytecode: '0x' + o.evm.deployedBytecode.object, immutables, + note: 'runtime code of a deployment = deployedBytecode with each immutable written at its positions as a 32-byte word (addresses right-aligned, bytes4 left-aligned); compare with eth_getCode', +}; +fs.writeFileSync(path.join(AICI, 'AereComputeMarketV3.json'), JSON.stringify(art, null, 1) + '\n'); +console.log(`AereComputeMarketV3.json: ${art.solc}, runtime ${(art.deployedBytecode.length - 2) / 2} bytes, immutables ${Object.keys(immutables).join(', ')}, source sha256 ${art.sourceSha256.slice(0, 18)}..`); diff --git a/market-settlement/piata.mjs b/market-settlement/piata.mjs new file mode 100644 index 0000000..3d598a9 --- /dev/null +++ b/market-settlement/piata.mjs @@ -0,0 +1,142 @@ +// piata.mjs: the dispute and settlement rail of the verifiable infrastructure market (roadmap master point 28, 2026-10-02), on what is +// live: AereComputeMarketV3 (escrow, provider bond, challenge window, dispute with a challenger bond, arbiter with a permissionless +// timeout, deadline reclaim), the AIP-23 execution envelope of the provider's result notarized on AereNotary (the chain's time for the +// delivery, under a post-quantum certified anchor), and the AIP-23 settlement receipt of the terminal payout. This file has three parts: +// 1. the deployment: the runtime code a market MUST have, rebuilt from the committed artifact and the constructor arguments +// (`codulAsteptat`), so a reader checks eth_getCode before trusting any event the market emitted; +// 2. the timeline: every event of a job with its block time and the sender of its transaction (`cronologie`), a JSON a reader can keep; +// 3. the JUDGE (`judeca`): pure rules over the timeline, no chain: deadlines, the challenge window, who resolved, that the terminal +// payout matches the state, that the result bytes hash to the on-chain commitment, that a REPLAY of the public spec agrees with +// whoever the arbiter sided with, and that the provider's notarized envelope names this result and existed before the window +// closed. Every rule carries a PAZA marker for the planting control. `chitanta` turns the terminal payout into an AIP-23 +// `settlement` envelope, verifiable with the reference verifier. +// ethers is injected (createRequire of the caller's ethers); the rest is node:crypto and the siblings beside this component. +import fs from 'node:fs'; +import path from 'node:path'; +import crypto from 'node:crypto'; +import { fileURLToPath } from 'node:url'; +import { buildProof } from '../proof-kinds/proof-kinds.mjs'; +import { ruleaza, rezultatHash, rezultatOcteti, specHash as specHashOf, keccak, canonical } from './sarcina.mjs'; + +const AICI = path.dirname(fileURLToPath(import.meta.url)); +export const ARTEFACT = path.join(AICI, 'AereComputeMarketV3.json'); +export const STATUS = ['None', 'Open', 'Claimed', 'Submitted', 'Disputed', 'Paid', 'Refunded', 'Slashed']; +export const MODE = ['REPLAY', 'ZK_VERIFIED', 'OPTIMISTIC']; +const H32 = /^0x[0-9a-f]{64}$/i; +const sha256 = (b) => '0x' + crypto.createHash('sha256').update(b).digest('hex'); + +export function incarcaArtefact(f = ARTEFACT) { + const a = JSON.parse(fs.readFileSync(f, 'utf8')); + if (a.kind !== 'aere-compute-market-v3-artifact' || !a.deployedBytecode || !a.immutables || !a.abi) throw new Error('not a market artifact: ' + f); + return a; +} +/** The runtime code of a deployment: the artifact's deployedBytecode with every immutable written at its positions. */ +export function codulAsteptat(a, args) { + const cod = Buffer.from(a.deployedBytecode.slice(2), 'hex'); + for (const [nume, im] of Object.entries(a.immutables)) { + const v = args[nume]; if (v === undefined) throw new Error('missing immutable ' + nume); + const w = Buffer.alloc(32); + if (/^address|^contract/.test(im.type)) Buffer.from(v.replace(/^0x/, '').padStart(40, '0'), 'hex').copy(w, 12); + else if (/^bytes(\d+)$/.test(im.type)) Buffer.from(v.replace(/^0x/, ''), 'hex').copy(w, 0); + else throw new Error('immutable type not handled: ' + im.type); + for (const p of im.positions) { if (p.length !== 32) throw new Error('immutable slot not 32 bytes'); w.copy(cod, p.start); } + } + return '0x' + cod.toString('hex'); +} +/** eth_getCode of the market equals the artifact with these constructor arguments; returns { ok, motiv }. */ +export async function verificaDesfasurarea({ provider, market, artifact, args }) { + const viu = (await provider.getCode(market)).toLowerCase(); + const asteptat = codulAsteptat(artifact, args).toLowerCase(); + if (viu === '0x') return { ok: false, motiv: 'no code at ' + market }; + if (viu !== asteptat) return { ok: false, motiv: `the code at ${market} is not AereComputeMarketV3 with these immutables (${viu.length / 2 - 1} vs ${asteptat.length / 2 - 1} bytes, first difference at byte ${[...viu].findIndex((c, i) => c !== asteptat[i]) >> 1})` }; + return { ok: true, motiv: 'runtime code equals the artifact (' + (viu.length / 2 - 1) + ' bytes) with ZK_VERIFIER, PINNED_PROOF_SELECTOR, ARBITER, GOVERNANCE as given' }; +} +export const contract = (ethers, provider, market, artifact, signer = null) => new ethers.Contract(market, artifact.abi, signer || provider); +const s = (v) => (typeof v === 'bigint' ? v.toString() : v); +export function jobDinLant(j) { + return { requester: j.requester, provider: j.provider, token: j.token, reward: s(j.reward), providerBond: s(j.providerBond), specHash: j.specHash, resultHash: j.resultHash, zkProgramVKey: j.zkProgramVKey, + mode: Number(j.mode), status: Number(j.status), pqcSettlement: j.pqcSettlement, offchainResult: j.offchainResult, deadline: Number(j.deadline), challengeWindow: Number(j.challengeWindow), submittedAt: Number(j.submittedAt), disputedAt: Number(j.disputedAt) }; +} +/** The timeline of a job: its state, its constants, and every event (with block time and tx sender), oldest first. */ +export async function cronologie({ ethers, provider, market, artifact, jobId, fromBlock = 0, spec = null, envelope = null }) { + const c = contract(ethers, provider, market, artifact); + const [net, job, arbiter, governance, timeout, zk, pin] = await Promise.all([provider.getNetwork(), c.getJob(jobId), c.ARBITER(), c.GOVERNANCE(), c.ARBITRATION_TIMEOUT(), c.ZK_VERIFIER(), c.PINNED_PROOF_SELECTOR()]); + const nume = artifact.abi.filter((x) => x.type === 'event' && x.inputs[0] && x.inputs[0].name === 'id').map((x) => x.name); + const brute = []; + for (const n of nume) for (const l of await c.queryFilter(c.filters[n](jobId), fromBlock, 'latest')) brute.push(l); + brute.sort((a, b) => a.blockNumber - b.blockNumber || a.index - b.index); + const blocuri = new Map(), txs = new Map(); + const events = []; + for (const l of brute) { + if (!blocuri.has(l.blockHash)) blocuri.set(l.blockHash, await provider.getBlock(l.blockHash)); + if (!txs.has(l.transactionHash)) txs.set(l.transactionHash, await provider.getTransaction(l.transactionHash)); + const b = blocuri.get(l.blockHash), t = txs.get(l.transactionHash); + const args = {}; l.fragment.inputs.forEach((inp, i) => { args[inp.name] = s(l.args[i]); }); + events.push({ name: l.fragment.name, args, blockNumber: l.blockNumber, blockHash: l.blockHash, timestamp: b.timestamp, txHash: l.transactionHash, from: t.from, logIndex: l.index }); + } + const sub = events.find((e) => e.name === 'ResultSubmitted'); + return { chainId: Number(net.chainId), market, jobId: String(jobId), constants: { arbiter, governance, arbitrationTimeout: Number(timeout), zkVerifier: zk, pinnedProofSelector: pin }, + job: jobDinLant(job), events, result: sub ? sub.args.result : null, spec, envelope }; +} + +// ----- the judge: pure rules over a timeline ----- +const ok = (m, cond, text) => { if (!cond) m.push(text); return !!cond; }; +const low = (x) => String(x || '').toLowerCase(); +export function judeca(d) { + const motive = [], randuri = []; const j = d.job, ev = d.events || []; const un = (n) => ev.find((e) => e.name === n); const toate = (n) => ev.filter((e) => e.name === n); + const t = (e) => (e ? e.timestamp : null); + if (!j || !ev.length) return { verdict: 'INCOMPLETE', motive: ['no job or no events'], randuri }; + for (const e of ev) randuri.push(`${new Date(e.timestamp * 1000).toISOString()} #${e.blockNumber} ${e.name} by ${e.from.slice(0, 10)}.. ${Object.entries(e.args).filter(([k]) => k !== 'result').map(([k, v]) => k + '=' + (H32.test(String(v)) ? String(v).slice(0, 10) + '..' : String(v).length > 20 ? String(v).slice(0, 10) + '..' : v)).join(' ')}`); + const posted = un('JobPosted'), claimed = un('JobClaimed'), submitted = un('ResultSubmitted') || un('ResultReferenced'), disputed = un('JobDisputed'), resolved = un('DisputeResolved'), timedOut = un('DisputeTimedOut'), paid = un('JobPaid'), refunded = un('JobRefunded'), slashed = un('JobSlashed'); + // R0 the posting matches the job (the reward is compared through the payout events: the contract zeroes j.reward on settlement) + ok(motive, posted && low(posted.args.requester) === low(j.requester) && low(posted.args.specHash) === low(j.specHash) && Number(posted.args.deadline) === j.deadline && (j.reward === '0' || posted.args.reward === j.reward), 'the JobPosted event does not match the job (requester, reward, specHash, deadline)'); + // R1 deadlines: a claim and a submission only up to the deadline + if (claimed) ok(motive, t(claimed) <= j.deadline /*PAZA:termen*/, 'the job was claimed after its deadline'); + if (submitted) ok(motive, t(submitted) <= j.deadline && t(submitted) === j.submittedAt /*PAZA:termen*/, 'the result was submitted after the deadline, or submittedAt does not match the event'); + if (refunded && claimed && !submitted && !disputed) ok(motive, t(refunded) > j.deadline /*PAZA:termen*/, 'the escrow was reclaimed as expired before the deadline'); + // R2 the challenge window: a dispute strictly inside it, a finalize (by anyone but the requester) only after it + if (disputed) ok(motive, submitted && t(disputed) < j.submittedAt + j.challengeWindow /*PAZA:fereastra*/, 'the dispute was raised after the challenge window closed'); + if (paid && !resolved && submitted) ok(motive, low(paid.from) === low(j.requester) || t(paid) >= j.submittedAt + j.challengeWindow /*PAZA:fereastra*/, 'the provider was paid inside the challenge window by someone other than the requester (acceptResult is the requester\'s)'); + // R3 who resolved: the arbiter, or the permissionless timeout after ARBITRATION_TIMEOUT + if (resolved) ok(motive, low(resolved.from) === low(d.constants.arbiter) /*PAZA:arbitru*/, 'the dispute was resolved by an address that is not the ARBITER'); + if (timedOut) ok(motive, disputed && t(timedOut) >= j.disputedAt + d.constants.arbitrationTimeout /*PAZA:arbitru*/, 'the dispute was timed out before ARBITRATION_TIMEOUT'); + if (resolved || timedOut) ok(motive, !!disputed, 'a resolution without a dispute'); + // R4 the terminal payout matches the state + const st = STATUS[j.status]; let terminal = null; + if (st === 'Paid') { const okP = paid && low(paid.args.provider) === low(j.provider) && paid.args.reward === posted.args.reward && (!claimed || paid.args.bondReturned === claimed.args.providerBond) && (!resolved || resolved.args.providerWon === true) /*PAZA:plata*/; ok(motive, okP, 'status Paid without a matching JobPaid (provider, reward, bond returned, providerWon)'); terminal = paid && { status: st, payee: paid.args.provider, amount: paid.args.reward, txHash: paid.txHash, blockHash: paid.blockHash }; } + else if (st === 'Slashed') { const okS = slashed && disputed && resolved && resolved.args.providerWon === false && low(slashed.args.challenger) === low(disputed.args.challenger) && (!claimed || slashed.args.slashedProviderBond === claimed.args.providerBond) /*PAZA:plata*/; ok(motive, okS, 'status Slashed without a matching JobSlashed (challenger, provider bond) and DisputeResolved(false)'); terminal = slashed && { status: st, payee: slashed.args.challenger, amount: slashed.args.slashedProviderBond, refundedTo: j.requester, txHash: slashed.txHash, blockHash: slashed.blockHash }; } + else if (st === 'Refunded') { const okR = refunded && low(refunded.args.requester) === low(j.requester) && refunded.args.reward === posted.args.reward /*PAZA:plata*/; ok(motive, okR, 'status Refunded without a matching JobRefunded (requester, reward)'); terminal = refunded && { status: st, payee: refunded.args.requester, amount: refunded.args.reward, txHash: refunded.txHash, blockHash: refunded.blockHash }; } + ok(motive, j.status !== 5 || j.reward === '0', 'a paid job still holds a reward'); + // R5 the result bytes hash to the on-chain commitment + if (d.result && submitted) ok(motive, keccak(Buffer.from(d.result.slice(2), 'hex')) === low(j.resultHash) && low(submitted.args.resultHash) === low(j.resultHash) /*PAZA:rezultat*/, 'the submitted bytes do not hash to the job\'s resultHash'); + // R6 REPLAY: the public spec recomputed; the arbiter's decision must agree with the recomputation + let replay = null; + if (d.spec && d.result && submitted) { + ok(motive, specHashOf(d.spec) === low(j.specHash), 'the public spec does not hash to the job\'s specHash'); + try { const r = ruleaza(d.spec); const corect = rezultatHash(r) === low(j.resultHash); replay = { recomputedHash: rezultatHash(r), providerRight: corect }; + if (disputed) { replay.challengerRecomputedRight = low(disputed.args.recomputedResultHash) === rezultatHash(r); } + if (resolved) ok(motive, resolved.args.providerWon === corect /*PAZA:replay*/, `the arbiter sided with the ${resolved.args.providerWon ? 'provider' : 'challenger'} but the replay says the provider is ${corect ? 'right' : 'wrong'}`); + if (st === 'Paid' && !resolved) ok(motive, corect /*PAZA:replay*/, 'the provider was paid for a result the replay does not reproduce (no one disputed in time)'); + } catch (e) { motive.push('the replay could not run: ' + e.message); } + } + // R7 the provider's envelope names this result and existed before the window closed + if (d.envelope) { + const e = d.envelope, stmt = e.statement || {}; + const okE = e.kind === 'aere-proof-of-execution-attestation' && low(stmt.outputHash) === low(j.resultHash) && low(stmt.inputHash) === low(j.specHash) && sha256(Buffer.from(JSON.stringify(stmt), 'utf8')) === low(e.statementHash) /*PAZA:dovada*/; + ok(motive, okE, 'the execution envelope does not name this job\'s specHash/resultHash, or its statementHash is not its statement\'s'); + if (e.notarization && submitted) ok(motive, Number(e.notarization.firstSeen) <= j.submittedAt + j.challengeWindow /*PAZA:dovada*/, 'the envelope was notarized only after the challenge window closed'); + } + const terminalStatus = ['Paid', 'Refunded', 'Slashed'].includes(st); + return { verdict: motive.length ? 'INVALID' : terminalStatus ? 'VALID' : 'INCOMPLETE', motive, randuri, status: st, terminal, replay }; +} +/** The AIP-23 settlement receipt of a terminal job: the payout transaction, the parties, the amount, the instruction (market, job, status). */ +export function chitanta(d, { createdAt = new Date().toISOString() } = {}) { + const r = judeca(d); if (r.verdict !== 'VALID' || !r.terminal) throw new Error('no valid terminal settlement to receipt: ' + (r.motive[0] || r.verdict)); + const t = r.terminal; + return buildProof('settlement', { chainId: d.chainId, txHash: t.txHash, blockHash: t.blockHash, from: d.market, to: t.payee, amount: t.amount, asset: 'native', instruction: Buffer.from(canonical({ market: d.market, jobId: d.jobId, status: t.status, resultHash: d.job.resultHash }), 'utf8'), createdAt }); +} +/** The provider's execution envelope for a result (spec in, result out), to notarize before submitting. */ +export function plicExecutie({ spec, result, programSha256, createdAt = new Date().toISOString() }) { + return buildProof('execution', { program: spec.task, inputHash: specHashOf(spec), outputHash: rezultatHash(result), programSha256, exitCode: 0, createdAt }); +} +export { ruleaza, rezultatHash, rezultatOcteti, specHashOf as specHash, canonical }; diff --git a/market-settlement/proba-judecata.mjs b/market-settlement/proba-judecata.mjs new file mode 100644 index 0000000..3f0a8c5 --- /dev/null +++ b/market-settlement/proba-judecata.mjs @@ -0,0 +1,71 @@ +#!/usr/bin/env node +// proba-judecata.mjs: the judge of the market settlement (piata.mjs) in the laboratory, without a chain, on the timelines the live run +// recorded (dovezi/piata-28001-*.json, the newest): the honest timelines are VALID for their named status, and nine forged ones are +// INVALID for their named reason. --control-negativ plants every PAZA marker out, one at a time, in a copy of piata.mjs and requires +// the forged fixture it guards to be accepted: a check that cannot be made to fail is not a check. +// Exit 0 when every row is as named; 1 otherwise; 2 when no evidence file exists (run proba-piata-28001.mjs first). +// node proba-judecata.mjs [--control-negativ] env: AERE_PIATA_MODUL (the module under test; the control sets its planted copy) +import fs from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath, pathToFileURL } from 'node:url'; + +const AICI = path.dirname(fileURLToPath(import.meta.url)); +const MODUL = process.env.AERE_PIATA_MODUL || path.join(AICI, 'piata.mjs'); +const control = process.argv.includes('--control-negativ'); +const dovezi = fs.existsSync(path.join(AICI, 'dovezi')) ? fs.readdirSync(path.join(AICI, 'dovezi')).filter((f) => /^piata-28001-.*\.json$/.test(f)).sort() : []; +if (!dovezi.length) { console.log('NEMASURAT: no dovezi/piata-28001-*.json (run proba-piata-28001.mjs first)'); process.exit(2); } +const D = JSON.parse(fs.readFileSync(path.join(AICI, 'dovezi', dovezi[dovezi.length - 1]), 'utf8')); +const P = await import(pathToFileURL(MODUL).href + '?t=' + Date.now()); +const clona = (x) => JSON.parse(JSON.stringify(x)); +const date = (s) => { const x = D.scenarii[s]; if (!x || !x.date) throw new Error('scenario ' + s + ' has no timeline in the evidence'); return clona(x.date); }; +const ev = (d, n) => d.events.find((e) => e.name === n); + +/** The fixtures: honest timelines (VALID, named status) and forged ones (INVALID, named reason); `paza` names the marker that guards each forgery. */ +export function fixturi(P) { + const F = []; + for (const [s, st] of [['S1', 'Paid'], ['S2', 'Slashed'], ['S3', 'Paid'], ['S4', 'Refunded'], ['S5', 'Refunded']]) F.push({ nume: `${s} the recorded timeline is VALID with status ${st}`, asteptat: 'VALID', r: () => { const r = P.judeca(date(s)); return { verdict: r.verdict, detail: r.status + (r.replay ? ' replay providerRight=' + r.replay.providerRight : '') + '; ' + r.motive.join('; ') }; } }); + F.push({ nume: 'N1 S1 finalized INSIDE the window by a third party (timestamp moved back)', asteptat: 'INVALID', paza: 'fereastra', r: () => { const d = date('S1'); ev(d, 'JobPaid').timestamp = d.job.submittedAt + 1; return v(P.judeca(d)); } }); + F.push({ nume: 'N2 S2 dispute raised AFTER the window (timestamp moved forward)', asteptat: 'INVALID', paza: 'fereastra', r: () => { const d = date('S2'); ev(d, 'JobDisputed').timestamp = d.job.submittedAt + d.job.challengeWindow + 5; return v(P.judeca(d)); } }); + F.push({ nume: 'N3 S2 resolved by an address that is not the arbiter', asteptat: 'INVALID', paza: 'arbitru', r: () => { const d = date('S2'); ev(d, 'DisputeResolved').from = d.job.requester; return v(P.judeca(d)); } }); + F.push({ nume: 'N4 S1 claimed after the deadline (deadline moved before the claim)', asteptat: 'INVALID', paza: 'termen', r: () => { const d = date('S1'); d.job.deadline = ev(d, 'JobClaimed').timestamp - 1; ev(d, 'JobPosted').args.deadline = String(d.job.deadline); return v(P.judeca(d)); } }); + F.push({ nume: 'N5 S1 paid to someone who is not the provider', asteptat: 'INVALID', paza: 'plata', r: () => { const d = date('S1'); ev(d, 'JobPaid').args.provider = d.job.requester; return v(P.judeca(d)); } }); + F.push({ nume: 'N6 S1 result bytes that do not hash to the commitment', asteptat: 'INVALID', paza: 'rezultat', r: () => { const d = date('S1'); d.result = d.result.slice(0, -2) + (d.result.endsWith('00') ? '01' : '00'); return v(P.judeca(d)); } }); + F.push({ nume: 'N7 S3 the arbiter sided with the provider although the replay contradicts it (spec swapped to another seed)', asteptat: 'INVALID', paza: 'replay', r: () => { const d = date('S3'); d.spec = { ...d.spec, seed: '0x' + 'ab'.repeat(32) }; d.job.specHash = P.specHash(d.spec); ev(d, 'JobPosted').args.specHash = d.job.specHash; return v(P.judeca(d)); } }); + F.push({ nume: 'N8 S1 the envelope names another result (outputHash changed, statementHash kept)', asteptat: 'INVALID', paza: 'dovada', r: () => { const d = date('S1'); d.envelope.statement.outputHash = '0x' + 'cc'.repeat(32); return v(P.judeca(d)); } }); + F.push({ nume: 'N9 S1 the envelope notarized only after the window closed', asteptat: 'INVALID', paza: 'dovada', r: () => { const d = date('S1'); d.envelope.notarization.firstSeen = d.job.submittedAt + d.job.challengeWindow + 1; return v(P.judeca(d)); } }); + F.push({ nume: 'N10 S4 reclaimed as expired BEFORE the deadline', asteptat: 'INVALID', paza: 'termen', r: () => { const d = date('S4'); ev(d, 'JobRefunded').timestamp = d.job.deadline - 1; return v(P.judeca(d)); } }); + F.push({ nume: 'R1 the settlement receipt of S1 is an AIP-23 settlement envelope naming the payout tx and the provider', asteptat: 'VALID', r: () => { const d = date('S1'); const c = P.chitanta(d); const t = ev(d, 'JobPaid'); return { verdict: c.kind === 'aere-proof-of-settlement-attestation' && c.statement.txHash === t.txHash && c.statement.to.toLowerCase() === d.job.provider.toLowerCase() && c.statement.chainId === 28001 ? 'VALID' : 'INVALID', detail: c.statementHash.slice(0, 18) + '..' }; } }); + return F; +} +const v = (r) => ({ verdict: r.verdict, detail: r.motive.join('; ') }); + +if (!control) { + let verzi = 0, rosii = 0, stricate = 0; + for (const f of fixturi(P)) { + let r; try { r = f.r(); } catch (e) { r = { verdict: 'STRICAT', detail: String(e.message).slice(0, 160) }; } + const stare = r.verdict === 'STRICAT' ? 'STRICAT' : r.verdict === f.asteptat ? 'VERDE' : 'ROSU'; stare === 'VERDE' ? verzi++ : stare === 'ROSU' ? rosii++ : stricate++; + console.log(` [${stare.padEnd(7)}] ${f.nume}: ${r.verdict}${r.detail ? ' (' + r.detail.slice(0, 150) + ')' : ''}`); + } + console.log(`\nmarket judge (evidence ${dovezi[dovezi.length - 1]}): ${verzi} VERDE, ${rosii} ROSU, ${stricate} STRICAT`); + process.exitCode = rosii || stricate ? 1 : 0; +} else { + const SURSA = fs.readFileSync(MODUL, 'utf8'); const marcaje = ['termen', 'fereastra', 'arbitru', 'plata', 'rezultat', 'replay', 'dovada']; let bune = 0; + for (const m of marcaje) { + const copie = path.join(AICI, `_plantat-piata-${process.pid}-${m}.mjs`); const n = SURSA.split(`/*PAZA:${m}*/`).length - 1; const tinte = fixturi(P).filter((f) => f.paza === m); + let stare, detaliu; + try { + if (n < 1 || !tinte.length) { stare = 'STRICAT'; detaliu = `marker ${n} times, ${tinte.length} fixtures`; } + else { + fs.writeFileSync(copie, SURSA.split(`/*PAZA:${m}*/`).join("|| String(1) === '1' /*PLANTAT*/")); + const Q = await import(pathToFileURL(copie).href + '?t=' + Date.now()); const fx = fixturi(Q); const rez = []; + for (const t of tinte) { const f = fx.find((x) => x.nume === t.nume); const r = f.r(); rez.push(`${t.nume.split(' ')[0]}:${r.verdict}`); } + const toate = rez.every((x) => x.endsWith(':VALID')); stare = toate ? 'VERDE' : 'ROSU'; detaliu = (toate ? 'the forged fixture is accepted with the check planted out: ' : 'the planting did not change the verdict: ') + rez.join(' '); + } + } catch (e) { stare = 'STRICAT'; detaliu = String(e.message).slice(0, 160); } finally { fs.rmSync(copie, { force: true }); } + if (stare === 'VERDE') bune++; + console.log(` [${stare.padEnd(7)}] PAZA:${m} (${n} marker${n === 1 ? '' : 's'}) ${detaliu}`); + } + const ramase = fs.readdirSync(AICI).filter((f) => f.startsWith('_plantat-piata-')); + console.log(`CONTROL: ${bune} of ${marcaje.length} checks proven load-bearing${ramase.length ? '; copies left: ' + ramase.join(',') : ''}`); + process.exitCode = bune === marcaje.length && !ramase.length ? 0 : 1; +} diff --git a/market-settlement/proba-piata-28001.mjs b/market-settlement/proba-piata-28001.mjs new file mode 100644 index 0000000..e70bd66 --- /dev/null +++ b/market-settlement/proba-piata-28001.mjs @@ -0,0 +1,170 @@ +#!/usr/bin/env node +// proba-piata-28001.mjs: the complete market flow MEASURED on testnet 28001 (roadmap point 28): order -> proof -> dispute with a deadline +// -> settlement, on AereComputeMarketV3 deployed from the committed artifact, with test keys only (the requester's key from +// AERE_TESTNET_KEY_FILE; the provider's and the arbiter's derived from it, never printed, funded from it). Never chain 2800. +// S1 happy path post (escrow) -> claim (bond) -> compute -> execution envelope NOTARIZED -> submit -> finalize refused inside the +// window (WindowOpen) -> window passes -> dispute refused (WindowClosed) -> finalize by a third party -> Paid; +// the judge VALID; the envelope read back under a post-quantum certified anchor; the AIP-23 settlement receipt +// S2 dispute upheld post -> claim -> a WRONG result -> the requester recomputes and disputes (bond) -> timeout refused +// (ArbitrationTimeoutNotPassed), a non-arbiter refused (NotArbiter) -> the arbiter rules against the provider -> Slashed +// S3 dispute lost post -> claim -> a correct result -> a bad-faith dispute -> the arbiter rules for the provider -> Paid, challenger forfeits +// S4 deadline post (short deadline) -> claim -> no result -> reclaim refused before the deadline -> after it, reclaimExpired -> Refunded +// S5 open job post (short deadline) -> after it, claim refused (DeadlinePassed) -> cancelJob -> Refunded +// Every scenario's timeline is judged by piata.mjs (pure rules) and saved in dovezi/ for the offline laboratory (proba-judecata.mjs). +// Exit 0 when every row is as named; 1 otherwise; 2 when the chain, the key or ethers are missing. +// AERE_TESTNET_KEY_FILE= AERE_ETHERS_DIR= node proba-piata-28001.mjs [--fereastra 90] [--piata 0x..] +import fs from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import crypto from 'node:crypto'; +import { createRequire } from 'node:module'; +import { spawnSync } from 'node:child_process'; +import { fileURLToPath } from 'node:url'; +import { incarcaArtefact, verificaDesfasurarea, contract, cronologie, judeca, chitanta, plicExecutie, ruleaza, rezultatOcteti, rezultatHash, specHash } from './piata.mjs'; +import { specNou, programSha256 } from './sarcina.mjs'; +import { notarizeEnvelope } from '../agents/agent-ancora.mjs'; + +const AICI = path.dirname(fileURLToPath(import.meta.url)); +const RAD = path.resolve(AICI, '..', '..'); +const a = process.argv.slice(2); const opt = (k, d) => { const i = a.indexOf(k); return i >= 0 ? a[i + 1] : d; }; +const RPC = process.env.AERE_TESTNET_RPC || 'https://testnet-rpc.aere.network'; +const KF = process.env.AERE_TESTNET_KEY_FILE || path.join(RAD, 'tools', 'aere-quantum-shield', 'dovezi-l1', '.chei', 'cheie-de-proba-28001.key'); +const ETHERS_DIR = process.env.AERE_ETHERS_DIR || path.join(RAD, 'contracts'); +const VERIFY_PROOF = process.env.AERE_VERIFY_PROOF || path.join(RAD, 'verificator-falcon', 'verify-proof.mjs'); +const FEREASTRA = Number(opt('--fereastra', 90)); +const NOTAR_28001 = '0x70099E62735500AA2F85B60C518551a57B202d54'; +const PIN = '0x4388a21c'; +const DOVEZI = path.join(AICI, 'dovezi'); fs.mkdirSync(DOVEZI, { recursive: true }); +const DESF = path.join(AICI, 'desfasurare-28001.json'); +const nem = (m) => { console.log('NEMASURAT: ' + m); process.exit(2); }; +let verzi = 0, rosii = 0; const cer = (n, c, d = '') => { console.log(` [${c ? 'VERDE ' : 'ROSU '}] ${n}${d ? ' (' + String(d).slice(0, 200) + ')' : ''}`); c ? verzi++ : rosii++; }; + +if (!fs.existsSync(KF)) nem('no test key at ' + KF + ' (AERE_TESTNET_KEY_FILE)'); +let ethers; try { ({ ethers } = createRequire(path.join(ETHERS_DIR, 'package.json'))('ethers')); } catch (e) { nem('ethers not loadable from ' + ETHERS_DIR + ': ' + e.message); } +const cheia = (f) => { const l = fs.readFileSync(f, 'utf8').split(/\r?\n/).map((x) => x.trim()).find((x) => /^(d|PRIVATE_KEY)=/.test(x)) || ''; const h = l.replace(/^(d|PRIVATE_KEY)=/, '').replace(/^0x/, ''); if (!/^[0-9a-fA-F]{1,64}$/.test(h)) nem('the key file has no d= line'); return '0x' + h.padStart(64, '0'); }; +const provider = new ethers.JsonRpcProvider(RPC, undefined, { staticNetwork: false }); +const chainId = Number((await provider.getNetwork()).chainId); if (chainId !== 28001) nem(`the RPC serves chain ${chainId}; this flow runs only on testnet 28001`); +const req = new ethers.Wallet(cheia(KF), provider); +const deriva = (rol) => new ethers.Wallet('0x' + crypto.createHash('sha256').update(req.privateKey + ':' + rol).digest('hex'), provider); // derived, never printed +const prov = deriva('provider'), arb = deriva('arbiter'); +const art = incarcaArtefact(); +const E = (n) => ethers.parseEther(n); +const ora = async () => (await provider.getBlock('latest')).timestamp; +const asteapta = async (ts, ce) => { process.stdout.write(` waiting for chain time >= ${ts} (${ce})`); while ((await ora()) < ts) { await new Promise((r) => setTimeout(r, 3000)); process.stdout.write('.'); } console.log(''); }; +const tx = async (nume, p) => { const r = await (await p).wait(1, 180000); if (!r || r.status !== 1) throw new Error(nume + ' failed'); console.log(` ${nume}: tx ${r.hash.slice(0, 18)}.. block ${r.blockNumber} gas ${r.gasUsed}`); return r; }; +// a refusal by a NAMED custom error (static call), not just "it reverted" +const refuza = async (nume, fn, eroare, c) => { try { await fn(); return cer(nume, false, 'did not revert'); } catch (e) { let n = e.revert && e.revert.name; if (!n && e.data) { try { n = c.interface.parseError(e.data).name; } catch {} } if (!n && e.info && e.info.error && e.info.error.data) { try { n = c.interface.parseError(e.info.error.data).name; } catch {} } cer(nume, n === eroare, 'reverted with ' + (n || String(e.shortMessage || e.message).slice(0, 80))); } }; +const verifyProof = (env, rpc = null) => { const f = path.join(os.tmpdir(), 'piata-' + crypto.randomUUID() + '.json'); fs.writeFileSync(f, JSON.stringify(env)); try { const r = spawnSync(process.execPath, [VERIFY_PROOF, f, '--json', ...(rpc ? ['--rpc', rpc, '--chain', '28001'] : [])], { encoding: 'utf8', timeout: 300000 }); try { return JSON.parse(r.stdout); } catch { return null; } } finally { fs.rmSync(f, { force: true }); } }; +const dovada = { la: new Date().toISOString(), chainId, rpc: RPC, fereastra: FEREASTRA, scenarii: {} }; + +// ----- deployment (reused when the code at the recorded address is the artifact with our immutables) ----- +const ARGS = { ZK_VERIFIER: NOTAR_28001, PINNED_PROOF_SELECTOR: PIN, ARBITER: arb.address, GOVERNANCE: req.address }; +let piata = opt('--piata', null); +if (!piata && fs.existsSync(DESF)) { const d = JSON.parse(fs.readFileSync(DESF, 'utf8')); if (d.chainId === chainId) piata = d.market; } +if (piata) { const v = await verificaDesfasurarea({ provider, market: piata, artifact: art, args: ARGS }); if (!v.ok) { console.log(' the recorded market does not verify (' + v.motiv + '); deploying anew'); piata = null; } } +if (!piata) { + console.log(` deploying AereComputeMarketV3 from the artifact (${art.solc}; ZK_VERIFIER = AereNotary 28001: a contract with code, so ZK_VERIFIED jobs can never pay here; pin ${PIN})`); + const f = new ethers.ContractFactory(art.abi, art.bytecode, req); + const c = await f.deploy(ARGS.ZK_VERIFIER, ARGS.ARBITER, ARGS.GOVERNANCE, ARGS.PINNED_PROOF_SELECTOR); const rc = await c.deploymentTransaction().wait(1, 180000); + piata = await c.getAddress(); + fs.writeFileSync(DESF, JSON.stringify({ chainId, market: piata, deployTx: rc.hash, block: rc.blockNumber, args: ARGS, artifactSourceSha256: art.sourceSha256, at: new Date().toISOString() }, null, 1)); + console.log(` deployed at ${piata}, tx ${rc.hash.slice(0, 18)}.. block ${rc.blockNumber} gas ${rc.gasUsed}`); +} +const desf = JSON.parse(fs.readFileSync(DESF, 'utf8')); +const vd = await verificaDesfasurarea({ provider, market: piata, artifact: art, args: ARGS }); +cer('D1 the market\'s runtime code is the committed artifact with ZK_VERIFIER, pin, ARBITER, GOVERNANCE as recorded', vd.ok, vd.motiv); +dovada.desfasurare = { ...desf, codeOk: vd.ok }; +// ----- funding the derived keys from the requester's test key ----- +for (const [w, n, min] of [[prov, 'provider', '0.06'], [arb, 'arbiter', '0.03']]) { if ((await provider.getBalance(w.address)) < E(min)) await tx('fund ' + n, req.sendTransaction({ to: w.address, value: E(min) })); } +const C = (w) => contract(ethers, provider, piata, art, w); +const posteaza = async (spec, { deadlineIn = 600, window = FEREASTRA, reward = '0.01', bond = '0.004' } = {}) => { + const deadline = (await ora()) + deadlineIn; + const r = await tx('postJob', C(req).postJob({ token: ethers.ZeroAddress, reward: E(reward), providerBond: E(bond), specHash: specHash(spec), zkProgramVKey: ethers.ZeroHash, mode: 0, deadline, challengeWindow: window, pqcSettlement: false, offchainResult: false }, { value: E(reward) })); + const id = Number(C(req).interface.parseLog(r.logs.find((l) => l.address.toLowerCase() === piata.toLowerCase())).args.id); + return { id, deadline, bond: E(bond) }; +}; +const scenariu = async (nume, titlu, fn) => { console.log(`\n${nume} ${titlu}`); const spec = specNou({ iters: 20000 }); const s = { spec, pasi: [] }; dovada.scenarii[nume] = s; try { await fn(spec, s); } catch (e) { cer(nume + ' did not break', false, e.shortMessage || e.message); } }; +const judecaSiSalveaza = async (nume, s, id, extra = {}) => { const d = await cronologie({ ethers, provider, market: piata, artifact: art, jobId: id, fromBlock: desf.block, spec: s.spec, envelope: extra.envelope || null }); const r = judeca(d); s.date = d; s.judecata = r; for (const l of r.randuri) console.log(' ' + l); cer(`${nume} the judge on the timeline: VALID, status ${r.status}${r.replay ? ', replay ' + (r.replay.providerRight ? 'confirms' : 'contradicts') + ' the provider' : ''}`, r.verdict === 'VALID', r.motive.join('; ')); return { d, r }; }; + +try { + await scenariu('S1', 'happy path: order -> proof notarized -> submit -> window -> finalize -> Paid', async (spec, s) => { + const { id } = await posteaza(spec); s.jobId = id; + await tx('claimJob (provider, bond)', C(prov).claimJob(id, '0x', { value: E('0.004') })); + const t0 = Date.now(); const rez = ruleaza(spec); s.computeMs = Date.now() - t0; + const env = plicExecutie({ spec, result: rez, programSha256: programSha256() }); + // one notarization formula for the whole house (agents/agent-ancora.mjs): it reads the key from a file, so the provider's derived + // key goes through a 0600 temp file that lives only for this call + const kt = path.join(os.tmpdir(), 'piata-prov-' + process.pid + '.key'); fs.writeFileSync(kt, 'd=' + prov.privateKey.slice(2) + '\n', { mode: 0o600 }); + let n; try { n = await notarizeEnvelope({ envelope: env, kind: 'aere-proof-of-execution', rpc: RPC, keyFile: kt, ethers }); } finally { fs.rmSync(kt, { force: true }); } + if (!n.ok) throw new Error('notarization of the execution envelope: ' + n.motiv); + const notarizat = n.envelope; console.log(` notarized the execution envelope (provider): firstSeen ${notarizat.notarization.firstSeen}${notarizat.notarization.txHash ? ', tx ' + notarizat.notarization.txHash.slice(0, 18) + '..' : ''}`); + s.envelope = notarizat; + await tx('submitResult (provider)', C(prov).submitResult(id, rezultatOcteti(rez))); + await refuza('S1 finalize inside the window is refused: WindowOpen', () => C(arb).finalize.staticCall(id, '0x'), 'WindowOpen', C(arb)); + const j = await C(req).getJob(id); await asteapta(Number(j.submittedAt) + FEREASTRA, 'the challenge window'); + await refuza('S1 a dispute after the window is refused: WindowClosed', () => C(req).dispute.staticCall(id, rezultatHash(rez), { value: E('0.004') }), 'WindowClosed', C(req)); + const before = await provider.getBalance(prov.address); + await tx('finalize (a third party: the arbiter key as "anyone")', C(arb).finalize(id, '0x')); + const after = await provider.getBalance(prov.address); + cer('S1 the provider received reward + bond (0.014 tAERE) at finalize', after - before === E('0.014'), ethers.formatEther(after - before) + ' tAERE'); + const { d, r } = await judecaSiSalveaza('S1', s, id, { envelope: notarizat }); + let v = null; for (let k = 0; k < 24; k++) { v = verifyProof(notarizat, RPC); const f = v && (v.levels || []).find((l) => l.level === 'finality'); if (f && f.state !== 'PENDING') break; await new Promise((ok) => setTimeout(ok, 5000)); } + const fin = v && (v.levels || []).find((l) => l.level === 'finality'); s.verifyProof = v; + cer('S1 the provider\'s execution envelope verifies with the reference verifier under a post-quantum certified anchor (finality PASSED)', v && v.verdict === 'VALID' && fin && fin.state === 'PASSED', fin ? fin.state + ': ' + String(fin.detail).slice(0, 120) : '?'); + cer('S1 the notarized proof existed before the window closed (firstSeen <= submittedAt + window)', notarizat.notarization.firstSeen <= d.job.submittedAt + d.job.challengeWindow, `firstSeen ${notarizat.notarization.firstSeen}, window end ${d.job.submittedAt + d.job.challengeWindow}`); + const ch = chitanta(d); s.chitanta = ch; const vc = verifyProof(ch); s.chitantaVerdict = vc; + cer('S1 the settlement receipt (AIP-23 settlement) names the payout tx, the provider and 0.01 tAERE, and verifies (VALID, finality ABSENT: not notarized)', ch.statement.txHash === r.terminal.txHash && ch.statement.to.toLowerCase() === prov.address.toLowerCase() && ch.statement.amount === E('0.01').toString() && vc && vc.verdict === 'VALID', vc && (vc.levels || []).map((l) => l.level + ':' + l.state).join(' ')); + }); + await scenariu('S2', 'dispute upheld: a wrong result, the requester recomputes and disputes, the arbiter slashes', async (spec, s) => { + const { id } = await posteaza(spec); s.jobId = id; + await tx('claimJob (provider, bond)', C(prov).claimJob(id, '0x', { value: E('0.004') })); + const rez = ruleaza(spec); const gresit = { ...rez, digest: '0x' + 'ee'.repeat(32) }; + await tx('submitResult (provider, WRONG digest)', C(prov).submitResult(id, rezultatOcteti(gresit))); + const recomputat = rezultatHash(ruleaza(spec)); + await tx('dispute (requester as challenger, recomputed hash, bond)', C(req).dispute(id, recomputat, { value: E('0.004') })); + await refuza('S2 resolveByTimeout before ARBITRATION_TIMEOUT is refused: ArbitrationTimeoutNotPassed', () => C(req).resolveByTimeout.staticCall(id), 'ArbitrationTimeoutNotPassed', C(req)); + await refuza('S2 resolveDispute by a non-arbiter is refused: NotArbiter', () => C(req).resolveDispute.staticCall(id, false), 'NotArbiter', C(req)); + const before = await provider.getBalance(req.address); + const r = await tx('resolveDispute(false) by the arbiter', C(arb).resolveDispute(id, false)); + const after = await provider.getBalance(req.address); + cer('S2 the requester got the reward back + its bond back + the provider\'s slashed bond (0.018 tAERE)', after - before === E('0.018'), ethers.formatEther(after - before) + ' tAERE'); + await judecaSiSalveaza('S2', s, id); + s.gasResolve = String(r.gasUsed); + }); + await scenariu('S3', 'dispute lost: a correct result disputed in bad faith; the arbiter sides with the provider', async (spec, s) => { + const { id } = await posteaza(spec); s.jobId = id; + await tx('claimJob (provider, bond)', C(prov).claimJob(id, '0x', { value: E('0.004') })); + const rez = ruleaza(spec); + await tx('submitResult (provider, correct)', C(prov).submitResult(id, rezultatOcteti(rez))); + await tx('dispute (requester, a made-up recomputed hash, bond)', C(req).dispute(id, '0x' + 'dd'.repeat(32), { value: E('0.004') })); + const before = await provider.getBalance(prov.address); + await tx('resolveDispute(true) by the arbiter', C(arb).resolveDispute(id, true)); + const after = await provider.getBalance(prov.address); + cer('S3 the provider received reward + its bond + the challenger\'s forfeited bond (0.018 tAERE)', after - before === E('0.018'), ethers.formatEther(after - before) + ' tAERE'); + await judecaSiSalveaza('S3', s, id); + }); + await scenariu('S4', 'deadline: claimed, never delivered; the requester reclaims after the deadline, the bond is slashed to it', async (spec, s) => { + const { id, deadline } = await posteaza(spec, { deadlineIn: 45 }); s.jobId = id; + await tx('claimJob (provider, bond)', C(prov).claimJob(id, '0x', { value: E('0.004') })); + await refuza('S4 reclaimExpired before the deadline is refused: DeadlineNotPassed', () => C(req).reclaimExpired.staticCall(id), 'DeadlineNotPassed', C(req)); + await asteapta(deadline + 1, 'the deadline'); + await refuza('S4 submitResult after the deadline is refused: DeadlinePassed', () => C(prov).submitResult.staticCall(id, rezultatOcteti(ruleaza(spec))), 'DeadlinePassed', C(prov)); + const before = await provider.getBalance(req.address); + const r = await tx('reclaimExpired (requester)', C(req).reclaimExpired(id)); + const after = await provider.getBalance(req.address); const gaz = r.gasUsed * (r.gasPrice || r.effectiveGasPrice || 0n); + cer('S4 the requester got the reward + the slashed provider bond (0.014 tAERE, minus its own gas)', after - before + gaz === E('0.014'), ethers.formatEther(after - before + gaz) + ' tAERE net of gas'); + await judecaSiSalveaza('S4', s, id); + }); + await scenariu('S5', 'an open job past its deadline: a claim is refused, the requester cancels', async (spec, s) => { + const { id, deadline } = await posteaza(spec, { deadlineIn: 30 }); s.jobId = id; + await asteapta(deadline + 1, 'the deadline'); + await refuza('S5 claimJob after the deadline is refused: DeadlinePassed', () => C(prov).claimJob.staticCall(id, '0x', { value: E('0.004') }), 'DeadlinePassed', C(prov)); + await tx('cancelJob (requester)', C(req).cancelJob(id)); + await judecaSiSalveaza('S5', s, id); + }); +} finally { + dovada.rezumat = { verzi, rosii }; const out = path.join(DOVEZI, 'piata-28001-' + new Date().toISOString().replace(/[:.]/g, '').slice(0, 15) + 'Z.json'); + fs.writeFileSync(out, JSON.stringify(dovada, null, 1)); console.log('\n evidence: ' + path.relative(RAD, out)); + console.log(`market settlement on 28001: ${verzi} VERDE, ${rosii} ROSU`); + process.exitCode = rosii ? 1 : 0; +} diff --git a/market-settlement/sarcina.mjs b/market-settlement/sarcina.mjs new file mode 100644 index 0000000..9d316cb --- /dev/null +++ b/market-settlement/sarcina.mjs @@ -0,0 +1,55 @@ +// sarcina.mjs: the REPLAY workload of the market flow (roadmap point 28): a deterministic task anyone can recompute, so a challenger +// can dispute a wrong result with the hash it recomputed and an arbiter (or any reader) can see who is right. keccak-chain: start from a +// 32-byte seed and apply keccak256 `iters` times. The spec is public (its keccak256 is the job's specHash); the result is the JSON +// bytes { task, seed, iters, digest } whose keccak256 is the job's resultHash. Only node:crypto: keccak-256 is the dependency-free +// BigInt implementation of the Cloud gateway (cloud-gateway/gateway.mjs), copied here so the public component has no package to install; +// its positive control is the recorded testnet evidence itself (resultHash computed on chain = the replay here, proba-judecata.mjs S1/S3). +import crypto from 'node:crypto'; + +// ----- keccak-256 (FIPS 202 permutation, keccak padding 0x01..0x80, rate 136) ----- +const MASK = (1n << 64n) - 1n; +const RC = [0x0000000000000001n, 0x0000000000008082n, 0x800000000000808an, 0x8000000080008000n, 0x000000000000808bn, 0x0000000080000001n, 0x8000000080008081n, 0x8000000000008009n, + 0x000000000000008an, 0x0000000000000088n, 0x0000000080008009n, 0x000000008000000an, 0x000000008000808bn, 0x800000000000008bn, 0x8000000000008089n, 0x8000000000008003n, + 0x8000000000008002n, 0x8000000000000080n, 0x000000000000800an, 0x800000008000000an, 0x8000000080008081n, 0x8000000000008080n, 0x0000000080000001n, 0x8000000080008008n]; +const ROT = [[0, 36, 3, 41, 18], [1, 44, 10, 45, 2], [62, 6, 43, 15, 61], [28, 55, 25, 21, 56], [27, 20, 39, 8, 14]]; +const rotl = (v, n) => (n === 0 ? v : (((v << BigInt(n)) | (v >> BigInt(64 - n))) & MASK)); +function keccakF(A) { + for (let rr = 0; rr < 24; rr++) { + const C = new Array(5), D = new Array(5); + for (let x = 0; x < 5; x++) C[x] = A[x] ^ A[x + 5] ^ A[x + 10] ^ A[x + 15] ^ A[x + 20]; + for (let x = 0; x < 5; x++) D[x] = C[(x + 4) % 5] ^ rotl(C[(x + 1) % 5], 1); + for (let x = 0; x < 5; x++) for (let y = 0; y < 5; y++) A[x + 5 * y] ^= D[x]; + const B = new Array(25); + for (let x = 0; x < 5; x++) for (let y = 0; y < 5; y++) B[y + 5 * ((2 * x + 3 * y) % 5)] = rotl(A[x + 5 * y], ROT[x][y]); + for (let x = 0; x < 5; x++) for (let y = 0; y < 5; y++) A[x + 5 * y] = B[x + 5 * y] ^ ((~B[((x + 1) % 5) + 5 * y] & MASK) & B[((x + 2) % 5) + 5 * y]); + A[0] ^= RC[rr]; + } +} +export function keccak256(bytes) { + const rate = 136; const A = new Array(25).fill(0n); const msg = Buffer.from(bytes); + const padded = Buffer.concat([msg, Buffer.alloc(rate - (msg.length % rate))]); + padded[msg.length] |= 0x01; padded[padded.length - 1] |= 0x80; + for (let off = 0; off < padded.length; off += rate) { for (let i = 0; i < rate / 8; i++) A[i] ^= padded.readBigUInt64LE(off + i * 8); keccakF(A); } + const out = Buffer.alloc(32); for (let i = 0; i < 4; i++) out.writeBigUInt64LE(A[i], i * 8); return out; +} + +export const TASK = 'keccak-chain'; +const hex = (b) => '0x' + Buffer.from(b).toString('hex'); +export const keccak = (b) => hex(keccak256(b)); +/** Canonical JSON of a spec or a result: keys sorted, no whitespace. */ +export const canonical = (x) => JSON.stringify(x, Object.keys(x).sort()); +export function specNou({ iters = 20000, seed = hex(crypto.randomBytes(32)) } = {}) { return { task: TASK, seed, iters }; } +export const specHash = (spec) => keccak(Buffer.from(canonical(spec), 'utf8')); +/** Runs the task: the digest after `iters` keccak256 applications to the seed. */ +export function ruleaza(spec) { + if (spec.task !== TASK) throw new Error('unknown task ' + spec.task); + if (!/^0x[0-9a-f]{64}$/.test(spec.seed) || !Number.isInteger(spec.iters) || spec.iters < 1 || spec.iters > 5e6) throw new Error('bad spec'); + let d = Buffer.from(spec.seed.slice(2), 'hex'); + for (let i = 0; i < spec.iters; i++) d = keccak256(d); + return { task: TASK, seed: spec.seed, iters: spec.iters, digest: hex(d) }; +} +/** The result bytes a provider submits (and a challenger recomputes), and their on-chain hash. */ +export const rezultatOcteti = (r) => Buffer.from(canonical(r), 'utf8'); +export const rezultatHash = (r) => keccak(rezultatOcteti(r)); +/** The SHA-256 of this program's own source, for the `programSha256` of the execution envelope. */ +export const programSha256 = () => '0x' + crypto.createHash('sha256').update(Buffer.from(ruleaza.toString() + keccak.toString(), 'utf8')).digest('hex');