This proposal allows the transaction payload to define write protections for balances and storage slots that are enforced at the protocol level. These protected transactions empower Ethereum users to restrict the behavior of the deployed on-chain smart contracts without needing to perform a deep analysis of their EVM bytecode.
The total value of crypto assets that have been stolen to date exceeds the yearly GDP of a medium-sized nation. This level of loss and waste is indefensible and has a long list of negative consequences for everyone involved.
Specifically, one of the major ways in which Ethereum users end up losing their funds is not exposing private keys, but instead being tricked into signing transactions that appear innocent in their Wallet applications but in practice perform a complete sweep of the senders' assets.
The ability of an average user or a Wallet application to find, collect, review, and analyze the EVM code the transaction will execute is very limited.
This leaves the users with no mechanism to enforce any restrictions on what the transaction actually does once it is signed. This leads users to perform blind signing in order to interact with Ethereum, exposing them to significant and avoidable risks.
By providing the Wallets and dApps with the ability to restrict the possible outcomes of a transaction, we create a tool that users and wallets will apply to reduce their risk levels.
| Name | Value |
|---|---|
| RESTRICTED_TX_COST | TBD |
| TRACE_CALL_GAS_COST | TBD |
| GET_TRACE_CALL_ADDRESS | TBD |
| RESTRICTED_EXECUTION_TX_TYPE | TBD |
We introduce a new EIP-2718 transaction, "restricted execution transaction", where the TransactionType is RESTRICTED_EXECUTION_TX_TYPE and the TransactionPayload is the RLP serialization of the following:
asserter_address - the address of an existing contract that will be called for the Assertion Frame.asserter_data - the data to be passed as a call data to the Assertion Frame. In case the asserter_address is not set, this field acts as a One-Time Restrictions Code.asserter_gas_limit - the gas limit provided to the asserter call frame.The asserter_address, asserter_data and asserter_gas_limit fields behave similarly to the destination, calldata and gas_limit fields in existing transaction types.
If the asserter_address value is not set, the asserter_data is loaded and executed as asserter_code. This is similar to the init_code parameter logic of a legacy transaction type.
This code is executed in a static context and cannot modify the blockchain state, set contract code or deploy new contracts.
After the transaction execution frame is finished without reverting, the RESTRICTED_EXECUTION_TX_TYPE transactions MUST also successully execute a second execution frame. This frame runs in a static context and cannot modify storage or emit logs.
The purpose of this frame is to execute the state change assertions as prescribed by the asserter_address and asserter_data parameters.
In case of a revert in the Assertion Frame, the entire transaction is reverted.
The gas costs in the Assertion Frame are charged same as in the regular execution.
There are a number of parameters that constitute the core of the transaction's execution restriction. These parameters are joined together and RLP encoded as part of the transaction payload. There are no additional costs associated with providing this parameter other than its gas cost equivalent to calldata.
In case any of the specified restrictions is violated, the entire transaction MUST revert on-chain and its gas MUST be paid until the point of the restriction violation.
The transaction is considered to be a valid transaction that can be included in a block and pays its own gas regardless of the contents of the execution_restrictions parameter.
We introduce a precompile at address GET_TRACE_CALL_ADDRESS.
When called in a regular execution frame, the call returns a full stack trace of the current frame up to this point.
When called in the Assertion Frame, the call returns a full stack trace of the entire transaction.
The format of the returned transaction stack trace is described in Transaction Trace Data Structure.
The stack trace is represented as an ABI encoding of the following struct:
Including all opcodes called during a transaction execution in the stack trace is not practical. Instead, only the following opcodes with potentially dangerous non-local effects are reported as part of the opCodes field:
SELFDESTRUCT (0xFF)DELEGATECALL (0xF4)CALLCODE (0xF2)STATICCALL (0xFA)CALL (0xFA)LOG (0xA0)LOG1 (0xA1)LOG2 (0xA2)LOG3 (0xA3)LOG4 (0xA4)REVERT (0xFD)INVALID (0xFE)KECCAK256 (0x20)One of the main advantages of a new Transaction Type for the Restricted Behaviour feature is the ability to protect all existing EOAs, and not just smart accounts. This makes it preferable to introduce a new Transaction Type instead of any other approach that would only work for smart contract accounts.
It is important for us to provide the same protection level to both EOAs and Smart Accounts. The Smart Accounts are not able to initiate a RESTRICTED_EXECUTION_TX_TYPE transaction themselves, and instead need to rely on checks performed during the regular execution frame of any transaction type.
By exposing the GET_TRACE_CALL_ADDRESS precompile at all times, we allow any smart contract to perform the state change assertions it may need to ensure safety and security.
In some scenarios, the wallets are likely to want to apply the exact same transaction behaviour to all transactions they initiate.
In this case, it is reasonalbe and more efficient to deploy the assertions on-chain as a smart contract module, and provide its address and the inputs it may need.
However, it is possible that the wallet may want to prepare the restrictions for the transaction dynamically. In that case, there is no benefit in having the assertion code permanently deployed, and it is more efficient to provide such code as part of the transaction payload. Luckily, the EVM already has a very similar behaviour defined for the init_code field, and it appears to fit the task perfectly.
This proposal describes a new transaction type that should not affect the functionality of existing systems.
Successfull use of the RESTRICTED_EXECUTION_TX_TYPE transaction type requires the wallets to be abile to correctly understand and present the restrictions imposed on the transaction to the users.
Wallets will need to be able to understand the meaning of the state changes being permitted by the transaction. This requires wallets to be aware of all major ERC standards, such as ERC-20 and ERC-721. In many cases, this also requires the wallets to be able to fetch and analyze the source code of the executed contracts.
However, the introduction of the Execution Restrictions feature significantly streamlines the process by removing the need for a deep understanding of the executed code. Instead, only high-level information about the stack traces' meaning is required for a clear and safe representation of possible transaction outcomes.
The worst outcome of introducing a security feature is creating a false sense of security for its user.
Wallets are expected to provide the behaviour restriction logic that protects their users' valuable assets.
It is critical that dApps, wallets, and users become educated about the consequences of not limiting their transactions' execution with sufficient strictness.
Copyright and related rights waived via CC0.