Demystifying EIP-1153: Transient Storage

Seungmin Jeon
11 min readJul 12, 2023

--

Introduction: EVM, Gas Fee, and Storage

EVM is a virtual machine that operates on Ethereum, designed to perform computations while ensuring a certain level of decentralization and security. Consequently, the development of contracts currently takes place in a very restricted environment. Gas is an example of this. To prevent the Tragedy of the Commons, anyone wishing to carry out all tasks consuming EVM’s computing resources has to pay a fee called gas to the nodes.

Gas varies according to network congestion. It’s a mechanism for validators to receive rewards as the size of Ethereum’s state increases. This greatly influences the way data is stored in the contract. Contracts primarily have three storage spaces: stack, storage, and memory.

In simple terms, these three spaces are as follows:

(Structure of EVM | Source: Getting Deep into EVM: How Ethereum Works Backstage)
  1. Stack: Where opcode operations occur. It is a LIFO (Last In First Out) data structure.
  2. Memory: A byte-level storage space where data is temporarily stored, primarily used to pass data during function execution to the parameters of internal functions. Since data is deleted when the function execution ends, it can be said that it has volatility / dependency on the function.
  3. Storage: A permanent data storage space where once a variable is stored, it remains in that storage forever (it is not impossible to modify it).

Due to the operational characteristics of the stack and the volatility of the memory, the data of the contract must be stored in the storage. However, a gas problem arises here.

Storing data in storage (SSTORE) requires the highest level of gas among opcodes in the EVM. Although it varies depending on the value of the variable or the situation, it usually consumes about 20,000 GAS. This is because storing data in storage is an act that increases the state size of Ethereum and exacerbates the burden on nodes.

Therefore, contract developers are using various gas optimization techniques to perform calculations without using storage as much as possible. Nonetheless, somewhat odd situations can occur, as follows:

Why Does Reentrancy Guard Have to Pay Gas?

modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}

function _nonReentrantBefore() private {
// On the first call to nonReentrant, _status will be _NOT_ENTERED
if (_status == _ENTERED) {
revert ReentrancyGuardReentrantCall();
}
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
}
function _nonReentrantAfter() private {
// By storing the original value once again, a refund is triggered (see
// <https://eips.ethereum.org/EIPS/eip-2200>)
_status = _NOT_ENTERED;
}

The code above is part of the Reentrancy Guard implemented by Openzeppelin. It prevents specific functions within the contract from being re-entered. If we look closely at the logic, it works as follows:

  1. Before executing the function, it changes _status from _NOT_ENTERED to _ENTERED. If _status is _ENTERED, it stops the function execution and reverts the state.
  2. After executing the function, it changes _status back from _ENTERED to _NOT_ENTERED.

The value of _status ultimately does not change once before and after execution. However, because the value of the variable _status stored in the storage changes twice during execution, the user has to pay the corresponding cost. The actual cost incurred in Ethereum is more than 10,000 GAS, which amounts to more than $0.3 when the gas price is assumed to be 20 Gwei. Why should $0.3 be paid for a value that doesn't even change ultimately? Isn't there a way to reduce unnecessary costs and perform tasks?

Gas Refund Cannot be the Solution

Fortunately, as you can see from the comments inside the Reentrancy Guard from Openzeppelin, Ethereum has a gas refund feature that returns gas fees. This is a solution that motivates dApp developers to create a ‘better state’ by deleting unused storage slots and contracts.

For example, contracts that are no longer in use can be deleted via the SELFDESTRUCT opcode in Ethereum. In this case, ethereum refunds the gas fee because it's a positive act that prevents the block space of Ethereum from being wasted unnecessarily, which increases the burden on the nodes. This also includes SSTORE, and if you delete the value stored in the state (to zero), it also contributes to reducing the state, so you can receive a gas refund.

If this is used to delete (initialize) the variable used in the reentrancy guard each time, it might be possible to reduce the consumed cost by receiving some gas refund. However, as the gas refund unexpectedly led to side effects, this is also hard to realize.

