Skip to content

Instantly share code, notes, and snippets.

@0age
Created November 14, 2019 16:05
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save 0age/f5b302703222b52e430fb6699ecc2638 to your computer and use it in GitHub Desktop.
Save 0age/f5b302703222b52e430fb6699ecc2638 to your computer and use it in GitHub Desktop.

Minimal Upgrade Beacon Proxy (runtime code)

  • Get the current implementation contract address from the upgrade beacon via STATICCALL
  • Then, put calldata in memory to supply as argument in DELEGATECALL to implementation
  • Finally, return or revert based on DELEGATECALL status, supplying return buffer in either case
  • 48 bytes long when using an upgrade beacon with a compact address (starts with 5 zero bytes)
0x59595959365960205959596e<upgrade_beacon_last_15_bytes>5afa1551368280375af43d3d93803e602e57fd5bf3

pc  op  name                      [stack] <memory> {return_buffer} *return* ~revert~
--  --  ------------------------  --------------------------------------------------
// put four zeroes + size of calldata + another zero on the stack to use later.
00  59  MSIZE                     [0]
01  59  MSIZE                     [0, 0]
02  59  MSIZE                     [0, 0, 0]
03  59  MSIZE                     [0, 0, 0, 0]
04  36  CALLDATASIZE              [0, 0, 0, 0, cds]
05  59  MSIZE                     [0, 0, 0, 0, cds, 0]

// put size of implementation address returned from upgrade beacon on the stack.
06  60  PUSH1 0x20                [0, 0, 0, 0, cds, 0, 32]

// put three zeroes on the stack: offset in memory for return data, no input data.
08  59  MSIZE                     [0, 0, 0, 0, cds, 0, 32, 0]
09  59  MSIZE                     [0, 0, 0, 0, cds, 0, 32, 0, 0]
10  59  MSIZE                     [0, 0, 0, 0, cds, 0, 32, 0, 0, 0]

// put the address of the compact upgrade beacon onto the stack.
11  6e  PUSH15 <upgrade_beacon>   [0, 0, 0, 0, cds, 0, 32, 0, 0, 0, beacon]

// put current available gas onto the stack - upgrade beacon is unable to waste it.
27  5a  GAS                       [0, 0, 0, 0, cds, 0, 32, 0, 0, 0, beacon, gas]

// perform static call to upgrade beacon and put returned implementation in memory.
28  fa  STATICCALL                [0, 0, 0, 0, cds, 0, 1] <impl>

// flip success status stack item. Note that a call to upgrade beacon above will
// never fail unless gas runs out or the call stack depth is too great, in which
// case the next delegatecall will also fail, so we can infer it will be 1 => 0
29  15  ISZERO                    [0, 0, 0, 0, cds, 0, 0]

// take the implementation from memory and place it onto the stack.
30  51  MLOAD                     [0, 0, 0, 0, cds, 0, impl]

// put size of calldata and two zeroes onto the stack.
31  36  CALLDATASIZE              [0, 0, 0, 0, cds, 0, impl, cds]
32  82  DUP3                      [0, 0, 0, 0, cds, 0, impl, cds, 0]
33  80  DUP1                      [0, 0, 0, 0, cds, 0, impl, cds, 0, 0]

// load all calldata (0 to calldatasize) into memory starting at position 0.
34  37  CALLDATACOPY              [0, 0, 0, 0, cds, 0, impl] <calldata>

// put current available gas onto the stack - 1/64th reserved to handle return.
35  5a  GAS                       [0, 0, 0, 0, cds, 0, impl, gas] <calldata>

// supply calldata, delegatecall to implementation, and put status on the stack.
36  f4  DELEGATECALL              [0, 0, suc] {returndata}

// push and arrange items to the stack for getting data from the return buffer.
37  3d  RETURNDATASIZE            [0, 0, suc, rds]
38  3d  RETURNDATASIZE            [0, 0, suc, rds, rds]
39  93  SWAP4                     [rds, 0, suc, rds, 0]
40  80  DUP1                      [rds, 0, suc, rds, 0, 0]

// copy return buffer to memory so as to support dynamically-sized return data.
41  3e  RETURNDATACOPY            [rds, 0, suc] <returndata>

// put pc to jump to in the event that delegatecall was successful on the stack.
42  60  PUSH1 0x2e                [rds, 0, suc, 46]

// jump to that location if delegatecall was successful, otherwise continue.
44  57  JUMPI                     [rds, 0]

// delegatecall was unsuccessful: revert and pass along returned revert message.
45  fd  REVERT                    [] ~returndata (revert message)~

// jump here if and only if delegatecall was successful.
46  5b  JUMPDEST                  [rds, 0]

// delegatecall was successful: return and pass along returned data.
47  f3  RETURN                    [] *returndata*
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment