@@ -13,85 +13,112 @@ import { IDepositContract } from "../interfaces/IDepositContract.sol";
13
13
* @dev Provides functionality to process multiple validator deposits to the Beacon Chain deposit contract
14
14
*/
15
15
library DepositLogistics {
16
- uint256 internal constant SIGNATURE_LENGTH = 96 ;
17
- uint256 internal constant PUBLIC_KEY_LENGTH = 48 ;
18
- uint256 internal constant SIZE_LENGTH = 8 ;
16
+ /**
17
+ * @notice Byte length of the BLS12-381 public key (a.k.a. validator public key)
18
+ */
19
+ uint256 internal constant PUBKEY_LENGTH = 48 ;
20
+
21
+ /**
22
+ * @notice Byte length of the BLS12-381 signature of the deposit message
23
+ */
24
+ uint256 internal constant SIG_LENGTH = 96 ;
25
+
26
+ /**
27
+ * @notice Byte length of the deposit amount (value) in gwei
28
+ */
29
+ uint256 internal constant AMOUNT_LENGTH = 8 ;
30
+
31
+ /**
32
+ * @notice Error thrown when the number of deposits is zero
33
+ */
34
+ error ZeroDeposits ();
19
35
20
- error ZeroKeyCount ();
36
+ /**
37
+ * @notice Error thrown when the length of the pubkeys array does not match the expected length
38
+ */
21
39
error PubkeysLengthMismatch (uint256 actual , uint256 expected );
22
- error SignaturesLengthMismatch (uint256 actual , uint256 expected );
23
- error SizesLengthMismatch (uint256 actual , uint256 expected );
40
+
41
+ /**
42
+ * @notice Error thrown when the length of the signatures array does not match the expected length
43
+ */
44
+ error SigsLengthMismatch (uint256 actual , uint256 expected );
45
+
46
+ /**
47
+ * @notice Error thrown when the length of the concatenated amounts does not match the expected length
48
+ */
49
+ error AmountsLengthMismatch (uint256 actual , uint256 expected );
24
50
25
51
/**
26
52
* @notice Processes multiple validator deposits to the Beacon Chain deposit contract
27
53
* @param _depositContract The deposit contract interface
28
- * @param _keyCount Number of validator keys to process
54
+ * @param _deposits Number of validator keys to process
29
55
* @param _creds Withdrawal credentials for the validators
30
56
* @param _pubkeys Concatenated validator public keys
31
57
* @param _sigs Concatenated validator signatures
32
- * @param _sizes Array of deposit sizes in gwei
33
- * @dev Each validator requires a 48-byte public key, 96-byte signature, and 8-byte deposit size
58
+ * @param _amounts Concatenated deposit amounts in gwei in byte format
34
59
*/
35
60
function processDeposits (
36
61
IDepositContract _depositContract ,
37
- uint256 _keyCount ,
62
+ uint256 _deposits ,
38
63
bytes memory _creds ,
39
64
bytes memory _pubkeys ,
40
65
bytes memory _sigs ,
41
- bytes memory _sizes
66
+ bytes memory _amounts
42
67
) internal {
43
- if (_keyCount == 0 ) revert ZeroKeyCount ();
44
- if (_pubkeys.length != PUBLIC_KEY_LENGTH * _keyCount) revert PubkeysLengthMismatch (_pubkeys.length , PUBLIC_KEY_LENGTH * _keyCount);
45
- if (_sigs.length != SIGNATURE_LENGTH * _keyCount) revert SignaturesLengthMismatch (_sigs.length , SIGNATURE_LENGTH * _keyCount);
46
- if (_sizes.length != SIZE_LENGTH * _keyCount) revert SizesLengthMismatch (_sizes.length , SIZE_LENGTH * _keyCount);
47
-
48
- bytes memory pubkey = Memory.alloc (PUBLIC_KEY_LENGTH);
49
- bytes memory signature = Memory.alloc (SIGNATURE_LENGTH);
50
- bytes memory size = Memory.alloc (SIZE_LENGTH);
51
-
52
- for (uint256 i; i < _keyCount; i++ ) {
53
- Memory.copy (_pubkeys, pubkey, i * PUBLIC_KEY_LENGTH, 0 , PUBLIC_KEY_LENGTH);
54
- Memory.copy (_sigs, signature, i * SIGNATURE_LENGTH, 0 , SIGNATURE_LENGTH);
55
- Memory.copy (_sizes, size, i * SIZE_LENGTH, 0 , SIZE_LENGTH);
56
-
57
- uint256 sizeInWei = uint256 (uint64 (bytes8 (size))) * 1 gwei ;
58
- bytes32 root = _computeRoot (_creds, pubkey, signature, size);
59
-
60
- _depositContract.deposit {value: sizeInWei}(pubkey, _creds, signature, root);
68
+ if (_deposits == 0 ) revert ZeroDeposits ();
69
+ if (_pubkeys.length != PUBKEY_LENGTH * _deposits) revert PubkeysLengthMismatch (_pubkeys.length , PUBKEY_LENGTH * _deposits);
70
+ if (_sigs.length != SIG_LENGTH * _deposits) revert SigsLengthMismatch (_sigs.length , SIG_LENGTH * _deposits);
71
+ if (_amounts.length != AMOUNT_LENGTH * _deposits) revert AmountsLengthMismatch (_amounts.length , AMOUNT_LENGTH * _deposits);
72
+
73
+ // Allocate memory for pubkey, sig, and amount to be reused for each deposit
74
+ bytes memory pubkey = Memory.alloc (PUBKEY_LENGTH);
75
+ bytes memory sig = Memory.alloc (SIG_LENGTH);
76
+ bytes memory amount = Memory.alloc (AMOUNT_LENGTH);
77
+
78
+ for (uint256 i; i < _deposits; i++ ) {
79
+ // Copy pubkey, sig, and amount to the allocated memory slots
80
+ Memory.copy (_pubkeys, pubkey, i * PUBKEY_LENGTH, 0 , PUBKEY_LENGTH);
81
+ Memory.copy (_sigs, sig, i * SIG_LENGTH, 0 , SIG_LENGTH);
82
+ Memory.copy (_amounts, amount, i * AMOUNT_LENGTH, 0 , AMOUNT_LENGTH);
83
+
84
+ uint256 amountInWei = _gweiBytesToWei (amount);
85
+ bytes32 root = _computeRoot (_creds, pubkey, sig, amount);
86
+
87
+ _depositContract.deposit {value: amountInWei}(pubkey, _creds, sig, root);
61
88
}
62
89
}
63
90
64
91
/**
65
92
* @notice Computes the deposit data root hash
66
93
* @param _creds Withdrawal credentials
67
94
* @param _pubkey BLS12-381 public key
68
- * @param _signature BLS12-381 signature
69
- * @param _size Deposit size in gwei
95
+ * @param _sig BLS12-381 signature
96
+ * @param _amount Deposit amount in gwei
70
97
* @return bytes32 The computed deposit data root hash
71
98
* @dev Implements the deposit data root calculation as specified in the Beacon Chain deposit contract
72
99
*/
73
100
function _computeRoot (
74
101
bytes memory _creds ,
75
102
bytes memory _pubkey ,
76
- bytes memory _signature ,
77
- bytes memory _size
103
+ bytes memory _sig ,
104
+ bytes memory _amount
78
105
) internal pure returns (bytes32 ) {
79
106
bytes32 pubkeyRoot = keccak256 (abi.encodePacked (_pubkey, bytes16 (0 )));
80
107
81
108
bytes32 sigRoot = keccak256 (
82
109
abi.encodePacked (
83
- keccak256 (abi.encodePacked (Memory.slice (_signature , 0 , 64 ))),
84
- keccak256 (abi.encodePacked (Memory.slice (_signature , 64 , SIGNATURE_LENGTH - 64 ), bytes32 (0 )))
110
+ keccak256 (abi.encodePacked (Memory.slice (_sig , 0 , 64 ))),
111
+ keccak256 (abi.encodePacked (Memory.slice (_sig , 64 , SIG_LENGTH - 64 ), bytes32 (0 )))
85
112
)
86
113
);
87
114
88
- bytes memory sizeInGweiLE64 = _toLittleEndian (_size );
115
+ bytes memory amountInGweiLE64 = _toLittleEndian (_amount );
89
116
90
117
return
91
118
keccak256 (
92
119
abi.encodePacked (
93
120
keccak256 (abi.encodePacked (pubkeyRoot, _creds)),
94
- keccak256 (abi.encodePacked (sizeInGweiLE64 , bytes24 (0 ), sigRoot))
121
+ keccak256 (abi.encodePacked (amountInGweiLE64 , bytes24 (0 ), sigRoot))
95
122
)
96
123
);
97
124
}
@@ -109,5 +136,14 @@ library DepositLogistics {
109
136
result[i] = _value[_value.length - i - 1 ];
110
137
}
111
138
}
139
+
140
+ /**
141
+ * @notice Converts a gwei value in bytes to a uint256 wei value
142
+ * @param _value The gwei value in bytes
143
+ * @return result The converted uint256 wei value
144
+ */
145
+ function _gweiBytesToWei (bytes memory _value ) internal pure returns (uint256 ) {
146
+ return uint256 (uint64 (bytes8 (_value))) * 1 gwei ;
147
+ }
112
148
}
113
149
0 commit comments