docs/superpowers/specs/2026-06-18-settlement-rails-and-finality.md and 2026-06-04-phase1-pool-settlement-design.md.
The shape
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
0x41CREATE2 prefix rather than0xff.
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.