Some developers made it possible to arbitrage gas fees using the gas refund mechanism. When the gas price is low, store information in the contract, and when the gas price is high, delete the state to create a situation where the refunded gas fee is higher than the gas fee used for storage. The representative examples of this are $GST and the $CHI token created by 1inch developers. The mechanism is to mint tokens and store the state in the contract, and when the gas price goes up, send the token back to the contract and destroy it to receive an arbitrage profit. The picture below illustrates this well.

The arbitrage trade using gas tokens had the side effect of increasing the state size when the gas price is low. This was not the intention of the Ethereum core developers. Therefore, Vitalik Buterin and Martin Swende proposed in EIP-3529 to eliminate the gas refund allocated to SELFDESTRUCT, reduce the gas refund allocated to SSTORE, and reduce the maximum amount of gas refund from 50% of the amount used to 20%. This proposal was implemented in the 2021 London hard fork, and currently, it's not easy to arbitrage using gas tokens.

However, this has also reduced the amount of gas refunded in storage set temporarily, such as in a reentrancy guard, resulting in the generation of unnecessary costs. So how can we reduce this cost?

EIP-1153

To address certain design limitations of the EVM, in 2018, Alexey Akhunov and Moody Salem proposed EIP-1153 to introduce an opcode for implementing transient storage in the EVM. In this proposal, the authors explained the need for transient storage as follows.

The operations of transactions within Ethereum can create multiple nested execution frames. Each execution frame is generated by a CALL instruction. If a contract has multiple execution frames, the contract is re-entrant, and communication between these frames is conducted in two ways.

  1. Via the input/output (calldata) passed through the CALL instruction.
  2. Through storage updates: after saving the data shared by the two execution frames in the storage, communication is performed by updating it as needed.

The first method can be risky if there is an intermediate execution frame belonging to a different contract, in other words, when the CALL flow includes an external contract call. This could lead to unexpected security issues such as re-entrancy attacks.

The second method, as mentioned above, has a costly gas issue.

Therefore, EIP-1153 proposes a new storage space, transient storage. Transient storage operates exactly like storage, but is discarded like memory at the end of the transaction. It operates much like a computer’s RAM. To achieve this, new opcodes TSTORE, TLOAD are introduced in the EVM.

The gas cost for invoking these opcodes is approximately 100 GAS each, which is much cheaper than the original storage call (SLOAD) and store (SSTORE).

Mechanism of Transient Storage

Let’s look a little more into the operation of transient storage and TLOAD, TSTORE. First of all, transient storage operates exactly like existing storage, with a 32-byte address pointing to a 32-byte word. Here, TLOAD and TSTORE operate as follows:

  • TLOAD pops a 32-byte word from the stack, uses this value as an address to fetch from the transient storage, and then pops the fetched value from the stack.
  • TSTORE pops two 32-byte words from the stack, using the first word as an address and the second word as a value to store in the transient storage.

The difference from storage is that all values stored in transient storage are discarded at the end of the transaction.

Usage of Transient Storage

At a low level, using transient storage has the following benefits:

  • Data communication between functions was previously only possible through calldata or SSTORE/SLOAD. If TSTORE/TLOAD is added, it will be possible to communicate data between functions in safe and cheap way, using transient storage.

At a higher level, use cases include:

  1. The cost of re-entrancy guards is reduced by more than 90%.
  2. ERC20 approval can be done within a single transaction. This means there is no longer a need to ‘forever’ allow third parties access to one’s tokens. This is a significant enhancement to security, and there is no need to revoke in case of a hacked protocol.
  3. Callback functions can be implemented more safely and cheaply. This can be done by implementing path independent variables at the start and end of the callback function, and ensuring path independence through transient storage. The authors of EIP-1153 call this the ‘Till’ pattern.

This EIP is known to be implemented in the next Ethereum hardfork, the Cancun-Deneb (Dencun) update, which includes EIP-4844, also known as proto-danksharding. Also, it is already implemented in well-known Ethereum client implementations such as Geth and Nethermind.

If these opcodes are implemented in Solidity, it is expected that a modifier called transient, which would play a similar role to existing storage / memory / calldata, will be added. It could be utilized as follows.

contract A {
...
bytes transient example = "0x"
}

Controversies about Transient Storage

