4
4
;; ██╔╝ ████╔╝██║████╔╝██║██╔═══╝ ██╔══██║╚════██║██║╚██╔╝██║
5
5
;; ██║ ╚██████╔╝╚██████╔╝███████╗ ██║ ██║███████║██║ ╚═╝ ██║
6
6
;; ╚═╝ ╚═════╝ ╚═════╝ ╚══════╝ ╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝
7
- ;;
7
+ ;;
8
8
;; This is an implementation of EIP-7002's pre-deploy contract. It implements an
9
9
;; unvalidated withdrawal requests queue for beacon chain validators. The queue
10
10
;; is tracked using head and tail index pointers. After the queue is emptied,
45
45
46
46
.start:
47
47
;; Protect the system subroutine by checking if the caller is the system
48
- ;; address.
48
+ ;; address.
49
49
caller ;; [caller]
50
50
push20 SYSTEM_ADDR ;; [sysaddr, caller]
51
51
eq ;; [sysaddr == caller]
@@ -177,7 +177,7 @@ check_input:
177
177
;; with each record being exactly 76 bytes.
178
178
;;
179
179
;; Withdrawal request record:
180
- ;;
180
+ ;;
181
181
;; +------+--------+--------+
182
182
;; | addr | pubkey | amount |
183
183
;; +------+--------+--------+
@@ -240,7 +240,7 @@ accum_loop:
240
240
push QUEUE_OFFSET ;; [offset, 3*(i+head_idx), record_offset, i, ..]
241
241
add ;; [addr_offset, record_offset, i, ..]
242
242
243
- ;; Read address.
243
+ ;; Read address.
244
244
dup1 ;; [addr_offset, addr_offset, record_offset, i, ..]
245
245
sload ;; [addr, addr_offset, record_offset, i, ..]
246
246
@@ -259,13 +259,13 @@ accum_loop:
259
259
260
260
;; Write values to memory flat and contiguously. This require combining the
261
261
;; three storage elements (addr, pk[0:32], pk2_am) so there is no padding.
262
- ;;
262
+ ;;
263
263
;; Each stack element has the following layout:
264
264
;;
265
265
;; 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
267
267
;; 0x10 | aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa
268
- ;;
268
+ ;;
269
269
;; B: pk[0:32]
270
270
;; 0x00 | bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb
271
271
;; 0x10 | bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb bb
@@ -281,9 +281,9 @@ accum_loop:
281
281
282
282
;; Shift addr bytes.
283
283
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, ..]
285
285
shl ;; [addr<<96, pk[0:32], pk2_am, record_offset, i, ..]
286
-
286
+
287
287
;; Store addr at offset = i*RECORD_SIZE.
288
288
dup4 ;; [record_offset, addr<<96, pk[0:32], pk2_am, record_offset, i, ..]
289
289
mstore ;; [pk[0:32], pk2_am, record_offset, i, ..]
@@ -294,11 +294,26 @@ accum_loop:
294
294
add ;; [record_offset+20, pk[0:32], pk2_am, record_offset, i, ..]
295
295
mstore ;; [pk2_am, record_offset, i, ..]
296
296
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, ..]
302
317
303
318
;; Increment i.
304
319
push 1 ;; [1, i, ..]
@@ -342,7 +357,7 @@ update_excess:
342
357
;; Update the new excess withdrawal requests.
343
358
push SLOT_EXCESS ;; [excess_slot, count]
344
359
sload ;; [excess, count]
345
-
360
+
346
361
;; Check if excess needs to be reset to 0 for first iteration after
347
362
;; activation.
348
363
dup1 ;; [excess, excess, count, count]
@@ -368,11 +383,11 @@ skip_reset:
368
383
add ;; [count+excess, target, count, excess, count]
369
384
gt ;; [count+excess > target, count, excess, count]
370
385
jumpi @compute_excess ;; [count, excess, count]
371
-
386
+
372
387
;; Zero out excess.
373
388
pop ;; [excess, count]
374
389
pop ;; [count]
375
- push0
390
+ push0
376
391
jump @store_excess
377
392
378
393
compute_excess:
@@ -401,3 +416,71 @@ revert:
401
416
push0
402
417
push0
403
418
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