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