Skip to main content

Phase 0: Designing a Non-Custodial Payment Stack

· 6 min read
OrcaRail
Crypto payment rails for web2 apps

April 20, 2026 — Before we write a line of Solidity, we freeze the spec. Phase 0 is the design and sign-off phase of the non-custodial roadmap: what moves on-chain, what does not, which chain ships first, who audits the contracts, and who holds the deployer keys.

TL;DR

  • Fee split is frozen to four buckets: merchant, platform, referral/affiliate, bridge fee. Everything in the on-chain splitter is expressible in basis points; no off-chain fix-ups.
  • Base is the launch chain for Phase 1. Cheap, fast, already in the wallet service chain list, and USDC-native.
  • Subscriptions adopt ERC-20 approve + pull (EVM) and SPL delegate (Solana). Escrow and session-key designs were rejected — see the decision matrix below.
  • Contracts are deployed by a 3-of-5 Safe multisig (EVM) and 3-of-5 Squads multisig (Solana). Per-link receivers are immutable. Factories and SubscriptionHub sit behind a small proxy with a 48-hour timelock.

What this phase changes

Nothing in production. Phase 0 is a written spec, three audit proposals, a deployer-key ceremony, and a couple of merged ADRs.

The fee split spec (frozen)

Today, SmartAccountWalletService.drainSmartAccountWallet in api/src/withdrawals/services/smart-account-wallet.service.ts composes transfers into a UserOperation with three recipients: the merchant (toAddress), the support wallet (supportWalletAddress), and the commission wallet. The contract version mirrors this exactly:

struct Split {
address merchant; // main receiver
address platform; // support / platform fee
address referral; // commission / affiliate (optional, zero = skip)
address bridgeFee; // Relay bridge fee carrier (optional, zero = skip)
uint16 platformBps;
uint16 referralBps;
uint16 bridgeFeeBps;
}

Everything the keeper does today in TypeScript is computable from this struct and the payment amount. Anything the current keeper cannot express (e.g. dynamic taxes, merchant-level holdbacks) is out of scope for Phase 1 — we add it in a later phase if needed.

Chain selection

Launch chain for Phase 1 is Base:

  • Already in our chainId map (8453 → base, 84532 → baseSepolia) in api/src/payments/wallet.service.ts.
  • Gas is cheap enough that PaymentLinkReceiver deploy + split on first pay is pennies per transaction.
  • Alchemy paymaster policy already supports it, which gives us an escape hatch if we want the keeper on SubscriptionHub.charge() sponsored.
  • Native USDC (not bridged), which matters for subscription allowances.

Ethereum mainnet, Arbitrum, Optimism, and Polygon follow in Phase 3. Solana is a separate program, tracked in Phase 4.

Subscription model: the decision matrix

We evaluated three designs. Only one works for us.

ModelCustodyPayer UXWallet compatibilityKeeper requirementVerdict
ERC-20 approve + pull (chosen)NoneOne-time approveMetaMask, Phantom, Ledger, Safe — nativeAny caller; keeper is optionalShip this
Escrow depositNoneDeposit N monthsAll walletsAny callerWorse UX; funds locked
Smart-wallet + session keysNoneOnboard to 43374337 wallets onlySession-key signerToo narrow compatibility

Approve + pull is the only one that works with the wallets payers already use (MetaMask, Phantom, hardware wallets, Safes). It is also the design we already publish in Auto-charge, which documents approve(spender, amount) and SPL delegation. Phase 2 replaces the pull side with a smart contract and leaves the payer side unchanged.

The long-form argument is in Why allowance-pull beats escrow and session keys.

Deployer key custody

  • EVM: Safe (formerly Gnosis Safe) on Base with 3-of-5 threshold. Signers: two founders, one ops lead, one advisor, one cold backup. Each signer uses a hardware wallet; no key on a server.
  • Solana: Squads multisig with the same 3-of-5 setup and the same signers.
  • Rotation: every signer rotates annually or on departure; any single rotation is a Safe/Squads transaction.
  • No hot keeper can deploy. The NestJS keeper EOA (used to call charge() in Phase 2) has no deploy authority, no upgrade authority, and no fee address.

Upgrade policy

  • Per-link PaymentLinkReceiver: immutable. No upgrade. This is a trust win for payers — the code they are paying into can't change after the fact.
  • PaymentLinkFactory: small UUPS proxy owned by the multisig, 48-hour timelock on upgradeTo. Upgrades cannot change already-deployed receivers.
  • SubscriptionHub: same pattern. charge() and cancel() semantics are stable between versions; if we ever need a breaking change, we deploy SubscriptionHubV2 and migrate instead of upgrading.
  • Refund and dispute semantics: on-chain refund(txId) callable by the merchant signer (via their API key → keeper EOA) or the deployer multisig. Payer cannot self-refund (matches today's product).

Audit vendor strategy

We will shortlist three firms and run one primary audit + one competitive review:

  • Primary candidates (EVM): Spearbit, Trail of Bits, Zellic.
  • Secondary candidates (Solana): OtterSec, Neodyme.
  • Scope: PaymentLinkFactory, PaymentLinkReceiver, FeeSplitter, SubscriptionHub. The Anchor programs get their own audit in Phase 4.
  • Budget: treat the audit as a hard prerequisite for Base mainnet launch. No mainnet before the fix-all report.
  • Public disclosure: audit reports land in the repo and link from /docs/non-custodial/security-model.

Risks and mitigations

  • Spec scope creep. Mitigation: everything not expressible as basis-points-split is deferred to a later phase. Phase 1 does not block on dynamic taxation or per-merchant overrides.
  • Multisig signer availability. Mitigation: 3-of-5, not 2-of-3, so any two signers can be unavailable without freezing deploys.
  • Audit timing. Mitigation: start vendor conversations now; ship contracts to testnet during audit; mainnet deploy is gated.
  • Forgotten fee case. Mitigation: reproduce every path in drainSmartAccountWallet today (native + ERC-20, with/without support, with/without commission) as a Foundry invariant test before audit.

Status checklist

  • Fee split struct approved and tagged
  • Base selected as Phase 1 launch chain
  • Three audit vendors shortlisted
  • Safe (Base) and Squads (Solana) deployer multisigs created and tested
  • ADR merged covering upgrade policy and timelock
  • ADR merged covering subscription model decision
  • Refund / dispute semantics documented

What is next

Phase 1 implements the spec: Contract-based payment links on EVM.


Reference docs: Phase 0 status · Security model · Architecture