© 2026 Alchemii
BLOCKCHAIN

How Reflection Tokens Work — and What Breaks Them in a Pool

Reflection tokens pay holders by changing one rate, not by looping over wallets. The on-chain mechanics, the permanent 25% ceiling, and a forked-mainnet test showing why an un-exempted DEX pool turns sells into reverts.

Gary Zhao
Gary Zhao
Founder of Alchemii ·

Already know you want to launch? No-code ERC-20 on Robinhood Chain, one signed transaction, flat fee.

Create my token
How Reflection Tokens Work — and What Breaks Them in a Pool

A reflection token is an ERC-20 that takes a percentage of each taxed transfer and credits it to every holder at once, by shrinking the total of a second internal accounting unit rather than by sending anyone a transaction. Because balanceOf is computed as a division against that unit, every remaining holder's balance simply reads higher the moment a fee is collected — nothing is minted, nothing is claimed, and the gas cost does not grow with the number of holders. The pattern comes from reflect.finance's RFI contract in late 2020 and the SafeMoon wave that popularised it through 2021, and the two things that decide whether it works in practice are both configuration, not code: the fee ceiling you launch under, and whether your liquidity pool is excluded from the mechanism.

This article uses one reflection token we deployed to Robinhood Chain mainnet on 26 August 2026 and one forked-mainnet experiment against the live Uniswap V3 factory there. Every balance is a getter reading, every gas figure comes off a receipt, and both the transaction hashes and the fork block are printed so you can re-run all of it.

Diagram of one taxed reflection transfer: 1,000 tokens sent splits into 930 delivered to the recipient, 20 to the fee wallet, and 50 reflected, where the 50 is shown not moving to any address but instead raising every holder's balance through a rate change of 1.000050002500, with the deployer holding 98.9 percent of supply capturing 49.45 of the 50 tokens

The mechanism: a rate change, not a payment

The naive way to pay every holder is to loop over them. That cannot ship: the loop's gas grows with the holder count, so the token gets more expensive to use as it gets more popular, and eventually transfers stop fitting in a block.

Reflection tokens solve it with two ledgers. Each account has an rOwned balance in a large internal unit, and the contract tracks _rTotal for that unit against _tTotal, the real token supply. The rate is simply _rTotal / _tTotal, and:

balanceOf(account) = rOwned[account] / rate

When a taxed transfer happens, the reflected share is subtracted from _rTotal and never credited to an address. The rate drops, so the same rOwned now divides into more tokens — for everyone, simultaneously, in one storage write. That is the whole trick. The relevant three lines of _transfer read:

if (v.rFee > 0) {
    _rTotal -= v.rFee;
    _tFeeTotal += v.tFee;
}

Two consequences follow immediately, and both are worth knowing before you launch one:

  • Balances are derived, not stored. A holder's number moves without any transaction touching their account, which is exactly why block explorers and portfolio trackers sometimes disagree about a reflection token's balance history. There is no Transfer event for the reflection, because no transfer happened.
  • Exclusions cost gas. Accounts excluded from rewards (a pool, a locker, a bridge) have to be carved out of both supplies before the rate can be computed, which means walking a list on every balanceOf. The template caps that list at 50 addresses (MAX_EXCLUDED). That constant is a gas ceiling, not a policy — but it is a hard limit on how many pairs and contracts you can carve out over the token's life.
Permanent fee ceiling
25%
MAX_TOTAL_FEE_BPS = 2,500. Enforced in the constructor and in setFees, with no setter for the constant itself
Share of the reflection the largest holder took
98.90%
49.45 of 50 tokens, on a wallet holding 98.9% of supply — reflections pay strictly in proportion to balance
Reward-exclusion list cap
50 addresses
MAX_EXCLUDED. Every balanceOf call walks this list, so the cap is a gas ceiling, not a policy
Delivered to a buyer on a taxed swap
93.05%
0.8436 of the 0.9066 tokens the pool debited, measured on a forked-mainnet Uniswap V3 pool
Contract constants read from the deployed token, and two measured outcomes. The 93.05% is 93% plus the buyer's own share of the reflection it just funded.

What one real deployment shows

