@feelyourprotocol/util 8141.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (223) hide show
  1. package/LICENSE +373 -0
  2. package/README.md +297 -0
  3. package/dist/cjs/account.d.ts +165 -0
  4. package/dist/cjs/account.d.ts.map +1 -0
  5. package/dist/cjs/account.js +530 -0
  6. package/dist/cjs/account.js.map +1 -0
  7. package/dist/cjs/address.d.ts +67 -0
  8. package/dist/cjs/address.d.ts.map +1 -0
  9. package/dist/cjs/address.js +136 -0
  10. package/dist/cjs/address.js.map +1 -0
  11. package/dist/cjs/authorization.d.ts +41 -0
  12. package/dist/cjs/authorization.d.ts.map +1 -0
  13. package/dist/cjs/authorization.js +135 -0
  14. package/dist/cjs/authorization.js.map +1 -0
  15. package/dist/cjs/bal.d.ts +129 -0
  16. package/dist/cjs/bal.d.ts.map +1 -0
  17. package/dist/cjs/bal.js +529 -0
  18. package/dist/cjs/bal.js.map +1 -0
  19. package/dist/cjs/binaryTree.d.ts +148 -0
  20. package/dist/cjs/binaryTree.d.ts.map +1 -0
  21. package/dist/cjs/binaryTree.js +240 -0
  22. package/dist/cjs/binaryTree.js.map +1 -0
  23. package/dist/cjs/blobs.d.ts +76 -0
  24. package/dist/cjs/blobs.d.ts.map +1 -0
  25. package/dist/cjs/blobs.js +175 -0
  26. package/dist/cjs/blobs.js.map +1 -0
  27. package/dist/cjs/bytes.d.ts +291 -0
  28. package/dist/cjs/bytes.d.ts.map +1 -0
  29. package/dist/cjs/bytes.js +606 -0
  30. package/dist/cjs/bytes.js.map +1 -0
  31. package/dist/cjs/constants.d.ts +91 -0
  32. package/dist/cjs/constants.d.ts.map +1 -0
  33. package/dist/cjs/constants.js +97 -0
  34. package/dist/cjs/constants.js.map +1 -0
  35. package/dist/cjs/db.d.ts +65 -0
  36. package/dist/cjs/db.d.ts.map +1 -0
  37. package/dist/cjs/db.js +14 -0
  38. package/dist/cjs/db.js.map +1 -0
  39. package/dist/cjs/env.d.ts +9 -0
  40. package/dist/cjs/env.d.ts.map +1 -0
  41. package/dist/cjs/env.js +13 -0
  42. package/dist/cjs/env.js.map +1 -0
  43. package/dist/cjs/errors.d.ts +3 -0
  44. package/dist/cjs/errors.d.ts.map +1 -0
  45. package/dist/cjs/errors.js +19 -0
  46. package/dist/cjs/errors.js.map +1 -0
  47. package/dist/cjs/helpers.d.ts +21 -0
  48. package/dist/cjs/helpers.d.ts.map +1 -0
  49. package/dist/cjs/helpers.js +50 -0
  50. package/dist/cjs/helpers.js.map +1 -0
  51. package/dist/cjs/index.d.ts +67 -0
  52. package/dist/cjs/index.d.ts.map +1 -0
  53. package/dist/cjs/index.js +93 -0
  54. package/dist/cjs/index.js.map +1 -0
  55. package/dist/cjs/internal.d.ts +72 -0
  56. package/dist/cjs/internal.d.ts.map +1 -0
  57. package/dist/cjs/internal.js +182 -0
  58. package/dist/cjs/internal.js.map +1 -0
  59. package/dist/cjs/kzg.d.ts +14 -0
  60. package/dist/cjs/kzg.d.ts.map +1 -0
  61. package/dist/cjs/kzg.js +3 -0
  62. package/dist/cjs/kzg.js.map +1 -0
  63. package/dist/cjs/lock.d.ts +15 -0
  64. package/dist/cjs/lock.d.ts.map +1 -0
  65. package/dist/cjs/lock.js +45 -0
  66. package/dist/cjs/lock.js.map +1 -0
  67. package/dist/cjs/mapDB.d.ts +17 -0
  68. package/dist/cjs/mapDB.d.ts.map +1 -0
  69. package/dist/cjs/mapDB.js +46 -0
  70. package/dist/cjs/mapDB.js.map +1 -0
  71. package/dist/cjs/package.json +3 -0
  72. package/dist/cjs/provider.d.ts +46 -0
  73. package/dist/cjs/provider.d.ts.map +1 -0
  74. package/dist/cjs/provider.js +84 -0
  75. package/dist/cjs/provider.js.map +1 -0
  76. package/dist/cjs/request.d.ts +20 -0
  77. package/dist/cjs/request.d.ts.map +1 -0
  78. package/dist/cjs/request.js +35 -0
  79. package/dist/cjs/request.js.map +1 -0
  80. package/dist/cjs/signature.d.ts +47 -0
  81. package/dist/cjs/signature.d.ts.map +1 -0
  82. package/dist/cjs/signature.js +147 -0
  83. package/dist/cjs/signature.js.map +1 -0
  84. package/dist/cjs/tasks.d.ts +32 -0
  85. package/dist/cjs/tasks.d.ts.map +1 -0
  86. package/dist/cjs/tasks.js +51 -0
  87. package/dist/cjs/tasks.js.map +1 -0
  88. package/dist/cjs/types.d.ts +64 -0
  89. package/dist/cjs/types.d.ts.map +1 -0
  90. package/dist/cjs/types.js +78 -0
  91. package/dist/cjs/types.js.map +1 -0
  92. package/dist/cjs/units.d.ts +22 -0
  93. package/dist/cjs/units.d.ts.map +1 -0
  94. package/dist/cjs/units.js +51 -0
  95. package/dist/cjs/units.js.map +1 -0
  96. package/dist/cjs/withdrawal.d.ts +72 -0
  97. package/dist/cjs/withdrawal.d.ts.map +1 -0
  98. package/dist/cjs/withdrawal.js +93 -0
  99. package/dist/cjs/withdrawal.js.map +1 -0
  100. package/dist/esm/account.d.ts +165 -0
  101. package/dist/esm/account.d.ts.map +1 -0
  102. package/dist/esm/account.js +505 -0
  103. package/dist/esm/account.js.map +1 -0
  104. package/dist/esm/address.d.ts +67 -0
  105. package/dist/esm/address.d.ts.map +1 -0
  106. package/dist/esm/address.js +125 -0
  107. package/dist/esm/address.js.map +1 -0
  108. package/dist/esm/authorization.d.ts +41 -0
  109. package/dist/esm/authorization.d.ts.map +1 -0
  110. package/dist/esm/authorization.js +126 -0
  111. package/dist/esm/authorization.js.map +1 -0
  112. package/dist/esm/bal.d.ts +129 -0
  113. package/dist/esm/bal.d.ts.map +1 -0
  114. package/dist/esm/bal.js +522 -0
  115. package/dist/esm/bal.js.map +1 -0
  116. package/dist/esm/binaryTree.d.ts +148 -0
  117. package/dist/esm/binaryTree.d.ts.map +1 -0
  118. package/dist/esm/binaryTree.js +226 -0
  119. package/dist/esm/binaryTree.js.map +1 -0
  120. package/dist/esm/blobs.d.ts +76 -0
  121. package/dist/esm/blobs.d.ts.map +1 -0
  122. package/dist/esm/blobs.js +163 -0
  123. package/dist/esm/blobs.js.map +1 -0
  124. package/dist/esm/bytes.d.ts +291 -0
  125. package/dist/esm/bytes.d.ts.map +1 -0
  126. package/dist/esm/bytes.js +562 -0
  127. package/dist/esm/bytes.js.map +1 -0
  128. package/dist/esm/constants.d.ts +91 -0
  129. package/dist/esm/constants.d.ts.map +1 -0
  130. package/dist/esm/constants.js +94 -0
  131. package/dist/esm/constants.js.map +1 -0
  132. package/dist/esm/db.d.ts +65 -0
  133. package/dist/esm/db.d.ts.map +1 -0
  134. package/dist/esm/db.js +11 -0
  135. package/dist/esm/db.js.map +1 -0
  136. package/dist/esm/env.d.ts +9 -0
  137. package/dist/esm/env.d.ts.map +1 -0
  138. package/dist/esm/env.js +9 -0
  139. package/dist/esm/env.js.map +1 -0
  140. package/dist/esm/errors.d.ts +3 -0
  141. package/dist/esm/errors.d.ts.map +1 -0
  142. package/dist/esm/errors.js +14 -0
  143. package/dist/esm/errors.js.map +1 -0
  144. package/dist/esm/helpers.d.ts +21 -0
  145. package/dist/esm/helpers.d.ts.map +1 -0
  146. package/dist/esm/helpers.js +43 -0
  147. package/dist/esm/helpers.js.map +1 -0
  148. package/dist/esm/index.d.ts +67 -0
  149. package/dist/esm/index.d.ts.map +1 -0
  150. package/dist/esm/index.js +67 -0
  151. package/dist/esm/index.js.map +1 -0
  152. package/dist/esm/internal.d.ts +72 -0
  153. package/dist/esm/internal.d.ts.map +1 -0
  154. package/dist/esm/internal.js +170 -0
  155. package/dist/esm/internal.js.map +1 -0
  156. package/dist/esm/kzg.d.ts +14 -0
  157. package/dist/esm/kzg.d.ts.map +1 -0
  158. package/dist/esm/kzg.js +2 -0
  159. package/dist/esm/kzg.js.map +1 -0
  160. package/dist/esm/lock.d.ts +15 -0
  161. package/dist/esm/lock.d.ts.map +1 -0
  162. package/dist/esm/lock.js +41 -0
  163. package/dist/esm/lock.js.map +1 -0
  164. package/dist/esm/mapDB.d.ts +17 -0
  165. package/dist/esm/mapDB.d.ts.map +1 -0
  166. package/dist/esm/mapDB.js +42 -0
  167. package/dist/esm/mapDB.js.map +1 -0
  168. package/dist/esm/package.json +3 -0
  169. package/dist/esm/provider.d.ts +46 -0
  170. package/dist/esm/provider.d.ts.map +1 -0
  171. package/dist/esm/provider.js +79 -0
  172. package/dist/esm/provider.js.map +1 -0
  173. package/dist/esm/request.d.ts +20 -0
  174. package/dist/esm/request.d.ts.map +1 -0
  175. package/dist/esm/request.js +30 -0
  176. package/dist/esm/request.js.map +1 -0
  177. package/dist/esm/signature.d.ts +47 -0
  178. package/dist/esm/signature.d.ts.map +1 -0
  179. package/dist/esm/signature.js +137 -0
  180. package/dist/esm/signature.js.map +1 -0
  181. package/dist/esm/tasks.d.ts +32 -0
  182. package/dist/esm/tasks.d.ts.map +1 -0
  183. package/dist/esm/tasks.js +47 -0
  184. package/dist/esm/tasks.js.map +1 -0
  185. package/dist/esm/types.d.ts +64 -0
  186. package/dist/esm/types.d.ts.map +1 -0
  187. package/dist/esm/types.js +71 -0
  188. package/dist/esm/types.js.map +1 -0
  189. package/dist/esm/units.d.ts +22 -0
  190. package/dist/esm/units.d.ts.map +1 -0
  191. package/dist/esm/units.js +46 -0
  192. package/dist/esm/units.js.map +1 -0
  193. package/dist/esm/withdrawal.d.ts +72 -0
  194. package/dist/esm/withdrawal.d.ts.map +1 -0
  195. package/dist/esm/withdrawal.js +86 -0
  196. package/dist/esm/withdrawal.js.map +1 -0
  197. package/dist/tsconfig.prod.cjs.tsbuildinfo +1 -0
  198. package/dist/tsconfig.prod.esm.tsbuildinfo +1 -0
  199. package/package.json +116 -0
  200. package/src/account.ts +630 -0
  201. package/src/address.ts +158 -0
  202. package/src/authorization.ts +180 -0
  203. package/src/bal.ts +761 -0
  204. package/src/binaryTree.ts +353 -0
  205. package/src/blobs.ts +209 -0
  206. package/src/bytes.ts +659 -0
  207. package/src/constants.ts +125 -0
  208. package/src/db.ts +86 -0
  209. package/src/env.ts +9 -0
  210. package/src/errors.ts +28 -0
  211. package/src/helpers.ts +46 -0
  212. package/src/index.ts +88 -0
  213. package/src/internal.ts +212 -0
  214. package/src/kzg.ts +24 -0
  215. package/src/lock.ts +42 -0
  216. package/src/mapDB.ts +57 -0
  217. package/src/provider.ts +109 -0
  218. package/src/request.ts +48 -0
  219. package/src/signature.ts +202 -0
  220. package/src/tasks.ts +59 -0
  221. package/src/types.ts +177 -0
  222. package/src/units.ts +56 -0
  223. package/src/withdrawal.ts +133 -0
