Walletless Onboarding
The most innovative aspect of ZingPay is its ability to onboard users who have never interacted with a blockchain before. No wallet apps. No seed phrases. No browser extensions. Just a phone number and a browser.
The Problem
In traditional crypto flows, receiving funds requires:
- Understanding what a wallet is
- Downloading a wallet app (Phantom, Solflare, etc.)
- Writing down and securely storing a 12-24 word seed phrase
- Sharing your public key with the sender
This creates massive friction for non-crypto users, especially in regions where digital literacy varies widely.
The ZingPay thesis: If we can defer the wallet setup to after the user has already received funds, we dramatically lower the barrier to entry. The incentive to learn is built-in. There's already money waiting for them.
The Solution: Ephemeral Keypairs
ZingPay implements a three-step walletless claiming process:
Ephemeral Generation
When an un-onboarded user visits the claim page, ZingPay generates a temporary Solana Keypair entirely within the browser context using Keypair.generate(). No server involvement. No external API calls.
Delegated Claiming
This temporary keypair acts as the delegated identity to sign the transaction that claims the funds from the Escrow PDA. The smart contract verifies the phone hash, confirms the escrow exists, and releases the SOL to the ephemeral wallet.
Non-Custodial Export
The secret key array is serialized to JSON and triggered as a browser download (solpay-keypair.json). The user retains absolute custody of their temporary wallet without relying on browser local storage, cookies, or centralized databases.
Implementation
// walletless.ts: Core logic
import { Keypair } from '@solana/web3.js';
function generateEphemeralWallet(): Keypair {
// Generate a fresh keypair in the browser
return Keypair.generate();
}
function exportKeypair(keypair: Keypair): void {
const secretArray = Array.from(keypair.secretKey);
const blob = new Blob(
[JSON.stringify(secretArray)],
{ type: 'application/json' }
);
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'solpay-keypair.json';
a.click();
URL.revokeObjectURL(url);
}
Security Considerations
| Concern | Mitigation |
|---|---|
| Keypair lives in browser memory | Keypair is generated fresh per session and never persisted to localStorage |
| Key export could be intercepted | Download is initiated via Blob URL. No network request is made |
| User might lose the file | The UI prominently warns users to back up their keypair file |
| Ephemeral key has no SOL for fees | The claim transaction fee is deducted from the escrowed amount |
What happens after claiming? The user now has a funded Solana wallet in the form of a JSON file. They can import this keypair into any Solana wallet app (Phantom, Solflare, Backpack) to manage their funds going forward.
Why Not Use Existing Wallet Adapters?
ZingPay intentionally avoids wallet adapter libraries (like @solana/wallet-adapter) for the claiming flow because:
- No wallet installed: The target user literally does not have a browser extension or app
- Zero dependencies: The ephemeral keypair approach requires only
@solana/web3.js - True non-custodial: At no point does any server or third party hold the private key
The sending flow does use wallet adapters, since senders are expected to already have Solana wallets. The walletless architecture applies exclusively to the receiver onboarding path.