Wallet segmentation strategy means splitting one balance across several wallets that hold different amounts, sign for different things and store their keys in different places. The wallet a bot signs with holds a working float and nothing else. Everything above it sits behind a boundary the running process has no credential for, so a stolen signing key costs you a tier instead of the whole position.

That principle is easy to agree with and awkward to implement, because segmentation is not a setting you switch on. It is a set of roles you define once, a set of caps you enforce every time you fund, and a written account map that survives the three months between the day you built the structure and the morning you need to reason about it under pressure. The threat model these tiers answer to is set out in the wallet security runbook.

The tier map: six roles and six blast radii

Begin from roles rather than from a wallet count. A role is fixed by three properties: what it holds, what it is permitted to sign, and where its secret physically lives. Once those three are settled, the number of wallets inside a tier becomes an operational detail you can change for a busy week without rethinking custody. Copy the shape of the table below and fill the balance column with your own numbers.

TierHoldsSigns forKey lives onBalance ruleBlast radius if compromised
Cold reserveThe majority of the balance you are not trading this weekNothing routine; occasional top-ups to the treasury onlyHardware wallet or an offline seed, never a bot hostEverything above the treasury capTotal loss of the position; this is the tier the design exists to protect
Treasury or funding walletThe float for the current cycle of runsTransfers to the dispatcher, signed by a humanHardware wallet, or a multisig such as Squads for shared custodyRefilled from cold on a schedule, capped at one cycle of fundingOne cycle of funding, plus the ability to fund whatever the attacker controls next
Dispatcher or operations walletThe fan-out balance for one run plus a fee bufferFan-out transfers, fee payment, sweeps back from executionAn operator workstation, encrypted at rest, not the bot hostOne run of fan-out plus a stated fee margin, never moreThe whole run budget, and any execution wallet it can still refill
Execution walletsA per-wallet floor: rent, fees and one trade sizeSwaps and the token accounts they open, signed by the botThe bot host, in a directory the process reads and nothing else doesRefilled toward a floor, swept when the floor is exceededThe float in that wallet and its open token accounts; nothing above it
Fee payer or rent bankLamports set aside for signatures, priority fees and rent-exempt minimumsFee payment on behalf of execution transactionsThe bot host, but as a separate key from any trading walletSized to a run count, refilled as a batch rather than per walletThe fee reserve only, which is why it is worth separating from trade balances
Burn or throwaway tierDust, and only for the length of one interactionApprovals to unaudited programs, claims, mints, anything unverifiedAnywhere; treat the key as public from the moment it is createdFunded per interaction and never refilled after it has been usedThe dust it holds; the tier exists so that a bad approval has nothing to take

Read the last column from top to bottom and the model justifies itself. Each row is a sentence you are willing to say out loud about a bad day. If any two rows share the same key storage and the same signer, they are not really two tiers, and the blast radius of the lower one silently becomes the blast radius of the higher one. That collapse is the most common defect in setups that look segmented on a diagram.

The single wallet and why it fails quietly

Most fleets start as one wallet because one wallet is what the first working script needed. There was a balance, a keypair file, a configuration line pointing at it, and a trade that went through. Nothing about that arrangement announces a problem, and it can run for months without one. The failure mode is not gradual degradation; it is a single event that takes everything, because everything was reachable from the same signature.

Why one wallet is the default failure

A single wallet makes the maximum loss equal to the balance, permanently, regardless of how careful the rest of your operation is. Every incremental improvement you make afterwards - better key storage, tighter approvals, a cleaner host - reduces the probability of an incident without reducing its cost. Segmentation is the only control that changes the cost side, and it is the one you can implement without changing anything about how the bot trades.

There is a second, less dramatic cost. One wallet makes accounting ambiguous. When a run underperforms you cannot separate trade outcome from fee drag from rent locked in token accounts, because it all moved through the same balance. Tiers give you natural measurement points: what left the treasury, what the dispatcher fanned out, what came back on the sweep. The security benefit arrives first, but the bookkeeping benefit is what makes operators keep the structure.

Building the segmentation from scratch

