Skip to content

feat(v2): Circle Refund Protocol adapter for PredgeRefundArbiterV2 (Arc Demo Day) - #8

Merged
predge-ai merged 1 commit into
v2/contractsfrom
feat/circle-refund-protocol-adapter
Nov 1, 2026
Merged

predge-ai merged 1 commit into
v2/contractsfrom
feat/circle-refund-protocol-adapter

Conversation

@predge-ai

@predge-ai predge-ai commented Oct 31, 2026 •

Copy link
Copy Markdown
Member

Why

For Arc Demo Day (16 Nov) we want to show Predge as the arbiter of Circle's Refund Protocol (circlefin/refund-protocol). PredgeRefundArbiterV2 was built against our MockRefundProtocolV2. To find out whether it works with Circle's real contract, we read Circle's public src/RefundProtocol.sol. No Circle code was cloned, installed or run.

Gap analysis: does the deployed arbiter work with Circle's contract as it is? No. It needs a small adapter.

What PredgeRefundArbiterV2 calls Circle RefundProtocol Gap
paymentInfo(id) -> (payer, payee, amount, releaseTimestamp) does not exist; the public getter is payments(id) -> (to, amount, releaseTimestamp, refundTo, withdrawnAmount, refunded) Blocking. Every fileEvidence and rule call would revert.
payer Circle does not store who called pay; refunds go to refundTo, and refundTo can be changed with updateRefundTo map payer to the current refundTo
amount, in native wei (sizes the bond) in USDC's 6 decimals (Arc native gas uses 18) scale by 1e12 on Arc
refundByArbiter(id) same signature, onlyArbiter; reverts on already refunded or InsufficientFunds; no check on release time compatible. The adapter turns "already refunded" into a no-op
setLockupSeconds(r, s) same signature, onlyArbiter, cap is 180 days compatible. Predge allows up to 365 days, so Circle reverts between 180 and 365 days
caller identity arbiter is set once in Circle's constructor and has no setter the adapter becomes Circle's arbiter and accepts writes only from the bound Predge arbiter
payment ids start at 0 fine (the Predge status for id 0 is None)
unused by Predge earlyWithdrawByArbiter, deposit/withdrawArbiterFunds not exposed. A refund comes only from the recipient's balance in Circle; if that balance is short, finalize reverts and expire voids the ruling

The live Arc/Base PredgeRefundArbiterV2 points immutably at MockRefundProtocolV2. Pointing at Circle's contract therefore needs a new arbiter instance with refundProtocol = adapter. The bytecode does not change.

What this PR adds

  • contracts/v2/interfaces/ICircleRefundProtocol.sol: our own interface, signatures only.
  • contracts/v2/adapters/CircleRefundProtocolAdapter.sol: about 120 lines, no owner, holds no funds. A one-time bind checks the wiring in both directions.
  • contracts/v2/mocks/MockCircleRefundProtocol.sol and MockUSDC.sol: our own local stand-ins that mirror Circle's interface and behaviour, for tests and demos only.
  • test/foundry-v2/CircleRefundAdapter.t.sol: 14 tests covering release, refund on verdict, dispute (overturned to refund, refund upheld), the seller refunding first, already-refunded payments, zero lockup refused, the 180-day cap, a refundTo change after the ruling, and a 6-line demo log.
  • scripts/foundry/DeployCircleRefundDemo.s.sol: deploy script for Arc testnet. Simulated only, nothing broadcast.

No change to PredgeRefundArbiterV2, config/set.v2.json or the deployed addresses.

Tests

FOUNDRY_CONFIG=foundry-v2.toml forge test: 166/166 pass (14 new). The node test plan-v2.test.mjs #2 ("would collide with a v2.0 address") already fails on v2/contracts without this PR and is unrelated.

Before mainnet

The adapter and both mocks are unaudited. Circle's RefundProtocol is itself marked unaudited and educational. Do not merge this until it has been reviewed.

PredgeRefundArbiterV2 cannot drive Circle's RefundProtocol directly: Circle
has no paymentInfo (it exposes payments(id) with to/refundTo), amounts are in
USDC 6dp while the bond is sized in native wei, and Circle's arbiter is fixed
in its constructor. CircleRefundProtocolAdapter is set as Circle's arbiter,
accepts writes only from the bound Predge arbiter, maps refundTo->payer,
to->payee, scales the amount, and treats an already-refunded payment as done.

Adds our own ICircleRefundProtocol (signatures only, read from the public
source), a local MockCircleRefundProtocol mirroring its behaviour, MockUSDC,
14 Foundry tests (release, refund on verdict, dispute overturned/upheld, edge
cases) and an Arc testnet deploy script (simulation only, nothing broadcast).
The deployed arbiter and the v2 plan are unchanged.
@predge-ai
predge-ai merged commit 18f7548 into v2/contracts Nov 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant