The problem being solved
A crypto payment processor has to answer one question: where does the customer’s money go first? Almost every processor answers “into our wallet.” That single choice creates everything merchants dislike about them — withdrawal delays, account freezes, minimum payout thresholds, and the risk that the processor’s insolvency becomes your insolvency. We answer “into a contract that can only pay the merchant.” Everything else follows from that.The pool
Each merchant gets a pool — a small, immutable contract, one per chain. Three properties matter:Immutable
No admin function, no upgrade path, no pause switch. The code that exists at deployment is the code that runs forever.
Ownerless
Nobody holds a privileged key. There is no owner to compromise, subpoena, or socially engineer.
Address-bound
Payout addresses are part of the contract’s creation code, so the contract’s address is derived from them. Different recipients means a different address.
Counterfactual addresses
Addresses are computed before the contract exists, using CREATE2 — a deterministic function of the creation code and a salt. Two consequences you’ll notice:- Your pool has the same address on all seven EVM chains, because the creation code is byte-identical across them. One address to whitelist, one to reconcile against.
- We can show a customer a payment address before any contract exists there. The contract is deployed lazily, at the moment it’s needed.
Two rails
Customers arrive in two different states, so there are two paths in.- Connect rail
- Deposit rail
The customer has a browser wallet. They sign one transaction that calls
deposit() on your pool directly.- Funds move straight into the pool
- The customer pays their own network fee
- Attribution is exact — the payment ID is in the transaction
- Requires your pool to be deployed on that chain
Distribution
Funds accumulate. Nothing is split per payment, because splitting per payment means three transfers per order and network fees that dwarf small orders. When you claim,distribute() reads the pool’s balance and credits each recipient, then claim() moves your share out.
distribute() is callable by anyone. Not just you, not just us. This is the property that makes the whole arrangement non-custodial — there is no party who can decline to release your funds, because releasing them doesn’t require anyone’s permission.Where the trust actually sits
The honest map:
The database is display-only for money. If it were entirely rewritten by an attacker, the checkout would still refuse to send funds anywhere except your real address — because the browser checks the chain, not the database. How that check works.
What this costs you
Non-custody isn’t free. The honest trade-offs:You pay two on-chain fees
You pay two on-chain fees
Deploying your pool once per chain, and each claim. Both are transactions you sign. A custodial processor absorbs these — and charges you for them elsewhere.
You need native gas on each chain
You need native gas on each chain
You can’t claim on a chain where you hold no ETH, POL, BNB, AVAX, or TRX.
Refunds are manual
Refunds are manual
We can’t refund on your behalf, because we never hold the money. Refunds.
Mistakes are permanent
Mistakes are permanent
A wrong payout address cannot be undone by support. This is why the payout attestation is signed from your own wallet and shown back to you for confirmation.
Next: the two rails in detail
When each is offered, and how to think about them.