Wallet-per-User (SDP)
Custodial Solana wallets for your users, backed by the Solana Developer Platform. The solana-sdp client gem and the solrengine-sdp Rails engine.
SolRengine has two custody models. The rest of these docs cover the first — your users bring wallets: they sign in with Phantom, Solflare, or any Wallet Standard wallet and keep their own keys. This page covers the second — you hold wallets for your users: people sign up with an email and your app provisions a custody wallet for each of them through the Solana Developer Platform (SDP).
Both are first-class paths, and they mix in one app. Lamport, a neobank demo on devnet, is the worked example of the mix.
Prerequisites
Honest list — Wallet-per-User has real infrastructure requirements, and SDP is pre-mainnet, unaudited, and devnet-oriented:
- A running SDP instance — self-hosted dev stack or managed. The gems talk to SDP’s wallets and payments API.
- A managed custody provider (e.g. Privy) configured in SDP. Local custody holds a single root wallet and cannot provision per-user wallets.
- Kora as SDP’s fee-payment provider (
FEE_PAYMENT_PROVIDER=kora). Without it, SDP’s native adapter can build and sign transfers but cannot submit them. - An SDP API key with
custody:admin,wallets:*, andpayments:*scopes.
When one of these is missing, the gems raise typed errors that name the limitation and the fix (Sdp::ProviderCapabilityError, Sdp::TransferExecutionError) instead of failing obscurely.
The gems
solana-sdp — the API client
Plain Ruby, zero runtime dependencies. Wallets, balances, and transfers against SDP’s API, with typed rescuable errors that mirror SDP’s real failure modes and a retry posture that never re-sends a transfer.
# Gemfile
gem "solana-sdp"
client = Sdp::Client.new(api_key: "sk_...")
client.initialize_custody
wallet = client.create_wallet(label: "user-42")
client.create_transfer(
source: wallet.id,
destination: "RecipientPublicKeyBase58...",
amount: "0.1",
token: "SOL"
)
Usable anywhere Ruby runs — no Rails required. See the solana-sdp README for the full surface, error taxonomy, and the SDP version pin.
solrengine-sdp — the Rails engine
Builds Wallet-per-User on top of the client: your user model gains a custody wallet provisioned at signup (or on demand), every transfer is persisted and tracked to a renderable terminal state, and a watcher process pushes live balance updates to the browser via Turbo Streams when money moves on chain.
# Gemfile
gem "solrengine-sdp"
bin/rails generate solrengine:sdp:install
bin/rails db:migrate
user.provision_wallet! # pending → provisioning → ready
transfer = Solrengine::Sdp::Transfer.execute!(
source: user.sdp_wallet_id,
destination: "RecipientPublicKeyBase58...",
amount: "0.1"
)
transfer.status # "processing" → tracked to "confirmed" → "finalized"
It composes the family: solrengine-realtime for the WebSocket doorbell and optionally solrengine-tokens as a USD price fallback. See the solrengine-sdp README for the quickstart from rails new to a first confirmed transfer.
Which path do I want?
- Users already have wallets and want to keep their keys → the non-custodial stack. Start at the Quickstart.
- Users have an email address and no wallet (neobank-style apps, consumer fintech UX) → Wallet-per-User, this page.
- Both kinds of users → mix them. The models live side by side in one Rails app.
License
MIT