Who assigns bit 11?
Eleven bits of a 256-bit word mean something today. Deciding what the twelfth means is the part of this design with no good answer, and the systems that hit the problem first gave five different ones.

The behaviour word is a single uint256, and eleven of its bits currently name something: fee on transfer, rebasing, transfer hook, pausable, blocklist, non-transferable, upgradeable, mintable, seizable, and two that only mean anything for a collection, operator-restricted and metadata-mutable. That leaves 245 bits unspoken for, which sounds like room to spare. Space was never the constraint.
A twelfth bit is not hypothetical
ERC-7984 settled a shape for confidential fungible tokens, where balances and transfer amounts are ciphertext handles rather than numbers. The standard states plainly that this breaks ERC-20 compatibility, and that existing tooling, routers and block explorers included, cannot be used with such a token. That is a behaviour an integrator has to know about before touching the contract, and there is no bit for it.
The cost of not knowing is measurable. In July, RWA.xyz published its reconciliation of Robinhood's tokenised stocks: across 21 mismatched tokens, reported supply was overstated by roughly 64,000 tokens, a 56% discrepancy, with some tokens off by ten times and others by a hundred. Nothing was exploited. The contracts absorb distributions and reverse splits through a multiplier, and indexers assuming ERC-20 conventions could not see it. New behaviours arrive faster than any fixed vocabulary names them, which is the problem in one sentence.
What a bitmask actually costs
Bit values get copied into integrator code. That is the point of a bitmask rather than a hierarchy of interfaces: reading it is cheap and local, and a caller can test it without a network round trip or a library. It also means that the moment a twelfth bit is assigned, every deployed copy of the vocabulary is stale, and a caller holding an old copy drops a behaviour it has never heard of.
Silently is the problem. Not reverting, not returning unknown, just quietly treating a token as understood while a bit it cannot name is set. The partial fix is a rule that a caller reading a word containing bits outside its known mask must treat the token as not fully classified. That rule is necessary and it is not sufficient, because it converts every expansion of the vocabulary into a compatibility break for everyone who has not updated.
Every expansion is a compatibility event. That is a strong reason never to expand, and a stronger one to squat the bits nobody has claimed yet.
Five answers already in the wild
This problem is not new and it is not specific to Ethereum. Any protocol with a fixed-width field of flags has had to decide who fills it. The answers cluster into a small number of shapes, and they are not equally good.
- BIP-9
- keeps a living assignments file in the specification repository, and permits a bit to be reused once an earlier deployment has timed out or activated, discouraged but allowed. The registry is a file rather than a contract, and it has worked for a decade.
- EIP-155
- requires chain IDs to be unique and names no registry at all. A third-party repository became the de facto one, and a years-old issue against the spec points out that demanding uniqueness without publishing the values already taken is not a workable design. This is the cautionary case.
- ERC-7579 and ERC-7780
- allocated four module type IDs and then simply claimed six more in a successor proposal. That is roughly what the ERC process does in practice, and there is no stated rule for what happens when two drafts reach for the same number.
- ERC-6617
- lets each deployment pick its own bits and offers an optional extension so a contract can name them in strings. Self-description instead of allocation, which trades a machine-comparable value for a human-readable one and puts the caller back to one question per call.
- EIP-8141
- assigns bits 0 through 2, reserves the rest, and enforces it with a hard assertion that the whole field is below 8. An unknown bit makes the transaction invalid. That works at the consensus layer, where everybody upgrades together. Integrators do not.
Two things worth stealing from TLS
The sixth answer is the useful one. RFC 8447 split the TLS extension registry: values whose first byte is 0 through 254 are allocated by specification, and first byte 255 is reserved for Private Use, where it is the responsibility of those using the range to avoid conflicts within their own scope. Squatting stops being a violation and becomes a supported operation somewhere it cannot collide with the public vocabulary.
The transplant is clean. The low 128 bits are allocated by the specification text; the high 128 are private use and a generic caller never interprets them. It also repairs the unknown-bit rule, which as written would classify every token using a private bit as unclassified. The strict rule applies to the public half only.
GREASE, or why that rule will not be implemented
The second idea is the one that changed my mind about how urgent any of this is. A forward-compatibility rule of the shape described above will be written into a specification and then not implemented, because no integrator ever encounters an unknown bit during development. Their handling of it stays untested for years and then fails on the day the vocabulary first grows, which is precisely the day it mattered.
TLS has the same structural weakness and solved it by making the rare case common. GREASE reserves values that are defined to mean nothing and sends them anyway, so an implementation that mishandles unknown values breaks immediately, in testing, against ordinary traffic, rather than years later against a real extension.
A path that is never exercised is not a path. It is a paragraph in a document.
Applied here: reserve one public bit defined to carry no meaning, and set it on a meaningful share of tokens. An integrator whose unknown-bit handling is broken finds out on the first day rather than at the first expansion. This does not answer who assigns bit 11. It removes most of what made the answer urgent.
What Token-2022 makes obvious
Solana's token program stores extensions on the mint account as type-length-value entries. A reader walks them, decodes the ones it recognises, and skips the ones it does not by advancing past each entry's declared length. One account read, an arbitrary vocabulary, and no compatibility event when that vocabulary grows. The property this design wants is already in production somewhere else, and the RWA.xyz write-up says so from the outside: on Solana a data platform can query multiplier changes directly, and EVM networks have no equivalent.
Comparing the two finally made the price nameable. A TLV entry carries its own length, so an unknown entry is skippable. A bit carries nothing. An unknown bit is noticeable and uninterpretable, and there is no safe thing for a caller to do with it except distrust the entire word.
That is not a defect in the implementation. It is what a fixed-size, cacheable read costs, and it is the reason the allocation question is hard here and easy there.
A second assumption, and a draft that would move it
The verification half of this framework rests on a different sentence: a contract's code cannot change, so a caller who reads it once never has to read it again. That sentence has been reliably true for a while, and it is worth tracing how it got that way, because a draft now in discussion would end it.
- EIP-1052
- introduced EXTCODEHASH, and its motivation names the use case directly: a contract wanting to check whether another contract's bytecode is one of a set of permitted implementations.
- EIP-6780
- restricted SELFDESTRUCT to the transaction that created the account, which removed the last way a deployed contract's code could change.
- EIP-7702
- deliberately preserved the property. EXTCODEHASH does not follow a delegation pointer, and the rationale says why in as many words.
- EIP-8298
- proposes SETCODEFROM, an instruction that sets the executing account's code hash to another account's. It is runtime-path only, and the specification states that an account can call it again to upgrade later.
If instead delegations were followed, an account would be able to temporarily masquerade as having a particular codehash, which would break contracts that rely on codehashes as a definition of possible account behavior.
That is EIP-7702's rationale, rejecting temporary masquerading. EIP-8298 would permit a permanent change of identity, and the two proposals do not currently talk to each other about it. I do not think that makes the draft wrong. It makes the interaction something worth raising in its thread rather than asserting from outside it, which is where I intend to put this next.
What it would do here is narrower than it first looks, and the difference is worth stating precisely rather than either ignoring or dramatising. A forty-five byte minimal proxy contains no such instruction, so the clone stays immutable and reading its bytes stays permanently valid. What stops being permanent is the second half of the check. Verification compares the address embedded in those bytes against a pinned implementation, and address X would no longer imply the code reviewed at X forever.
Since the implementation is reviewed anyway, that is checkable rather than fatal. The honest revised claim is that verification by address is as durable as the reviewed implementation's own code, which is permanent today and would remain permanent under EIP-8298 only if the reviewed code contains no SETCODEFROM.
The broader point is the one that belongs in that discussion. EIP-7702 created a mutable class of account that identifies itself: a delegated account's code hash carries a fixed prefix and any caller can see it. An account that adopted code through a new instruction would look exactly like an ordinary deployed contract. Deciding whether a given contract belongs to the mutable class would require disassembling it carefully enough to tell the opcode from a PUSH immediate, which is tractable off chain and impractical on it. Every existing code-hash allowlist would keep working and quietly mean something weaker.
Where this leaves it
The allocation question is still open, and I no longer think it is the emergency it looked like. Reserving a private half removes the incentive to squat, and greasing the public half makes the forward-compatibility rule real instead of aspirational. What remains is the plain governance question of who holds the pen, and the honest answer from the five systems above is that a file in a specification repository has outperformed every cleverer mechanism anyone has tried.
The larger doubt is the one worth ending on. If bit meanings cannot be allocated centrally, then what this is describing is a convention rather than a standard, and conventions do not obviously belong in a standards process. If they can, then the allocation mechanism is the actual standard and the function signature is trivia. That question is open on Ethereum Magicians, and it is the one I would most like to be argued out of.