Logo
New RPC users get 35% off their first monthView the offer
OnFinality Learn
Infrastructure & Operations11 min read

Non-Custodial Digital Wallet: Key Control, RPC Dependencies, and Verification Workflows

A practical guide to how non-custodial digital wallets hold keys, depend on RPC infrastructure, and how to verify signing, broadcasting, and recovery behavior without trusting a provider.

TL;DR

A non-custodial digital wallet is software in which the user, not a platform, controls the private keys that authorize transactions. The wallet itself usually holds no funds; it derives keys, signs payloads locally, and relies on RPC infrastructure to read chain state and broadcast signed transactions. This article explains the key-control model, the trust boundary between wallet and RPC provider, and a reproducible procedure for verifying that signing stays local and that broadcasting behaves as expected. It also covers failure modes such as nonce conflicts, stale chain state, and seed-phrase loss, and points to concrete endpoint selection resources where provider choice matters.

Scope and the core definition

A non-custodial digital wallet is a wallet in which the private keys that control an address are generated and stored on infrastructure the user controls, and transaction signatures are produced locally. The wallet application may be a browser extension, a mobile app, a hardware device, or a command-line tool. In every case, the defining property is that no service holds a key capable of moving the user's assets.

This article focuses on the operational and integration side: what the wallet does locally, what it delegates to remote infrastructure, and how to verify the boundary. It does not recommend a specific wallet product. Where a concrete endpoint or provider decision is needed, the companion RPC Assistant resources linked below cover that selection.

  • Keys and signing: local to the user's device or hardware module.
  • Chain state reads and transaction broadcast: delegated to an RPC endpoint.
  • Recovery: depends on a user-held seed phrase or backup, not on a support desk.

Assumptions and prerequisites

The procedures below assume you have a wallet capable of exporting a public address (never a private key) and a test network where you can move valueless assets. You need Node.js 18 or later for the JavaScript examples, and curl for the RPC checks. Treat every key you generate for testing as disposable.

You should also have a funded test account on a public testnet. If you are choosing an endpoint for a production wallet integration, review the multi-chain endpoint guidance at /en/learn/multi-chain-rpc-endpoints-guide before running the checks, because rate limits and archive requirements differ by network.

  • A test wallet with a known seed phrase stored offline.
  • A testnet RPC_URL you control or have quota on.
  • Node.js 18+, curl, and a terminal.
  • No production private keys in any script or shell history.

How key control and the RPC trust boundary interact

The wallet's local component derives a key pair from entropy, typically a BIP-39 seed phrase, and computes the address. Signing a transaction is a local cryptographic operation over a payload that includes the chain ID, nonce, recipient, value, gas parameters, and data. The signed transaction is then sent to an RPC node, which validates and propagates it to the peer-to-peer network.

The RPC provider therefore sees your signed transactions and your read queries, but it never sees your private key. That is the trust boundary: a malicious or compromised RPC endpoint can censor, delay, return stale state, or misreport balances, but it cannot forge a signature for your address. This is why wallet security and RPC reliability are separate problems that require separate verification.

  • Local: entropy generation, key derivation, address computation, payload construction, signing.
  • Remote: balance and nonce reads, gas estimation, eth_call simulation, transaction broadcast, receipt polling.
  • Never remote: private key material, seed phrase, or signing operation.

Verifying that signing stays local with a runnable check

The following Node.js script derives an address from a test mnemonic, signs a transaction payload locally, and prints the recovered address. If the recovered address matches the derived address, signing occurred locally and the payload is internally consistent. No network call is made in this step.

Run it with a disposable test mnemonic only. The script uses ethers v6; install it with npm install ethers.

const { Wallet, Transaction, getAddress } = require('ethers');

async function main() {
  const mnemonic = process.env.TEST_MNEMONIC; // disposable test phrase only
  const wallet = Wallet.fromPhrase(mnemonic);
  console.log('derived address:', wallet.address);

  const tx = Transaction.from({
    to: '0x000000000000000000000000000000000000dEaD',
    value: 1n,
    nonce: 0,
    gasLimit: 21000n,
    maxFeePerGas: 1000000000n,
    maxPriorityFeePerGas: 1000000000n,
    chainId: 11155111,
    type: 2
  });

  const signed = await wallet.signTransaction(tx);
  const parsed = Transaction.from(signed);
  console.log('recovered address:', getAddress(parsed.from));
  console.log('match:', getAddress(parsed.from) === getAddress(wallet.address));
}

main().catch((e) => { console.error(e); process.exit(1); });

Expected verification result and what a mismatch means

A correct run prints the same address for derived and recovered, with match: true. That confirms the local signing path is coherent. A mismatch usually means the transaction fields were mutated after signing, the chain ID is wrong for the target network, or the signing library version differs from the one that produced the payload.