package/src/account.ts ADDED
@@ -0,0 +1,630 @@
1
+ import { RLP } from '@feelyourprotocol/rlp'
2
+ import { secp256k1 } from '@noble/curves/secp256k1.js'
3
+ import { keccak_256 } from '@noble/hashes/sha3.js'
4
+
5
+ import {
6
+ bigIntToUnpaddedBytes,
7
+ bytesToBigInt,
8
+ bytesToHex,
9
+ bytesToInt,
10
+ concatBytes,
11
+ equalsBytes,
12
+ hexToBytes,
13
+ intToUnpaddedBytes,
14
+ toBytes,
15
+ utf8ToBytes,
16
+ } from './bytes.ts'
17
+ import { BIGINT_0, KECCAK256_NULL, KECCAK256_RLP } from './constants.ts'
18
+ import { EthereumJSErrorWithoutCode } from './errors.ts'
19
+ import { assertIsBytes, assertIsHexString, assertIsString } from './helpers.ts'
20
+ import { stripHexPrefix } from './internal.ts'
21
+
22
+ import type { BigIntLike, BytesLike, NestedUint8Array, PrefixedHexString } from './types.ts'
23
+
24
+ export interface AccountData {
25
+ nonce?: BigIntLike
26
+ balance?: BigIntLike
27
+ storageRoot?: BytesLike
28
+ codeHash?: BytesLike
29
+ }
30
+
31
+ export interface PartialAccountData {
32
+ nonce?: BigIntLike | null
33
+ balance?: BigIntLike | null
34
+ storageRoot?: BytesLike | null
35
+ codeHash?: BytesLike | null
36
+ codeSize?: BigIntLike | null
37
+ version?: BigIntLike | null
38
+ }
39
+
40
+ export type AccountBodyBytes = [Uint8Array, Uint8Array, Uint8Array, Uint8Array]
41
+
42
+ /**
43
+ * Handles the null indicator for RLP encoded accounts
44
+ * @returns {null} is the null indicator is 0
45
+ * @returns The unchanged value is the null indicator is 1
46
+ * @throws if the null indicator is > 1
47
+ * @throws if the length of values is < 2
48
+ * @param value The value to convert
49
+ * @returns The converted value
50
+ */
51
+ function handleNullIndicator(values: NestedUint8Array | Uint8Array): Uint8Array | null {
52
+ // Needed if some values are not provided to the array (e.g. partial account RLP)
53
+ if (values[0] === undefined) {
54
+ return null
55
+ }
56
+
57
+ const nullIndicator = bytesToInt(values[0] as Uint8Array)
58
+
59
+ if (nullIndicator === 0) {
60
+ return null
61
+ }
62
+ if (nullIndicator > 1) {
63
+ throw EthereumJSErrorWithoutCode(`Invalid isNullIndicator=${nullIndicator}`)
64
+ }
65
+ if (values.length < 2) {
66
+ throw EthereumJSErrorWithoutCode(`Invalid values length=${values.length}`)
67
+ }
68
+ return values[1] as Uint8Array
69
+ }
70
+
71
+ /**
72
+ * Account class to load and maintain the basic account objects.
73
+ * Supports partial loading and access required for stateless with null
74
+ * as the placeholder.
75
+ *
76
+ * Note: passing undefined in constructor is different from null
77
+ * While undefined leads to default assignment, null is retained
78
+ * to track the information not available/loaded because of partial
79
+ * witness access
80
+ */
81
+ export class Account {
82
+ _nonce: bigint | null = null
83
+ _balance: bigint | null = null
84
+ _storageRoot: Uint8Array | null = null
85
+ _codeHash: Uint8Array | null = null
86
+ // codeSize and version is separately stored in VKT
87
+ _codeSize: number | null = null
88
+ _version: number | null = null
89
+
90
+ get version() {
91
+ if (this._version !== null) {
92
+ return this._version
93
+ } else {
94
+ throw Error(`version=${this._version} not loaded`)
95
+ }
96
+ }
97
+ set version(_version: number) {
98
+ this._version = _version
99
+ }
100
+
101
+ get nonce() {
102
+ if (this._nonce !== null) {
103
+ return this._nonce
104
+ } else {
105
+ throw Error(`nonce=${this._nonce} not loaded`)
106
+ }
107
+ }
108
+ set nonce(_nonce: bigint) {
109
+ this._nonce = _nonce
110
+ }
111
+
112
+ get balance() {
113
+ if (this._balance !== null) {
114
+ return this._balance
115
+ } else {
116
+ throw Error(`balance=${this._balance} not loaded`)
117
+ }
118
+ }
119
+ set balance(_balance: bigint) {
120
+ this._balance = _balance
121
+ }
122
+
123
+ get storageRoot() {
124
+ if (this._storageRoot !== null) {
125
+ return this._storageRoot
126
+ } else {
127
+ throw Error(`storageRoot=${this._storageRoot} not loaded`)
128
+ }
129
+ }
130
+ set storageRoot(_storageRoot: Uint8Array) {
131
+ this._storageRoot = _storageRoot
132
+ }
133
+
134
+ get codeHash() {
135
+ if (this._codeHash !== null) {
136
+ return this._codeHash
137
+ } else {
138
+ throw Error(`codeHash=${this._codeHash} not loaded`)
139
+ }
140
+ }
141
+ set codeHash(_codeHash: Uint8Array) {
142
+ this._codeHash = _codeHash
143
+ }
144
+
145
+ get codeSize() {
146
+ if (this._codeSize !== null) {
147
+ return this._codeSize
148
+ } else {
149
+ throw Error(`codeSize=${this._codeSize} not loaded`)
150
+ }
151
+ }
152
+ set codeSize(_codeSize: number) {
153
+ this._codeSize = _codeSize
154
+ }
155
+
156
+ /**
157
+ * This constructor assigns and validates the values.
158
+ * It is not recommended to use this constructor directly. Instead use the static
159
+ * factory methods to assist in creating an Account from varying data types.
160
+ * undefined get assigned with the defaults, but null args are retained as is
161
+ * @deprecated
162
+ */
163
+ constructor(
164
+ nonce: bigint | null = BIGINT_0,
165
+ balance: bigint | null = BIGINT_0,
166
+ storageRoot: Uint8Array | null = KECCAK256_RLP,
167
+ codeHash: Uint8Array | null = KECCAK256_NULL,
168
+ codeSize: number | null = 0,
169
+ version: number | null = 0,
170
+ ) {
171
+ this._nonce = nonce
172
+ this._balance = balance
173
+ this._storageRoot = storageRoot
174
+ this._codeHash = codeHash
175
+
176
+ if (codeSize === null && codeHash !== null && !this.isContract()) {
177
+ codeSize = 0
178
+ }
179
+ this._codeSize = codeSize
180
+ this._version = version
181
+
182
+ this._validate()
183
+ }
184
+
185
+ private _validate() {
186
+ if (this._nonce !== null && this._nonce < BIGINT_0) {
187
+ throw EthereumJSErrorWithoutCode('nonce must be greater than zero')
188
+ }
189
+ if (this._balance !== null && this._balance < BIGINT_0) {
190
+ throw EthereumJSErrorWithoutCode('balance must be greater than zero')
191
+ }
192
+ if (this._storageRoot !== null && this._storageRoot.length !== 32) {
193
+ throw EthereumJSErrorWithoutCode('storageRoot must have a length of 32')
194
+ }
195
+ if (this._codeHash !== null && this._codeHash.length !== 32) {
196
+ throw EthereumJSErrorWithoutCode('codeHash must have a length of 32')
197
+ }
198
+ if (this._codeSize !== null && this._codeSize < BIGINT_0) {
199
+ throw EthereumJSErrorWithoutCode('codeSize must be greater than zero')
200
+ }
201
+ }
202
+
203
+ /**
204
+ * Returns an array of Uint8Arrays of the raw bytes for the account, in order.
205
+ */
206
+ raw(): Uint8Array[] {
207
+ return [
208
+ bigIntToUnpaddedBytes(this.nonce),
209
+ bigIntToUnpaddedBytes(this.balance),
210
+ this.storageRoot,
211
+ this.codeHash,
212
+ ]
213
+ }
214
+
215
+ /**
216
+ * Returns the RLP serialization of the account as a `Uint8Array`.
217
+ */
218
+ serialize(): Uint8Array {
219
+ return RLP.encode(this.raw())
220
+ }
221
+
222
+ serializeWithPartialInfo(): Uint8Array {
223
+ const partialData = []
224
+ const zeroEncoded = intToUnpaddedBytes(0)
225
+ const oneEncoded = intToUnpaddedBytes(1)
226
+
227
+ if (this._nonce !== null) {
228
+ partialData.push([oneEncoded, bigIntToUnpaddedBytes(this._nonce)])
229
+ } else {
230
+ partialData.push([zeroEncoded])
231
+ }
232
+
233
+ if (this._balance !== null) {
234
+ partialData.push([oneEncoded, bigIntToUnpaddedBytes(this._balance)])
235
+ } else {
236
+ partialData.push([zeroEncoded])
237
+ }
238
+
239
+ if (this._storageRoot !== null) {
240
+ partialData.push([oneEncoded, this._storageRoot])
241
+ } else {
242
+ partialData.push([zeroEncoded])
243
+ }
244
+
245
+ if (this._codeHash !== null) {
246
+ partialData.push([oneEncoded, this._codeHash])
247
+ } else {
248
+ partialData.push([zeroEncoded])
249
+ }
250
+
251
+ if (this._codeSize !== null) {
252
+ partialData.push([oneEncoded, intToUnpaddedBytes(this._codeSize)])
253
+ } else {
254
+ partialData.push([zeroEncoded])
255
+ }
256
+
257
+ if (this._version !== null) {
258
+ partialData.push([oneEncoded, intToUnpaddedBytes(this._version)])
259
+ } else {
260
+ partialData.push([zeroEncoded])
261
+ }
262
+
263
+ return RLP.encode(partialData)
264
+ }
265
+
266
+ /**
267
+ * Returns a `Boolean` determining if the account is a contract.
268
+ */
269
+ isContract(): boolean {
270
+ if (this._codeHash === null && this._codeSize === null) {
271
+ throw Error(`Insufficient data as codeHash=null and codeSize=null`)
272
+ }
273
+ return (
274
+ (this._codeHash !== null && !equalsBytes(this._codeHash, KECCAK256_NULL)) ||
275
+ (this._codeSize !== null && this._codeSize !== 0)
276
+ )
277
+ }
278
+
279
+ /**
280
+ * Returns a `Boolean` determining if the account is empty complying to the definition of
281
+ * account emptiness in [EIP-161](https://eips.ethereum.org/EIPS/eip-161):
282
+ * "An account is considered empty when it has no code and zero nonce and zero balance."
283
+ */
284
+ isEmpty(): boolean {
285
+ // helpful for determination in partial accounts
286
+ if (
287
+ (this._balance !== null && this.balance !== BIGINT_0) ||
288
+ (this._nonce !== null && this.nonce !== BIGINT_0) ||
289
+ (this._codeHash !== null && !equalsBytes(this.codeHash, KECCAK256_NULL))
290
+ ) {
291
+ return false
292
+ }
293
+
294
+ return (
295
+ this.balance === BIGINT_0 &&
296
+ this.nonce === BIGINT_0 &&
297
+ equalsBytes(this.codeHash, KECCAK256_NULL)
298
+ )
299
+ }
300
+ }
301
+
302
+ // Account constructors
303
+
304
+ export function createAccount(accountData: AccountData) {
305
+ const { nonce, balance, storageRoot, codeHash } = accountData
306
+ if (nonce === null || balance === null || storageRoot === null || codeHash === null) {
307
+ throw Error(`Partial fields not supported in fromAccountData`)
308
+ }
309
+
310
+ return new Account(
311
+ nonce !== undefined ? bytesToBigInt(toBytes(nonce)) : undefined,
312
+ balance !== undefined ? bytesToBigInt(toBytes(balance)) : undefined,
313
+ storageRoot !== undefined ? toBytes(storageRoot) : undefined,
314
+ codeHash !== undefined ? toBytes(codeHash) : undefined,
315
+ )
316
+ }
317
+
318
+ export function createAccountFromBytesArray(values: Uint8Array[]) {
319
+ const [nonce, balance, storageRoot, codeHash] = values
320
+
321
+ return new Account(bytesToBigInt(nonce), bytesToBigInt(balance), storageRoot, codeHash)
322
+ }
323
+
324
+ export function createPartialAccount(partialAccountData: PartialAccountData) {
325
+ const { nonce, balance, storageRoot, codeHash, codeSize, version } = partialAccountData
326
+
327
+ if (
328
+ nonce === null &&
329
+ balance === null &&
330
+ storageRoot === null &&
331
+ codeHash === null &&
332
+ codeSize === null &&
333
+ version === null
334
+ ) {
335
+ throw Error(`All partial fields null`)
336
+ }
337
+
338
+ return new Account(
339
+ nonce !== undefined && nonce !== null ? bytesToBigInt(toBytes(nonce)) : nonce,
340
+ balance !== undefined && balance !== null ? bytesToBigInt(toBytes(balance)) : balance,
341
+ storageRoot !== undefined && storageRoot !== null ? toBytes(storageRoot) : storageRoot,
342
+ codeHash !== undefined && codeHash !== null ? toBytes(codeHash) : codeHash,
343
+ codeSize !== undefined && codeSize !== null ? bytesToInt(toBytes(codeSize)) : codeSize,
344
+ version !== undefined && version !== null ? bytesToInt(toBytes(version)) : version,
345
+ )
346
+ }
347
+
348
+ export function createAccountFromRLP(serialized: Uint8Array) {
349
+ const values = RLP.decode(serialized) as Uint8Array[]
350
+
351
+ if (!Array.isArray(values)) {
352
+ throw EthereumJSErrorWithoutCode('Invalid serialized account input. Must be array')
353
+ }
354
+
355
+ return createAccountFromBytesArray(values)
356
+ }
357
+
358
+ export function createPartialAccountFromRLP(serialized: Uint8Array) {
359
+ const values = RLP.decode(serialized)
360
+
361
+ if (!Array.isArray(values)) {
362
+ throw EthereumJSErrorWithoutCode('Invalid serialized account input. Must be array')
363
+ }
364
+
365
+ for (const value of values) {
366
+ // Ensure that each array item is an array
367
+ if (!Array.isArray(value)) {
368
+ throw EthereumJSErrorWithoutCode('Invalid partial encoding. Each item must be an array')
369
+ }
370
+ }
371
+
372
+ const [nonceRaw, balanceRaw, storageRoot, codeHash, codeSizeRaw, versionRaw] =
373
+ values.map(handleNullIndicator)
374
+
375
+ const nonce = nonceRaw === null ? null : bytesToBigInt(nonceRaw)
376
+ const balance = balanceRaw === null ? null : bytesToBigInt(balanceRaw)
377
+ const codeSize = codeSizeRaw === null ? null : bytesToInt(codeSizeRaw)
378
+ const version = versionRaw === null ? null : bytesToInt(versionRaw)
379
+
380
+ return createPartialAccount({ balance, nonce, storageRoot, codeHash, codeSize, version })
381
+ }
382
+
383
+ /**
384
+ * Checks if the address is a valid. Accepts checksummed addresses too.
385
+ */
386
+ export const isValidAddress = function (hexAddress: string): hexAddress is PrefixedHexString {
387
+ try {
388
+ assertIsString(hexAddress)
389
+ } catch {
390
+ return false
391
+ }
392
+
393
+ return /^0x[0-9a-fA-F]{40}$/.test(hexAddress)
394
+ }
395
+
396
+ /**
397
+ * Returns a checksummed address.
398
+ *
399
+ * If an eip1191ChainId is provided, the chainId will be included in the checksum calculation. This
400
+ * has the effect of checksummed addresses for one chain having invalid checksums for others.
401
+ * For more details see [EIP-1191](https://eips.ethereum.org/EIPS/eip-1191).
402
+ *
403
+ * WARNING: Checksums with and without the chainId will differ and the EIP-1191 checksum is not
404
+ * backwards compatible to the original widely adopted checksum format standard introduced in
405
+ * [EIP-55](https://eips.ethereum.org/EIPS/eip-55), so this will break in existing applications.
406
+ * Usage of this EIP is therefore discouraged unless you have a very targeted use case.
407
+ */
408
+ export const toChecksumAddress = function (
409
+ hexAddress: string,
410
+ eip1191ChainId?: BigIntLike,
411
+ ): PrefixedHexString {
412
+ assertIsHexString(hexAddress)
413
+ const address = stripHexPrefix(hexAddress).toLowerCase()
414
+
415
+ let prefix = ''
416
+ if (eip1191ChainId !== undefined) {
417
+ const chainId = bytesToBigInt(toBytes(eip1191ChainId))
418
+ prefix = chainId.toString() + '0x'
419
+ }
420
+
421
+ const bytes = utf8ToBytes(prefix + address)
422
+ const hash = bytesToHex(keccak_256(bytes)).slice(2)
423
+ let ret = ''
424
+
425
+ for (let i = 0; i < address.length; i++) {
426
+ if (parseInt(hash[i], 16) >= 8) {
427
+ ret += address[i].toUpperCase()
428
+ } else {
429
+ ret += address[i]
430
+ }
431
+ }
432
+
433
+ return `0x${ret}`
434
+ }
435
+
436
+ /**
437
+ * Checks if the address is a valid checksummed address.
438
+ *
439
+ * See toChecksumAddress' documentation for details about the eip1191ChainId parameter.
440
+ */
441
+ export const isValidChecksumAddress = function (
442
+ hexAddress: string,
443
+ eip1191ChainId?: BigIntLike,
444
+ ): boolean {
445
+ return isValidAddress(hexAddress) && toChecksumAddress(hexAddress, eip1191ChainId) === hexAddress
446
+ }
447
+
448
+ /**
449
+ * Generates an address of a newly created contract.
450
+ * @param from The address which is creating this new address
451
+ * @param nonce The nonce of the from account
452
+ */
453
+ export const generateAddress = function (from: Uint8Array, nonce: Uint8Array): Uint8Array {
454
+ assertIsBytes(from)
455
+ assertIsBytes(nonce)
456
+
457
+ if (bytesToBigInt(nonce) === BIGINT_0) {
458
+ // in RLP we want to encode null in the case of zero nonce
459
+ // read the RLP documentation for an answer if you dare
460
+ return keccak_256(RLP.encode([from, Uint8Array.from([])])).subarray(-20)
461
+ }
462
+
463
+ // Only take the lower 160bits of the hash
464
+ return keccak_256(RLP.encode([from, nonce])).subarray(-20)
465
+ }
466
+
467
+ /**
468
+ * Generates an address for a contract created using CREATE2.
469
+ * @param from The address which is creating this new address
470
+ * @param salt A salt
471
+ * @param initCode The init code of the contract being created
472
+ */
473
+ export const generateAddress2 = function (
474
+ from: Uint8Array,
475
+ salt: Uint8Array,
476
+ initCode: Uint8Array,
477
+ ): Uint8Array {
478
+ assertIsBytes(from)
479
+ assertIsBytes(salt)
480
+ assertIsBytes(initCode)
481
+
482
+ if (from.length !== 20) {
483
+ throw EthereumJSErrorWithoutCode('Expected from to be of length 20')
484
+ }
485
+ if (salt.length !== 32) {
486
+ throw EthereumJSErrorWithoutCode('Expected salt to be of length 32')
487
+ }
488
+
489
+ const address = keccak_256(concatBytes(hexToBytes('0xff'), from, salt, keccak_256(initCode)))
490
+
491
+ return address.subarray(-20)
492
+ }
493
+
494
+ /**
495
+ * Checks if the private key satisfies the rules of the curve secp256k1.
496
+ */
497
+ export const isValidPrivate = function (privateKey: Uint8Array): boolean {
498
+ return secp256k1.utils.isValidSecretKey(privateKey)
499
+ }
500
+
501
+ /**
502
+ * Checks if the public key satisfies the rules of the curve secp256k1
503
+ * and the requirements of Ethereum.
504
+ * @param publicKey The two points of an uncompressed key, unless sanitize is enabled
505
+ * @param sanitize Accept public keys in other formats
506
+ */
507
+ export const isValidPublic = function (publicKey: Uint8Array, sanitize: boolean = false): boolean {
508
+ assertIsBytes(publicKey)
509
+ if (publicKey.length === 64) {
510
+ // Convert to SEC1 for secp256k1
511
+ // Automatically checks whether point is on curve
512
+ try {
513
+ secp256k1.Point.fromBytes(concatBytes(Uint8Array.from([4]), publicKey))
514
+ return true
515
+ } catch {
516
+ return false
517
+ }
518
+ }
519
+
520
+ if (!sanitize) {
521
+ return false
522
+ }
523
+
524
+ try {
525
+ secp256k1.Point.fromBytes(publicKey)
526
+ return true
527
+ } catch {
528
+ return false
529
+ }
530
+ }
531
+
532
+ /**
533
+ * Returns the ethereum address of a given public key.
534
+ * Accepts "Ethereum public keys" and SEC1 encoded keys.
535
+ * @param pubKey The two points of an uncompressed key, unless sanitize is enabled
536
+ * @param sanitize Accept public keys in other formats
537
+ */
538
+ export const pubToAddress = function (pubKey: Uint8Array, sanitize: boolean = false): Uint8Array {
539
+ assertIsBytes(pubKey)
540
+ if (sanitize && pubKey.length !== 64) {
541
+ pubKey = secp256k1.Point.fromBytes(pubKey).toBytes(false).slice(1)
542
+ }
543
+ if (pubKey.length !== 64) {
544
+ throw EthereumJSErrorWithoutCode('Expected pubKey to be of length 64')
545
+ }
546
+ // Only take the lower 160bits of the hash
547
+ return keccak_256(pubKey).subarray(-20)
548
+ }
549
+ export const publicToAddress = pubToAddress
550
+
551
+ /**
552
+ * Returns the ethereum public key of a given private key.
553
+ * @param privateKey A private key must be 256 bits wide
554
+ */
555
+ export const privateToPublic = function (privateKey: Uint8Array): Uint8Array {
556
+ assertIsBytes(privateKey)
557
+ // skip the type flag and use the X, Y points
558
+ return secp256k1.getPublicKey(privateKey, false).slice(1)
559
+ }
560
+
561
+ /**
562
+ * Returns the ethereum address of a given private key.
563
+ * @param privateKey A private key must be 256 bits wide
564
+ */
565
+ export const privateToAddress = function (privateKey: Uint8Array): Uint8Array {
566
+ return publicToAddress(privateToPublic(privateKey))
567
+ }
568
+
569
+ /**
570
+ * Converts a public key to the Ethereum format.
571
+ */
572
+ export const importPublic = function (publicKey: Uint8Array): Uint8Array {
573
+ assertIsBytes(publicKey)
574
+ if (publicKey.length !== 64) {
575
+ publicKey = secp256k1.Point.fromBytes(publicKey).toBytes(false).slice(1)
576
+ }
577
+ return publicKey
578
+ }
579
+
580
+ /**
581
+ * Returns the zero address.
582
+ */
583
+ export const zeroAddress = function (): PrefixedHexString {
584
+ return bytesToHex(new Uint8Array(20))
585
+ }
586
+
587
+ /**
588
+ * Checks if a given address is the zero address.
589
+ */
590
+ export const isZeroAddress = function (hexAddress: string): boolean {
591
+ try {
592
+ assertIsString(hexAddress)
593
+ } catch {
594
+ return false
595
+ }
596
+
597
+ const zeroAddr = zeroAddress()
598
+ return zeroAddr === hexAddress
599
+ }
600
+
601
+ export function accountBodyFromSlim(body: AccountBodyBytes) {
602
+ const [nonce, balance, storageRoot, codeHash] = body
603
+ return [
604
+ nonce,
605
+ balance,
606
+ storageRoot.length === 0 ? KECCAK256_RLP : storageRoot,
607
+ codeHash.length === 0 ? KECCAK256_NULL : codeHash,
608
+ ]
609
+ }
610
+
611
+ const emptyUint8Arr = new Uint8Array(0)
612
+ export function accountBodyToSlim(body: AccountBodyBytes) {
613
+ const [nonce, balance, storageRoot, codeHash] = body
614
+ return [
615
+ nonce,
616
+ balance,
617
+ equalsBytes(storageRoot, KECCAK256_RLP) ? emptyUint8Arr : storageRoot,
618
+ equalsBytes(codeHash, KECCAK256_NULL) ? emptyUint8Arr : codeHash,
619
+ ]
620
+ }
621
+
622
+ /**
623
+ * Converts a slim account (per snap protocol spec) to the RLP encoded version of the account
624
+ * @param body Array of 4 Uint8Array-like items to represent the account
625
+ * @returns RLP encoded version of the account
626
+ */
627
+ export function accountBodyToRLP(body: AccountBodyBytes, couldBeSlim = true) {
628
+ const accountBody = couldBeSlim ? accountBodyFromSlim(body) : body
629
+ return RLP.encode(accountBody)
630
+ }