How it works

One transaction, four strangers

A strip is not four transactions in a row. It is one transaction that visits four contracts, none of which EIP1153 controls, and two of which interrupt it partway through to ask for money.

WHO IS RUNNINGHATCHED = NOT YOUR CODEyour striplenderthe rest of your strip runs in herepool Acalls back inpool Bcalls back inSCRATCH PAPERwiped at every return, invisible to the boxes aboveTHE METERone transaction, reachable from every box, gone the moment it endsPERMANENTonly the result, because this one is billed forever

Read it left to right

The yellow bar is your strip running. Underneath it are the contracts it calls. The hatched ones belong to somebody else. When EIP1153 asks pool A for a swap, the pool sends the tokens out first and then calls straight back into EIP1153 to collect payment, which is the small box sitting inside it.

That callback is a fresh function call. Everything your original function had written down on scratch paper is out of reach. If the running total lived there, the payment leg would have nothing to write to.

The flash loan is the extreme case

When you borrow, the lender hands over the money and then runs the entire rest of your strip inside its own call, before checking whether it got paid back. Your last block executes several frames deep inside a contract you did not write.

Every meter movement in there has to land somewhere both the lender's frame and the final check can see. That is what the pink bar is.

Which parts actually need it

Most projects that mention EIP-1153 are using it as a cheaper flag and calling that an innovation. Two of the four things EIP1153 keeps there genuinely have nowhere else to go. The other two are just cheaper, and pretending otherwise would be silly.

#What is keptTouched fromVerdictWhy
01The meterWritten from inside the pool's own callbackNeeds itThe pool pays out first and then calls back into EIP1153 to be paid. That bookkeeping happens in the pool's frame, where the memory of your run has already been put away. Permanent storage would work and would charge you rent on a number that stops existing a moment later.
02Where you are in the stripWritten from inside the lender's callbackNeeds itA flash loan runs the rest of your strip nested inside the lender's call. The cursor has to survive that, and so does the table the composer draws.
03The reentrancy guardEIP1153's own frameJust cheaperA permanent storage flag would work exactly as well. It would cost more gas and that is the only difference. Worth saying out loud, because this is the use case everyone reaches for first.
04Who ran the stripRead back in the final stepJust tidierThis could be threaded through as an argument. Keeping it in one place is nicer to write and saves a little gas. It is convenience, not necessity.

The test worth remembering

The question is not whether a value outlives a function call. An ordinary local variable survives every venue call perfectly well, as long as nothing needs to touch it while control is somewhere else.

The question is whether a frame that is not yours has to read or write it.

EIP1153's meter fails that test in two places, which is why it is built this way and not as a demo with a nice logo.

The contractit compiles, you can check
Compilersolc 0.8.28, via-ir
EVM targetcancun
Deployed size5 911 bytes
Transient instructions10 TSTORE, 16 TLOAD

Those counts come from taking apart the compiled bytecode, not from reading the source. Everything you run on this site is a real transaction against a real node.

cd contracts && forge build

Go and break something

Failed attempts are free apart from gas, so the fastest way to understand any of this is to build a strip that cannot possibly work and watch the chain erase it.