Grouped Token Transfers: How Frozen Tokens Can Still Move
In the ERC-7943 reference code, a transfer of 80 was refused, yet 40 + 40 in one batch went through. How did frozen tokens move?

IN 30 SECONDS
A batch transfer bypass is a bug where several small amounts sent in one call add up to a transfer the token’s own check refuses. In the ERC-7943 reference code, it let a holder move frozen tokens (fix proposed, unmerged as of 7 October 2026). This stage shows how.
KEY TAKEAWAYS · 3
- In the ERC-7943 reference code, the uRWA1155 contract checked each entry of a batch against a balance it only debited after the loop.
- Repeating a token id (40 + 40) let a holder move frozen tokens, although canTransfer refused one transfer of 80.
- The bug is in the reference implementation, not in the standard’s text. PR #2045 proposes a fix, unmerged as of 7 October 2026.
On this page
The problem: two transfers of 40 where 80 was refused
IN SHORT In the ERC-7943 reference code, a refused transfer got through once it was split into two entries on the same token id.
One transfer of 80
- The check says no: 80 is over the 40 unfrozen.
- The transfer fails.
One batch of 40 + 40, same id
- Each entry is checked against the same 40, so both pass.
- 80 moves. Balance 20, frozen still 60.
That’s how the ERC-7943 reference contract for ERC-1155 tokens behaved when I checked on 7 October 2026. A fix sits in a pull request, not merged when I checked (see the PR for its current state).
The bug sits in that reference code, not in the standard’s text. I’m one of five named authors of ERC-3643, not of ERC-7943, and I didn’t find this bug.
IN PLAIN WORDS
An ERC is a standard for Ethereum apps. A pull request is a proposed change to the code. A permissioned token is one whose transfers go through permission checks.
The bug class is generic. I’d test for it in any permissioned token with a batch path.
Coming up next: But what does “frozen” mean for a token you still own?
Words to know before the bug
IN SHORT A frozen token is like money on hold at your bank: still yours, but not yours to send.
ADAM says: Picture a teller who checks each withdrawal slip against your free balance, but only updates your account at closing. A person might spot two slips for one account; this code never compared them.
WORDS TO KNOW
- Token id
- One ERC-1155 contract holds many kinds of token. The token id says which kind, like a product code.
- Frozen tokens
- Tokens that an authorized role has locked in a holder’s account. The holder still owns them but can’t send them.
- Batch transfer
- One call that moves several amounts at once, given as a list of token ids and a list of amounts.
- canTransfer
- A read-only function, or view, that answers yes or no: would this transfer be allowed? Apps can ask it before they send.
- Reference implementation
- Example code published next to a standard to show one way to build it. It is not the standard’s rules themselves.
How can a batch transfer bypass frozen balances?
IN SHORT The reference code checks each entry against a balance it hasn’t debited yet, so a repeated id is measured twice against the same 40.
STEP BY STEP
Step 1. Ask first. The holder wants to send 80 tokens of id 1 to another account, and asks the pre-check first.
- Ask first The holder wants to send 80 tokens of id 1 to another account, and asks the pre-check first.
- Refused The pre-check says no: 80 is over the 40 unfrozen.
- Send a batch The holder sends one batch instead: id 1 twice, 40 each time.
- First check The first entry asks for 40. The unfrozen balance is 40, so it passes.
- Second check The second entry also asks for 40. Nothing was debited yet, so it still reads 40. It passes too.
- Debits Only now, after both checks, does the contract debit the two entries: 80 in total.
- Result Balance 20, frozen still 60. Part of the frozen position has left the account.
ERC-7943 (uRWA, the universal real-world asset interface) is a Final ERC by Dario Lo Buglio, Tino Martinez Molina and Mihai Colceriu. Final is the stage where the text is settled. Its multi-token version lets an authorized role freeze part of an account’s balance of one Token id One ERC-1155 contract holds many kinds of token. The token id says which kind, like a product code. See the glossary.
Frozen tokens cannot be transferred by the account.
So the holder must not be able to move Frozen tokens Tokens that an authorized role has locked in a holder’s account. The holder still owns them but can’t send them. See the glossary. And canTransfer A read-only function, or view, that answers yes or no: would this transfer be allowed? Apps can ask it before they send. See the glossary “MUST validate that the amount being transferred doesn’t exceed the unfrozen amount”.
The Reference implementation Example code published next to a standard to show one way to build it. It is not the standard’s rules themselves. See the glossary, uRWA1155, aims to enforce this in _update, the internal function ordinary transfers go through. For a Batch transfer One call that moves several amounts at once, given as a list of token ids and a list of amounts. See the glossary, it checks each entry against the unfrozen balance. The catch: the debit only happens after the loop.
ITEM GET
Checked one by one, debited at the end
The damage is bounded. Sent to another account, the batch can’t move more than the raw balance. And each single entry still has to fit inside the unfrozen amount.
WATCH OUT
Within those bounds, a holder with no special role can move the frozen part of a partially frozen position. They only need to be on the token’s approved list, its whitelist.
Yet the pre-check that apps can call refuses that same total.
Sources: ERCs issue #1814, ERCs PR #2045 (open as of 7 Oct 2026), ERC-7943 (Final), uRWA1155 reference contract.
STAGE CLEAR
What you now know
- Why a check that looks at one entry at a time can miss what a whole batch does.
- Why the debit coming after the loop let 40 + 40 pass where 80 was refused.
- Where the bug lives: in the reference code, not in the standard’s text.
Check yourself
Tap or click a question to see the answer.
A batch sends 30 of id 1 and 30 of id 2, with 40 unfrozen on each id. Does it slip past the frozen amount?
No. Each id appears once, so each entry already is its id’s total. The trick needs the same id twice.
Former CTO of Integra. Named author (1 of 5) of ERC-3643, first author of ERC-6960, co-author of ERC-7410, and co-author of ERC-8203, which is still a draft. Building production AI and regulated Web3 systems.
Have a project to ship or a role to fill?
Discuss your project or roleFollow the engineering notes
Get new articles on production AI and smart contracts by email.

