betterERC
Docs/Reference

Behaviour flags

Nine bits, their values, what each one costs you, and the two combinations that cannot exist on chain.

All docs

Bit values live in BehaviorFlags.sol. Copy the library verbatim or inline the numbers; there is nothing in it but constants and one pure function.

BitFlagValueWhat it means for you
0FEE_ON_TRANSFER1The recipient receives less than the amount you named
1REBASING2balanceOf can move without a Transfer event naming the account
2TRANSFER_HOOK4A transfer calls another contract, which can revert it or burn gas
3PAUSABLE8An authority can halt all transfers
4BLOCKLIST16An authority can bar individual accounts
5NON_TRANSFERABLE32Transfers always revert; only mint and burn move value
6UPGRADEABLE64The code can be replaced, so every row above can change
7MINTABLE128An authority can create supply and dilute every holder
8SEIZABLE256An authority can destroy any account's balance

Two kinds of bit

The division at bit six is the most useful thing on this page. Bits 0 to 5 describe what the token itself does: five of them change what a transfer does and will show up in a simulation, and REBASING shows up instead as a balance that moved with no Transfer event naming the account.

Bits 6 to 8 describe powers an authority holds. Nothing reveals any of them until they are used — no simulation, no test transfer, no amount of watching. Which is exactly what makes them the ones an integrator discovers late, and why they are in the word at all.

Both reference tokens and every runtime clone set MINTABLE and SEIZABLE unconditionally, because mint and burn live on the shared base and no extension set can remove them. Without those bits, a token with no extensions would report zero — which this vocabulary defines as indistinguishable from a plain ERC-20 — while its supply authority could dilute every holder and take any balance.

SEIZABLE is not BLOCKLIST. A freeze stops value moving, is reversible, and leaves the balance where it was. A seizure takes it, and nothing later restores it.

Two rules

A flag is set when the extension is installed, not when it is currently active. And the word never changes: configuration moves, declarations do not. Both rules exist for one reason — so that a single read is enough.

There is one exception, and the vocabulary names it itself. A token declaring UPGRADEABLE can have its code replaced, and the replacement is not bound by the set the old code sealed. The word is safe to cache forever exactly when that bit is clear — and a verified clone of an immutable runtime is the case where forever is a fact about bytecode rather than a promise.

Reserved bits

REBASING is defined here but implemented by no module in this framework. It exists so the vocabulary is complete: a token elsewhere can declare it and you can read it with exactly the same code. Bits outside the assigned set are reserved, and declaring one is rejected at deployment rather than quietly ignored.

Forbidden combinations

Some declarations contradict each other, and a token making both would be lying about at least one. The constructor rejects them, so you will never meet one on chain.

CombinationWhy it cannot exist
NON_TRANSFERABLE + FEE_ON_TRANSFERThe transfer path is unreachable, so no fee can ever be charged
NON_TRANSFERABLE + TRANSFER_HOOKThe transfer path is unreachable, so no hook can ever fire

Both share one rationale: a declaration that can never manifest is not a harmless extra, it is a false warning that costs integrators a code path they will never need. The check runs at deployment against BehaviorFlags.conflictingPair — the same pure function you can run yourself, against a token you did not deploy.

All thirty-two subsets of the five modules are deployed in the test suite. The twenty permitted ones must transfer correctly; the twelve forbidden ones must fail inside their own constructor.