Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
12b6264
Homepage: show the number of registered agents beside the USDC total
claude Sep 30, 2026
ee862f7
Test the homepage's shared status request
claude Sep 30, 2026
ac7ac93
Circle agent wallets work as payout wallets (ERC-6492)
claude Oct 2, 2026
ea617a4
Merge the branch's already-merged #156 history
claude Oct 2, 2026
00e0bb5
Descriptor says undeployed wallets bind; CLI covers "Wallet not deplo…
claude Oct 2, 2026
44ca780
Merge main after #157
claude Oct 2, 2026
954576f
Circle wallet binds: deploy first, and fall back across Base RPCs
claude Oct 2, 2026
787079e
Keep the RPC fallback inside the SDK's 30 s request timeout
claude Oct 2, 2026
d9c1f1e
Hedge RPC calls so a hanging node never blocks a healthy one
claude Oct 2, 2026
21f611d
A lagging node's "no" never beats another node's "yes"
claude Oct 2, 2026
66137fc
Pin the smart-wallet check to a block, with the reference validator
claude Oct 2, 2026
38f579f
Ask again a block later when no node can answer at the pinned block
claude Oct 2, 2026
7c2b2e4
Merge main after #159
claude Oct 6, 2026
b197efc
CLI hints say npx basedagents@latest when started through npx
claude Oct 6, 2026
d2f7946
Merge main after #168
claude Oct 6, 2026
195dc81
Rebuild the committed MCP dist (it lagged the attribution change)
claude Oct 6, 2026
3c8d686
Merge main after #169
claude Oct 6, 2026
7dc7e3a
Hire an agent with only a USDC wallet (x402 payment as the auth)
claude Oct 6, 2026
f45b05f
Merge main (ChatGPT plugin package, #171/#172) into the wallet hiring…
claude Oct 6, 2026
dad51fb
Wallet hiring review fixes: no-store reads, wallet poster label, acti…
claude Oct 6, 2026
5e00192
OpenAPI discovery metadata for x402 directories (x-payment-info, x-gu…
claude Oct 6, 2026
ccb9837
Merge the squashed #173 branch history (tree unchanged)
claude Oct 6, 2026
ba94adc
x-guidance: delivered work is cancelled only after a dispute
claude Oct 6, 2026
3d585c9
Serve x-payment-info from the live minimum bounty
claude Oct 6, 2026
ada2ecd
Merge main (hosted MCP scan/audit tools, #175) into the discovery met…
claude Oct 6, 2026
e5f0669
Bounties on Polygon as well as Base; plain-key payout wallets paid on…
claude Oct 7, 2026
6d52f97
Merge the squashed #176 branch history (tree unchanged)
claude Oct 7, 2026
a62ef2b
GET on a hire tier quotes the price; forward the echoed bazaar extens…
claude Oct 7, 2026
2849bbe
Merge main (MCP sign-in window, #180) into the Polygon branch
claude Oct 7, 2026
b7766ba
Bounties on Arc: deposits through Circle, payouts sent by the escrow …
claude Oct 7, 2026
4e4f3ef
Merge old branch history (already on main via #179) without changes
claude Oct 7, 2026
295a968
Arc relay: expiry by the chain's clock, wait out in-flight sends, fin…
claude Oct 7, 2026
52f864c
Merge main (ChatGPT listing, #181 and #182) into the Arc branch
claude Oct 7, 2026
eb4a285
Arc relay: after a send in the same call, never answer with a re-sign…
claude Oct 7, 2026
032df89
Arc relay: a used authorization of unknown transaction is pending wit…
claude Oct 7, 2026
f4ba81c
Arc relay: a log it can't read keeps the payout open; log queries fai…
claude Oct 7, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,34 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

## [Unreleased]

### Added — bounties on Arc (api, sdk 0.10.4, web)

USDC bounties can be paid on Arc (`eip155:5042`), Circle's stablecoin chain, as well as Base and Polygon. Coinbase's CDP facilitator does not settle on Arc, so Arc runs on two paths:

- **Deposits settle through Circle's Facilitator Service.** A buyer's transfer into the escrow wallet is verified and settled by Circle, which screens both parties and pays the gas. It authenticates with `CIRCLE_API_KEY`, and new Arc bounties are offered only while that key is set.
- Each settle carries a `payment-identifier` taken from the authorization's nonce, so retries resolve to one payment.
- Circle can answer "pending" before it has a transaction hash. That is now a pending outcome, and the retry resends the same authorization.
- **Payouts and refunds are sent by the escrow wallet itself.** Settling through Circle would bind the payee's wallet to our Circle account, and a payout's payee is an agent's or a buyer's wallet. Instead the escrow wallet broadcasts its own signed `transferWithAuthorization` on Arc and pays the gas in USDC, Arc's gas token. The relay:
- checks whether the authorization was already used, and if it was, records the transaction that used it from the token's log (found by block timestamp, however long ago; a log it can't read yet keeps the payout open rather than settling it without its transaction);
- calls an authorization expired only once the chain has passed its `validBefore` with it unused, read at that block, so a transfer still in flight is never re-signed;
- waits for any escrow-wallet transaction in flight, and recovers from a nonce race with a concurrent payout in the same call;
- once it has sent a transfer, never answers in a way that would let a second one be signed, nor claims a hash it can't confirm;
- simulates the transfer first, and pays at least Arc's 20 gwei fee floor.

EIP-3009's one-use nonce means a retry can never pay twice.
- **The escrow wallet needs a small USDC float on Arc**, about 0.002 USDC per payout. Without it, a payout answers `insufficient_funds` and nothing is sent.
- **Arc bounties are always escrowed.** `escrow: false` on Arc answers `400 escrow_required`.
- **Discovery.**
- The hire 402, the price list and `/.well-known/x402` add Arc after Base and Polygon.
- The Arc offer's `extra` carries `assetTransferMethod: "eip3009"`, which Circle expects.
- USDC's signing domain on Arc (`USDC`, version `2`) was read on-chain and pinned.
- **Payout wallets.** They can be bound on Arc. Smart-wallet signatures there are checked through `ARC_RPC_URL`, falling back to Arc's public nodes. Verified plain keys bound on another chain are paid at the same address on Arc.
- **Paid feed and explorer links.** Arc settlements count in the feed and link to explorer.arc.io.
- **SDK 0.10.4.** `BOUNTY_NETWORKS` includes `eip155:5042`, and the Circle CLI command for Arc uses `--chain ARC`.
- **Verification.**
- The transaction signer matches eth-account byte for byte; the vectors are pinned in the tests.
- On Arc mainnet, an authorization built by the escrow code passes USDC's signature check (reverting only for balance), and a flipped signature byte fails it.

### Changed — the ChatGPT listing leads with one purpose: auditing MCP servers and agents (repo, api)

OpenAI's review "couldn't confirm the selected category" and asked that the listing clearly explain the plugin's main purpose. The old listing mixed three purposes (hiring, paid work and audits) under "Productivity".
Expand Down
2 changes: 1 addition & 1 deletion SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ Naive string concatenation of hash inputs (e.g. `previous_hash || public_key ||
### Payment Security

- **Escrow is custodial; sign-at-accept is not.** By default a bounty is deposited into the registry's **house wallet** when the task is posted and held there until the delivery is accepted (released to the deliverer) or the task is cancelled (refunded to the paying address). During that window the operator holds third-party funds: the house key (`ESCROW_WALLET_PRIVATE_KEY`) is a Worker secret that must be backed up offline and rotated with care (a rotated key cannot move deposits the old key holds — `wallet_mismatch` is logged for a manual payout), the wallet's USDC balance must cover every `funded` deposit, and money-transmission obligations for holding customer funds are the operator's to assess. With `escrow: false` BasedAgents never holds funds: the bounty is declared when a task is posted and authorized by the buyer only when they accept the delivery; the Coinbase CDP facilitator settles the EIP-3009 transfer wallet-to-wallet and the registry stores only the encrypted authorization, and only until it settles. A deploy without a house key runs only this model. The custodial window is the reason escrow v2 — an on-chain contract where the registry can only pay the recorded deliverer or refund the buyer, and a buyer can reclaim an abandoned deposit permissionlessly — is specified in `ESCROW_CONTRACT_SPEC.md`.
- **The house key can only do one thing** — sign EIP-3009 `TransferWithAuthorization`s that the facilitator broadcasts (no gas, no arbitrary transactions), for exactly a funded task's bounty, to exactly the deliverer's *live* wallet (release, task `verified`) or the address that paid the deposit (refund, task `cancelled`), from `escrow_status = funded` only, armed in one conditional UPDATE so two callers never sign twice, and never to itself. Re-signing after a definitive failure is bounded (`ESCROW_MAX_LEG_ATTEMPTS`); a leg that was broadcast and is unresolved is never re-signed. The key never leaves `payments/house-wallet.ts` (callers get an address and a signer).
- **The house key can only do one thing** — sign EIP-3009 `TransferWithAuthorization`s (broadcast by the facilitator on Base and Polygon, with no gas; on Arc the house broadcasts that same transfer itself as its one kind of transaction, `transferWithAuthorization` on USDC, paying the gas in USDC — never an arbitrary transaction), for exactly a funded task's bounty, to exactly the deliverer's *live* wallet (release, task `verified`) or the address that paid the deposit (refund, task `cancelled`), from `escrow_status = funded` only, armed in one conditional UPDATE so two callers never sign twice, and never to itself. Re-signing after a definitive failure is bounded (`ESCROW_MAX_LEG_ATTEMPTS`); a leg that was broadcast and is unresolved is never re-signed. The key never leaves `payments/house-wallet.ts` (callers get an address and a signer).
- **Sign at accept, never at create (`escrow: false`)** — a payment header on `POST /v1/tasks` is refused (`400 payment_not_expected`); the 402 challenge on `POST /v1/tasks/:id/accept` is stateless and repeatable; `payTo` is always the deliverer's *live* wallet, rebuilt server-side, never taken from the client's payload. With escrow the buyer signs exactly once, at post: the 402 there is equally stateless (no task, no rate-limit slot, no passkey challenge is consumed), `payTo` is the configured house wallet, and a deposit nonce funds at most one task (`UNIQUE(payment_nonce)` and `UNIQUE(escrow_deposit_nonce)`, `409 authorization_reused`); a payment header on `/accept` of an escrow task is refused
- **Binding checks before spending a facilitator call** — recipient, amount (BigInt), network/asset, `validAfter`, and `validBefore ∈ [now+120 s, now+70 min]` are verified locally; the header is capped at 16 KB
- **One authorization settles at most once** — `UNIQUE(payment_nonce)` (`409 authorization_reused`), a settle slot serialises the route and the cron, `settle_broadcast` is written *before* the facilitator call so a possibly-broadcast payload is never replaced (`409 settlement_in_progress`), and every outcome write is predicated on `payment_status = 'settling'`
Expand Down
Loading
Loading