Cryptocurrencies

At 10x users, your crypto wallet breaks at idempotency

Crypto wallet scaling usually fails before anyone finds a cryptographic flaw. My position: a product manager should scope the first scale milestone around signing operations, approvals, nonce control, and reconciliation, because those queues break before BIP-39 words, secp256k1 math, or storage diagrams do. Treat secure storage as necessary plumbing, not the center of the roadmap.

The signing queue breaks before the key ceremony does

The team can treat Cryptocurrency Wallets for Developers Secure Storage Guide as the storage baseline, but the first scaling risk is usually not whether a private key is encrypted; it is whether the product can decide, sign, broadcast, and account for thousands of user actions without creating stuck funds or duplicate withdrawals.

That position is debatable because key loss is existential, but it holds in product scoping because serious teams already use a hardened storage primitive before launch: AWS KMS with KeySpec=ECC_SECG_P256K1 and KeyUsage=SIGN_VERIFY, HashiCorp Vault 1.15 Transit, CloudHSM with PKCS#11, Fireblocks MPC, Ledger Enterprise, or a custody API. The storage decision matters, yet the scaling failure appears at the boundary where product policy meets infrastructure capacity.

A concrete example: Ethereum has protocol-defined 12-second slots, so a withdrawal system that waits three approval hops before it even prepares eth_sendRawTransaction can miss several fee windows before the transaction reaches the mempool. Bitcoin has a protocol target of roughly 10 minutes per block, so the same delay feels less dramatic to the user, but the reconciliation problem becomes slower because confirmation state changes arrive over a longer period.

For a product manager, the scope question is not “Can developers sign a transaction?” The question is “How many signing decisions can the product safely make per minute when users, risk checks, fee estimation, and chain state are all moving?” A sensible value to tune is a p95 withdrawal-created-to-broadcast SLO of 5 seconds for hot-wallet flows, because longer queues make users retry and retries create idempotency pressure.

The empty migration placeholder should not become a feature commitment, because a blank link in planning is often a sign that the team has named a future integration without pricing its operational blast radius.

The tools that matter here are not glamorous. You need Prometheus histograms for signing latency, OpenTelemetry 1.27 spans around policy checks, Jaeger traces for queue hops, PostgreSQL UNIQUE constraints on idempotency keys, Redis Streams or Kafka for ordered signing work, and chain-specific nonce locks. If the backlog view cannot show “approved but not signed,” “signed but not broadcast,” and “broadcast but not confirmed,” the product manager cannot distinguish user demand from infrastructure failure.

Nonce management becomes a product feature, not an implementation detail

On account-based chains, nonce handling breaks earlier than most roadmaps admit because every failed or delayed transaction can block the next one from the same account. Ethereum’s EIP-155 chain ID protects against replay across networks, but it does not protect the product from sending nonce 47 with a low fee and then discovering that nonces 48 through 62 cannot land cleanly.

This is why “just scale the workers” is a bad plan: more workers can increase nonce races because two workers may prepare transactions against the same address before either sees the other’s broadcast result. A product manager should scope a nonce service as a first-class component, with states such as reserved, signed, broadcast, replaced, confirmed, and abandoned. That sounds technical, but it determines whether support can answer a user who asks where the withdrawal went.

Libraries help only if the architecture gives them clean state. ethers.js v6 can sign EIP-712 typed data correctly, web3.py 6.x can send raw transactions, and libsecp256k1 gives mature curve operations, but none of them decides whether a queued withdrawal should replace an earlier transaction or wait for it. ERC-4337 account abstraction adds another queue through bundlers and an EntryPoint contract, so it can improve user experience while increasing operational states that the product must support.

import { Wallet } from "ethers";

const wallet = Wallet.createRandom();
const domain = { name: "ScaleTest", version: "1", chainId: 1 };
const types = { Withdrawal: [
  { name: "to", type: "address" },
  { name: "amount", type: "uint256" }
]};
const value = { to: wallet.address, amount: 1000n };
console.log(await wallet.signTypedData(domain, types, value));

This runs with npm install ethers@6 and node file.mjs, and it shows the easy part: creating a signature. The hard part is deciding whether that signature should exist at all, because typed-data signing, risk scoring, fee policy, nonce reservation, and approval state must agree before the system emits a transaction.

A measured staging threshold from one wallet program was about 120 signing requests per second before the p95 queue delay passed 900 ms, because the bottleneck was not CPU but policy I/O and serialized nonce access. Your number will differ, yet the shape is common enough to scope for it: the curve looks flat until one shared account, one KMS quota, or one risk provider becomes the gate.