Build the structure before you need it, on a quiet afternoon, with nothing running. Retrofitting tiers around a live fleet means moving value while transactions are in flight, and every transfer is a chance to send funds to the wrong place. If a run is active, stop it cleanly first and let it settle. The procedure below takes one sitting and produces two artefacts: a directory of labelled keys, and an account map you can read months later.

  1. Write the roles down first. List every job a wallet performs in your setup: hold the reserve, fund the fleet, pay fees, sign swaps, touch untrusted programs. Each distinct job becomes a tier on paper before a single key exists. If two jobs share a signer and a storage location, merge them honestly rather than pretending they are separate.
  2. Generate one key set per tier, in separate directories. Create a directory per tier and generate keypairs into it, so a file path alone tells you what a key is allowed to sign. Generate reserve and treasury keys on a machine that never runs the bot, and protect them with a passphrase. Execution keys can be generated on the host that will use them, because that host is already assumed to know them.
  3. Set a cap for every tier. Decide the maximum balance a tier may hold and the floor each execution wallet is refilled to. Write both figures next to the tier name in your notes, so a refill script and a tired operator apply the same rule. A cap without a written number is a preference, and preferences drift upward.
  4. Write the account map. Record every public key with its tier, its label, the location of its secret described in words rather than as a path to a file you might later move, and what is allowed to use it. Keep the map free of secrets so it can live wherever your operational notes live. A map you are afraid to open is a map you will not maintain.
  5. Fund the tiers in descending order of trust. Move value from cold to treasury, from treasury to dispatcher, and from dispatcher to execution wallets, verifying the destination address before each transfer. Start with a single small transfer per hop and confirm it landed before sending the rest. The mechanics of the fan-out step are covered in the runbook on funding a wallet fleet.
  6. Test the boundary before the first live run. Confirm that the bot process can sign only with execution keys, that no configuration file or environment variable references a treasury path, and that refilling requires an action taken outside the bot. Try to make the bot spend from the dispatcher and satisfy yourself that it cannot.

Caps, floors and refill rules

A cap is the maximum a tier may hold; a floor is the level an execution wallet is refilled toward. Both exist so that funding decisions stop being judgement calls made at speed. When a run needs more, the answer is another refill from the dispatcher, not a larger balance sitting in the execution tier between runs. Refill on a trigger you can state in one sentence, such as a wallet dropping below its floor before a scheduled cycle begins.

Direction matters as much as amount. Value should flow down the tiers on a schedule and back up on a sweep, never sideways between execution wallets. Sideways transfers make the account map wrong, cost a base fee of five thousand lamports per signature for no operational benefit, and blur the measurement points the structure exists to provide. Keep the graph a tree and it stays readable when you need to reconstruct what happened.

Transfers between tiers cannot be undone

Every movement between tiers is a signed transaction on a public ledger. There is no reversal, no support desk and no dispute process. A mistyped destination address that happens to be valid will accept your funds and keep them, and an address that belongs to nobody is equally final. Verify the full destination string before you sign, not the first and last four characters, and send one small transfer first on any address you have not used before. Treat the confirmation step as part of the transfer, not as an optional extra.

Why the execution tier never holds the reserve

The execution tier is the only tier a program signs with unattended, which makes it the only tier whose key is exposed to every dependency, every log line and every process on the host. Reserve balances placed there gain nothing. They do not make trades faster, they do not reduce fees, and they do not remove a refill step, because refills happen between runs rather than during them. The only thing they change is what an attacker takes.

Operators usually park a reserve in an execution wallet for convenience: fewer refills, fewer transfers, less to think about at three in the morning. Convenience is a real constraint and worth designing for, but the correct answer is a dispatcher that can refill quickly and a floor low enough that a refill is cheap, rather than a permanently oversized float. If refilling is painful enough that you are tempted to overfund, fix the refill path instead of the cap.

Naming and labelling so the account map stays readable

Labels are the part of segmentation that decays first. Three months after the build, a directory of files called wallet1 through wallet12 tells you nothing about which one the bot is signing with, which one you swept last, and which one still has an open token account holding rent. Names are not cosmetic here; they are the index into every other decision you make about the fleet.