On 26 August 2026 we deployed a reflection token to Robinhood Chain mainnet — RSMOKE, at 0x4d13fc75…388c5 — with a 5% reflection share and a 2% fee-wallet share. Its whole life is five transactions, and the interesting thing about it is that all of it is still readable.

BlockCallWhat movedTaxed?Reading afterwards
46,299,482createReflectionToken1,000,000 RSMOKE minted to the deployertotalSupply() = 1,000,000
46,299,595transfer10,000 to 0x1111…1111No — sender is fee-exempttotalReflected() = 0
46,299,744setFeeExemption(owner, false)Nothing moves; the deployer loses its exemptionisExcludedFromFee(owner) = false
46,299,936transfer1,000 sent → 930 delivered, 20 to the fee wallet, 50 reflectedYes — neither side exempttotalReflected() = 50
46,300,130setFeeExemption(owner, true)Nothing moves; the exemption is restoredisExcludedFromFee(owner) = true
The complete event history of RSMOKE (0x4d13fc75…388c5) on Robinhood Chain mainnet, read from the token's own logs on 1 September 2026. Five transactions, one of them taxed. The deployer had to remove its own fee exemption to produce a taxed transfer at all — the constructor exempts the creator so that seeding a pool is not taxed.

Note the third row. To produce a taxed transfer at all we had to remove the deployer's own fee exemption, because the constructor exempts the creator on purpose: taxing the transfers that seed a pool or fund an airdrop would misprice the launch before anyone has traded. takeFee requires that neither side of a transfer be exempt.

The taxed transfer moved 1,000 tokens and split them into 930 delivered, 20 to the fee wallet, and 50 reflected. totalReflected() on the live token still reads exactly 50 tokens.

Who actually received the 50

The reflection raised the rate by a factor of 1.000050002500 — that is 1,000,000 divided by the 999,950 tokens held by participating accounts at that moment. Multiply every pre-reflection balance by it and you get the current on-chain balances to the last of 18 decimals:

HolderBalance beforeBalance now (on-chain)GainedShare of the 50 reflected
Deployer 0x68253486…A2de989,000989,049.452472623631181559+49.45247262498.90%
Holder 0x1111…111110,00010,000.500025001250062503+0.5000250011.00%
Buyer 0x2222…2222930930.046502325116255812+0.0465023250.09%
Fee wallet 0xf05FCB23…59192020.001000050002500125+0.0010000500.00%
Total999,9501,000,000+50100%
Where the 50 reflected tokens actually went. Balances are `balanceOf` returns read on 1 September 2026, not estimates. Every one of them equals the holder's pre-reflection balance multiplied by 1.000050002500 — the single rate change the reflection performed. The holder who paid the tax received 0.09% of it back; the deployer, who paid nothing, took 98.90%.

This is the part most reflection-token marketing does not say out loud. Reflections pay in proportion to holdings, so the largest holder collects almost all of them. Our deployer wallet still held 98.9% of supply, so it took 98.90% of the redistribution — 49.45 tokens out of 50 — while the wallet that actually paid the tax received 0.046 tokens, or 0.09% of what it paid.

Nothing here is a flaw in the contract; it is arithmetic, and every reflection token that has ever shipped behaves this way. But it reframes the pitch. "Holders earn on every transaction" is true and describes a mechanism whose payout schedule is identical to holding a percentage of supply. If your token launches with a large team or treasury allocation that stays in the reward set, the reflection is mostly a transfer from traders to that allocation. Excluding your own wallets from rewards is the one-line fix, and it is worth deciding before launch rather than after somebody graphs it.

The pool problem, tested rather than assumed

A reflection token is a fee-on-transfer token, and fee-on-transfer tokens have a long history of not working in AMM pools. Robinhood Chain's DEX liquidity — including the pools our own liquidity tooling creates — runs on Uniswap V3, so I wanted a measurement rather than an opinion.

The experiment: fork chain 4663 at block 51,787,000, deploy a fresh copy of the same reflection contract with the same 5% / 2% split, create a real pool through the live V3 factory at 0x1f7d7550…2EfA against WETH9 0x0Bd7D308…AD73, seed it with full-range liquidity, then trade against it from a wallet that is not fee-exempt.

Side-by-side comparison of a sell and a buy on a reflection token in a Uniswap V3 pool, measured on a forked Robinhood Chain mainnet: the sell sends 1,000 tokens, the tax delivers only 930 to the pool, the pool balance check fails and the swap reverts with IIA, while the buy debits 0.9066 tokens from the pool, delivers 0.8436 to the trader and settles because the pool never verifies what the recipient received

ScenarioPool fee-exempt?ResultWho ends up with the tax
Sell: trader sends 1,000 tokens into the poolNoSwap reverts — Uniswap V3 raises `IIA`Nobody. The trade does not happen
Buy: trader sends 1 WETH into the poolNoSucceeds. Pool debits 0.9066 tokens, trader receives 0.8436 (93.05%)5% reflected to holders, 2% to the fee wallet
Sell, after excluding the pool from feesYesSucceedsNobody — `totalReflected()` does not move
Any taxed transfer while the pool still earns rewardsn/aPool's token balance grows on its ownThe pool, which cannot spend it
Four outcomes from one Foundry experiment against a fork of Robinhood Chain mainnet pinned at block 51,787,000, using the live Uniswap V3 factory (0x1f7d7550…2EfA) and WETH9 (0x0Bd7D308…AD73). The first two rows together are the failure mode worth remembering: buys work, sells revert. That is the on-chain shape of a honeypot, produced here by an ordinary configuration mistake rather than malice.

The first two rows are the finding. The sell reverts and the buy does not.

A V3 pool verifies, after calling back to the swapper, that its own balance actually rose by the amount it was promised. A taxed transfer into the pool delivers 93%, the check fails, and the pool raises IIA — insufficient input amount. Meanwhile a buy is a transfer out of the pool, and the pool never verifies what the recipient received, so the trade settles with the buyer quietly receiving 93.05% of what the pool debited. Buys work, sells revert: that is the on-chain signature every trader is taught to read as a honeypot, and here it is produced by nothing more sinister than launching a reflection token and forgetting to configure the pair.

Two switches fix it, and they are separate calls:

  1. setFeeExemption(pair, true) — swaps stop being taxed, so the pool's balance check passes and the token trades normally.
  2. excludeFromReward(pair) — the pool stops accruing reflections. Skip this one and, as the last row of the table shows, the pair's token balance grows on its own with every taxed transfer elsewhere in the supply. A pool cannot spend a reflection; the tokens just sit on the reserve side, and every holder who "earned" them earned a slightly smaller share instead.

Both calls are owner-only functions on the token, and — being straight about our own product — neither is in Alchemii's create or pool flow today. You make them from the token's write tab on Blockscout or from cast send against your own contract. That is a gap in our tooling, not a property of reflection tokens, and it is the single most likely way a reflection launch goes wrong: the create flow succeeds, the pool flow succeeds, and the token is one-way until somebody makes a call neither screen mentions.

And then the honest conclusion, which is the thing I would want to know before paying for a reflection deploy: once the pair is fee-exempt, no swap pays the tax. The reflection applies to wallet-to-wallet transfers only. If your economic model assumed a 5% cut of trading volume, on a V3 venue that model does not exist — you get a cut of transfers between holders, which on most memecoins is a small fraction of on-chain activity.

Two limits of this experiment, stated so you can weigh it: we swapped directly against the pool contract, so a production router adds at least one more taxed hop and its own accounting checks, meaning "buys work" is the best case rather than a guarantee. And this is V3 behaviour specifically; the older V2-style routers ship explicit supportingFeeOnTransferTokens paths, which is why fee-on-transfer tokens felt workable in 2021 and feel broken now.

The 25% ceiling: what it guarantees, and what it does not

The template's combined fee is capped at 2,500 basis points, and the cap is enforced in three places: the constructor reverts above it, setFees reverts above it, and there is no setter for the constant itself. Our contract test asserts both halves of that — a constructor above the ceiling fails, setFees(2_400, 101) fails, and setFees(2_300, 200) succeeds.

