Skip to content

Repository files navigation

Square

Square

Compliance-gated settlement for autonomous agent work, on Arc.

Built on Arc

An institution commits a private spending mandate on-chain: the chain holds a commitment to it, and the institution's own tools prove each release in their own process, so the policy behind the commitment never leaves them (prover-trust-boundary.md). The app's job page is the exception: it sends the policy to the prover it is configured with, whose operator sees it. Identified agents execute against the mandate. The hook that releases escrow carries a compliance slot: with a module installed, a release must first prove, in zero knowledge, that it fits the mandate. Escrow protects the provider against everything except that mandate: a payment the mandate forbids returns to the client with the reason on chain, and a proof that is merely missing holds the escrow until the institution does its duty (decided in proof-required.md, built into the contracts on main; the deployed stack carries it with the next redeploy, and until then refunds a missing proof as it refunds a refused one). The receivable created during the challenge window is discountable, and sells only to a buyer the institution's policy approved.

The slot is empty on the shared deployed hook, so no release on that stack is proof gated: SquareHook.complianceModule() returns the zero address, and the app's network page reads it live. The gate itself has run on Arc Testnet, on a stack deployed with the module installed (#28): a compliant payment released for 815,728 gas (0.017946 USDC), and a payment over its daily cap, to a blocked recipient, against a replaced policy, outside its time window or carrying another job's proof refused by name (refusal-scenarios.md). The circuit and the prover are live (#14, #18), and the check is wired into settlement by #27's ComplianceModule. A proof built here verifies against Arc's own pairing precompiles, which the verifies on Arc Testnet check shows on every pull request. The Groth16 verifier deployed for #17 is superseded and rejects every proof this repository now produces (Status, below); the ceremony in #16 fixes the key that gets a permanent address.


Status

Pre-alpha on Arc Testnet. The settlement layer and the Groth16 verifier are deployed on the testnet; the verifier sits at an address the ceremony will replace. Nothing carries an assurance claim.

Layer State
Identity: did:aip v2, agent card, CLI, Universal Resolver driver live against ERC-8004 on Arc Testnet (docs/smoke)
Settlement: SquareJob, KeeperEvaluator, Arbitration, ClaimMarket, SquareHook deployed on Arc Testnet, covered by the Foundry suite including a bond-solvency invariant, the five settlement paths run on the testnet with real USDC and the deployed ERC-8004 registries (docs/deploy/lifecycle-5042002-2026-09-09.md)
Services: indexer, keeper, sanctions screener, x402 gateway, data layer, observability implemented and tested against the local stack; the screener also against TRM's sanctions API (#35)
Compliance: circuit, prover, Groth16 verifier, ComplianceModule, the institution's side circuit, prover and verifier live (#14, #18, #17); the module exists (#27) and the shared hook's slot is empty; the institution's side, @squaresdk/policy, the square policy commands, square_hire, the hosted agent and the app, commits policies and keeps proofs bound to jobs (#335, #338), tested against a local stack with the module installed
Website (site/) live at square-protocol.vercel.app, adapted from an MIT template with Square's own copy and surfaces, every button leads to the app
App: reference web application (app/) live at square-wienerlabs.vercel.app, a static Next.js export that reads the deployed contracts through @squaresdk/core and drives every lifecycle action from a connected wallet; no mocked data (app/README.md)

The ZK trusted setup inherited from the prior work is a demo setup, not a ceremony, in both phases: phase 2 carries a single contribution and no beacon, and phase 1 was generated locally. Either half on its own lets that machine forge a proof for any statement.

A key built in this repository is a different artifact. Its phase 1 is real, the Perpetual Powers of Tau contribution 80 adopted in #15 and verified by hash (docs/ceremony/phase1-ptau.md), and its phase 2 is still a development one, a single contribution with no beacon. #16 is the public phase-2 ceremony and it has not been held. Until it completes, nothing here carries an assurance claim of any kind. Evidence and wording: docs/disclosure/; read either phase out of any key with circuits/scripts/inspect-zkey-setup.mjs.

Design

Three layers. Arc supplies the bottom one already.

Layer What we build Arc primitive it sits on
Identity did:aip v2 resolver, agent card schema ERC-8004 IdentityRegistry
Settlement SquareJob (ERC-8183 kernel, pull-payment ledger), KeeperEvaluator (optimistic challenge window, paid permissionless finalize), Arbitration (bonded disputes, M-of-N), ClaimMarket (receivable discounting) ERC-8183 IACP
Compliance SquareHook routes the payout, runs the Groth16 proof check and writes reputation; ComplianceHook plugs into its slot ERC-8183 IACPHook, ERC-8004 ReputationRegistry and ValidationRegistry

The composition point is the hook: the proof gates release, not deposit, and it is bound to the address the kernel will actually pay, which is the receivable's buyer when the receivable was sold. Who can become that buyer is gated too: the poster's policy publishes the root of a salted list of approved buyers, and buy checks the purchaser against it without the list reaching the chain (buyer-eligibility.md). Reputation stays with the agent that did the work.

Design notes, each the record of a decision:

Provenance

Distilled from three prior repositories. Selected components only; the on-chain layer is not ported.

Source What carries over
aperture Circom circuit, Poseidon policy commitment, prover service
aip-beta did:aip spec and resolver, A2A task protocol, MCP bridge, agent SDK
covenant Escrow state machine (as specification), x402 verifier, chain-agnostic hardening

Running it

Everything, on a local chain, from one command:

make up

That brings up anvil, deploys the contracts to it, migrates Postgres, builds the circuit artifacts, and starts the prover, the indexer, the screener, the keeper and the application, returning only once all five report healthy. Docker, git and make are the whole prerequisite. docs/deploy/local-stack.md has the ports, the measured start-up time and how to point the same stack at Arc testnet.

Layout

contracts/   Foundry: SquareJob, KeeperEvaluator, Arbitration, ClaimMarket, SquareHook,
             PolicyRegistry, deploy scripts and the test suite
circuits/    Circom payment-compliance circuit + ceremony scripts
packages/    did-resolver, cli, did-aip-driver, core (SDK, embedded ABIs), data (Postgres
             access layer + migrations), hardening (SSRF, idempotency, rate limit, RPC
             failover, signed actions), observability (logs, metrics, health, alerts),
             x402 (payment gateway), aa (ERC-4337 smart accounts), a2a (task protocol),
             agent (an agent in a few lines: card, A2A tasks paid through escrow, x402),
             mcp (agents calling MCP tools; Square as an MCP server for Claude Desktop),
             hosted (an institution's agent run from a configuration: Claude with MCP
             tools per capability, delegation to other agents under its on-chain policy),
             policy (the institution's side of the compliance gate: commit a policy,
             keep the proof bound to each job current, release)
services/    prover, indexer, keeper, screener (sanctions screening, #35)
app/         Next.js reference application (static export, wagmi, Open Runde design system)
site/        The website at https://square-protocol.vercel.app: what Square is, and the door to the app
docs/        Specifications, design notes, measurements, disclosure

The packages publish to npm under @squaresdk, all thirteen at one version from a v<version> tag (docs/decisions/distribution-channel.md); the first tag has not been cut, so today each is built from this clone, and every pull request packs the thirteen and installs the tarballs into an empty project so that the day it is cut nothing is missing from them.

Every pull request runs the contract, circuit, prover, package and application suites. The circuit and prover jobs build the artifacts their tests refuse to run without, because a suite that quietly skips itself is the failure this is set up to catch. docs/ci.md lists the checks, what each proves, and which are required to merge.

Network

Chain Arc Testnet
Chain ID 5042002
RPC https://rpc.testnet.arc.io
Explorer https://testnet.arcscan.app
Gas token USDC (18 decimals native, 6 decimals ERC-20 at 0x3600000000000000000000000000000000000000)
USDC from elsewhere Circle's CCTP V2, domain 26: burned on Ethereum, Base or Arbitrum Sepolia, attested by Circle, minted here, then funded into a job (docs/design/cctp-funding.md)
ERC-8004 Identity 0x8004A818BFB912233c491871b3d84c89A494BD9e, Reputation 0x8004B663056A597Dffe9eCcC1965A193B7388713, Validation 0x8004Cb1BF31DAf7788923b405b754f57acEB4272
ERC-4337 EntryPoint v0.7 0x0000000071727De22E5E9d8BAf0edAc6f37da032, SimpleAccountFactory 0x91E60e0613810449d098b0b5Ec8b51A0FE8c8985

Escrow and payment paths use the 6-decimal ERC-20 interface, not native value: docs/decisions/erc20-vs-native-usdc.md.

Deployments

Contract Address Status
Groth16Verifier 0x35d7B65BDDf5C19DE107B1f90110B1FB381F7Ae1 superseded — keyed to the circuit before #119, rejects every proof this repository now produces

That contract is left standing rather than replaced, because replacing it would not help: circuits/scripts/build.mjs draws fresh phase-2 entropy on every build, so any verifier deployed today is already wrong for tomorrow's build. Every deployment before #16 has a lifetime of one npm run build. The ceremony fixes one key, and that is the one worth an address.

A proof from the prover service still verifies against Arc — the same contract source, the same precompiles, keyed to the build that produced the proof, put on chain for one eth_call with a state override:

$ node contracts/script/verify-on-arc.mjs
rpc      https://rpc.testnet.arc.io
chain id 5042002

verifier state override at a scratch address (nothing deployed)

a proof the prover service produced
  ok    compliant proof verifies
  ok    non-compliant proof also verifies, is_compliant is a signal, not a gate

tampering is rejected
  ok    flipped is_compliant
  ok    altered amount

Arc gas for one verification: 281596

All checks passed against Arc.

Measured on Arc, from receipts: 262,403 gas for a whole verification call and 714,837 to deploy, 0.0058 and 0.0158 USDC at the 22.17 gwei both receipts paid. The deployment receipt is this verifier's; the verification receipt is the snarkjs verifier's it replaced, the only verifyProof transaction sent on chain so far — see contracts/README.md. The verifier is written here under Apache-2.0 from the pairing equation, not generated by snarkjs; the previous generated deployment at 0x7b8E8089129094FD20a7C9243904343e4C6aBff7 is superseded (docs/decisions/groth16-verifier-license.md).

The verifier address is temporary. It is generated from a proving key and is valid only for that key; today's is a development key, so #16 will produce a different verifier at a different address. See contracts/README.md.

Square contracts

First deployed on 2026-09-07 with contracts/script/DeploySettlement.s.sol, then redeployed with contracts/script/deploy-arc-testnet.sh on 2026-09-08 after four findings and again on 2026-09-09 after the second review round changed the job record, the market's buy signature and the hook's constructor. All three runs came from 0xaFF9CD31ae93e1bdD70FFDf0763C2e010037c65c. The addresses below are the 2026-09-09 redeploy's; the superseded sets, what changed each time and the sweep of the balances they held are in docs/deploy/redeploy-2026-09-08.md and docs/deploy/redeploy-2026-09-09.md. The checklist a redeploy walks is docs/deploy/README.md. Testnet parameters: challenge window 120 s, dispute window 300 s, finalize grace 600 s (so settlementHorizon() reads 1020 s), evaluator fee 0.5 %, platform fee 1 %, bond 10 % with a 1 USDC floor, three arbiters with threshold 2. The owner is still the deployer; a Safe takes over before mainnet.

Contract Address
SquareJob 0x76E8690cEa9d94df810eE6b1F453866f0ee68c7B
KeeperEvaluator 0x08100b5211463861f26aC8Bc73Df32A8A2f6ebbD
Arbitration 0x1c6Be0d4a84a8F0770341269393EaB13098866C2
ClaimMarket 0x54cd26490dF9212DC6187C73CC07132cd39A1a36
SquareHook 0xb44aCCBb8d1eae0e2D2e8B33CEC32f1fD613e7e6

@squaresdk/core carries these addresses (deployments[5042002]). The five settlement paths were run against them with real USDC and a provider registered as ERC-8004 agent 892531; every transaction hash and the measured gas are in docs/deploy/lifecycle-5042002-2026-09-09.md, the dated record of that run. docs/deploy/lifecycle-5042002.md holds whatever ran last.

License

Apache-2.0. See LICENSE. NOTICE carries the MIT notices of the code that came from the prior repositories, and the SIL OFL 1.1 notice of the Open Runde typeface the app and the site are set in.

Parts of the circuit, the prover and the client came from wienerlabs/aperture and dr-wilson-empty/aip-beta, both MIT; NOTICE says which parts and carries their copyright, as MIT requires.

Nothing here derives from wienerlabs/covenant, which is LGPL-2.1.

Arc is a trademark of Circle Internet Group, Inc. and/or its affiliates. Square is built on Arc and is not affiliated with or endorsed by Circle.

About

Compliance-gated agent job settlement on Circle Arc. USDC-native escrow with optimistic challenge windows, ZK spending-mandate proofs, and ERC-8004 agent identity.

Resources

Stars

3 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages