Skip to content
Available on private testnetTestnet: yesMainnet: Not availableSoftware: Core bad4a06ea · protocol pqwerai-v8-testnet/1Updated

ServiceEscrow reference

Solidity 0.8.26, SPDX MIT. Constants: REVENUE_POLICY_VERSION = 3, MAX_PAYEES = 4, BPS_DENOMINATOR = 10000, DOMAIN = keccak256("PQAI-SERVICE-QUOTE/1").

Constructor

constructor(address arbiter, address[] payees, uint16[] bps, uint256 challengeBlocks, uint256 disputeBlocks)

arbiter ≠ 0; windows 1..100000 blocks; up to 4 distinct non-zero payees, each bps > 0, total < 10000 (the provider always keeps a share). distributionHash = keccak256(abi.encode(3, payees, bps)) commits the schedule for life.

Quote

struct Quote { bytes32 job; address payer; address provider; bytes32 model;
               uint256 maxTokens; uint256 pricePerToken; uint64 expiresAt; uint32 serviceBlocks; }

quoteHash(q) = keccak256(abi.encode(DOMAIN, block.chainid, address(this), q)), signed by the provider as an EIP-191 personal message over the 32-byte hash (65-byte signature, low-s, v ∈ {27, 28}).

Functions

Function Caller Effect
fund(Quote, bytes sig) payable payer Requires msg.value == maxTokens × pricePerToken, unexpired quote (block.number ≤ expiresAt), valid provider signature. State → Funded, deadline = now + serviceBlocks
propose(bytes32 id, bytes32 receipt, uint256 tokens) provider Before deadline; receipt unused; 0 < tokens ≤ maxTokens. charge = tokens × price. → Proposed
accept(bytes32 id) payer → Accepted; deadline = now + challengeBlocks
dispute(bytes32 id) payer (Proposed/Accepted) or provider (Proposed) Before deadline. → Disputed; deadline = now + disputeBlocks
resolve(bytes32 id, uint256 approvedCharge) arbiter approvedCharge ≤ charge; → Accepted, final
finalize(bytes32 id) anyone After the Accepted deadline: credits payer refund, payee shares (floor), provider remainder. → Settled
refundExpired(bytes32 id) anyone Funded/Proposed/Disputed after deadline: full budget to payer. → Refunded
withdraw() any creditor Pull payment of credits[msg.sender] (reentrancy-guarded)
distribution(), quoteHash(), jobs(id), credits(addr), usedReceipts(r) view

States: 0 None, 1 Funded, 2 Proposed, 3 Accepted, 4 Disputed, 5 Settled, 6 Refunded.

Events

Event When
Funded(bytes32 indexed job, bytes32 quoteHash) fund
Proposed(bytes32 indexed job, bytes32 receipt, uint256 charge) propose
Changed(bytes32 indexed job, State state) accept, dispute, resolve, finalize, refundExpired
Paid(address indexed recipient, uint256 amount) withdraw

Revert reasons are listed in the tutorial.

Integration notes

  • Jobs funded on older escrows (v1 80/7/4/4/4/1, v2 81/7/4/4/4/0) keep their terms; new markets deploy v3.
  • A reorganisation can undo allocation and withdrawal; wait for BFT finality before irreversible delivery.
  • After final allocation, pull credits are not revocable by the contract.

Sources at 72057fe3ec: contracts/ai/ServiceEscrow.sol

Found a problem? Report a documentation issue · Build testnet-rc1+72057fe3ec