That last one is the part to read carefully. The ceiling is permanent; the fee underneath it is not. An owner who launches at 5% can move to 25% in one transaction. This is a real and reasonable design choice — a token that needs to lower its tax also needs a setter — but it means the trust question is not "what is the fee?" It is:

  • taxFeeBps() and walletFeeBps() — today's split.
  • The FeesUpdated event log — every change ever made, in order.
  • owner() — whether anyone can still make one. Ownership here is Ownable2Step, so a transfer requires the recipient to accept, and renouncing is what actually retires the risk.

For contrast, the honeypot design this ceiling exists to prevent is an uncapped, owner-mutable transfer fee: launch at 3%, wait for buyers, set it to 99%, and nobody can sell. A permanent ceiling written into the bytecode is the difference between "trust me" and "check it" — which is also why we publish the factory addresses rather than a screenshot of them.

Why it is a separate contract, not a checkbox

On the standard Robinhood Chain token creator, transfer fees, deflation, mint, pause and trading limits are toggles on one configurable template. Reflection is not one of them, for two reasons.

The mechanical one: reflection's balance accounting is incompatible with the limit features. Max-wallet and max-transaction checks compare a stored number against a threshold, but under reflection a wallet's balance grows on its own between transfers — so a holder can cross a max-wallet limit having done nothing at all, and a token that can trap its own holders is worse than a token without limits. The two feature sets are mutually exclusive in the form for the same reason they are separate on chain.

The unglamorous one: the main factory's Feature enum is immutable on chain. Adding reflection as a seventh feature would have meant redeploying the live factory and migrating the addresses every published article cites. A second factory at 0xad440a5a…07071e was the cheaper honest answer.

What we deliberately left out of the template is worth listing too, because in this lineage the omissions are the safety feature:

  • No swap-and-liquify. The auto-liquidity machinery that converts collected fees into LP is where most of the audited incidents in the SafeMoon lineage live — reentrancy during the swap, sandwichable internal trades, fee-on-fee recursion. Liquidity belongs in separate tooling you trigger deliberately.
  • No mint. Fixed supply, set in the constructor.
  • No pause, no burn hook. Both are powers a buyer can read, and neither is needed for reflection to work.

What it costs, with the numbers dated

LineReadingGas usedSource
Reflection token, service fee0.025 ETH (~$61.17)creationFee() on 0xad440a5a…07071e, block 51,783,073
Standard fixed-supply token, service fee0.01 ETH (~$24.47)creationFee() on 0x6b6D348F…5c0Ac
Reflection deployment, gas0.0000365 ETH (~$0.09)1,400,071tx 0xb65185d6…14b7, 26 Aug 2026, 0.026036 gwei
Configurable token deployment, gas0.0000414 ETH (~$0.10)1,586,188tx 0x397d0dee…d5f34, createConfigurableToken
Fixed-supply deployment, gas0.0000147 ETH (~$0.04)564,315tx 0xb1d81169…0812e, createToken
Same reflection deployment at 1 Sep gas price0.000833 ETH (~$2.04)1,400,0710.594798 gwei, eth_gasPrice, 1 Sep 2026
Service fees read from the live getters and gas read from real mainnet receipts, all on chain 4663. Dollar figures use ETH at $2,446.855 (Coinbase spot, 1 September 2026 14:23 UTC). The fee getters are owner-adjustable, so the wallet prompt at signing time is the binding number, not this table.

Three things in that table deserve to be said plainly rather than buried:

The reflection template costs 2.5x a plain token — 0.025 ETH against 0.01 ETH. If you want a token and not a mechanism, the standard factory is the cheaper product, and 10 Coin Lab's plain deploy is cheaper still; our Robinhood Chain creator comparison scores that honestly.

The transaction we cite paid 0.0001 ETH, not 0.025. Our deployer wallet is whitelisted for the discounted fee, so the receipt shows a price no public user pays. The public number is the one from creationFee(), and it is in the table.

Gas is a rounding error, but it moves an order of magnitude. The same 1,400,071-gas deployment cost $0.09 at the 0.026 gwei the chain ran on 26 August and would cost about $2.04 at the 0.5948 gwei we read on 1 September. Interestingly, reflection deploys cheaper than the configurable template (1,400,071 against 1,586,188 gas) — it is a smaller contract once you drop the toggles.

