Skip to content

cartoonitunes/ef1-foo2-verification

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 

Repository files navigation

EF1 ABI Test (foo() v2) — Bytecode Verification

Contract: 0xdf8eb001f29302ee380c548044dce4a09bd9e48d
Deployed: September 20, 2015 (block 261,486)
Deployer: 0x5eD8Cee6b63b1c6AFce3AD7c92f4fD7E1B8fAd9F (Ethereum Foundation Wallet 1)
Compiler: solc 0.5.17 (Yul strict-assembly)
Runtime size: 77 bytes
Result: ✅ Exact runtime bytecode match

Part of the Awesome Ethereum Proofs project.


Background

This contract was deployed by the Ethereum Foundation's first wallet (0x5eD8Cee6b63b1c6AFce3AD7c92f4fD7E1B8fAd9F) on September 20, 2015 — the same block as the companion foo() contract at 0xe30608b5. Together they appear to be ABI compatibility tests written by Ethereum Foundation developers testing the early Solidity ABI encoding.

The contract exposes a single function foo() (selector 0xc2985578) which returns an address value.

The Key Insight: PUSH21 vs PUSH20

The critical discovery that unlocked this crack: the return value 0x05CBAeB5B771Cf21b59f17Ea9c70915A27041E5409 is a 21-byte value, not a 20-byte address. This forces the compiler to emit a PUSH21 (opcode 0x74) instruction rather than the PUSH20 (0x73) that would be used for a standard 20-byte Ethereum address.

If you try to write mstore(0x40, 0xCBAeB5B771Cf21b59f17Ea9c70915A27041E5409) (20 bytes), the compiler emits PUSH20 and the bytecode doesn't match. The leading 0x05 byte is significant — it's part of the stored value, making the full pushed value 21 bytes.

Source Code

object "Foo" {
  code {
    let size := datasize("runtime")
    datacopy(0, dataoffset("runtime"), size)
    return(0, size)
  }
  object "runtime" {
    code {
      let sel := div(calldataload(0), 0x100000000000000000000000000000000000000000000000000000000)
      if eq(sel, 0xc2985578) {
        mstore(0x40, 0x05CBAeB5B771Cf21b59f17Ea9c70915A27041E5409)
        return(0x40, 0x20)
      }
    }
  }
}

Compilation

Compiled using solc 0.5.17 in Yul strict-assembly mode:

const solc = require('solc');
// solc version: 0.5.17

const source = `...`; // Foo.yul contents

const input = {
  language: 'Yul',
  sources: { 'Foo.yul': { content: source } },
  settings: {
    outputSelection: { '*': { '*': ['evm.bytecode', 'evm.deployedBytecode'] } },
    evmVersion: 'istanbul'
  }
};

const output = JSON.parse(solc.compile(JSON.stringify(input)));
const runtime = output.contracts['Foo.yul']['Foo'].evm.deployedBytecode.object;
// → matches on-chain runtime bytecode exactly

Verification

Run node verify.js to reproduce the compilation and verify the match:

$ node verify.js
On-chain runtime:  6000357c010000000000000000000000000000000000000000000000000000000090048063c29855781461002257005b6060604052740...
Compiled runtime:  6000357c010000000000000000000000000000000000000000000000000000000090048063c29855781461002257005b6060604052740...
✅ MATCH (77 bytes)

On-Chain Data

  • Contract address: 0xdf8eb001f29302ee380c548044dce4a09bd9e48d
  • Block: 261,486
  • Transaction: See Etherscan
  • EthereumHistory: View entry

Related

About

Bytecode verification for EF1 ABI Test foo() v2 (0xdf8eb001) — solc 0.5.17 Yul strict-assembly, Sep 2015

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors