44;; ██╔╝ ████╔╝██║████╔╝██║██╔═══╝ ██╔══██║╚════██║██║╚██╔╝██║
55;; ██║ ╚██████╔╝╚██████╔╝███████╗ ██║ ██║███████║██║ ╚═╝ ██║
66;; ╚═╝ ╚═════╝ ╚═════╝ ╚══════╝ ╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝
7- ;;
7+ ;;
88;; This is an implementation of EIP-7002's pre-deploy contract. It implements an
99;; unvalidated withdrawal requests queue for beacon chain validators. The queue
1010;; is tracked using head and tail index pointers. After the queue is emptied,
4545
4646.start:
4747 ;; Protect the system subroutine by checking if the caller is the system
48- ;; address.
48+ ;; address.
4949 caller ;; [caller]
5050 push20 SYSTEM_ADDR ;; [sysaddr, caller]
5151 eq ;; [sysaddr == caller]
@@ -177,7 +177,7 @@ check_input:
177177;; with each record being exactly 76 bytes.
178178;;
179179;; Withdrawal request record:
180- ;;
180+ ;;
181181;; +------+--------+--------+
182182;; | addr | pubkey | amount |
183183;; +------+--------+--------+
@@ -240,7 +240,7 @@ accum_loop:
240240 push QUEUE_OFFSET ;; [offset, 3*(i+head_idx), record_offset, i, ..]
241241 add ;; [addr_offset, record_offset, i, ..]
242242
243- ;; Read address.
243+ ;; Read address.
244244 dup1 ;; [addr_offset, addr_offset, record_offset, i, ..]
245245 sload ;; [addr, addr_offset, record_offset, i, ..]
246246
@@ -259,13 +259,13 @@ accum_loop:
259259
260260 ;; Write values to memory flat and contiguously. This require combining the
261261 ;; three storage elements (addr, pk[0:32], pk2_am) so there is no padding.
262- ;;
262+ ;;
263263 ;; Each stack element has the following layout:
264264 ;;
265265 ;; A: addr
266- ;; 0x00 | 00 00 00 00 00 00 00 00 00 00 00 00 aa aa aa aa
266+ ;; 0x00 | 00 00 00 00 00 00 00 00 00 00 00 00 aa aa aa aa
267267 ;; 0x10 | aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa
268- ;;
268+ ;;
269269 ;; B: pk[0:32]
270270 ;; 0x00 | bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb
271271 ;; 0x10 | bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb
@@ -281,9 +281,9 @@ accum_loop:
281281
282282 ;; Shift addr bytes.
283283 swap2 ;; [addr, pk[0:32], pk2_am, record_offset, i, ..]
284- push 12*8 ;; [96, addr, pk0 :32], pk2_am, record_offset, i, ..]
284+ push 12*8 ;; [96, addr, pk[0 :32], pk2_am, record_offset, i, ..]
285285 shl ;; [addr<<96, pk[0:32], pk2_am, record_offset, i, ..]
286-
286+
287287 ;; Store addr at offset = i*RECORD_SIZE.
288288 dup4 ;; [record_offset, addr<<96, pk[0:32], pk2_am, record_offset, i, ..]
289289 mstore ;; [pk[0:32], pk2_am, record_offset, i, ..]
@@ -294,11 +294,26 @@ accum_loop:
294294 add ;; [record_offset+20, pk[0:32], pk2_am, record_offset, i, ..]
295295 mstore ;; [pk2_am, record_offset, i, ..]
296296
297- ;; Store pk2_am at offset = i*RECORD_SIZE + 52.
298- swap1 ;; [record_offset, pk2_am, i, ..]
299- push 52 ;; [52, record_offset, pk2_am, i, ..]
300- add ;; [record_offset+52, pk2_am, i, ..]
301- mstore ;; [i, ..]
297+ ;; Extract pk2 from pk2_am.
298+ dup1 ;; [pk2_am, pk2_am, record_offset, i, ..]
299+ push pk2_mask ;; [mask, pk2_am, pk2_am, record_offset, i, ..]
300+ and ;; [pk2, pk2_am, record_offset, i, ..]
301+
302+ ;; Store pk2 at offset = i*RECORD_SIZE + 52.
303+ dup3 ;; [record_offset, pk2, pk2_am, record_offset, i, ..]
304+ push 52 ;; [52, record_offset, pk2, pk2_am, record_offset, i, ..]
305+ add ;; [record_offset+52, pk2, pk2_am, record_offset, i, ..]
306+ mstore ;; [pk2_am, record_offset, i, ..]
307+
308+ ;; Extract am from pk2_am.
309+ push 8*8 ;; [shft, pk2_am, record_offset, i, ..]
310+ shr ;; [am, record_offset, i, ..]
311+
312+ ;; Store am at offset = i*RECORD_SIZE + 68.
313+ swap1 ;; [record_offset, am, i, ..]
314+ push 68 ;; [68, record_offset, am, i, ..]
315+ add ;; [record_offset+68, am, i, ..]
316+ %mstore_uint64_le() ;; [i, ..]
302317
303318 ;; Increment i.
304319 push 1 ;; [1, i, ..]
@@ -342,7 +357,7 @@ update_excess:
342357 ;; Update the new excess withdrawal requests.
343358 push SLOT_EXCESS ;; [excess_slot, count]
344359 sload ;; [excess, count]
345-
360+
346361 ;; Check if excess needs to be reset to 0 for first iteration after
347362 ;; activation.
348363 dup1 ;; [excess, excess, count, count]
@@ -368,11 +383,11 @@ skip_reset:
368383 add ;; [count+excess, target, count, excess, count]
369384 gt ;; [count+excess > target, count, excess, count]
370385 jumpi @compute_excess ;; [count, excess, count]
371-
386+
372387 ;; Zero out excess.
373388 pop ;; [excess, count]
374389 pop ;; [count]
375- push0
390+ push0
376391 jump @store_excess
377392
378393compute_excess:
@@ -401,3 +416,71 @@ revert:
401416 push0
402417 push0
403418 revert
419+
420+ ;; -----------------------------------------------------------------------------
421+ ;; MACROS ----------------------------------------------------------------------
422+ ;; -----------------------------------------------------------------------------
423+
424+ ;; This defines a mask for accessing the top 16 bytes of a number.
425+ #define pk2_mask 0xffffffffffffffffffffffffffffffff00000000000000000000000000000000
426+
427+ ;; Helper for storing little-endian amount.
428+ #define %mstore_uint64_le() { ;; [offset, value]
429+ dup2 ;; [value, offset, value]
430+ push 7*8 ;; [56, value, offset, value]
431+ shr ;; [value>>56, offset, value]
432+ dup2 ;; [offset, value>>56, offset, value]
433+ push 7 ;; [7, offset, value>>56, offset, value]
434+ add ;; [offset+7, value>>56, offset, value]
435+ mstore8 ;; [offset, value]
436+
437+ dup2 ;; [value, offset, value]
438+ push 6*8 ;; [48, value, offset, value]
439+ shr ;; [value>>48, offset, value]
440+ dup2 ;; [offset, value>>48, offset, value]
441+ push 6 ;; [6, offset, value>>48, offset, value]
442+ add ;; [offset+6, value>>48, offset, value]
443+ mstore8 ;; [offset, value]
444+
445+ dup2 ;; [value, offset, value]
446+ push 5*8 ;; [40, value, offset, value]
447+ shr ;; [value>>40, offset, value]
448+ dup2 ;; [offset, value>>40, offset, value]
449+ push 5 ;; [2, offset, value>>40, offset, value]
450+ add ;; [offset+5, value>>40, offset, value]
451+ mstore8 ;; [offset, value]
452+
453+ dup2 ;; [value, offset, value]
454+ push 4*8 ;; [32, value, offset, value]
455+ shr ;; [value>>32, offset, value]
456+ dup2 ;; [offset, value>>32, offset, value]
457+ push 4 ;; [4, offset, value>>32, offset, value]
458+ add ;; [offset+4, value>>32, offset, value]
459+ mstore8 ;; [offset, value]
460+
461+ dup2 ;; [value, offset, value]
462+ push 3*8 ;; [24, value, offset, value]
463+ shr ;; [value>>24, offset, value]
464+ dup2 ;; [offset, value>>24, offset, value]
465+ push 3 ;; [3, offset, value>>24, offset, value]
466+ add ;; [offset+3, value>>24, offset, value]
467+ mstore8 ;; [offset, value]
468+
469+ dup2 ;; [value, offset, value]
470+ push 2*8 ;; [16, value, offset, value]
471+ shr ;; [value>>16, offset, value]
472+ dup2 ;; [offset, value>>16, offset, value]
473+ push 2 ;; [2, offset, value>>16, offset, value]
474+ add ;; [offset+2, value>>16, offset, value]
475+ mstore8 ;; [offset, value]
476+
477+ dup2 ;; [value, offset, value]
478+ push 1*8 ;; [8, value, offset, value]
479+ shr ;; [value>>8, offset, value]
480+ dup2 ;; [offset, value>>8, offset, value]
481+ push 1 ;; [1, offset, value>>8, offset, value]
482+ add ;; [offset+1, value>>8, offset, value]
483+ mstore8 ;; [offset, value]
484+
485+ mstore8 ;; []
486+ }
0 commit comments