Case study - Web3 wallet layer

A cryptographic login. Three ways to fund it.

A gaming platform that takes crypto needs its wallet to be more than a balance widget. We designed and built the Web3 layer of a white-label gaming platform: the wallet as a first-class identity - Sign-In-With-Ethereum with a server-issued, server-verified challenge - and a funding triad of on-chain ETH deposits, a server-signed card on-ramp, and plain crypto transfers, all credited to one multi-currency balance carried at exact decimal precision.

  • wallet sign-in via SIWE - challenge issued and verified server-side
  • three funding rails into one balance - on-chain, card, crypto transfer
  • exact money math - crypto at eight decimals, fiat at two
Sign in
Connect a wallet
MetaMaskinjected
WalletConnectQR · v2
0x7a3f…9c4econnected
Ethereum mainnet
Signature request
domain██████.gg
address0x7a3f…9c4e
statementSign in with Wallet
chain id1
nonce████████
Sign message
challenge issued server-side · verified server-side
Client
Web3 wallet layer - white-label gaming platform
Sector
Gaming - wallet identity, deposits & payments
Role
Product design & frontend engineering, end to end
Chain / Rails
Ethereum mainnet · on-chain, card on-ramp, crypto transfer
Stack
Next.js · wagmi · viem · TypeScript
The challenge

Two ways to get a crypto wallet wrong

A gaming platform that takes crypto has two ways to fail its players. The first is to ignore what a wallet is and make Web3 users type passwords like it is 2015 - an email form in front of people who carry a cryptographic identity in their pocket. The second is worse: bolt on a wallet button that treats the browser as trusted, reads a balance and calls it authentication, and hands client JavaScript the API keys and signing decisions it should never hold. Both fail the same audience - one on experience, the other on security.

The brief was to do neither. The wallet had to be a real login - a signature over a challenge the server issues and the server verifies, producing the same session as any other sign-in method, attached to the same player account as email or Steam. And funding had to meet players where they are: on-chain from the connected wallet, by card for players without crypto, or by plain transfer to a deposit address - three rails into one balance, with every secret staying server-side.

Inside the wallet

Four panels, one argument

The product shipped white-label, so these panels are its flows redrawn to spec in this page's own design language rather than screenshots of any one brand. The order is the player's: connect a wallet and sign the challenge, pick one of three rails in, watch the deposit confirm on chain, and land on a balance that belongs to the same account as every other way of signing in.

On-chain ETH
wallet → platform, tracked to confirmation
Card / Google Pay
fiat on-ramp, server-signed
Crypto transfer
address + QR, ~3–5 min
One balance, three ways in - on-chain ETH from a connected wallet, a fiat card on-ramp, and a plain crypto transfer.
Waiting for approvaldone
Confirming on chainon chain
Deposit confirmedpending
tx0.05 ETH → 0x8b1d…44a0
The transaction lifecycle is shown to the player - approval, on-chain confirmation, credit - not a spinner.
ETH0.025000008 dp
USDT450.002 dp
EUR120.002 dp
rates refreshed live
Crypto at eight decimals, fiat at two - exact money math, never floats.
MetaMaskSIWEsignature
WalletConnectSIWEsignature
SteamOpenID
GoogleOAuth
Email + passwordcredentials
Five ways into one account - the wallet is a first-class identity, linked to the same player as email or Steam.
What we built

The architecture behind the wallet

Each piece exists to keep one promise: the wallet is a first-class identity, and no secret ever reaches the browser.

01

Sign-In-With-Ethereum - a login, not a balance read

Authentication is a SIWE (EIP-4361) message bound to the domain, URI, address, and chain ID, with the statement “Sign in with Wallet”. The server issues the nonce challenge - reCAPTCHA-gated and tenant-scoped - the wallet signs it, and the signature is verified locally and again server-side before a session JWT is returned. It is wired as a credentials provider in the same auth route as every other sign-in method: a cryptographic login, not a wallet check.

02

Two connectors, and mobile deep-links that land

MetaMask connects through the injected provider; WalletConnect v2 through a QR modal themed to the brand. On iOS and Android, when no wallet is injected, the flow deep-links straight into the MetaMask app - dapp:// with the metamask.app.link fallback - while desktop falls back to the install page. Underneath: wagmi and viem over http and WebSocket clients on Ethereum mainnet, with sessions that reconnect automatically.

03

On-chain deposits with a visible lifecycle

The backend mints a fresh deposit address per deposit, the wallet sends the transaction, and the player watches it move through three honest states - waiting for approval, confirming on chain, deposit confirmed - instead of a spinner. Amount presets run at eight-decimal precision, a currency-match guard stops a wallet from sending the wrong asset against the selected balance, and deposit and first-time-deposit events feed analytics.

04

A card on-ramp that keeps its secret

Fiat funding runs through an overlay on-ramp widget (MoonPay under the hood) paying by Google Pay, Visa, or Mastercard. The widget URL is signed server-side and injected into the page - the on-ramp secret never reaches the browser. A live FX calculator quotes the conversion at eight decimals of crypto against two of fiat, success and failure are surfaced in-product, and the whole rail is feature-flagged per brand.

05

Crypto transfer, honestly disclosed

The third rail is the plainest: a deposit address and QR code from a payments processor, with the processing window - around three to five minutes - disclosed up front rather than discovered in support chat.

06

Five ways into one account

One auth route carries them all: the two wallet connectors signing SIWE, Steam over OpenID with account linking, Google, and email-and-password credentials with reCAPTCHA, date of birth, and affiliate data. Remember-device controls session length - thirty days against one hour - and the player IP is forwarded for fraud and geo checks. A wallet player and an email player are the same kind of player, on the same account surface.

07

Exact money, across every brand

All money math runs on decimal.js and bignumber.js - never floats - with crypto rendered at six to eight decimals and fiat at two, and balance switching that branches fiat from crypto through live currency-rate conversion. The layer ships inside a white-label platform of roughly eighteen brand apps on one shared component library, every wallet feature flagging on per brand.

Results

Measured in the field

2
Wallet connectors
3
Funding rails
5
Sign-in methods
8 dp
Crypto precision
0
Secrets in browser
~18
Brands, one codebase

These are properties of the build, not a campaign report: two connectors and three funding rails resolve into one balance, five sign-in methods resolve into one account, money is carried at exact decimal precision, and the secrets - the on-ramp signature, the SIWE challenge, the verification - live server-side, where the count in the browser is zero. Crypto-native onboarding is the promise; keeping the browser out of the trust boundary is how it holds.

Under the hood

The stack

  • Next.js
  • React
  • TypeScript
  • wagmi
  • viem
  • ethers
  • WalletConnect v2
  • SIWE / EIP-4361
  • NextAuth
  • decimal.js

Adding a wallet to a product players fund?

Connectors, SIWE, deposit rails, exact money math - we've designed and shipped the whole layer with every secret server-side. Tell us what you're building and we'll tell you exactly how we'd approach it.

15 min · no pitch · usually within 24h