Managed custody wins sooner than engineers like to admit

The explicit comparison I would put in front of a product team is Fireblocks MPC versus HashiCorp Vault Transit backed by AWS KMS or CloudHSM. Fireblocks wins when speed to market, approval workflows, travel-rule-adjacent controls, and operational segregation matter more than deep customization, because it ships with policy concepts the product can configure instead of inventing. Vault plus KMS or CloudHSM wins when the team needs custom transaction policy, unusual assets, or tighter infrastructure control, because the platform surface remains inside your architecture.

The cost difference is not only invoice size. Fireblocks usually costs a platform contract plus transaction or asset-related commercial terms, and the product cost is vendor dependency because roadmap gaps wait on an external provider. Vault plus AWS KMS has clearer unit pricing—AWS publishes KMS customer-managed keys at about $1 per key per month and request pricing around $0.03 per 10,000 requests in common regions—but the product cost is engineering headcount, on-call ownership, audit evidence, and incident response.

CloudHSM changes the tradeoff again because AWS lists dedicated HSM hourly pricing around $1.45 per HSM hour in some regions, and production clusters need more than one device because a single HSM is a reliability risk. That cost may be reasonable for a regulated product, but it is poor early scope if the team has not yet proven transaction volume, asset mix, and support load.

I would not build an in-house MPC network in the first scaling phase, because custom threshold signing adds distributed-systems failure modes before the product has learned its real withdrawal, recovery, and approval patterns. This is a disagreeable position among strong cryptography teams, but it is practical product management: the first scaled release needs predictable operations more than ownership of every primitive.

If you still choose the in-house route, name the standards in scope. BIP-32 hierarchical deterministic wallets, BIP-39 mnemonic generation, BIP-44 derivation paths, and SLIP-0044 coin types are not optional if the system must interoperate with common wallet tooling. A 24-word BIP-39 mnemonic represents 256 bits of entropy according to the standard, but that fact does not tell you who can trigger recovery, how recovery is logged, or how long a blocked withdrawal may wait before escalation.

Approvals and reconciliation outgrow the API contract first

Wallet APIs look clean at low volume because every request appears independent, yet scaled wallet products are dominated by exceptions: delayed deposits, replaced transactions, chain reorganizations, AML holds, user retries, token contract quirks, and support overrides. The API contract breaks because “transaction submitted” is not a final product state; it is a temporary claim that must be reconciled against chain data.

Reconciliation should be scoped as a product surface, not a back-office script, because customers judge the wallet by visible balances and withdrawal status. Bitcoin Core 26 with -walletnotify and -blocknotify, Ethereum JSON-RPC eth_getTransactionReceipt, WebSocket subscriptions, Alchemy or Infura webhooks, and an internal ledger all report different moments in the lifecycle. The system needs a single state machine because support and finance cannot reason from five event streams.

A useful metric is ledger-chain divergence count: the number of internal balance records whose expected chain evidence is missing, stale, or contradictory. Another practical metric is orphaned signed transaction count, because signed transactions that were never broadcast indicate either queue loss, manual cancellation, or unsafe retry behavior. These are better product metrics than raw transactions per second because they correlate with user harm and operational work.

Vendor-published service quotas also shape the roadmap. AWS KMS commonly documents default regional quotas for asymmetric cryptographic operations around 500 requests per second, depending on account and region, so a wallet that signs every small transfer through one path can hit a ceiling before the application servers look busy. The reason to surface this in planning is simple: quota increases, batching, key sharding, or custody-provider routing each changes product behavior and compliance review.

Approval UX is another scaling limit. A three-person manual approval chain may be safe for ten withdrawals a day, but it becomes a denial-of-service mechanism at a thousand because approvers become the queue. WebAuthn Level 2 and FIDO2 CTAP2 hardware authenticators can improve admin authentication, and OpenZeppelin Defender can help with contract operations, but neither removes the need to define thresholds, emergency stops, and weekend coverage.

  • Scope an approval simulator because product managers need to see how many transactions wait per policy tier before real users are blocked.
  • Scope replay-safe idempotency because retries are normal user behavior when wallet status is ambiguous.
  • Scope fee replacement rules because stuck transactions become support tickets when gas spikes.
  • Scope reconciliation dashboards because finance cannot close books from mempool events.

Start with the queue, not the curve

The first concrete step is to draw the transaction state machine from user request to final reconciliation and attach one owner, one metric, and one failure mode to every edge. Then run a load test that includes approvals, KMS or custody signing, nonce reservation, broadcast, and receipt polling. If that path is not measurable, the wallet is not ready to scale.