EIP2997 - 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 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 and related rights waived via CC0 (opens new window).

▲ Powered by Vercel