When a reflection token is the wrong choice

Written as a filter, because most projects that ask for reflection want something else:

  • You want a cut of trading volume. On a V3 venue you cannot have it, per the experiment above. What you can have is a creator fee on a launchpad — the Pons bonding curve takes a fee on every curve trade by design.
  • You plan a CEX listing. Fee-on-transfer tokens are routinely rejected or require bespoke integration work, because exchange internal transfers arrive short.
  • You want holders to be paid in something other than your own token. Reflection pays in the token itself. A dividend in ETH or a stablecoin is a different contract with a claim function and a different risk surface.
  • Your allocation is large and stays in the reward set. Then the mechanism mostly pays you, which is fine as a decision and corrosive as a surprise.
  • You are on Solana. SPL Token has no fee-on-transfer; the equivalent is the Token-2022 transfer-fee extension, with its own compatibility trade-offs — see SPL Token vs Token-2022.

Reflection is the right pick when you want a visible, permanent, contract-enforced reason for holders to hold rather than rotate, you accept that it taxes transfers rather than trades, and you would rather have a 25%-capped mechanism in an audited-shape template than a bespoke one nobody has read.

Launch checklist for a reflection token

  1. Decide the split before you deploy. Reflection share and wallet share are constructor arguments; the fee wallet must exist if the wallet share is above zero.
  2. Create the pool, then immediately exempt and exclude the pair. Two owner-only calls on the token — setFeeExemption(pair, true) and excludeFromReward(pair) — made from Blockscout's write tab or cast, because no UI carries them yet. Do it in the same sitting as the pool, and test one buy and one sell from a wallet that is not exempt before you announce anything.
  3. Exclude every other contract that holds tokens — lockers, bridges, vesting — remembering the 50-address cap.
  4. Decide what happens to the owner key. A live owner can move the fee under the ceiling. Renouncing ownership is the strongest signal available on this template; keeping it is defensible if you say so and say why.
  5. Publish the addresses and the getters. taxFeeBps(), walletFeeBps(), totalReflected() and the FeesUpdated log turn every claim you make into something a buyer can check in a block explorer, which is the only kind of claim that survives contact with a skeptical trader.
  6. Seed real liquidity. Reflection changes nothing about the fact that a thin pool reads as a rug setup — see the launch cost breakdown for what "credible" costs on this chain.

Reproducing the pool experiment

