The shape of a funding run

Funding wallets on Solana is a fan-out with a ledger attached. Value leaves a reserve you keep offline, lands in a treasury, moves once into a dispatcher account, and is then split across execution wallets in chunked batches. Each wallet receives a floor made of three parts: the rent-exempt minimum, a fee buffer and the working amount. When the run ends, the residue is swept back and every line is reconciled against something you can read on chain.

The reason to write this down as a procedure rather than a script is that the arithmetic is trivial and the bookkeeping is not. A transfer costs you one instruction. Knowing six hours later which of forty wallets received which amount, and whether a missing fraction of a SOL is spend or a chunk that never landed, takes a record you started before the first signature. This is the step where value is most exposed and least interesting, which is exactly why it gets done casually.

Two artefacts carry the whole run. The first is the account map: a file listing every public key in the fleet, its role, its intended balance and the keypair that signs for it. The second is the ledger described further down this page, which records every movement of value with a stated basis and a stated thing it reconciles against. Both belong to the same discipline that sets the tiers in the first place, described in the wallet segmentation strategy.

Roles matter here because they set the blast radius. The reserve signs rarely and never from the trading host. The treasury signs a handful of times per week. The dispatcher signs many times in a few minutes and touches every wallet in the fleet, which makes it the most useful key an attacker could take and the one you should fund per run rather than leave standing. The rest of the operational runbooks assume that split is already in place.

Preconditions before any SOL moves

Preconditions are not a formality. Every item below is something that, if false, turns an ordinary fan-out into either a stranded balance or a permanent loss. Check them in a single pass and check them from the machine you are about to sign from, because a configuration that is correct on your laptop and wrong on the host is a configuration that will send real value to the wrong cluster or from the wrong key.

  • The account map exists as a file, lists every fleet public key, and names the keypair that signs for each one.
  • Every destination address in the map has been confirmed by machine comparison against its keypair, not read off a screen.
  • The CLI is pointed at the cluster you intend to fund, and you have confirmed that rather than assumed it.
  • The dispatcher keypair is the one you think it is, verified by deriving its address from the file rather than from memory.
  • The reserve is not the source of this fan-out and is not loaded on the signing machine.
  • The per-wallet amount is written down in lamports, agreed before the run, and not adjusted mid-fan-out.
  • The dispatcher balance covers the fan-out total plus its own signature fees, with headroom for a retry.
  • You know how many signatures the fleet is expected to produce during the run, at least as an order of magnitude.
  • Someone other than the operator can find the account map and the ledger if the run has to be picked up by another person.

Transfers are final

A confirmed transfer on Solana cannot be reversed, cancelled, disputed or recovered. There is no support desk with the authority to move value back, because no such authority exists in the protocol. A mistyped address, a truncated paste, or a copy that lost its last characters is final the moment the transaction confirms. Sending into an address for which you hold no keypair is a permanent loss of that value, not a delay, and it stays permanent no matter who you contact afterwards. Verify destinations before the transfer, never after.

The per-wallet floor and what it is made of

Every execution wallet needs a minimum balance before it is useful, and that minimum is not a single number you invent. It is a sum of three separate obligations, each with its own reason to exist and its own behaviour at the end of the run. Treating the floor as one opaque figure is how operators end up with wallets that cannot pay for their own final transaction, or with far more value parked in hot keys than the strategy ever needed.

Why a floor exists at all

The first component is the rent-exempt reserve. A system account with no data must hold 890,880 lamports to persist; below that it is not exempt and is subject to collection. Those lamports are not spent, they are locked, and they come back when the account is closed. The second component is a fee buffer: every signature costs 5,000 lamports and is charged whether the transaction succeeds or fails, so a wallet that is out of fee headroom cannot even sign its own sweep. The third is the working amount, which is the only part your strategy actually consumes. Any wallet that will hold tokens needs a fourth line as well, because each SPL token account locks 2,039,280 lamports of its own.

Sizing the fee buffer is the part most people skip. Count the signatures you expect the wallet to produce during the run, add the ones it will produce during the sweep, then add headroom for failures, because a failed transaction still pays. Priority fees sit on top of that and are set as micro-lamports per compute unit multiplied by the compute unit limit you request, so a congested run costs more than a quiet one. If you cannot estimate the count, over-provision the buffer and sweep the excess back; the money is recoverable, an under-funded wallet mid-run is not free to fix.

Locked lamports deserve their own line in your accounting because they are not spend. A fleet that appears to be consuming SOL steadily may simply be opening accounts, and the difference between a cost and a deposit matters when you are deciding whether a strategy is working. The mechanics of what is locked, what is refundable and what is genuinely gone are worked through in rent and account costs.

The fan-out procedure