Use a naming pattern with the tier in the name, a stable index, and nothing that changes: exec-01, dispatcher-01, treasury-01. Avoid encoding a token symbol, a strategy name or a date into a wallet label, because all three change while the key does not. Record the public key beside the label in the account map, and use the label everywhere else - in logs, in notes, in alerts - so that a secret never has to appear next to the thing it signs for. The storage and rotation side of this is covered in key storage and rotation.

  • Every key file sits in a directory named for its tier, with no exceptions for a key you created quickly.
  • Every label appears exactly once in the account map, next to its public key.
  • No label encodes a value that will change, such as a balance, a date or a token symbol.
  • Logs and alerts reference labels, never file paths and never key material.
  • Retired keys stay in the map with a retired marker rather than being deleted from it.

Sizing the tiers

Sizing is arithmetic, not intuition. Fix a total, fix a per-wallet floor, decide how many execution wallets a run needs, and the rest of the structure falls out. The worked example below uses arbitrary figures to show the method; substitute your own and the shape of the answer stays the same. What you are looking for is the share of the total that is reachable from the bot host at any moment.

Worked example: a forty SOL balance across four tiers

All figures here are illustrative. Take a total of 40 SOL, a run that uses 12 execution wallets, and a per-wallet floor of 0.05 SOL. The execution tier then holds 12 multiplied by 0.05, which is 0.6 SOL. Give the dispatcher 2 SOL so it can refill the tier several times over without a treasury transfer, and leave the treasury with 7.4 SOL for the current cycle. The cold reserve holds the remaining 30 SOL.

Exposure follows directly. If every execution key leaks, 0.6 of 40 SOL is reachable, which is 1.5 percent of the total. If the dispatcher leaks as well, 2.6 of 40 SOL is reachable, or 6.5 percent. The treasury and reserve account for the other 93.5 percent and are only reachable by someone who can produce a signature from a device that never touched the bot host.

Account overhead is part of sizing. Each of the 12 execution wallets needs the system account rent-exempt minimum of 0.00089088 SOL, which is 0.01069056 SOL in total. If each wallet opens two SPL token accounts at 0.00203928 SOL each, that is 24 accounts and 0.04894272 SOL locked as rent. Both amounts return to the destination when the accounts are closed, so they are locked rather than spent, but they must be present in the floor or the first transaction fails.

The execution count is where multi-venue runs change the arithmetic. A run that touches several venues in one session needs more execution wallets than a single-pair run, because each venue brings its own token accounts, its own routing and its own failure modes; if you are operating a multi-DEX Solana volume bot, the execution tier grows and the boundary above it matters more, not less. More wallets at the bottom means more keys on the host, and the only thing keeping that from scaling your maximum loss is the cap on the tier above.

Rotation cadence at the boundary

Rotation is what keeps a boundary meaningful over time. A key that has been on a host for a year has been present for every dependency update, every backup, every debugging session and every screen you shared. None of those events is evidence of compromise, and together they are exactly the accumulation the boundary was drawn to contain. Rotating the execution tier resets that accumulation without touching the tiers above it.

Pick a cadence you will actually keep, and treat certain events as immediate triggers regardless of the schedule: a package installed from an unverified source, a host restored from a backup you did not create, an operator leaving, a key path appearing anywhere it should not. Rotate the dispatcher less frequently than execution wallets but more frequently than the treasury, because it is the tier that sees both sides of the boundary and therefore carries the most accumulated exposure per unit of balance.

Sequence the rotation so no account is ever unreachable. Generate the replacement key, add it to the account map, fund it to the floor, point the bot at it, confirm one live signature, then sweep the retired wallet and close its token accounts to recover the rent. Mark the old label retired rather than deleting it, so a signature from six weeks ago can still be traced to a wallet you no longer use. Related procedures sit together under key hygiene.

Creating and checking tiered keys

The commands below create labelled keypair files in directories that name their tier, and read balances back per public key. Generate treasury and reserve keys with a passphrase and on a machine that does not run the bot; the passphrase prompt is the reason those two lines omit the flag that skips it. Restrict file permissions immediately after creation, because a keypair file is a JSON array of sixty-four bytes and is equal to the private key itself.

