EIP-2997: IMPERSONATECALL Opcode
Abstract
Add a new opcode, IMPERSONATECALL
at 0xf6
, which is similar in idea to CALL (0xF1)
, except that it impersonates a sender, i.e. the callee sees a sender different from the real caller. The impersonated sender address is derived from the real caller address and a salt.
Motivation
This proposal enables native multi-user wallets (wallets that serve multiple users) that can be commanded by EIP-712 based messages and therefore enable meta-transactions. Multi-user wallets also enable the aggregation of transfer operations in batches similar to rollups, but maintaining the same address space as normal onchain transactions, so the sender's wallet does not need to be upgraded to support sinding ether or tokens to a user of a multi-user wallet. Additionally, many times a sponsor company wants to deploy non-custodial smart wallets for all its users. The sponsor does not want to pay the deployment cost of each user contract in advance. Counterfactual contract creation enables this, yet it forces the sponsor to create the smart wallet (or a proxy contract to it) when the user wants to transfer ether or tokens out of his/her account for the first time. This proposal avoids this extra cost, which is at least 42000 gas per user.
Specification
IMPERSONATECALL
: 0xf6
, takes 7 operands:
gas
: the amount of gas the code may use in order to execute;to
: the destination address whose code is to be executed;in_offset
: the offset into memory of the input;in_size
: the size of the input in bytes;ret_offset
: the offset into memory of the output;ret_size
: the size of the scratch pad for the output.salt
is a32
bytes value (a stack item).
Computation of impersonated sender
The impersonated sender address is computed as keccak256( 0xff ++ address ++ salt ++ zeros32)[12:]
.
-
0xff
is a single byte, -
address
is always20
bytes, and represents the address of the real caller contract. -
salt
is always32
bytes. -
The field zeros32 corresponds to 32 zero bytes.
This scheme emulates CREATE2
address derivation, but it cannot practically collude with the CREATE2
address space.
Notes
- The opcode behaves exactly as
CALL
in terms of gas consumption. - In the called context
CALLER (0x33)
returns the impersonated address. - If value transfer is non-zero in the call, the value is transferred from the impersonated account, and not from the real caller. This can be used to transfer ether out of an impersonated account.
Rationale
Even if IMPERSONATECALL
requires hashing 3 words, implying an additional cost of 180 gas, we think the benefit of accounting for hashing doesn't not compensate increasing the complexity of the implementation.
We use the zeros32 field to base address derivation in a pre-image of similar size than CREATE2 and reuse the existing address derivation functions. We also avoid worrying about address collisions between EOA derivation (65 bytes pre-image), CREATE derivation (from 23 to 27 bytes pre-image, for a 32bit nonce) and CREATE2 derivation (85 bytes pre-image).
An option is to omit the zeros32 field: the resulting length of the Keccak pre-image for IMPERSONATECALL address is 53 bytes , which does not generate address collision.
While the same functionality could be provided in a pre-compiled contract, we believe using a new opcode is a cleaner solution.
Clarifications
-
This EIP makes address collisions possible, yet practically impossible.
-
If a contract already exists with an impersonated address, the
IMPERSONATECALL
is executed in the same way, and the existing code will not be executed. It should be noted thatSELFDESTRUCT
(0xff
) cannot be executed directly withIMPERSONATECALL
as no opcode is executed in the context of the impersonated account.
Backward Compatibility
The opcode number 0xf6
is currently unused and results in an out-of-gas (OOG) exception. Solidity uses the INVALID (0xfe)
opcode (called ABORT
by EIP-1803) to raise OOG exceptions, so the 0xf6
opcode does not appear in normal Solidity programs. Programmers are already advised not to include this opcode in contracts written in EVM assembly. Therefore is does not pose any backward compatibility risk.
Test Cases
We present 4 examples of impersonated address derivation:
Example 0
- address
0x0000000000000000000000000000000000000000
- salt
0x0000000000000000000000000000000000000000000000000000000000000000
- result:
0xFFC4F52F884A02BCD5716744CD622127366F2EDF
Example 1
- address
0xdeadbeef00000000000000000000000000000000
- salt
0x0000000000000000000000000000000000000000000000000000000000000000
- result:
0x85F15E045E1244AC03289B48448249DC0A34AA30
Example 2
- address
0xdeadbeef00000000000000000000000000000000
- salt
0x000000000000000000000000feed000000000000000000000000000000000000
- result:
0x2DB27D1D6BE32C9ABFA484BA3D591101881D4B9F
Example 3
- address
0x00000000000000000000000000000000deadbeef
- salt
0x00000000000000000000000000000000000000000000000000000000cafebabe
- result:
0x5004E448F43EFE3C7BF32F94B83B843D03901457
Security Considerations
The address derivation scheme prevents address collision with another deployed contract or an externally owned account, as the impersonated sender address is derived from the real caller address and a salt.
Copyright
Copyright and related rights waived via CC0.