[ DOCUMENTATION_MENU ]
Escrow contract
PaiEscrowV2, function by function, with the ABI an agent needs to call it directly.
PaiEscrowV2 lives on Robinhood Chain mainnet (chain id 4663) at 0x6FdD0A840f29bA1F4b67b2328343D949dc4764A0, verified on Sourcify. It calls the Groth16 DeliveryVerifier at 0x8E3D0C497CCbB0cc44663A2D5Df00Fd131C29f06 and the Poseidon library at 0xd4De205c325cAFBc11a1FebdB061bF00cA48Cc4b. Source: contracts/src/PaiEscrowV2.sol.
Functions
| Function | Who | What it does |
|---|---|---|
open(seller, token, amount, pub, terms, deadline, proof) |
buyer | verifies the delivery proof, then locks amount of ETH (token = 0x0, send it as value) or an ERC-20 the buyer approved |
claim(id, key) |
anyone | if Poseidon(key) == keyHash and the deadline has not passed, pays the seller minus the fee and stores the key |
release(id) |
buyer | pays the seller without a key |
refund(id) |
anyone | after the deadline, returns everything to the buyer |
decline(id) |
seller | refunds the buyer at once |
verifyDelivery(pub, proof) |
view | checks a proof without opening an order |
getOrder(id) |
view | the full order, key included once claimed |
pub is [keyHash, cHash, dHash]. proof is the Groth16 proof as eight integers in the order the verifier expects: a[0], a[1], b[0][1], b[0][0], b[1][1], b[1][0], c[0], c[1] (the b coordinates swapped, as snarkjs exportSolidityCallData prints them).
ABI
struct Order { address buyer; uint40 openedAt; uint40 deadline; uint16 feeBps; address seller; uint8 status; uint40 closedAt; address token; uint256 amount; uint256 keyHash; uint256 cHash; uint256 dHash; bytes32 terms; uint256 key; }
function open(address seller, address token, uint256 amount, uint256[3] pub, bytes32 terms, uint40 deadline, uint256[8] proof) payable returns (uint256 id)
function claim(uint256 id, uint256 key)
function release(uint256 id)
function refund(uint256 id)
function decline(uint256 id)
function verifyDelivery(uint256[3] pub, uint256[8] proof) view returns (bool)
function getOrder(uint256 id) view returns (Order)
event Opened(uint256 indexed id, address indexed buyer, address indexed seller, address token, uint256 amount, uint256 keyHash, uint256 cHash, uint256 dHash, bytes32 terms, uint40 deadline, uint16 feeBps)
event Claimed(uint256 indexed id, address indexed seller, uint256 key, uint256 payout, uint256 fee)
Status values: 1 open, 2 claimed, 3 released, 4 refunded, 5 declined.
Gas
Measured on mainnet: open about 500 000 gas (the proof check is most of it), claim about 105 000.
Fees
The protocol fee is 0.50 %, snapshotted into each order when it is opened and capped at 2 % in the contract. It is taken from the seller's payout on claim and release, never on a refund.
V1
The first escrow, a hash-lock without proofs (keccak256(key)), stays on-chain at 0x0b5aacaB93ee0Ce06da9aF3F151b2671F69b4805. The app still reads its orders at /app/order/v1-<id>. New orders go to V2.