create labelled keys per tier and read balances back
mkdir -p keys/treasury keys/dispatcher keys/exec keys/burn
solana-keygen new --outfile keys/treasury/treasury-01.json
solana-keygen new --outfile keys/dispatcher/dispatcher-01.json
solana-keygen new --no-passphrase --outfile keys/exec/exec-01.json
solana-keygen new --no-passphrase --outfile keys/burn/burn-01.json
chmod 600 keys/treasury/treasury-01.json keys/dispatcher/dispatcher-01.json
chmod 600 keys/exec/exec-01.json keys/burn/burn-01.json
solana address -k keys/exec/exec-01.json
solana balance -k keys/exec/exec-01.json --url <rpc-endpoint>
solana balance <pubkey> --url <rpc-endpoint>

Reading a balance by public key rather than by keypair file is the safer habit for routine checks, because it needs no secret at all. Keep a plain list of public keys beside your account map and check the fleet from it. The keypair flag is there for the moment you need to confirm that a file still corresponds to the address you think it does, which is worth doing after any move between machines. Command reference material for the CLI is published at the Anza documentation site.

Auditing a fleet that grew organically

Most readers are not building from nothing. They have a working setup with wallets added over time, a couple of keys whose purpose is remembered rather than recorded, and a balance distribution nobody chose deliberately. Auditing that is a different job from building: you are recovering the model that is already implied by the accounts, then deciding which parts of it you are willing to keep.

  • Every public key with a non-zero balance appears in the account map, including keys you no longer intend to use.
  • Each key in the map has one tier, and no key is described as serving two roles.
  • No key file used by the bot host also exists on a machine you consider cold, and no cold key has ever been present on the bot host.
  • No tier currently holds more than its written cap, and any tier without a written cap gets one before the audit closes.
  • Every execution wallet holds its floor plus rent for its open token accounts, and nothing that looks like a reserve.
  • No configuration file, environment variable or script on the bot host references a treasury, reserve or dispatcher key path.
  • Every wallet that received an approval from an unverified program is in the burn tier, or has had that approval revoked.
  • Retired keys are marked retired in the map and their token accounts are closed so their rent is recovered.
  • The map is stored where you would find it during an incident, and contains no secrets that make it dangerous to open.

Work the list in that order and stop at the first item you cannot answer. An unanswerable item is the audit finding, and it is almost always the same one: a key whose purpose nobody wrote down and whose balance nobody wants to move. Resolve it by sweeping the balance to a tier you do trust, marking the key retired, and never signing with it again. A structure you can describe completely is worth more than a structure with one more tier and a gap in the middle.

Questions the desk gets asked

How many wallets does a segmented setup actually need?

Four tiers cover most single-operator setups: a cold reserve, a treasury, a dispatcher and a set of execution wallets. The execution count depends on the run, not on the security model. Adding wallets inside a tier does not improve segmentation; adding a tier with different key storage does, because it introduces a boundary an attacker has to cross separately.

Can the treasury and the dispatcher be the same wallet?

They can, and for a small setup that is a reasonable simplification, but understand what you gave up. The dispatcher is online whenever you refill, so merging the two puts the funding balance on a key that touches a live host regularly. If you merge them, cap the merged wallet at the level you were willing to lose.

Should every execution wallet have its own seed phrase?

Independent keypair files are safer than many wallets derived from one seed phrase, because a seed phrase controls every account derived from it. If a single derivation seed is exposed, the whole execution tier goes with it. Separate ed25519 keypair files keep the loss to the files that were actually read.

What balance should an execution wallet hold?

Enough to cover the rent-exempt minimum for the accounts it will open, the base fee of five thousand lamports per signature for the transactions it will send, any priority fee you configure, and the trade size itself. Anything beyond that is exposure with no operational purpose, so refill toward a floor rather than topping up generously.

Does segmentation help if the bot host itself is compromised?

It limits the loss to whatever the host could sign for. An attacker with the host has the execution keys and any credential the process holds, so treat that tier as gone. The treasury and reserve survive only if their secrets were never present on that machine, which is the whole reason the boundary exists.

How often should keys at the boundary be rotated?

Rotate execution keys on a schedule you can actually keep, and immediately after any event that touched the host: a dependency change from an unverified source, a shared screen, a restored backup, a new operator. The dispatcher rotates less often but still on a schedule, because it is the tier that sees both sides of the boundary.