Frank Poncelet

erc721f · solidity · smart-contracts · gas

And single

08 Sep 2026

On 12 January 2022 Azuki sold 8,700 tokens in a few minutes on a new contract, ERC721A, written by Chiru Labs so that minting a hundred tokens costs about the same as minting one. Five days later I deployed the CryptoPunks V1 wrapper, which is a different story. Six weeks after that I published ERC721F. It was my answer to ERC721A.

Who pays

The trick in ERC721A is not hidden. Their own design notes say it: "ERC721A defers the initialization of token ownership slots from minting to transferring." The owner is written once for the whole batch; the first transfer of each token fills in the rest. Their table: a first transfer costs 92,822 gas against 45,331 for plain ERC721. They are open about the trade-off: "Although this has a higher total gas cost (minting + transfers), it gives significantly lower overall transaction fees in practice." Mint in the rush when the base fee is high, transfer later when it is low.

That works if the person who mints is the person who transfers. Usually it is not. The one minting a hundred at a discount is a whale. The one paying for the first transfer is whoever buys one of those hundred on OpenSea, because the buyer's transaction settles the sale. The whale gets a hundred for the price of a few, and the first buyer of each token pays double gas to make up for it. Someone minting one token gets nothing from the batch trick at all. And a mint happens once. Everything after it, every sale, every move to a new wallet, is the rest of the token's life, and that is where the gas keeps going. ERC721A optimises the one moment and charges it to the first of the many. I did not think that was honest to the single minter. I still don't.

Two March 2022

So I wrote my own. The first commit is dated 2 March 2022. It is not clever, and that is the point: OpenZeppelin's ERC721 without ERC721Enumerable, a counter for totalSupply(), and a walletOfOwner() that scans, with the warning "This read function is O(totalSupply)" in the code from day one. Every token is written to storage when it is minted. Nobody inherits a bill.

I borrowed Chiru Labs' README sentence and made two edits. Theirs: "a fully compliant implementation of IERC721 with significant gas savings for minting multiple NFTs in a single transaction." Mine: "a simple extension of IERC721 with significant gas savings for minting multiple and single NFTs in a single transaction." The edit was deliberate. It is the whole argument in two words, and it is still the first line of the README.

I wanted to call it ERC721B; the 1.0.0 source still says @title ERC721B. The CryptoPunks V1 crowd talked me out of it: "Are you crazy, call it F." F stands for Frank. Six months earlier, in September 2021, we had released We Are Dorkis, a collection of hand drawn characters, pen and coloured pencil on paper, by an artist in New Zealand. I wrote that contract too. It is the one I wish ERC721F had existed for.

The numbers

Measured in our own test suite in the autumn of 2022, optimizer at 1,000 runs:

ERC721Enumerable ERC721F ERC721A
Mint one 97,188 47,756 47,073
Mint a hundred 11,430,644 2,547,287 238,419
Transfer fifty out of a wallet of a hundred 2,320,165 to 2,366,160 725,022 to 752,750 1,912,753 to 3,472,597

For one person minting one token, ERC721F and ERC721A cost the same. For a whale minting a hundred, ERC721A is ten times cheaper. For the people who then buy from the whale, ERC721F is two and a half to five times cheaper. That is the disagreement in a table. Against Enumerable, the current benchmark (May 2026) saves 36% on one mint and 77% on a hundred.

Every number here is ours. As far as I know nobody independent has benchmarked ERC721F; the tests are in the repo, so anyone can run them...

The years in between

On 6 May 2022 there is a commit, "removed fallback on request of Foundtion". Foundation's lead engineer had phoned. Their marketplace contract did not ask a token contract what it supported through ERC-165; it probed for methods and read the result. My fallback() caught every probe for a method that did not exist and answered without reverting, and their marketplace broke on it. I took the fallback out; receive() was all we ever needed. Foundation, about $230 million in primary sales according to Cointelegraph, shut down in April 2026. That dates the era.

At NFT.NYC 2022 my first slide said "DON'T use ERC721Enumerable", and the room said "F stands for Frank" out loud. At NFT.London the slide gained a line: "DON'T use ERC721A either."

In September 2022 an intern, N1h1lum, arrived at Xplore Group and turned one Solidity file into a project: structure, Hardhat, tests, royalties, the comparison above, the npm package. He currently has 1,034 of the 1,367 commits. We hired him... Somewhere in there I decided the version tags should follow OpenZeppelin's. Before that, nobody, me included, could tell which ERC721F went with which OpenZeppelin; it was confusing as hell. Now OpenZeppelin is at 5.7 and ERC721F is at 5.7, and you know they fit. That is why the tags jump from 1.0.3 to 4.4.0.

Who uses it? By my knowledge over forty collections in the 2021 and 2022 rush. The npm package exists since December 2022 and a GitHub import leaves no trail. Since then, about two and a half thousand downloads, fifty-four a month.

Something did go wrong, and it took three and a half years to notice. In September 2022 we added an Enumerable extension for people who wanted tokenByIndex back. It counted from token zero. Collections that start numbering at one got the wrong token back for every index. Nobody noticed, because most collections start at zero. I found it in March 2026 while writing tests for another project, wrote the tests that should have existed in 2022, and shipped the fix in 5.6.1.

A major bank

In August 2024 calculateAddress and randomAddress appeared in AddressUtils.sol. We added them for a major Belgian bank with a programme for wealthy clients: mint an NFT for a valuable item, attach the documents, and the NFT lives in the bank's vault. Built on ERC721F, live, in production. I am under an NDA, so that is all I can say about it.

It makes sense to me because I have argued for years that mass adoption only works when banks do custody for people who do not want self custody, so that the average person uses a blockchain application without knowing it. A vault of NFTs held by a bank for clients who will never see a seed phrase is that argument made concrete.

The maintainer is partly a machine

In July 2026 I applied to Anthropic's open source contributor programme for ERC721F and we were accepted: six months of Claude Max 20x, free. Claude is our main contributor now; since 11 July, twenty-two commits carry its co-author trailer, including the Hardhat 3 migration and an access-control fix. On Bassim Eledath's eight levels I would put the repo at six and seven, not eight. Everything is (and stays) under my supervision, and so far I have merged everything it proposed.

Nobody likes gas

The JPEG rush is over. What people tokenise now are real world assets, and what has not changed since January 2022 is that nobody likes gas and somebody always pays it. My problem with ERC721A was who gets the discount and who gets the bill.

So this is, once again, a story with no end. NFTs are dead. RWAs are not. And ERC721F under both of them lives on, writing every owner to storage, one token at a time.

Multiple and single. The edit was deliberate.