Meanwhile, there exist two controversies related to EIP-1153.

  1. Adam Cochran — EIP-1153 is not good EIP.

Well-known crypto analyst Adam Cochran posted a criticism of EIP-1153 on his Twitter in December of last year. The main points of his argument are as follows (this is a paraphrase, so for the exact context and meaning, it is recommended to check directly from the link):

After EIP-3529, only up to 20% of gas used can be refunded. This is to prevent network attacks. Before EIP-3529, there were side effects that maliciously increased the state size by abusing gas refunds through gas tokens. EIP-3529 was introduced to prevent this. However, TLOAD and TSTORE discard the data at the end of the transaction, receiving a 100% gas refund. This could mean that it becomes far too easy to launch network attacks on Ethereum. Under the current gas fee structure, i.e., EIP-1559, the baseFee increases exponentially if demand for block space increases over a certain period. This is intended to increase the cost of network attacks and decrease the incentive to attack. However, using TLOAD / TSTORE greatly reduces the cost of a network attack. Furthermore, there is a major downside in that the implementation of transient storage is highly complex. As the data is erased when the transaction is complete, it makes static analysis even more difficult. Uniswap is currently trying to introduce this (Note: Adam Cochran wrote this post in December last year). What could be their intention? One of the proposers of this EIP is a member of the Uniswap team, and they have suggested using transient storage for purposes such as KYC.

As Uniswap’s V3 license is expiring and they have acquired Genie, it seems inevitable to think that their intention to introduce this is due to the KYC system. Although cheap memory management and secure data access for contracts are important in Ethereum, whether this is more beneficial for Ethereum is unknown. What is certain, however, is that this would be greatly beneficial to dApps like Uniswap. We should always be critical of EIPs developed by ‘corporations’.

2. scottlewis.canto — Insider-aligned informal governance

The opinion raised by scottlewis.canto on Twitter also touches on an interesting topic. He claimed that Uniswap brought EIP-1153 through the Dencun update and deliberately hid it from the community before the V4 reveal. What he found problematic was that by doing so, Uniswap could monopolize the market and exclude competitors, creating an issue of ‘centralization’. He also pointed out that the timing of EIP-1153 being included in the Dencun update was in April, and Uniswap V4 was unveiled in mid-June, suggesting that Uniswap developers must have been aware that EIP-1153 would be included in the next Ethereum hard fork and worked on it accordingly.

The concerns raised by Adam Cochran are unlikely to happen. The opcodes for transient storage, TLOAD / TSTORE, do not refund the entire gas fee at the end of a transaction but use a fixed amount of gas, 100. 100 GAS is significantly less than the 20,000 GAS that SSTORE uses, but it's much higher than the cost of reading and writing memory. In other words, the gas consumed by these opcodes is fairly priced, making it virtually impossible to execute network attacks through them.

In addition, it is partially correct and partially incorrect to say that Uniswap brought EIP-1153 through the Dencun update and deliberately hid it from the community.

Uniswap has been working on the implementation of EIP-1153 through GitHub since 2022, and this process was transparently disclosed at Ethereum’s Core Devs Meeting and Execution Layer Meeting. EIP-1153 was switched to CFI (Considered For Inclusion) in November of last year and was included in this Dencun update.

Therefore, the criticism that Uniswap intentionally hid this from the community is incorrect. EIP-1153 was planned to be included in an upcoming Ethereum hard fork update at least six months before the public release of Uniswap V4, and Uniswap was not in an environment to monopolize information and exclude competitors.

Conclusion and Outlook

Transient storage helps implement dApp functionality in an efficient and safe manner. After the Dencun update, TLOAD / TSTORE is expected to create a variety of use cases, including reentrancy guards and flash accounting of Uniswap V4.

However, the operation of transient storage will be new to existing Solidity developers, and unforeseen security issues may arise. As with the standardization of proxy contracts through various security incidents (such as the Parity Wallet Hack), the use of transient storage opcodes should also be actively discussed in terms of standards.

The most representative example of a dApp using transient storage will certainly be Uniswap V4, and it is hoped that a lot of discussion will take place on what security considerations should be made there.

Reference

special thanks to Moody Salem

--

--