Run the steps in this order. The order exists because the cheapest place to catch a mistake is before it has been repeated across the fleet, and because a single verified wallet tells you more about your configuration than any amount of re-reading a config file. Nothing here is difficult; the discipline is in refusing to skip the single-wallet check when the run feels routine.

  1. Verify the account map. Read every public key from the map and confirm you hold a signing keypair for each. Derive the address from the keypair file and compare the two strings by machine. Eyes miss transposed characters in base58, and base58 has no checksum you can see at a glance.
  2. Compute the per-wallet amount. Add the rent-exempt minimum, the fee buffer and the working amount, and any token account reserves the wallet will need. Express the result in lamports. Working in decimal SOL introduces rounding that shows up later as unexplained residue.
  3. Confirm the dispatcher balance. Fund the dispatcher from the treasury in one movement sized to this run, then read its balance back. The dispatcher needs the fan-out total plus its own signature fees plus its own rent-exempt reserve, and no more.
  4. Fund one wallet and verify it. Send the computed amount to a single destination, wait for confirmation, and read that wallet balance from chain. A match proves the cluster, the signer, the amount unit and the destination format in one shot. A mismatch stops the run before it has scaled.
  5. Batch the rest in chunks. Split the remaining transfers into groups that fit inside the serialized size limit, and submit them a chunk at a time. Do not queue every chunk at once, because a queue that fails halfway leaves you reconstructing which half landed.
  6. Verify after every chunk. Read back the balance of each wallet in the chunk just submitted. Only advance when every wallet in the chunk matches. On a mismatch, stop, identify the missing transfer by signature, and resolve that one wallet before continuing.
  7. Verify the totals. Compare the dispatcher balance drop against the sum of credited wallets plus the fees the dispatcher paid. The residual should be explainable to the lamport. An unexplained residual is not rounding; it is a transfer you have not accounted for.
  8. Record the ledger. Write each movement into the funding ledger with its basis and its reconciliation source. Do this while the run is in front of you. A ledger written from memory the next day is a story, not a record.

Step four is the one people cut when they have done this before. Keep it. The single-wallet canary is the only cheap test of a whole class of configuration mistakes, and its cost is one signature and about the time it takes to read a balance back. The alternative is discovering the same mistake forty times in the same minute.

Batching and the transaction size limit

A fan-out is chunked because a Solana transaction is capped at 1,232 bytes once serialized. That cap is not a policy you can raise. Every recipient you add to a batched transfer contributes an account key and an instruction to the packed message, and signatures occupy space of their own, so the number of transfers that fit is a function of your actual message layout rather than a constant you can memorise from someone else's setup.

Work out your chunk size by packing and simulating rather than by guessing. Address lookup tables reduce the size of a transaction that touches many accounts, so a fleet using them will fit more transfers per transaction than one that does not. Whatever number you arrive at, hold it constant for the run and record it in the ledger, because a chunk size that drifts mid-run makes the arithmetic of "how many transactions should have been submitted" impossible to check afterwards.

Blockhash validity puts a second bound on batching. A recent blockhash is valid for 150 slots, and target slot time is about 400 milliseconds, so a transaction you sign and sit on will eventually expire rather than land. Expiry is a safer failure than a duplicate, but it still has to be detected, which is another argument for submitting a chunk, confirming it, and only then building the next one. Durable nonce accounts exist for the cases where you genuinely need a signature to stay valid beyond that window.

The funding ledger

The ledger is the artefact that makes a funding run auditable. Each line records one movement of value with four things attached: where it came from, where it went, how the amount was decided, and what you will compare it against when you check the run. That last column is what turns a list of transfers into a reconciliation. Without it you have a history, and a history only tells you what happened, not whether it was what you intended.

LineFromToAmount basisRecorded asReconciled against
L1Cold reserveTreasuryPlanned run total plus contingencyReserve drawdownReserve balance read before and after the movement
L2TreasuryDispatcherFan-out total plus dispatcher fee headroom and its own rent reserveDispatch floatTreasury balance change and dispatcher balance read back
L3DispatcherExecution walletsPer-wallet working amount multiplied by wallet countFan-out distributionPer-wallet balances read back against the account map
L4DispatcherExecution walletsRent-exempt minimum for each new system accountRent buffer, locked not spent890,880 lamports floor present in every funded wallet
L5DispatcherExecution walletsExpected signature count per wallet at 5,000 lamports eachFee buffer top-upSignature counts observed in the run history per wallet
L6Execution walletsTreasuryResidual balance less the fee for the sweep signature itselfSweep backDistribution total from L3 and L5 minus recorded spend
L7TreasuryCold reserveClosing treasury balance after the sweep has settledReserve returnL1 drawdown amount and the net result of the run