Everything in the pool section is a Foundry test against a pinned fork, so it is deterministic:

  • Fork: chain 4663 (https://rpc.mainnet.chain.robinhood.com) at block 51,787,000.
  • Contracts: V3 factory 0x1f7d7550B1b028f7571E69A784071F0205FD2EfA, WETH9 0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73, fee tier 3000 (tick spacing 60), full range ticks ±887,220, pool initialised at 1:1.
  • Token: fresh AlchemiiReflectionToken, 1,000,000 supply, taxFeeBps = 500, walletFeeBps = 200.
  • Sequence: seed liquidity from the exempt creator wallet → sell 1,000 tokens from a non-exempt wallet (expect IIA) → buy with 1 WETH (expect success, measure delivered share) → setFeeExemption(pair, true) → sell again (expect success, expect totalReflected() unchanged).

The measured buy: pool debited 0.906610481671849151 tokens, trader received 0.843601474996393133 — 9,305 basis points, which is the 9,300 the fee schedule predicts plus the buyer's own five-basis-point share of the reflection it had just funded.

FAQ

How do reflection tokens work?

A reflection token takes a percentage of each taxed transfer and credits it to every holder without sending anyone a transaction. Balances are stored in a second internal unit; collecting a fee shrinks the total of that unit, which raises the token value of every remaining balance at once. Nothing is minted, nothing is claimed, and the cost does not grow with the holder count.

Do reflection tokens work in a Uniswap V3 pool?

Not without configuration. In our forked-mainnet test, a sell into an un-exempted pool reverted with the pool's IIA error because a taxed transfer delivers the pool less than it asked for. Marking the pair fee-exempt makes trading work — and switches the tax off for swaps. On a V3 venue, treat reflection as a wallet-to-wallet mechanic.

What is the highest fee a reflection token can charge?

On this template, 25% combined. MAX_TOTAL_FEE_BPS is 2,500 basis points, checked in the constructor and in the setter, with no way to raise the constant. Under that ceiling the owner can still change the split, so read the FeesUpdated log and the owner() address, not just the current fee.

Who earns the most from reflections?

Whoever already holds the most, exactly in proportion to balance. On our mainnet token, one taxed transfer reflected 50 tokens and 49.45 of them — 98.90% — went to the deployer wallet holding 98.9% of supply. The wallet that paid the tax got 0.09% back.

Do I need to exclude the liquidity pool from reflections?

Yes, and it is a separate call from the fee exemption. setFeeExemption keeps swaps from reverting; excludeFromReward keeps the pair from accruing reflections it can never spend. Both, on every pair, before you announce.

Is a reflection token the same as a tax token?

They overlap. A tax token routes the fee to a wallet; a reflection token routes it to holders. This template does both in one transfer, with two independently settable shares — so "5% reflection plus 2% to the treasury" is one configuration, not two contracts.

Can the fee be raised after launch?

On this template, yes, up to the permanent 25% total, and every change emits FeesUpdated. A live owner key with a raiseable fee is a standing risk even when today's reading is 5% — which is why the strongest version of this token is one whose owner has renounced.

References

Everything above, and where to re-read it

  1. AlchemiiReflectionToken — RSMOKE, 0x4d13fc75…388c5Blockscout (Robinhood Chain)The token every ledger and balance figure in this article comes from. taxFeeBps(), walletFeeBps(), totalReflected() and balanceOf() are all public getters. (accessed 1 September 2026)
  2. AlchemiiReflectionFactory — 0xad440a5a…07071eBlockscout (Robinhood Chain)creationFee() read at 0.025 ETH and discountedCreationFee() at 0.0001 ETH, block 51,783,073. (accessed 1 September 2026)
  3. Deployment transaction 0xb65185d6…14b7Blockscout (Robinhood Chain)1,400,071 gas at 0.026036 gwei, 26 August 2026 04:25:26 UTC. The 0.0001 ETH value on this transaction is the whitelisted-deployer fee, not the public price. (accessed 1 September 2026)
  4. reflect.finance (RFI) — the first reflection ERC-20, deployed late 2020Origin of the patternThe rOwned / _rTotal design in this contract descends from RFI; the 2021 SafeMoon wave popularised it. Deliberately cited without a link: several addresses circulate as "the" RFI token and we have not verified which is canonical.
  5. Uniswap V3 core — swap() and the input-amount checkUniswap documentationThe balance check after the swap callback is what raises IIA when a fee-on-transfer token delivers the pool less than it asked for. (accessed 1 September 2026)
  6. Alchemii launch-data methodologyAlchemiiDefinitions and limits of the 47-token first-party sample and the 50,000-launch observational sample cited elsewhere on the site. (accessed 1 September 2026)
  7. ETH-USD spot priceCoinbase$2,446.855 at 14:23 UTC on 1 September 2026. Every dollar figure in this article uses this one reading. (accessed 1 September 2026)

Reflection is one of the few token mechanics whose entire behaviour is legible from public getters, which makes it a good test of whether a project wants to be checked. If you are launching one, publish the pair exclusions along with the contract address — and if you are buying one, place a 1-token sell before you place a real buy.

Deploy a reflection token on Robinhood Chain → — the reflection template, its 25% ceiling and the exclusion calls are all in the same flow, and the factory source is verified on Blockscout before you sign anything.

Your ERC-20 can be live on Robinhood Chain in one transaction

One signed transaction pays the service fee, deploys the contract and sends you the entire supply — with no backend custody and no administrator mint function unless you deliberately ask for one. Then open a Uniswap pool so the coin can actually be bought, and the position NFT stays in your wallet.

Related Topics

More guides covering the same Solana token creation, mint authority, LP burn, Raydium liquidity, and memecoin launch topics.