104 lines
5.6 KiB
Markdown
104 lines
5.6 KiB
Markdown
---
|
|
eip: 2997
|
|
title: IMPERSONATECALL Opcode
|
|
author: Sergio Demian Lerner (@SergioDemianLerner)
|
|
discussions-to: https://ethresear.ch/t/impersonatecall-opcode/8020
|
|
category: Core
|
|
type: Standards Track
|
|
status: Stagnant
|
|
created: 2020-09-24
|
|
---
|
|
|
|
## 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 a `32` 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 always `20` bytes, and represents the address of the real caller contract.
|
|
- `salt` is always `32` 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 that `SELFDESTRUCT` (`0xff`) cannot be executed directly with `IMPERSONATECALL` 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](../LICENSE.md).
|