Notice that lines L4 and L5 are separated from L3 even though all three are the same transfers on chain. The separation is deliberate. L3 is value your strategy will consume, L4 is value that is locked and refundable, and L5 is value that will be burned as fees regardless of outcome. Collapsing them into one figure is how a run that merely opened a lot of accounts gets mistaken for a run that lost money, and how a run that genuinely lost money gets excused as rent.

Verification after every chunk

Verification means reading state from chain, not trusting the return value of the tool that submitted the transfer. A submission tool reports what it sent; the chain reports what exists. Those two agree almost always, and the interesting cases are entirely inside the "almost". Read the balance of every wallet in the chunk, compare against the intended figure in lamports, and only then build the next chunk.

funding checks from the operator shell
solana config get
solana address -k <DISPATCHER_KEYPAIR>
solana balance <DISPATCHER_PUBKEY>
solana balance <WALLET_PUBKEY>
solana rent 0
solana rent 165
solana transfer <WALLET_PUBKEY> <AMOUNT> --from <DISPATCHER_KEYPAIR> --allow-unfunded-recipient
solana transaction-history <DISPATCHER_PUBKEY>
spl-token accounts --owner <WALLET_PUBKEY>

The --allow-unfunded-recipient flag is required when the destination does not yet exist, which is the normal case for a fresh fleet. Treat it as a signal rather than a convenience: it means the tool will happily create an account at whatever address you gave it, including one you cannot sign for. That flag and the account map verification in step one are two halves of the same safety property, and dropping either one removes it.

Keep the signature of every funding transfer. Signatures are how you resolve a disputed line months later, how you tell a failed chunk from a chunk that landed and was then spent, and how you answer the question of whether a wallet was funded twice. Treat retained signatures as part of the record rather than as debugging output, and start that habit here, because a funding run is the cheapest place to build it.

Arithmetic for a stated fleet

The following is worked in lamports so that nothing rounds. It uses only protocol constants: 890,880 lamports for the rent-exempt minimum of a system account with no data, 2,039,280 lamports for an SPL token account, and 5,000 lamports per signature. The wallet count and the working amount are chosen for the example and are not a recommendation; substitute your own and the structure of the calculation is unchanged.

Worked example: illustrative fan-out to 40 wallets at 0.05 SOL each

Take a fleet of 40 execution wallets, each to receive a working amount of 0.05 SOL, which is 50,000,000 lamports. Each wallet is new, so each needs the rent-exempt minimum of 890,880 lamports. Assume each wallet is expected to produce 20 signatures during the run, giving a fee buffer of 20 multiplied by 5,000, or 100,000 lamports per wallet.

The per-wallet floor is therefore 50,000,000 plus 890,880 plus 100,000, which is 50,990,880 lamports, or 0.05099088 SOL. Across 40 wallets that is 2,039,635,200 lamports, made up of 2,000,000,000 lamports of working amount, 35,635,200 lamports of locked rent reserve and 4,000,000 lamports of fee buffer.

The dispatcher pays for its own transfers. If the chunk size settles at 8 transfers per transaction, 40 transfers become 5 transactions, each carrying one signature, for 25,000 lamports of dispatcher fees. The dispatcher also needs its own rent-exempt reserve of 890,880 lamports. The treasury therefore sends the dispatcher 2,039,635,200 plus 25,000 plus 890,880, which is 2,040,551,080 lamports, or 2.04055108 SOL.

If every wallet will also hold one SPL token, add 2,039,280 lamports per token account. Across 40 wallets that is another 81,571,200 lamports, bringing the funded total to 2,122,122,280 lamports, or 2.12212228 SOL. Of that total, 35,635,200 plus 81,571,200, or 117,206,400 lamports, is locked rather than spent and returns when those accounts are closed.

All figures above are illustrative arithmetic on protocol constants, not observed results. Priority fees are excluded because they depend on the compute unit price you choose and the compute unit limit you request, and a congested run will cost more than this floor implies.

Two things fall out of that arithmetic. First, the locked portion is a meaningful share of what you moved, so a fleet that is churning accounts is tying up SOL that never appears as spend. Second, the dispatcher fee line is small enough to ignore and large enough to make a total fail to reconcile if you do ignore it. Write both into the ledger even when they look like noise.

Topping up mid-run without losing the thread

Mid-run top-ups are where clean ledgers go to die. A wallet runs out of fee headroom, someone sends it a quick amount from whatever key is nearest, and the run total no longer reconciles against anything. If a top-up is necessary, treat it as a new ledger line with its own basis and its own reconciliation source, and send it from the dispatcher rather than from the treasury or a personal wallet, so the fan-out keeps a single source.

