The Payment Flow
sequenceDiagram
autonumber
actor Payer
participant Registrar
participant Onramp
participant Safe as Safe (Smart Account)
Note over Payer: wants to pay an X handle (e.g., @X)
%% 1–2. Request deposit address
Payer->>Registrar: Ask for ETH deposit address for @X
%% 3. Registrar derives and returns address
Registrar->>Registrar: Deterministically derive deposit address
Registrar-->>Payer: Return deposit address (Safe address)
%% 4. Payment
alt Use onramp
Payer->>Onramp: Start onramp (buy/bridge any token)
Onramp->>Safe: Deposit funds to derived address
else Already has coins
Payer->>Safe: Transfer tokens/ETH to derived address
end
Safe Smart Account
graph TD
subgraph Safe["Safe Smart Account (deterministically derived address)"]
RegistrarOwner["Owner: Registrar"]
Exec["Ownable Executor Module"]
end
RegistrarOwner -->|controls| Safe
Safe --> Exec
Exec -->|later sets owner| Payee
RegistrarOwner:::actor
Payee:::actor
Safe:::contract
Exec:::module
Claim Flow (Setup)
sequenceDiagram
autonumber
actor Payee as Payee (X handle owner)
participant App as User App (browser / embedded wallet)
participant ZK as ZK Prover
participant Registrar
participant Safe as Safe (for @X)
participant Exec as Executor Module
%% 1–2. Payee arrives and enters handle
Payee->>App: Open site and enter handle (@X)
%% 3–4. App generates and stores embedded wallet
App->>App: Generate embedded wallet (private/public keypair)
Note right of App: Keypair securely stored locally<br/>within browser storage
%% 5. Generate zk proof for ownership and command
App->>ZK: Generate zk proof of handle ownership<br/>+ intent: setOwner(0x123)
ZK-->>App: zk proof
%% 6. Submit proof to registrar
App->>Registrar: Submit {handle=@X, proof, targetOwner=0x123}
%% 7. Registrar verifies and updates Safe
Registrar->>Registrar: Verify proof and resolve Safe for @X
Registrar->>Safe: Access Safe (owner = Registrar)
Registrar->>Exec: setOwner(0x123)
Exec-->>Registrar: Owner updated
%% Acknowledgement
Registrar-->>Payee: Confirmation: Executor Module owner set to 0x123
Claim Flow (Withdraw)
sequenceDiagram
autonumber
actor Payee
participant App as User App (browser + embedded wallet)
participant Exec as Executor Module (on Safe)
participant Safe as Safe (for @X)
participant Recipient as Recipient Address
participant Offramp as Off-ramp Service
%% Load embedded wallet
Payee->>App: Open site (Withdraw)
App->>App: Load embedded wallet from local storage
opt Wallet not found
App-->>Payee: No wallet found → redirect to Setup / Claim flow
end
%% Choose withdrawal path
alt Direct on-chain withdrawal
Payee->>App: Choose "Withdraw to address" (amount, token, recipient)
App->>Exec: withdraw(token, amount, to=Recipient) signed by embedded wallet
Exec->>Safe: Execute transfer
Safe-->>Recipient: Tokens / ETH transferred
App-->>Payee: Withdrawal complete (on-chain)
else Off-ramp withdrawal
Payee->>App: Choose "Off-ramp" (amount, token, payout option)
App->>Offramp: Initiate off-ramp request
Offramp-->>App: Return deposit address (D)
App->>Exec: withdraw(token, amount, to=D) signed by embedded wallet
Exec->>Safe: Execute transfer
Safe-->>Offramp: Tokens / ETH sent to D
Offramp-->>Payee: Fiat payout to bank / card / wallet
end