SKIP TO CONTENT
ETHEREUM STANDARDS6 minStandards That Ship / Ep. 9 · Stage 9-1

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?

XIN
Pixel-art night scene of a vault checkpoint. A red lamp at the gate refuses one large crate, while a conveyor belt carries two identical smaller crates through the same gate under a green lamp, and a padlocked shelf in the vault behind stands empty.

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 VS ONE BATCH

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.
Numbers from the reproduction in PR #2045, run against the uRWA1155 reference contract before the fix. Balance 100, frozen 60, so 40 unfrozen.

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

Sequence diagram: 4 participants: Holder, Pre-check, Transfer code, BalancesSequence diagram: 4 participants: Holder, Pre-check, Transfer code, Balances. Step 1: Holder to Pre-check, May 80 of id 1 go?. Step 2: Holder to Transfer code, One batch: id 1 twice, 40 each. Step 3: Transfer code to Balances, First 40: fits the 40 free. Step 4: Transfer code to Balances, Second 40: still 40 free, fits. Step 5: Transfer code to Balances, Now debit both: 80 leave. Step 6: Balances to Holder, Balance 20, frozen still 60.HOLDER > PRE-CHECKMay 80 of id 1 go?HOLDER > TRANSFER CODEOne batch: id 1 twice, 40 eachTRANSFER CODE > BALANCESFirst 40: fits the 40 freeTRANSFER CODE > BALANCESSecond 40: still 40 free, fitsNothing debited between thetwo checksTRANSFER CODE > BALANCESNow debit both: 80 leaveBALANCES > HOLDERBalance 20, frozen still 60

Step 1. Ask first. The holder wants to send 80 tokens of id 1 to another account, and asks the pre-check first.

Pick a step to see it move
  1. Ask first The holder wants to send 80 tokens of id 1 to another account, and asks the pre-check first.
  2. Refused The pre-check says no: 80 is over the 40 unfrozen.
  3. Send a batch The holder sends one batch instead: id 1 twice, 40 each time.
  4. First check The first entry asks for 40. The unfrozen balance is 40, so it passes.
  5. Second check The second entry also asks for 40. Nothing was debited yet, so it still reads 40. It passes too.
  6. Debits Only now, after both checks, does the contract debit the two entries: 80 in total.
  7. Result Balance 20, frozen still 60. Part of the frozen position has left the account.
Balance 100, frozen 60, so 40 unfrozen. The pre-check refuses 80; the batch moves 80 because the debits only start after both checks.

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.

ERC-7943, the standard’s text

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

Both entries were measured against the same 40, because nothing was debited until the loop ended.

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.

Next stage:How does the proposed fix stop the batch, and has it been merged?6 min
Adam Boudjemaa
Adam Boudjemaa

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 role
Follow the engineering notes

Get new articles on production AI and smart contracts by email.