What is a Split
A Split is one account on Solana, owned by the SPLIT program, at a deterministic address derived from ["split", creator, split_id]. It stores the recipient list (2 to 20 wallets), each recipient’s weight in basis points (summing to exactly 10,000), a 32-byte public label and a few flags.
The same account is the vault. SOL is held as lamports on it; each SPL token is held in the Split’s associated token account for that mint. One address receives everything.
v1 Splits are immutable. The program has no update, pause, close or withdraw instruction and no admin key. The creator pays rent and has no further powers. To change terms, create a new Split.
How deposits work
- Direct transfers. Send SOL to the Split address from any wallet or exchange that supports Solana. For tokens, send to the Split address and the wallet will use (or create) the Split’s associated token account.
- Instrumented deposits. The app’s deposit buttons call
fund_sol/fund_token, which transfer the same way and also emit aSplitFundedevent recording the funder.
Both kinds are settled identically. Direct transfers emit no program event, so the indexer also detects deposits from balance changes. Deposits never trigger payouts by themselves.
Permissionless settlement
settle_sol and settle_token can be called by anyone. The caller passes the recipients (or their token accounts) in the stored order; the program checks every account against the Split and rejects substitutes, reordering, missing or extra accounts.
- SOL: available = balance − rent reserve − pending. The whole available amount is allocated by weight and paid in the same transaction. One transaction regardless of recipient count.
- Tokens: the whole vault balance for that mint is allocated and transferred. Every recipient needs its canonical associated token account; the app creates missing ones for you (you pay their rent). With many missing accounts this takes a preparation transaction first.
- Settling with nothing new returns
NothingToSettleand moves nothing, so repeated or concurrent calls can’t pay twice.
Why a keeper is needed
Solana programs only run when a transaction calls them. Nothing on chain watches the Split and pays out when money arrives. A keeper is an off-chain service that checks eligible Splits (above a minimum amount, not settled too recently) and submits the same permissionless settlement you can submit yourself, paying the fee from its own small wallet.
Keeper automation is best-effort: it can be offline, out of fee balance or rate limited. It has no authority over funds; the worst it can do is not settle. You can always press “Distribute now”.
Exact rounding
All math is integer math in base units (lamports, token base units) with 128-bit intermediates. For an amount A and weights wᵢ:
- Each recipient first gets
floor(A × wᵢ / 10,000). - The leftover (always fewer units than there are recipients) is handed out one unit each to the recipients with the largest remainders
(A × wᵢ) mod 10,000. Ties go to the earlier recipient in the list. - So recipients receive exactly
Ain total. Nothing is kept as dust, nothing is created, and each share is within one base unit of its exact value.
Example: 100 lamports at 33.34% / 33.33% / 33.33% pays 34 / 33 / 33. The same algorithm runs in the program, the SDK and the calculator, and is property-tested in both Rust and TypeScript against shared vectors.
Pending SOL
Solana won’t let an account be created with less than its rent-exempt minimum (under 0.001 SOL for a plain wallet). If a recipient wallet doesn’t exist yet and its share is below that minimum, the program records the share as pending for that recipient instead of failing the whole settlement. Program (executable) accounts can’t receive lamports, so their shares stay pending too.
Pending amounts are excluded from future allocation and are paid automatically by any later settlement once payable (the wallet gets funded, or enough accumulates). They are never redistributed to others. There is no claim instruction in v1.
Fees and costs
| Item | Who pays | Amount |
|---|---|---|
| Protocol fee | — | 0. v1 has no fee account or fee logic. |
| Split account rent | Creator, once | Under 0.01 SOL (set by the network; shown before signing). Stays on the Split as its reserve; never distributed. |
| Network fee | Whoever signs | 5,000 lamports per signature plus any priority fee |
| Recipient token accounts | Whoever settles that token | About 0.002 SOL or less each, only when missing. Owned by the recipient. |
| Split token account | First instrumented depositor of that mint | About 0.002 SOL or less, once per mint |
Supported assets
- Native SOL.
- Classic SPL tokens (Token program
Tokenkeg…). Mint, token program, decimals and account ownership are checked on chain; browser-supplied accounts are never trusted. - The “accepts” flags only gate the app’s deposit buttons. Any classic SPL token that reaches the Split can still be settled, so mis-sent tokens are not trapped.
- Tokens whose mint has a freeze authority work, but the issuer can freeze a recipient’s account and block that token’s settlement until unfrozen.
- Token names and tickers are shown as mint addresses. Anyone can mint a token named anything.
Token-2022 extensions
v1 rejects every Token-2022 mint. Each extension was considered; none is accepted until exact accounting can be guaranteed:
| Extension | Why it’s rejected in v1 |
|---|---|
| Transfer fees | Recipients would receive less than allocated; conservation checks would need fee-aware math. |
| Transfer hooks | Arbitrary programs run on every transfer and could fail or re-enter settlement. |
| Permanent delegate | A third party could move tokens out of the vault at any time. |
| Confidential transfers | Balances aren’t visible, so allocation can’t be computed. |
| Non-transferable | Payouts would always fail. |
| Interest-bearing | Displayed amounts diverge from base units; risk of misleading UI. |
| Default account state (frozen) | New recipient accounts would start frozen and block settlement. |
Onchain vs offchain data
| Data | Where | Can change? |
|---|---|---|
| Recipients, weights, creator, Split ID, flags, 32-byte label | Onchain | Never |
| Balances, pending amounts, paid totals | Onchain | Only via deposits and settlement |
| Description, logo, recipient labels | Offchain database, wallet-signed | Yes, by the creator; display only |
| Network, RPC, priority fee, display options | Your browser | Yes |
| Keeper opt-in, thresholds | Offchain database, wallet-signed | Yes, by creator or recipients |
Trust assumptions
- Program code. SPLIT v1 is unaudited. A bug could lock or misdirect funds. Funds are held in a program-controlled vault until settlement; that is smart-contract custody, not “no custody”.
- Upgrade authority. Solana programs are upgradeable unless the authority is revoked. Whoever controls it could deploy different code. The current authority is visible on the program’s Explorer page; the launch plan moves it to a multisig with a timelock, then evaluates revoking it.
- RPC provider. This interface reads chain data through an RPC endpoint. A malicious endpoint could show false data. Your wallet shows the actual transaction; check the program ID and accounts before signing.
- Keeper. Optional, best-effort, and powerless over funds.
- Token issuers. Freeze authorities can block a token’s settlement.
Security limitations
- No independent audit yet. Treat any deployment as experimental and limit value.
- Recipient lists are permanent. A wrong address means that share is lost to whoever controls that address.
- Recipients that are program-derived addresses only benefit if their program can use the funds.
- Settlement of a token fails as a whole if any one recipient account is frozen.
- Compute usage is bounded by the 20-recipient cap; measured numbers are published in the repository’s testing notes once run on a validator.
Mainnet launch gate
The app labels every network and never claims to be live on mainnet. Mainnet stays disabled in the interface until all of these are done: an independent audit with findings resolved, a verifiable build matching the deployed binary, upgrade authority under a multisig, monitoring and keeper alerting, legal review, and an explicit go decision by the owner. The full checklist lives in docs/mainnet-checklist.md.
FAQ
Is there a $SPLIT token? No. It’s a project name. No token has been minted and the product doesn’t need one.
Can someone settle to the wrong people? No. Destinations are checked against the stored list and canonical token accounts; anything else is rejected.
What if two people settle at once? The first transaction pays; the second finds nothing new and fails with NothingToSettle, paying only its own network fee.
Can I see Splits that aren’t listed? Yes, if you have the address. Everything on Solana is public; “unlisted” only hides a Split from the Explore page.
Where do I start? Create a Split on devnet with devnet SOL.