Economics
Where the SOL goes: every lamport transfer in the protocol, traced from the
on-chain programs (the mail_program, alias_program, and domain_program
processors), and what each participant
class pays and collects. Amounts marked ≈ are rent-exemption minimums —
a refundable, one-time deposit every Solana account needs to exist, sized to
the account’s byte length rather than to any price or value it represents
(see Closing accounts for what rent is and
how to reclaim it) — and vary with account size at current rent parameters.
This is a completely separate quantity from postage: postage is a price
the recipient chooses; rent is a storage deposit nobody chooses and
everybody gets back.
The stamp lifecycle
A stamp is prepaid postage for one email from one sender (“from” address) to one recipient wallet. Its value cycles through three accounts, then settles across four destinations:
- Buying (
AddStamps/CreateFrombox): anyone may fund the frombox for a (from, recipient) pair. Each stamp costs the frombox’srequired_postageplus a two-signature fee surcharge (STAMP_FEE_SURCHARGE_LAMPORTS= 10 000 = 2 × the 5 000-lamport base fee); the surcharge prefunds both settlement signature refunds (SendMail and DeleteMail). The whole amount transfers into the frombox account. A new frombox inheritsrequired_postagefrom the recipient mailbox’sdefault_postage; only the recipient may change it afterwards (UpdateFromboxrequires the recipient’s signature). Price changes do not revalue stamps already bought — value amortizes over the remaining stamp count. Third-party purchases additionally pay the per-stamp protocol fee — the greater of a flat per-stamp amount and a small percentage of the escrowed postage, split between the recipient’s domain authority and the postoffice (see “The per-stamp protocol fee” below); purchases paid by the recipient wallet itself are fee-free. - Sending (
SendMail): the signer must be the sender named in the email (or the active domain authority for the recipient’s domain — the MX operator’s wallet, for relayed mail). The signer pays the transaction fee and fronts the message account’s rent-exemption (≈0.003–0.006 SOL depending on address/cid sizes — a deposit sized to the account’s byte length, not to the postage price; see the note above) as a new deposit, separate from anything paid at the Buying step. One proportional share of the frombox’s value —(balance − frombox rent) / stamps— moves onto the message account alongside that rent, and one stamp burns. A frombox whose share rounds to zero still sends (the stamp count is the gate; the value is what settles later). - Settling (
DeleteMail): only the sender or the recipient may delete. The message balance is split, in order: the sender recovers the message rent + one signature fee, the delete signer recovers this transaction’s signature fee (both prefunded by the surcharge), the recipient’s domain authority collects the operator share (operator_share_bps— defaultOPERATOR_SHARE_BPS= 10% of the remaining postage, delegate-tunable since v0.36.0), and the recipient collects the rest.1 Postage only settles on delete; until then it sits parked on message accounts.
Try it yourself: a worked example
The script below re-derives the three steps above as plain arithmetic —
paste it into a browser console or run it with node (no dependencies,
no network access, nothing on-chain). Change postageLamports,
messageRentLamports, or thirdPartyBuyer at the top to try a different
scenario.
Money enters this example at two different points, not one: the buyer’s
purchase at Buying, and the sender’s rent deposit at Sending (the same
wallet, if the buyer is also the sender — but still two separate
transactions). That’s why the settlement totals add up to more than
buyerPays alone: the conservation check sums both inputs
(buyerPays + messageRentLamports) against everything paid out, and only
that combined total should balance.
Note: the default
postageLamportsbelow is priced at roughly what a single US first-class postage stamp costs (about $0.82 as of this writing), converted to lamports at the SOL/USD rate on the date this page was last updated ($81.16/SOL, 2026-07-06) — a deliberate nod to the stamp analogy, not a protocol default. Change it to see how the split scales.
// SithBit stamp economics calculator -- a hypothetical worked example.
// Pure JavaScript, no dependencies: paste into a browser console, or run
// with `node stamp-calculator.js`. All amounts are in lamports
// (1 SOL = 1,000,000,000 lamports).
// Protocol constants (from mail_model::constants). The two bps rates are
// the DEFAULTS -- the delegate can retune both (SetSettlementBps), each
// bounded by its on-chain cap.
const SIGNATURE_FEE_LAMPORTS = 5_000;
const STAMP_FEE_SURCHARGE_LAMPORTS = 10_000; // 2 x SIGNATURE_FEE_LAMPORTS
const POSTOFFICE_STAMP_FEE_LAMPORTS = 100_000; // flat arm; waived if the buyer is the recipient
const DEFAULT_STAMP_FEE_BPS = 100; // bps arm: 1% of the escrowed postage
const OPERATOR_SHARE_BPS = 1_000; // 10% of postage, to the domain authority
const POSTAGE_ROUNDING_LAMPORTS = 1_000; // recipient payout rounds down to this
// --- Inputs: change these to try a different scenario ---
const postageLamports = 10_000_000; // ~0.01 SOL -- priced at ~$0.82, a US first-class stamp
const messageRentLamports = 4_000_000; // ~0.004 SOL -- rent-exemption sized to account bytes, independent of postage
const thirdPartyBuyer = true; // false = the recipient self-funds (fee waived)
const solUsdPrice = 81.16; // SOL/USD rate used for the $ comments below (2026-07-06)
function sol(lamports) {
return (lamports / 1_000_000_000).toFixed(9) + " SOL";
}
function usd(lamports) {
return "$" + ((lamports / 1_000_000_000) * solUsdPrice).toFixed(2);
}
// 1. Buying: AddStamps / CreateFrombox
// The protocol fee is a hybrid: the greater of the flat per-stamp fee and
// the bps share of the escrowed postage (the surcharge is a refundable
// prefund, not stamp value). At this example's 0.01 SOL postage the two
// arms meet exactly; raise postageLamports to watch the bps arm take over.
const stampValue = postageLamports + STAMP_FEE_SURCHARGE_LAMPORTS;
const hybridFee = Math.max(
POSTOFFICE_STAMP_FEE_LAMPORTS,
Math.floor((postageLamports * DEFAULT_STAMP_FEE_BPS) / 10_000),
);
const protocolFee = thirdPartyBuyer ? hybridFee : 0;
const buyerPays = stampValue + protocolFee;
// The purchase carries the operator tail (as current clients build it),
// so the fee splits: operator_share_bps to the recipient's domain
// authority, the remainder to the postoffice. The buyer's total is the
// same either way.
const feeOperatorShare = Math.floor((protocolFee * OPERATOR_SHARE_BPS) / 10_000);
const feePostofficeCut = protocolFee - feeOperatorShare;
console.log("== Buying: AddStamps / CreateFrombox ==");
console.log(`Buyer pays: ${buyerPays} lamports (${sol(buyerPays)})`);
console.log(` // ≈ ${usd(buyerPays)}`);
console.log(` -> frombox value: ${stampValue} lamports (${sol(stampValue)})`);
console.log(` -> protocol fee: ${protocolFee} lamports (${sol(protocolFee)})${thirdPartyBuyer ? "" : " (waived)"}`);
if (thirdPartyBuyer) {
console.log(` ${feeOperatorShare} to the domain authority (operator share) + ${feePostofficeCut} to the postoffice`);
}
// 2. Sending: SendMail
const messageBalance = messageRentLamports + stampValue;
console.log("\n== Sending: SendMail ==");
console.log(`Sender fronts message rent: ${messageRentLamports} lamports (${sol(messageRentLamports)})`);
console.log(` // a new deposit -- separate from what the buyer paid above`);
console.log(`One stamp's value moves onto the message account: ${stampValue} lamports (${sol(stampValue)})`);
console.log(`Message account now holds: ${messageBalance} lamports (${sol(messageBalance)})`);
// 3. Settling: DeleteMail
const senderShare = messageRentLamports + SIGNATURE_FEE_LAMPORTS;
const deleteSignerShare = SIGNATURE_FEE_LAMPORTS;
const remainingPostage = messageBalance - senderShare - deleteSignerShare; // == postageLamports
const operatorShare = Math.floor((remainingPostage * OPERATOR_SHARE_BPS) / 10_000);
const recipientRaw = remainingPostage - operatorShare;
const recipientShare = Math.floor(recipientRaw / POSTAGE_ROUNDING_LAMPORTS) * POSTAGE_ROUNDING_LAMPORTS;
const postofficeResidue = recipientRaw - recipientShare;
console.log("\n== Settling: DeleteMail ==");
console.log(`Sender recovers: ${senderShare} lamports (${sol(senderShare)}) [rent + 1 signature fee]`);
console.log(` // ≈ ${usd(senderShare)}`);
console.log(`Delete signer recovers: ${deleteSignerShare} lamports (${sol(deleteSignerShare)}) [1 signature fee]`);
console.log(` // ≈ ${usd(deleteSignerShare)}`);
console.log(`Domain authority earns: ${operatorShare} lamports (${sol(operatorShare)}) [10% operator share]`);
console.log(` // ≈ ${usd(operatorShare)}`);
console.log(`Recipient collects: ${recipientShare} lamports (${sol(recipientShare)}) [the rest, rounded down]`);
console.log(` // ≈ ${usd(recipientShare)}`);
// 4. Conservation check
const totalIn = buyerPays + messageRentLamports;
const totalOut = senderShare + deleteSignerShare + operatorShare + recipientShare + protocolFee + postofficeResidue;
console.log("\n== Conservation check ==");
console.log(" // totalIn = buyerPays + messageRentLamports: money entered at TWO steps, not one");
console.log(`Total in: ${totalIn} lamports`);
console.log(`Total out: ${totalOut} lamports`);
console.log(totalIn === totalOut ? "Every lamport is accounted for." : "Mismatch -- check the math!");
Example output for the defaults above (a stranger buying one first-class-stamp-priced stamp, with the recipient later deleting the message to collect payment):
== Buying: AddStamps / CreateFrombox ==
Buyer pays: 10110000 lamports (0.010110000 SOL)
// ≈ $0.82
-> frombox value: 10010000 lamports (0.010010000 SOL)
-> protocol fee: 100000 lamports (0.000100000 SOL)
10000 to the domain authority (operator share) + 90000 to the postoffice
== Sending: SendMail ==
Sender fronts message rent: 4000000 lamports (0.004000000 SOL)
// a new deposit -- separate from what the buyer paid above
One stamp's value moves onto the message account: 10010000 lamports (0.010010000 SOL)
Message account now holds: 14010000 lamports (0.014010000 SOL)
== Settling: DeleteMail ==
Sender recovers: 4005000 lamports (0.004005000 SOL) [rent + 1 signature fee]
// ≈ $0.33
Delete signer recovers: 5000 lamports (0.000005000 SOL) [1 signature fee]
// ≈ $0.00
Domain authority earns: 1000000 lamports (0.001000000 SOL) [10% operator share]
// ≈ $0.08
Recipient collects: 9000000 lamports (0.009000000 SOL) [the rest, rounded down]
// ≈ $0.73
== Conservation check ==
// totalIn = buyerPays + messageRentLamports: money entered at TWO steps, not one
Total in: 14110000 lamports
Total out: 14110000 lamports
Every lamport is accounted for.
Per-participant flows
Recipient (mailbox owner)
| Pays | Collects |
|---|---|
Mailbox rent ≈0.0012 SOL (once, at CreateMailbox) | Stamp value of every received-then-deleted mail |
| Encryption-key account rent ≈0.005 SOL (once) | |
| Frombox funding for correspondents they allow-list | That same funding back, as mail arrives and is deleted |
The recipient is the protocol’s revenue side: strangers pay
required_postage per message, and pricing is the recipient’s spam
control (the CLI defaults new mailboxes to 1 SOL per stamp — unknown
senders are priced out until the recipient lowers the price for them,
though a stranger with a real on-chain spending record pays a scaled
share of that default — see reputation-scaled first-contact
pricing).
When the recipient funds a correspondent’s frombox themselves, the value
round-trips back minus transaction fees — allow-listing costs only fees.
Accumulates SOL in proportion to mail from senders who paid their own
postage; net of their one-time rents otherwise.
Sender (wallet-holding)
Pays postage (the recipient’s price) plus the fee surcharge per stamp, and
fronts the message rent per send. On delete, rent and one signature fee
come back. Net cost per mail ≈ required_postage — the intended price of
communication. Spends SOL by design.
MX operator (runs sithbitd + the gRPC gateway)
For relayed mail, the operator’s domain-authority wallet is the on-chain
“sender”: it fronts the message rent and transaction fee per inbound
delivery, and recovers rent plus the surcharge-funded signature fee at
DeleteMail. On-chain revenue: the operator share — every settled
message for a mailbox on the operator’s active domain pays the authority
the operator share of the postage (operator_share_bps, default
OPERATOR_SHARE_BPS = 10%), and every third-party stamp purchase that
presents the operator accounts (what current clients build) pays the
authority the same share of the per-stamp protocol fee (v0.37.0). At
scale this turns relaying
into a revenue stream rather than a pure cost. Off-chain costs remain
(IPFS pinning, servers, RPC); the share offsets them on-chain.
The per-stamp protocol fee
The postoffice’s primary revenue: a hybrid fee per purchased stamp —
the greater of a flat amount and a bps share of the escrowed postage
(v0.36.0) — collected at purchase time. A purchase that presents the
recipient’s mailbox/domain/authority accounts (the operator tail,
which current clients build automatically) splits the fee:
operator_share_bps (default 10%) to the recipient’s domain authority,
the remainder to the postoffice PDA. A legacy account list keeps the
whole fee with the postoffice.
- Amount: the greater of the two arms —
max(stamp_fee_lamports × stamps, postage × stamp_fee_bps / 10 000). The flat arm isstamp_fee_lamportsfrom the postoffice account (defaultPOSTOFFICE_STAMP_FEE_LAMPORTS= 100 000 = 0.0001 SOL) per stamp; the bps arm isstamp_fee_bps(defaultDEFAULT_STAMP_FEE_BPS= 100 = 1%) of the postage being escrowed, so the fee scales with premium-priced stamps instead of rounding to noise beside them. At the defaults the arms cross at 0.01 SOL of postage per stamp: cheap friend-tier stamps pay the flat fee, a default-priced 1-SOL stranger stamp pays 0.01 SOL. The refundable signature surcharge is not stamp value and is never in the bps base. - Operator split (v0.37.0): when the purchase’s account list carries
the operator tail — the recipient’s mailbox, its named domain, and the
domain authority — the authority receives
operator_share_bpsof the fee and the postoffice the rest. The buyer’s total is identical either way; only the fee’s destination splits. The lapse and filler rules mirror the settlement share: no domain named, a closed or inactive domain, or a closed mailbox lapse the share back to the postoffice, while present-but-wrong accounts are refused (a purchaser cannot reroute the share to itself). Legacy five/six-account purchases keep today’s whole-fee-to-postoffice behavior — the tail is optional, so old clients never break. - Waiver: the fee is skipped iff the purchase’s fee payer is the
recipient wallet (
fee_payer == to_account) — the whole hybrid, both arms. The payer is a required signer, so the check is unforgeable. This keeps the adoption path free: a mailbox owner who prices a correspondent’s frombox low and prefunds its stamps pays no protocol fee, and the recipient’s settlement payouts are untouched — mailbox owners perceive zero cost. Gift purchases by anyone else pay the fee. - Governance: the delegate tunes the
flat arm with
SetStampFee(sithbit postmaster fee stamp <LAMPORTS>), hard-capped on-chain atMAX_POSTOFFICE_STAMP_FEE_LAMPORTS(1 000 000), and the bps arm withSetSettlementBps(sithbit postmaster fee settlement <OPERATOR_SHARE_BPS> <STAMP_FEE_BPS>), capped atMAX_STAMP_FEE_BPS(1 000 = 10%) — so a compromised delegate key cannot price-gouge purchasers. A zero bps rate stores the “unset” sentinel and resolves to the protocol default (the rate cannot be tuned to literal zero; the flat arm can). There is no on-chain read instruction — account state is world-readable; anyone can query the current schedule with the ungatedsithbit postoffice fee stamp(both arms) orsithbit postoffice fee settlement(both bps rates). - Layout migration: postoffice accounts created before the fee field (32-byte layout) still work everywhere — readers parse them with a versioned load that applies the default fee, and the writers (the fee setters and the ownership instructions) grow the account in place (resize + rent top-up from the signing delegate) on their next run.
Domain authorities
CreateDomain takes an explicit payer — either the delegate or the
domain authority may fund the domain account’s rent plus the
DOMAIN_AUTHORIZATION_FEE_LAMPORTS (0.01 SOL default, delegate-tunable
via SetDomainFee up to MAX_DOMAIN_AUTHORIZATION_FEE_LAMPORTS) paid to
the postoffice.
Either way the delegate must sign: domain ownership is proven
off-chain (the authority’s pubkey in the domain’s DNS TXT record, checked
by the delegate’s trusted agent), so on-chain authorization is always
the delegate’s — authority-pays is a co-signed two-signature
transaction, never authority-alone. The domain records its rent_payer,
and CloseDomain (delegate-signed) refunds the rent to whoever paid.
When the delegate sponsors a domain itself, the fee is a wash — it lands
in the postoffice the postmaster can sweep. Deactivation remains a
separate, reversible toggle. In exchange, the authority earns the
operator share (default 10%) on every settled message for its domain.
The permissionless proof-carrying
path (AuthorizeDomainByProof, the CLI’s
sithbit domain authorize) charges its payer the same fee, once the
on-chain DNSSEC verification succeeds — fee parity keeps the two
authorization routes economically interchangeable; a failed proof charges
nothing.
Alias holders
An alias costs its own account rent plus a claim fee paid to the
mail program’s postoffice — squatting a name now has a price. The claim
fee is length-tiered (v0.35.0): names of 5 or more characters pay the
flat ALIAS_FEE_LAMPORTS (0.01 SOL default), while 1–4 character names
are scarce assets (36 one-character, ~1.3k two-character combinations)
and pay a scarcity premium from the ALIAS_TIER_FEES_LAMPORTS schedule —
by default 10 SOL (1 char), 1 SOL (2), 0.1 SOL (3), and 0.05 SOL (4).
The CLI and the web register form both quote the fee before you sign;
premium pricing is never charged silently. Handing an alias to a new
holder for free likewise
pays the ALIAS_TRANSFER_FEE_LAMPORTS (0.001 SOL default) — charged when
the recipient accepts a zero-fee transfer offer (v0.7.0: every transfer is
an offer the recipient must accept), and waived when the offer’s holder is
the standing delegate; a priced sale pays the 90/10 split below instead.
The flat fees are
delegate-tunable via SetAliasFee (one instruction sets the claim and
transfer fees together) and the premium schedule via SetAliasTierFees,
every value bounded by its own on-chain cap
(MAX_ALIAS_FEE_LAMPORTS / MAX_ALIAS_TRANSFER_FEE_LAMPORTS /
MAX_ALIAS_TIER_FEES_LAMPORTS, the tier caps at 10× their defaults).
Delegate reservations waive the claim fee at every length, so the
postmaster can reserve premium short names for rent alone and resell them
on the marketplace at seller-set
prices. Names
remain globally unique, first-come, and never expire. CloseAlias lets
the holder (the wallet the alias points at) reclaim the rent; the fee is
not refunded.
Escrowed alias transfers
Selling an alias
(alias transfer init --fee) stages an offer that the named recipient later
accepts by paying the fee. Since v0.7.0 this escrowed offer is the ONLY
transfer path — a zero fee stages a free hand-off that still needs the
recipient’s accept. The money flow for a priced offer:
- Nothing monetary ever sits in escrow. The escrow account holds only the offer’s terms (recipient, fee, expiry) plus its own rent-exemption; the fee itself never parks anywhere. It moves at accept, in the same atomic instruction that repoints the alias — so a cancelled or expired offer has no refund leg, because no money was ever taken.
- At accept, the fee splits 90/10 (at the default rate): the paying
wallet (the recipient,
or a sponsor co-signing via
--payer-keypair) transfers the seller’s share to the alias’s current holder and the operator share to the mail program’s postoffice. The cut isoperator_share_bps(defaultOPERATOR_SHARE_BPS= 1 000 bps = 10%), the same delegate-tunable rate theDeleteMailsettlement uses for the domain operator’s share — retuned withSetSettlementBpsup toMAX_OPERATOR_SHARE_BPS(2 000 = 20%), one rate for every settlement split; the postoffice’s leg is floored and the rounding dust goes to the seller. - Escrow rent round-trips to the seller. The holder fronts the escrow account’s rent-exemption when staging the offer and gets it back when the escrow closes — on accept and on cancel (including the expiry-reclaim cancel). Replacing a standing offer reuses the funded account: no additional rent.
- No flat transfer fee rides a PRICED offer. The 90/10 split is the
paid path’s entire economics. A zero-fee accept (a free hand-off)
instead pays the flat
ALIAS_TRANSFER_FEE_LAMPORTSlever above to the postoffice — waived when the offer’s holder is the standing delegate, keeping operator reservation hand-offs fee-free end to end.
Open marketplace listings
Listing an alias or a
domain for sale (alias sell / domain sell) inherits the escrowed-transfer money flow above wholesale,
with one difference: there is no named recipient — any buyer may pay the
fixed price and take the asset. The seller is the alias’s current holder,
or the domain’s current authority (the one authority-signed domain
instruction; every other domain mutation is delegate-gated). The money
flow:
- Nothing monetary ever sits in the listing. The listing account holds only the sale’s terms (seller, price, staged-at, expiry) plus its own rent-exemption; the price never parks anywhere. It moves at buy, in the same atomic instruction that swaps ownership — so a cancelled or expired listing has no refund leg, because no money was ever taken.
- At buy, the price splits 90/10 (at the default rate): the paying
wallet (the buyer, or a
sponsor co-signing via
--payer-keypair, which also fronts the two-signature transaction fee) transfers the seller’s share to the seller and the operator share to the mail program’s postoffice. The cut isoperator_share_bps(defaultOPERATOR_SHARE_BPS= 1 000 bps = 10%), the same delegate-tunable rate theDeleteMailsettlement, the escrowed alias transfer, and the reply-bounty claim use — retuned withSetSettlementBpsup toMAX_OPERATOR_SHARE_BPS(2 000 = 20%), one rate for every settlement split; the postoffice’s leg is floored and the rounding dust goes to the seller. - The fee is seller-side. The buyer pays exactly the listed price, no more; the share comes out of the seller’s proceeds. A seller who wants to net a target amount prices it in — the marketplace’s positioning matches the rest of the protocol, where the postoffice’s revenue rides the party monetizing an asset, never the party adopting one.
- Listing rent round-trips to the seller. The seller fronts the listing account’s rent-exemption when staging and gets it back when the listing closes — on buy and on cancel (including the expiry-reclaim cancel). Replacing a standing listing reuses the funded account: no additional rent.
- No flat fee on this path either. Like the escrowed accept, a buy
pays no
ALIAS_TRANSFER_FEE_LAMPORTS-style flat fee — the 90/10 split is the marketplace’s entire economics, for aliases and domains alike (a marketplace domain sale also pays noDOMAIN_AUTHORIZATION_FEE_LAMPORTS; that fee prices authorizing a new domain, not re-selling an authorized one). - A listed name is locked to its listing. While a listing is open the
asset can’t be moved out from under it:
closeand the transfer paths (alias transfer init, the delegate’sdomain transfer) refuse until the seller cancels, and a domain mid-deactivation-timelock can be neither listed nor bought. The buy itself also re-checks the seller, so a stale listing surviving a change of ownership can never sell the new owner’s name at the old owner’s price. See the guard notes on the alias and domain listing pages. - A domain sale conveys protocol authority only — the mail-injection signing right and the operator share; never the DNS name, MX hosting, or DKIM keys, which stay with whoever holds them off-chain. Buyers should read What buying a domain does — and does not — buy before paying.
Reputation-scaled first-contact pricing
The mailbox default postage is a blunt instrument on purpose: 1 SOL per stamp prices out spam from senders the recipient has never met. But “never met” describes two very different wallets — a spammer’s freshly-minted burner and a legitimate organization that has been paying postage across the network for months. Since v0.39.0 the protocol tells them apart: the default price a stranger pays at first contact scales with the sender wallet’s on-chain track record, while spam economics are untouched (a burner wallet has no record and pays full price).
The record is the sender-reputation account — a small mail-program PDA,
one per sender wallet, holding the wallet’s cumulative
distinct-recipient postage spend. Every third-party CreateFrombox
(each one a first purchase toward a new recipient) that carries the
reputation tail records the postage it escrows — postage only, never the
refundable surcharge or the protocol fee — onto the payer’s record. Current
clients (the CLI, the wasm builders, and the web prepay) carry the tail by
default; the account is lazily created on its first use, rent funded by the
payer.
That cumulative spend steps the rate a stranger’s first contact is priced
at, in basis points of the recipient’s default_postage:
| Cumulative postage spend | First-contact rate | At the 1-SOL default postage |
|---|---|---|
| below 0.1 SOL | 10,000 bps (full price) | 1 SOL |
| from 0.1 SOL | 7,500 bps | 0.75 SOL |
| from 1 SOL | 5,000 bps | 0.5 SOL |
| from 10 SOL | 2,500 bps | 0.25 SOL |
Three boundaries keep the mechanic honest:
- Only the default is scaled — a recipient-set price is never touched. The discount applies exactly where the frombox would have inherited the mailbox’s default postage: a stranger’s first purchase. A price the recipient chose — cheaper for a friend, punitive for a nuisance — applies verbatim, whatever the sender’s reputation, and repricing stays exclusively the recipient’s lever. Recipients keep full sovereignty and full revenue: the discounted postage still settles to them, and a recipient who wants full price from everyone simply sets their prices rather than relying on the default.
- The discount has a floor. However much reputation a wallet
accumulates, first contact never prices below
reputation_floor_bpsof the recipient’s default —DEFAULT_REPUTATION_FLOOR_BPS= 1,000 bps (10%) by default, delegate-tunable withSetReputationFloor(sithbit postmaster fee reputation-floor <BPS>) up to the 10,000-bps cap (100%, which disables the discount entirely; over-cap refuses with custom error 102ReputationFloorAboveCap, and zero resets to the protocol default). And a nonzero asking price never rounds to zero — first contact is never free. - A verified-sender attestation is the fast path. A purchase whose account tail carries the payer’s attestation for the from address’s domain prices first contact at the floor immediately — no spend history required. Proven DNS control plus the attestation fee substitutes for months of postage: the two friction mechanics compose instead of stacking.
Owner purchases — the recipient prefunding a sender’s frombox — are
unaffected: they ride the legacy account list, pay the raw default, and
record no spend (a recipient prepaying their own inbound mail is not
sender reputation). Anyone can read a wallet’s standing with the
ungated sithbit postoffice reputation <WALLET>, which prints the
recorded cumulative spend and the effective first-contact rate in bps,
floor included; server operators get the same two figures over gRPC
via the gateway’s
GetSenderReputation RPC.
This is the positioning principle again, applied to the sender side: reputable and attested senders earn cheaper first contact — friction should price out spam, not commerce — while every discounted lamport still flows to the recipient, whose own prices the protocol never overrides.
Pinning leases
The auto-settle sweeper
releases a delivered copy’s IPFS pin about 30 days after delivery — a
generous default that most mail never needs to outlive. For the mail that
does, a pinning lease (sithbit mail lease)
pays for extended retention: a small on-chain account, one per
(CID, holder wallet), whose existence asks operators to keep that CID
pinned. Operators consult it before releasing a pin, and the check fails
safe — an operator that cannot prove a CID unleased keeps the pin.
The shape is deliberately deposit-heavy, fee-light:
- The deposit is reclaimable capital, not spend. A lease escrows at
least
PIN_LEASE_MIN_DEPOSIT_LAMPORTS(0.01 SOL) on its own account and returns it in full — with the rent — the moment the holder closes the lease. Retention costs opportunity, not money. - The only spend is a one-time creation fee (default 0.001 SOL, tunable up to 10×), split at the standard operator share with the recipient’s registered domain authority — the operator actually storing the bytes — the remainder to the postoffice. No recurring or renewal fee exists, deliberately: a lease held for a year costs exactly what a lease held for a week costs.
- Anyone may hold one. Retention is usually a recipient desire, but senders and third parties can lease a CID too; per-(CID, holder) keying means independent leases never contend.
Against the positioning principle: the default retention stays generous and free (nobody needs a lease to read their mail — the local copy survives settlement regardless), the lease is a strictly opt-in power-user extension, and its fee is sender/holder-side revenue that partly lands on the operator storing the data. The read path stays toll-free.
Where SOL parks or strands
- Message accounts hold rent + stamp value until settlement. Both
sides have an incentive to settle (sender: rent; recipient: postage),
but nothing on-chain forces it, and the only client-driven trigger is an
IMAP/POP expunge — so a recipient who archives mail forever, never
deleting it from their client, leaves every message’s postage parked on
its PDA indefinitely: their own postage revenue unrealized, the sender’s
rent locked, and the operator’s 10% share uncollected. The auto-settle
worker (
[spooler.settle], on by default) closes that gap without waiting on the recipient’s mail client: it firesDeleteMailafter_days(default 30) past confirmed delivery, which realizes the recipient’s postage and the operator share and returns the sender’s rent — while keeping the recipient’s local copy. Settlement reclaims the on-chain value; it does not delete the mail the recipient reads. What it does remove is the on-chain message account, and by default the sealed IPFS body too (keep_pin = falseunpins it), so a past-window settled message is only trustlessly fetchable from the decentralized copy ifkeep_pinwas set to leave the pin in place. - Every other account class now has a close path:
CloseFrombox(the recipient reclaims rent plus any residual stamp value — stamps never used; a sender who prepaid against their own wallet address can instead withdraw that residual themselves withReclaimFromboxStamps, leaving the account alive on its rent), the two-step mailbox close andCloseKey(owner reclaims rent — the mailbox’s only atFinalizeCloseMailbox, 7 days after the request; the key account’s on the spot),CloseAlias(holder reclaims rent),CloseDomain(rent back to the recorded payer), andWithdrawPostoffice(the postmaster — a revealed key-ceremony key, see The Postmaster — sweeps accumulated revenue). A closed mailbox’s undelivered message accounts stay open and settle individually viaDeleteMail; recreating the mailbox restarts message ids at zero, so new sends fail until those old message accounts are deleted — an availability nuisance, never a loss of funds.
Refunds: postage as a refundable deposit
DeleteMail settles a message to the recipient; RefundMail settles the
same message back to the sender. It is the mirror image of the split in
Where SOL parks or strands: where settlement
collects a stranger’s postage to the recipient and the domain operator, a
refund returns that postage to the sender in full — and, as in DeleteMail,
the message account then drains and is reaped.
The rent and signature legs are unchanged from DeleteMail: the sender
recovers the message rent plus one signature fee, and the refund signer
recovers this transaction’s signature fee — both still prefunded by the
STAMP_FEE_SURCHARGE_LAMPORTS bought at the Buying step. What changes is
where the postage goes:
- the operator share is waived — a refund is not a revenue event, so
OPERATOR_SHARE_BPSis not applied and the domain authority collects nothing; - the recipient collects nothing — the postage they would have earned on
a
DeleteMailis not theirs on a refund; - the whole remaining postage returns to the sender, on top of the rent and signature fee they already recover.
A refund is recipient-signed: only the mailbox owner can give a
stranger’s postage back, so a refund can never be used to claw postage away
from a recipient who means to keep it. Trigger it with the CLI —
sithbit mail refund <message_id> — or the RefundMail method on the
gRPC chain gateway.
Why refunds matter: a deposit, not a price
Without refunds, postage is a one-way price: a legitimate stranger who pays
the recipient’s spam-pricing floor (the CLI’s default 1 SOL — see
Sender) has no way to get it back, so the very
defense that prices out spammers also prices out good-faith strangers.
RefundMail reframes stranger postage as a refundable deposit rather
than a sunk cost. The spam defense is untouched — a spammer’s postage still
settles to the recipient on DeleteMail, and spammers never see a refund —
while a recipient who recognizes a good-faith first contact can choose to
make that sender whole. Because the deposit is only ever returned by the
recipient’s own signature, pricing stays the recipient’s spam control
exactly as it was; refunds add a release valve, not a loophole.
Reply bounties
Where postage pays the recipient for attention, a reply bounty pays them for an answer — the flagship of the protocol’s sender-pays positioning: the recipient doesn’t just avoid cost by being on SithBit, they earn by replying. Campaigns batch exactly this flow across an opted-in audience. The money flow:
- The escrow is the message account itself.
mail send --bountyfolds the bounty into the message account’s opening balance (rent + postage + bounty, all fronted by the sender at send time); no separate escrow account exists, so there is no extra rent leg and nothing else to close. - At claim, the bounty splits 90/10: the recipient — having put a
reply on-chain that carries the bounty’s reply linkage — collects 90%,
and the 10% operator share follows the same domain-resolution rules
as the
DeleteMailsettlement above: the claimant’s domain authority collects it when their mailbox names an active domain, and it falls to the mail program’s postoffice when the chain legitimately doesn’t resolve — no mailbox, no domain named, domain closed or inactive (whereDeleteMail’s unresolved share folds into the recipient’s postage, a claim’s goes to the postoffice). As inDeleteMail, a named, active domain must be presented with the correct authority account or the claim is rejected, so a claimant can’t redirect the operator’s cut with filler accounts. The cut isoperator_share_bps(defaultOPERATOR_SHARE_BPS= 1 000 bps = 10%), the same delegate-tunable rate theDeleteMailsettlement and the escrowed alias transfer use; the operator’s leg is floored and the rounding dust goes to the claimant. At the default rate a 5 000 007-lamport bounty splits as 500 000 to the claimant’s domain authority — or to the postoffice, for a domainless claimant — and 4 500 007 to the claimant. - An expired bounty refunds in full. Claims are legal through the
exact expiry instant; strictly after it,
mail refund-bountyreturns the whole bounty to the sender. LikeRefundMailabove, a bounty refund is not a revenue event — no operator or postoffice share is taken. - Deletion returns a riding bounty to the sender. If a bountied
message is settled by
DeleteMail— including the auto-settle worker’s — the unclaimed bounty joins the sender-refund leg. It never converts into recipient postage: the only path that pays the recipient is a claim. - Nothing is claimable without the on-chain reply linkage. The claim
evidence is a reply, in the sender’s mailbox, whose
reply_to_hashnames the bountied message account (a blake3 hash — no addresses on chain); claiming zeroes the bounty so no reply can claim twice.
Campaigns
A
campaign introduces no new money mechanics —
it is a batch of the flows already traced above, fired from one funded wallet
at a set of opted-in recipients. Economically it is N bountied
SendMails, and every lamport is sender-side: the
campaign wallet fronts the entire per-recipient cost, which is exactly the
quote itemization:
| Per recipient, the campaign wallet fronts | Which flow above |
|---|---|
| message account rent (≈, refundable) | the stamp lifecycle — parked on the message account |
| a new frombox’s rent (≈, refundable) | one frombox per (campaign wallet, recipient) pair |
| postage | the recipient’s price — settles to the recipient on DeleteMail |
| the escrowed reply bounty | folded into the message account, three exits |
one SIGNATURE_FEE_LAMPORTS + one STAMP_FEE_SURCHARGE_LAMPORTS | the base tx fee and the two-signature settlement prefund |
The recipient never pays — they only collect. A participant profits twice per campaign message: the postage lands as recipient income when the message settles, and the reply bounty pays 90% at the default rate (the operator share goes to their domain authority, or the postoffice when no active domain resolves) if they answer before the window closes. Unanswered bounties are refunded to the campaign wallet in full — a refund, not a revenue event.
Opting in costs a participant nothing but a refundable deposit: the beacon account’s rent, returned when they close it. This keeps campaigns squarely on the right side of the sender-pays positioning — the burden sits entirely on the advertiser, and the recipient’s whole interaction is upside.
Modeling the postoffice’s revenue base
The settlement rates above exist because the postoffice’s naive revenue model — “a flat fee on every stamp” — mostly rounds to zero once you segment who actually buys stamps. The honest model, at the defaults and the pinned $81.16/SOL rate used throughout this page:
Stamp purchases segment into three populations, and two of them pay nothing or almost nothing:
- Owner-prefunded fromboxes (the “friends mail you free” path): the recipient buys stamps for their correspondents, the waiver applies, revenue is zero by design. This waiver is load-bearing for the protocol’s feels-free positioning and is not a lever — every fee design must survive it.
- Known-sender third-party prepay (a sender funding their own frombox after the recipient priced it down): postage here is friend-tier — thousands to tens of thousands of lamports — so the flat arm dominates and each stamp yields the 100 000-lamport flat fee (~$0.008). Real, but linear in mail volume and small.
- Default-priced strangers (1 SOL postage): mostly priced out —
that is the postage floor’s job — so volume is low by construction.
(Since v0.39.0, reputation-scaled first-contact
pricing steps this
segment’s postage down for senders with a spending track record; the
bps fee arm rides whatever postage is actually escrowed, so a
discounted conversion pays proportionally less fee but converts more
often.)
Before v0.36.0 each rare conversion still paid only the 100 000
flat fee: the protocol earned ~$0.008 on a
$81 postage escrow. The bps arm fixes exactly this segment: at the default 100 bps a converted 1-SOL stamp now pays 0.01 SOL ($0.81) — 100× the flat fee — while segments 1 and 2 are untouched (waived, or below the 0.01-SOL crossover).
(Since v0.37.0, purchases carrying the operator tail split each charged
fee operator_share_bps to the recipient’s domain authority — so the
postoffice’s take in segments 2 and 3 is ~90% of the figures above at
the default rate, with the other 10% funding the operator the same way
settlements do.)
The non-stamp streams scale with marketplace activity, not mail
volume, and all ride the one operator_share_bps rate: alias/domain
marketplace sales and auction settlements (the share lands on the
postoffice directly), reply-bounty claims (domain authority, postoffice
only for domainless claimants), and the DeleteMail operator share
(domain authority — the postoffice keeps only the sub-1 000-lamport
rounding residue). A 1-SOL alias sale yields the postoffice 0.1 SOL at
the default rate; premium-name claim fees (the length tiers above) are
one-time but far larger per event.
Sensitivity, honestly stated: the dominant unknown is the waiver share — the fraction of stamps bought on the waived path — which no protocol lever changes and which the positioning wants high. Bps revenue scales with postage prices the protocol does not set (recipients do) and with conversion rates on a floor designed to deter conversion. The model’s conclusion is therefore structural, not a projection: stamp-fee revenue is real but bounded, the settlement rates are the scalable levers because they piggyback every value flow without new per-feature fees, and both are capped (10% / 20%) so the “minimal rake, no token” positioning survives a hostile delegate key.
Constants worth knowing
Protocol economics are consensus constants in mail_model::constants. Four
are fixed and never change without a program upgrade:
| Constant | Value | Used by |
|---|---|---|
SIGNATURE_FEE_LAMPORTS | 5 000 (0.000005 SOL) | the real base tx fee — replaces the deprecated 10 000-lamport fee-calculator default that overcharged buyers ~2× |
STAMP_FEE_SURCHARGE_LAMPORTS | 10 000 (2 signatures) | prefunds the SendMail + DeleteMail signature refunds; charged per stamp at AddStamps/CreateFrombox |
DEFAULT_POSTAGE_LAMPORTS | 1 000 000 000 (1 SOL) | the spam-pricing floor CreateMailbox applies when the instruction omits a price |
POSTAGE_ROUNDING_LAMPORTS | 1 000 | the quantum a recipient’s DeleteMail payout rounds down to; the remainder accrues to the postoffice |
The other nine are defaults, not fixed constants — the delegate can
retune each one, and each is bounded on-chain by its own MAX_* cap so a
compromised delegate key cannot price the protocol out of reach:
| Constant (default) | Default value | Hard cap | Set with | Charged by |
|---|---|---|---|---|
POSTOFFICE_STAMP_FEE_LAMPORTS | 100 000 (0.0001 SOL) | MAX_POSTOFFICE_STAMP_FEE_LAMPORTS = 1 000 000 | SetStampFee | AddStamps/CreateFrombox, third-party purchases only — the flat arm of the hybrid per-stamp fee |
DEFAULT_STAMP_FEE_BPS | 100 (1%) | MAX_STAMP_FEE_BPS = 1 000 (10%) | SetSettlementBps (a zero rate means “unset” and charges its default) | AddStamps/CreateFrombox — the bps arm of the hybrid, on the escrowed postage; same purchases, same waiver |
OPERATOR_SHARE_BPS | 1 000 (10%) | MAX_OPERATOR_SHARE_BPS = 2 000 (20%) | SetSettlementBps (one instruction sets both bps rates; zero means “unset”) | DeleteMail settlement, escrowed alias transfers, marketplace listings, auction settlements, and reply-bounty claims alike |
DOMAIN_AUTHORIZATION_FEE_LAMPORTS | 10 000 000 (0.01 SOL) | MAX_DOMAIN_AUTHORIZATION_FEE_LAMPORTS | SetDomainFee | CreateDomain and AuthorizeDomainByProof — both paths cost the same |
DEFAULT_SENDER_ATTESTATION_FEE_LAMPORTS | 10 000 000 (0.01 SOL) | MAX_SENDER_ATTESTATION_FEE_LAMPORTS = 100 000 000 | SetSenderAttestationFee (a zero fee means “unset” and charges the default) | AttestSender — the one-time verified-sender attestation, paid by the attesting payer; a failed proof charges nothing |
ALIAS_FEE_LAMPORTS | 10 000 000 (0.01 SOL) | MAX_ALIAS_FEE_LAMPORTS | SetAliasFee | CreateAlias, names of 5+ characters |
ALIAS_TRANSFER_FEE_LAMPORTS | 1 000 000 (0.001 SOL) | MAX_ALIAS_TRANSFER_FEE_LAMPORTS | SetAliasFee (one instruction sets both alias fees) | AcceptTransferAlias of a zero-fee (free hand-off) offer only — priced offers and marketplace sales pay the operator-share split instead; waived for a delegate holder |
ALIAS_TIER_FEES_LAMPORTS | 10 / 1 / 0.1 / 0.05 SOL for 1/2/3/4-character names | MAX_ALIAS_TIER_FEES_LAMPORTS (10× each default) | SetAliasTierFees (one instruction sets all four slots; a zero slot means “unset” and charges its default) | CreateAlias, names of 1–4 characters; waived — like every claim fee — for the delegate |
DEFAULT_REPUTATION_FLOOR_BPS | 1 000 (10%) | MAX_REPUTATION_FLOOR_BPS = 10 000 (100% — disables the discount) | SetReputationFloor (a zero rate means “unset” and resolves to the default) | not charged by anything — the floor under reputation-scaled first-contact pricing: the share of a mailbox’s default postage below which a stranger’s first contact never prices |
DEFAULT_PIN_LEASE_FEE_LAMPORTS | 1 000 000 (0.001 SOL) | MAX_PIN_LEASE_FEE_LAMPORTS = 10 000 000 | SetPinLeaseFee (a zero fee means “unset” and charges the default) | CreatePinLease — the one-time pinning-lease creation fee, split at the operator share with the recipient’s domain authority |
PIN_LEASE_MIN_DEPOSIT_LAMPORTS | 10 000 000 (0.01 SOL) | — (a plain constant, not a tunable) | — | the reclaimable deposit floor a CreatePinLease must escrow; returned in full at ClosePinLease |
Tune them with sithbit postmaster fee stamp / fee domain / fee alias
/ fee alias-tiers / fee settlement / fee attestation /
fee reputation-floor / fee pin-lease
(a delegate-only op), and read the current values back with the public,
read-only sithbit postoffice fee stamp / fee domain / fee alias /
fee settlement / fee pin-lease (the
alias getter prints the flat fees and the effective per-length premium
schedule together; the settlement getter prints both bps rates; the
effective floor prints with any wallet’s sithbit postoffice reputation). A
postoffice account that predates a fee field reads back its protocol
default.
On-chain CreateMailbox applies the 1-SOL DEFAULT_POSTAGE_LAMPORTS
spam-pricing floor when the instruction omits a price — a raw-instruction
caller must opt into a cheaper (or free) mailbox explicitly; the safety
margin is no longer client-side only.
Rent hygiene (implemented)
The follow-ups the original analysis recommended are now protocol behavior (see the “Economics” record in HANDOFF.md):
- Domain economics —
CreateDomaintakes an explicit payer (delegate or authority; the delegate always signs), chargesDOMAIN_AUTHORIZATION_FEE_LAMPORTSto the postoffice, and records therent_payersoCloseDomaincan refund the rent to whoever funded it. - Close instructions —
CloseFrombox(recipient reclaims residue + rent) and its sender-side counterpartReclaimFromboxStamps(a wallet-address sender withdraws its own unspent postage; the account survives on its rent),RequestCloseMailbox/FinalizeCloseMailboxandCloseKey(owner reclaims rent; see the close timelock below),CloseAlias(holder reclaims rent), andWithdrawPostoffice(the postmaster — via a key-ceremony proof — sweeps the postoffice balance above its rent-exempt minimum — without which the accumulated protocol fee revenue would be unspendable). - Alias fee — an
ALIAS_FEE_LAMPORTScharge on alias creation (and anALIAS_TRANSFER_FEE_LAMPORTScharge on transfer), CPI-transferred to the mail program’s postoffice, pricing out squatting. Both are delegate-tunable (SetAliasFee, capped on-chain) and waived when the payer is the delegate (the round-trip waiver kept its shape through the delegation cutover) — see bulk alias reservation.
The mailbox close timelock
Rent hygiene has an abuse edge. Rent that comes back instantly makes an
identity disposable: a sender whose wallet had burned its reputation could
CloseMailbox, take the full refund, and stand up a fresh identity for the
price of a signature. Cheap identity-cycling is the one thing a
postage-priced system cannot afford, because postage only bites a sender
who has something to lose by being recognized.
So closing a mailbox is now
timelocked: a request
starts a 7-day clock and refunds nothing (the mailbox stays open and keeps
receiving mail), a finalize past the clock closes it and returns both the
mailbox’s rent and the transient pending record’s, and a cancel aborts the
request meanwhile. The one-step CloseMailbox is refused on-chain with
error 94, InstantCloseDisabled.
The lever here is deliberately a delay, not a fee, and that follows straight from the positioning principle this whole page is written against — the system must feel free to use and be profitable for recipients, with the cost burden on senders. A mailbox owner is a recipient. Charging them to leave would be a recipient-side cost, which is presumptively the wrong shape. Time is the only currency available that bills the spammer (capital stuck for a week per burned identity, plus a week in which operators can watch a mailbox announce its own exit) while costing an honest owner nothing but patience on an action they take approximately never. The rent comes back in full either way.
CloseKey is deliberately exempt and stays instant — it revokes a
compromised delegated encryption key, where a waiting period would protect
the attacker rather than the owner. See
the threat model.
Money is only half the picture: for what each participant must trust —
the MX operator’s sender authentication, the postoffice admin keys, public
message metadata, and frombox custody (including that CloseFrombox
returns third-party-funded stamps to the recipient, not the buyer — a
sender can only withdraw postage they prepaid against their own wallet
address) — see
Trust assumptions and threat model.
-
The recipient’s payout is rounded down to the nearest
POSTAGE_ROUNDING_LAMPORTS(1 000 lamports); the sub-quantum remainder — at most 999 lamports per message — accrues to the postoffice. This is below the smallest price increment anyone quotes and isn’t something senders, recipients, or operators need to think about. ↩