How we hold keys, approve withdrawals, watch for problems and respond when something goes wrong.
Held offline, with key shares in separate locations. Moves only to the warm wallet, after a time delay.
Refills the hot wallet. Needs staff approval and can only send to our own wallets.
Automated client payouts to whitelisted addresses, within a daily cap.
Each key is split into shares with threshold signatures (MPC-TSS). The shares sign together without ever being combined.
One key share belongs to an independent policy service. It checks every request and withholds its signature when a rule is broken.
| Rule | Example | If it fails |
|---|---|---|
| Address whitelist | Payouts only to addresses approved in advance, after a waiting period | Rejected |
| Amount levels | Larger amounts need more approvers and may be delayed | Sent for approval |
| Speed limits | Hourly and daily caps per asset, per wallet and per merchant | Paused |
| Contract calls | Treasury wallets cannot use delegatecall, change owners, upgrade contracts or grant token approvals | Rejected, alert raised |
| Time windows | Warm and cold transfers only during staffed hours | Queued |
| AML screening | Destination is sanctioned or high-risk | Blocked |
Authorised staff can pause withdrawals at any time. Restarting them needs several authorised people. These conditions trigger a pause automatically.
Withdrawals far above the normal level for that hour, or above a fixed cap.
The on-chain balance differs from our internal ledger.
A wallet sends something our system did not create.
A node out of sync, unusual error rates, or a config change outside the release window.
Triggered automatically. An authorised officer can lift it after review.
Triggered automatically or by authorised staff. The restart needs more than one approval.
Triggered automatically or by authorised staff. The restart needs several key holders, including an executive, after the cause is understood.
A restart is a signed request, not a button. Each approver confirms it on their own hardware security key, and the policy service, which holds one key share, checks the signatures before it will sign anything again. One compromised admin account cannot unfreeze the system.
Deposits keep being credited. Withdrawals queue for the operations team, who apply the same rules and multi-person approval as the automated flow. Merchants see each request's status in the console.
Before any transfer is signed, we confirm that the transaction approvers see is exactly the transaction that will be executed. Nothing is signed on trust.
# Request signature signature = HMAC_SHA256(secret, timestamp + "\n" + nonce + "\n" + method + "\n" + path + "\n" + SHA256(body)) # Server-side checks ✓ client TLS certificate valid ✓ source IP on allow-list ✓ timestamp within allowed window ✓ nonce never used before ✓ signature matches ✓ key permitted for this action
Mutual TLS, signed requests and replay protection on every call.
Read, deposit and payout keys are separate. Payout keys cannot change whitelists.
Retried requests never create a second payout.
Verify our signature, then re-query the transaction before crediting a client.
Dedicated, managed devices that are never used for email, browsing or development.
No one person can create, approve and broadcast a transfer. Production access is granted per task and logged.
Pinned dependencies, integrity hashes on front-end files, and a second reviewer on every deployment.
Ledger, on-chain balances and provider records are matched continuously. Any difference pauses withdrawals.
Access to production and approval systems is logged. Security researchers can report issues through our responsible disclosure program.
Written runbooks for detecting, containing and investigating incidents.
Clients can request more detail on our security model during onboarding.