Skip to main content
Authoritative specs: docs/superpowers/specs/2026-06-18-settlement-rails-and-finality.md and 2026-06-04-phase1-pool-settlement-design.md.

The shape

Both rails settle into the same pool. Neither is a fallback for the other; they serve different customers.

Why two rails

The connect rail alone would be simpler and free for the platform. It is insufficient because a large share of real crypto payments originate from exchange withdrawals, where the customer has no connected wallet and the sending address belongs to a shared omnibus hot wallet. Refusing those payments refuses a large fraction of the market. Accepting them forces three things that shape the entire system:
1

A unique address per invoice

The only reliable way to attribute an anonymous inbound transfer is to give each invoice its own address. That address must be computable and displayable before it has any code, which means CREATE2 and counterfactual derivation.
2

Platform-sponsored gas

Nobody is present to sign the sweep. The keeper must deploy the forwarder and move the funds, paying native gas. Everything in Economics follows from this.
3

No safe refund target

Funds arriving from an omnibus hot wallet cannot be returned to the sender. This is what killed the on-chain refund window. See Finality and refunds.

The pool

MerchantPool is one contract per merchant per chain. It is immutable and ownerless — no admin, no upgrade path, no pause. Its constructor arguments include the merchant recipient, treasury, partner, and the basis-point splits, so those values are part of the CREATE2 preimage. The pool’s address commits to its own payout behaviour. Two consequences:
  • Changing where a merchant’s money goes requires deploying a different pool at a different address. It cannot be done quietly.
  • The same merchant has the same pool address on all seven EVM chains, because the init code is byte-identical across them. TRON derives separately because it uses a 0x41 CREATE2 prefix rather than 0xff.
MerchantPool.sol exposes exactly three external functions:
There is no receive, no fallback, and no token-received hook. A forwarder sweep is a plain ERC-20 transfer to the pool address and does not execute pool code at all. The pool reads balanceOf(address(this)) at distribute time. This is not a detail — it determines the economics of cloning and the load profile of the whole system.

Counterfactual deployment

Both pools and forwarders are computed at quote or setup time and deployed lazily. The forwarder is only ever deployed after funds arrive, which means it cannot be griefed into existence. The pool is different: deposit() is a contract call and reverts against an address with no code, so the connect rail requires a deployed pool. The deposit rail does not — a sweep into an undeployed pool is a plain transfer that becomes distributable the instant the pool exists.

Phase 1 scope

Phase 1 is stablecoin-only. USDC, USDT, and EURC. Token swapping at checkout — RouterFee.payWithSwap, payNative, accept_any_token, the multi-token picker, and Uniswap routing — is Phase 2. Those contracts are deployed and the code paths exist, but they are an opt-in path, not the default. Any document describing RouterFee as the payment path predates the 2026-06-18 lock.
RouterFee.payWithSwap carries a known encoding bug: V3_SWAP_EXACT_OUT is set to 0x09, which is V2’s opcode. It requires a redeploy to fix and is Phase-2 only. Do not build on that path.

Tracking

The settlement rail work is tracked in Linear under the Settlement v3 — accumulating pool rail project. The retired WS1–WS12 workstream model no longer exists.