Better than a clean top-up is not needing one. If a class of wallets consistently runs dry, the fee buffer is under-sized rather than unlucky, and the fix belongs in the per-wallet floor for the next run rather than in a stream of manual transfers during this one. Keep a note of which wallets needed topping up and by how much; that note is the input to the next floor calculation and is the sort of record that is worthless unless written at the time.

None of this changes when the distribution is performed by a hosted product rather than a script you run yourself. The floor is the same sum of rent reserve, fee buffer and working amount whether a shell command or an automated Solana volume bot emits the transfers, the size limit still forces the same chunking, and the operator still owns the reconciliation because only the operator knows what the run was supposed to cost. A tool can report balances; it cannot tell you whether the number it reports is the number you intended.

The sweep back

Sweeping back is the second half of funding, and it is a separate decision from closing accounts. The sweep moves spendable balance out of execution wallets and back to the treasury, which removes the reason for those hot keys to hold anything. Closing accounts recovers the locked rent reserve as well, but a system account has to be drained to nothing and an SPL token account can only be closed when its token balance is zero.

Order the sweep from the outside in. Empty the execution wallets first, then the dispatcher, then decide what returns to the reserve. Leave each wallet enough to pay for the signature that empties it, because a wallet with a balance below one signature fee is a wallet whose remaining lamports cannot be moved by that wallet at all. Sweeping the exact balance without accounting for the 5,000 lamport fee is the most common way to create dust that then needs a top-up to retrieve.

Reconcile the sweep against the distribution rather than against a feeling. Line L6 in the ledger exists to be compared with L3 and L5: what you sent out, minus what the run legitimately spent, should equal what came back. A gap that cannot be tied to a signature is a finding, not a rounding error. The full closing sequence, including account closure and the archive you keep afterwards, is set out in shutting a run down cleanly.

Where fan-outs go wrong

Most failed funding runs fail in one of a few ways, and none of them are exotic. An address is truncated by a copy that missed characters, and the value lands somewhere unreachable. A chunk is submitted, times out on the client, and is resubmitted, so a subset of wallets is funded twice. A tool is pointed at the wrong cluster, and everything appears to work while nothing real has moved. The per-wallet amount is edited mid-run, and the totals never reconcile again.

Each of those has a specific defence already in the procedure. Machine comparison of addresses defeats truncation. Confirming a chunk before building the next one defeats the double-send, because you see the credited balance before you decide what still needs sending. Reading the cluster configuration from the signing machine defeats the wrong-cluster case. Freezing the per-wallet amount before the first transfer defeats the drifting total. The defences are cheap; skipping them is what is expensive.

The last failure mode is organisational rather than technical: only one person knows how the fleet is funded. If the account map lives in one head and the ledger lives in a terminal scrollback, the run cannot be picked up, audited or safely stopped by anyone else. Write the map to a file, write the ledger as you go, and store both somewhere a colleague can reach without asking you for a key. Solana CLI behaviour, flags and account mechanics are documented in the official Solana documentation if you need to confirm a detail before a run.

Questions the desk gets asked

How much SOL should each wallet hold?

Enough to stay rent exempt, pay the signatures you expect it to produce, and carry the working amount your strategy needs. Anything above that is value sitting in a hot key for no reason. Pick the working amount deliberately, write it in the account map, and treat any wallet holding more than its stated ceiling as a reconciliation error.

Can I fund every wallet in a single transaction?

No. A serialized transaction is capped at 1,232 bytes, and every additional recipient adds an account key and an instruction. That cap is what forces a fan-out into chunks. Work out how many transfers fit by simulating the packed transaction rather than assuming a number, because address lookup tables and signer counts change the answer.

What happens if I send to an address I do not control?

The value is gone. A confirmed transfer on Solana cannot be reversed, cancelled or clawed back by any support desk, and an address you cannot sign for is unreachable forever. This is why the account map is verified before the first transfer and why the first wallet is funded alone and checked before the rest.

Do I get the rent-exempt lamports back?

Yes, when the account is closed the rent-exempt reserve is returned to the destination you name. A system account can be drained to zero and cleaned up; an SPL token account can only be closed once its token balance is zero. Until then those lamports are locked and should be shown as locked in your accounting.

Should the dispatcher hold the whole run budget?

Only the amount the current fan-out needs, plus its own fee headroom. The dispatcher is a hot key with a broad reach, so anything it holds beyond the immediate distribution is exposure without purpose. Keep the remainder in the treasury and top the dispatcher up per run rather than leaving a standing float in it.

When is the right time to sweep back?

As soon as a run is finished and no further signatures are expected from the fleet. Leaving residue in execution wallets means keeping hot keys funded with no work in front of them. Sweep the spendable balance first, then decide separately whether to close accounts and recover the rent-exempt reserve.