This check does not prove the wallet UI is honest. To test that, compare the address shown in the wallet interface with the address derived by the script from the same seed phrase. If they differ, stop and investigate before funding the account.

  • match: true — local signing path is consistent.
  • match: false — inspect chain ID, field ordering, and library version.
  • Address mismatch with wallet UI — treat as a security incident until explained.

Checking RPC behavior for broadcast and state reads

Once signing is verified, test the remote side. The following curl commands check chain ID, current nonce, and a simulated call against your RPC_URL. Replace RPC_URL with your endpoint and ADDRESS with your test address. These are read-only calls and cost no gas.

Record the outputs in a results table so you can compare endpoints or time windows. Do not invent values; capture what your endpoint returns and note the timestamp.

curl -s -X POST "$RPC_URL" \
  -H 'Content-Type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"eth_chainId","params":[]}'

curl -s -X POST "$RPC_URL" \
  -H 'Content-Type: application/json' \
  -d '{"jsonrpc":"2.0","id":2,"method":"eth_getTransactionCount","params":["ADDRESS","pending"]}'

curl -s -X POST "$RPC_URL" \
  -H 'Content-Type: application/json' \
  -d '{"jsonrpc":"2.0","id":3,"method":"eth_call","params":[{"to":"ADDRESS","data":"0x"},"latest"]}'

Results table procedure for endpoint comparison

Run the three calls above against each candidate endpoint at the same moment, and fill in a table with these columns: endpoint label, eth_chainId result, pending nonce, latest block number, response time in milliseconds, and error code if any. Repeat three times per endpoint and keep the median. This gives you a reproducible comparison without relying on vendor claims.

Endpoint labelchainIdpending noncelatest blockmedian latency (ms)error
endpoint A(capture)(capture)(capture)(measure)(capture)
endpoint B(capture)(capture)(capture)(measure)(capture)

If pending nonce differs between endpoints, one node is lagging on the mempool. That matters for wallets that pre-sign transactions. For production integrations, compare dedicated node options at /en/dedicated-node and review quota behavior at /en/pricing/rpc before committing.

Troubleshooting common non-custodial wallet failures

Most wallet failures fall into three buckets: key loss, state inconsistency, and broadcast rejection. Key loss is unrecoverable by design; state inconsistency and broadcast rejection are diagnosable.

For state inconsistency, compare the nonce returned by two independent endpoints. For broadcast rejection, inspect the JSON-RPC error code and message; replacement underpriced and nonce too low are the most common. If a transaction is stuck, a replacement transaction with the same nonce and higher fee is the standard remedy, but only sign it after confirming the original is not already mined.

  • Seed phrase lost and device lost — funds are unrecoverable; no support path exists.
  • nonce too low — the transaction was already mined or replaced; re-read the nonce.
  • replacement transaction underpriced — increase fee above the pending transaction.
  • Stale balance — the endpoint is behind; query a second endpoint or a block explorer.
  • Chain ID mismatch — the wallet is pointed at the wrong network; check /en/networks.

Limitations and tradeoffs of self-custody

Non-custodial wallets remove counterparty risk but concentrate operational risk on the user. There is no password reset, no chargeback, and no recovery desk. Hardware signing reduces key exposure but adds a device dependency. MPC-based wallets split key material across parties but introduce coordination complexity and new failure modes.

RPC dependency is the other tradeoff. A wallet that reads from a single endpoint inherits that endpoint's availability and correctness. Multi-endpoint fallback improves resilience but complicates nonce management, because different nodes may report different pending states. For teams building wallet infrastructure, the integration guidance at /en/api-service and the node hosting overview at /en/learn/blockchain-node-hosting-guide are the relevant starting points.

  • Self-custody: full control, full responsibility.
  • Hardware signing: stronger key isolation, device lifecycle burden.
  • MPC: no single point of key failure, added coordination overhead.
  • Single RPC: simple, but a single point of state and availability failure.

Next steps for wallet builders and operators

If you are integrating a non-custodial wallet into an application, start by verifying the local signing path with the script above, then benchmark at least two RPC endpoints using the results table procedure. Document the chain IDs and nonce behavior your integration depends on, and test recovery from a seed phrase on a clean device before holding real value.

For endpoint selection across networks, use the RPC Assistant guides rather than hardcoding a provider. The Ethereum API overview at /en/learn/best-ethereum-rpc-api and the broader endpoint guide at /en/learn/rpc-endpoints-guide cover the tradeoffs between shared and dedicated infrastructure. Keep your signing path local, your RPC path redundant, and your recovery path tested.

Never Worry about Infrastructure Again

OnFinality takes away the heavy lifting of DevOps so you can build smarter and faster.

Get Started