@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
@@ -0,0 +1,353 @@
1
+ import {
2
+ bigIntToBytes,
3
+ bytesToBigInt,
4
+ bytesToInt32,
5
+ concatBytes,
6
+ int32ToBytes,
7
+ intToBytes,
8
+ setLengthLeft,
9
+ setLengthRight,
10
+ } from './bytes.ts'
11
+
12
+ import type { Account } from './account.ts'
13
+ import type { Address } from './address.ts'
14
+ import type { PrefixedHexString } from './types.ts'
15
+
16
+ /**
17
+ * @dev Returns the 31-bytes binary tree stem for a given address and tree index.
18
+ * @param hashFunction The hashFunction for the binary tree
19
+ * @param {Address} address The address to generate the tree key for.
20
+ * @param treeIndex The index of the tree to generate the key for. Defaults to 0.
21
+ * @return The 31-bytes binary tree stem as a Uint8Array.
22
+ */
23
+ export function getBinaryTreeStem(
24
+ hashFunction: (value: Uint8Array) => Uint8Array,
25
+ address: Address,
26
+ treeIndex: number | bigint = 0,
27
+ ): Uint8Array {
28
+ const address32 = setLengthLeft(address.toBytes(), 32)
29
+
30
+ let treeIndexBytes: Uint8Array
31
+ if (typeof treeIndex === 'number') {
32
+ treeIndexBytes = setLengthRight(int32ToBytes(Number(treeIndex), true), 32)
33
+ } else {
34
+ treeIndexBytes = setLengthRight(bigIntToBytes(BigInt(treeIndex), true).slice(0, 32), 32)
35
+ }
36
+
37
+ const treeStem = hashFunction(concatBytes(address32, treeIndexBytes)).slice(0, 31)
38
+
39
+ return treeStem
40
+ }
41
+
42
+ export interface BinaryTreeStateDiff {
43
+ stem: PrefixedHexString
44
+ suffixDiffs: {
45
+ currentValue: PrefixedHexString | null
46
+ newValue: PrefixedHexString | null
47
+ suffix: number | string
48
+ }[]
49
+ }
50
+
51
+ // TODO: This is a placeholder type, the actual type is not yet defined
52
+ export type BinaryTreeProof = any
53
+
54
+ /**
55
+ * Experimental, object format could eventual change.
56
+ * An object that provides the state and proof necessary for binary tree stateless execution
57
+ * */
58
+ export interface BinaryTreeExecutionWitness {
59
+ /**
60
+ * The stateRoot of the parent block
61
+ */
62
+ parentStateRoot: PrefixedHexString
63
+ /**
64
+ * An array of state diffs.
65
+ * Each item corresponding to state accesses or state modifications of the block.
66
+ * In the current design, it also contains the resulting state of the block execution (post-state).
67
+ */
68
+ stateDiff: BinaryTreeStateDiff[]
69
+ /**
70
+ * The proof for the block.
71
+ * Proves that the provided stateDiff belongs to the canonical binary tree.
72
+ */
73
+ proof: BinaryTreeProof
74
+ }
75
+
76
+ export type BinaryTreeLeafType = (typeof BinaryTreeLeafType)[keyof typeof BinaryTreeLeafType]
77
+
78
+ export const BinaryTreeLeafType = {
79
+ BasicData: 0,
80
+ CodeHash: 1,
81
+ } as const
82
+
83
+ export type BinaryTreeLeafBasicData = {
84
+ version: number
85
+ nonce: bigint
86
+ balance: bigint
87
+ codeSize: number
88
+ }
89
+
90
+ export const BINARY_TREE_VERSION_OFFSET = 0
91
+ export const BINARY_TREE_CODE_SIZE_OFFSET = 5
92
+ export const BINARY_TREE_NONCE_OFFSET = 8
93
+ export const BINARY_TREE_BALANCE_OFFSET = 16
94
+
95
+ export const BINARY_TREE_VERSION_BYTES_LENGTH = 1
96
+ export const BINARY_TREE_CODE_SIZE_BYTES_LENGTH = 3
97
+ export const BINARY_TREE_NONCE_BYTES_LENGTH = 8
98
+ export const BINARY_TREE_BALANCE_BYTES_LENGTH = 16
99
+
100
+ export const BINARY_TREE_BASIC_DATA_LEAF_KEY = intToBytes(BinaryTreeLeafType.BasicData)
101
+ export const BINARY_TREE_CODE_HASH_LEAF_KEY = intToBytes(BinaryTreeLeafType.CodeHash)
102
+
103
+ export const BINARY_TREE_CODE_CHUNK_SIZE = 31
104
+ export const BINARY_TREE_HEADER_STORAGE_OFFSET = 64
105
+ export const BINARY_TREE_CODE_OFFSET = 128
106
+ export const BINARY_TREE_NODE_WIDTH = 256
107
+ export const BINARY_TREE_MAIN_STORAGE_OFFSET = BigInt(256) ** BigInt(BINARY_TREE_CODE_CHUNK_SIZE)
108
+
109
+ /**
110
+ * @dev Returns the tree key for a given binary tree stem, and sub index.
111
+ * @dev Assumes that the tree node width = 256
112
+ * @param stem The 31-bytes binary tree stem as a Uint8Array.
113
+ * @param subIndex The sub index of the tree to generate the key for as a Uint8Array.
114
+ * @return The tree key as a Uint8Array.
115
+ */
116
+ export const getBinaryTreeKey = (stem: Uint8Array, leaf: BinaryTreeLeafType | Uint8Array) => {
117
+ switch (leaf) {
118
+ case BinaryTreeLeafType.BasicData:
119
+ return concatBytes(stem, BINARY_TREE_BASIC_DATA_LEAF_KEY)
120
+ case BinaryTreeLeafType.CodeHash:
121
+ return concatBytes(stem, BINARY_TREE_CODE_HASH_LEAF_KEY)
122
+ default:
123
+ return concatBytes(stem, leaf)
124
+ }
125
+ }
126
+
127
+ /**
128
+ * Calculates the position of the storage key in the BinaryTree tree, determining
129
+ * both the tree index (the node in the tree) and the subindex (the position within the node).
130
+ * @param {bigint} storageKey - The key representing a specific storage slot.
131
+ * @returns {Object} - An object containing the tree index and subindex
132
+ */
133
+ export function getBinaryTreeIndicesForStorageSlot(storageKey: bigint): {
134
+ treeIndex: bigint
135
+ subIndex: number
136
+ } {
137
+ let position: bigint
138
+ if (storageKey < BINARY_TREE_CODE_OFFSET - BINARY_TREE_HEADER_STORAGE_OFFSET) {
139
+ position = BigInt(BINARY_TREE_HEADER_STORAGE_OFFSET) + storageKey
140
+ } else {
141
+ position = BINARY_TREE_MAIN_STORAGE_OFFSET + storageKey
142
+ }
143
+
144
+ const treeIndex = position / BigInt(BINARY_TREE_NODE_WIDTH)
145
+ const subIndex = Number(position % BigInt(BINARY_TREE_NODE_WIDTH))
146
+
147
+ return { treeIndex, subIndex }
148
+ }
149
+
150
+ /**
151
+ * Calculates the position of the code chunks in the BinaryTree tree, determining
152
+ * both the tree index (the node in the tree) and the subindex (the position within the node).
153
+ * @param {bigint} chunkId - The ID representing a specific chunk.
154
+ * @returns {Object} - An object containing the tree index and subindex
155
+ */
156
+ export function getBinaryTreeIndicesForCodeChunk(chunkId: number) {
157
+ const treeIndex = Math.floor((BINARY_TREE_CODE_OFFSET + chunkId) / BINARY_TREE_NODE_WIDTH)
158
+ const subIndex = (BINARY_TREE_CODE_OFFSET + chunkId) % BINARY_TREE_NODE_WIDTH
159
+ return { treeIndex, subIndex }
160
+ }
161
+
162
+ /**
163
+ * Asynchronously calculates the BinaryTree tree key for the specified code chunk ID.
164
+ * @param {Address} address - The account address to access code for.
165
+ * @param {number} chunkId - The ID of the code chunk to retrieve.
166
+ * @param hashFunction - The hash function used for BinaryTree-related operations.
167
+ * @returns {Uint8Array} - The BinaryTree tree key as a byte array.
168
+ */
169
+ export const getBinaryTreeKeyForCodeChunk = (
170
+ address: Address,
171
+ chunkId: number,
172
+ hashFunction: (input: Uint8Array) => Uint8Array,
173
+ ) => {
174
+ const { treeIndex, subIndex } = getBinaryTreeIndicesForCodeChunk(chunkId)
175
+ return concatBytes(getBinaryTreeStem(hashFunction, address, treeIndex), intToBytes(subIndex))
176
+ }
177
+
178
+ // This code was written by robots based on the reference implementation in EIP-7864
179
+ export const chunkifyBinaryTreeCode = (code: Uint8Array) => {
180
+ const PUSH1 = 0x60 // Assuming PUSH1 is defined as 0x60
181
+ const PUSH32 = 0x7f // Assuming PUSH32 is defined as 0x7f
182
+ const PUSH_OFFSET = 0x5f // Assuming PUSH_OFFSET is defined as 0x5f
183
+
184
+ // Calculate padding length
185
+ const paddingLength = (31 - (code.length % 31)) % 31
186
+ const paddedCode = new Uint8Array(code.length + paddingLength)
187
+ paddedCode.set(code)
188
+
189
+ // Pre-allocate the bytesToExecData array
190
+ const bytesToExecData = new Uint8Array(paddedCode.length + 32)
191
+
192
+ let pos = 0
193
+ while (pos < paddedCode.length) {
194
+ let pushdataBytes = 0
195
+ if (PUSH1 <= paddedCode[pos] && paddedCode[pos] <= PUSH32) {
196
+ pushdataBytes = paddedCode[pos] - PUSH_OFFSET
197
+ }
198
+ pos += 1
199
+ for (let x = 0; x < pushdataBytes; x++) {
200
+ bytesToExecData[pos + x] = pushdataBytes - x
201
+ }
202
+ pos += pushdataBytes
203
+ }
204
+
205
+ // Pre-allocate the chunks array
206
+ const numChunks = Math.ceil(paddedCode.length / 31)
207
+ const chunks = new Array<Uint8Array>(numChunks)
208
+
209
+ for (let i = 0, pos = 0; i < numChunks; i++, pos += 31) {
210
+ const chunk = new Uint8Array(32)
211
+ chunk[0] = Math.min(bytesToExecData[pos], 31)
212
+ chunk.set(paddedCode.subarray(pos, pos + 31), 1)
213
+ chunks[i] = chunk
214
+ }
215
+
216
+ return chunks
217
+ }
218
+
219
+ /**
220
+ * Asynchronously calculates the BinaryTree tree key for the specified storage slot.
221
+ * @param {Address} address - The account address to access code for.
222
+ * @param {bigint} storageKey - The storage slot key to retrieve the key for.
223
+ * @param hashFunction - The hash function used in the Binary Tree.
224
+ * @returns {Uint8Array} - The BinaryTree tree key as a byte array.
225
+ */
226
+ export const getBinaryTreeKeyForStorageSlot = (
227
+ address: Address,
228
+ storageKey: bigint,
229
+ hashFunction: (input: Uint8Array) => Uint8Array,
230
+ ) => {
231
+ const { treeIndex, subIndex } = getBinaryTreeIndicesForStorageSlot(storageKey)
232
+
233
+ return concatBytes(getBinaryTreeStem(hashFunction, address, treeIndex), intToBytes(subIndex))
234
+ }
235
+
236
+ /**
237
+ * This function extracts and decodes account header elements (version, nonce, code size, and balance)
238
+ * from an encoded `Uint8Array` representation of raw BinaryTree leaf-node basic data. Each component is sliced
239
+ * from the `encodedBasicData` array based on predefined offsets and lengths, and then converted
240
+ * to its appropriate type (integer or BigInt).
241
+ * @param {Uint8Array} encodedBasicData - The encoded BinaryTree leaf basic data containing the version, nonce,
242
+ * code size, and balance in a compact Uint8Array format.
243
+ * @returns {BinaryTreeLeafBasicData} - An object containing the decoded version, nonce, code size, and balance.
244
+ */
245
+ export function decodeBinaryTreeLeafBasicData(
246
+ encodedBasicData: Uint8Array,
247
+ ): BinaryTreeLeafBasicData {
248
+ const versionBytes = encodedBasicData.slice(0, BINARY_TREE_VERSION_BYTES_LENGTH)
249
+ const nonceBytes = encodedBasicData.slice(
250
+ BINARY_TREE_NONCE_OFFSET,
251
+ BINARY_TREE_NONCE_OFFSET + BINARY_TREE_NONCE_BYTES_LENGTH,
252
+ )
253
+ const codeSizeBytes = encodedBasicData.slice(
254
+ BINARY_TREE_CODE_SIZE_OFFSET,
255
+ BINARY_TREE_CODE_SIZE_OFFSET + BINARY_TREE_CODE_SIZE_BYTES_LENGTH,
256
+ )
257
+ const balanceBytes = encodedBasicData.slice(
258
+ BINARY_TREE_BALANCE_OFFSET,
259
+ BINARY_TREE_BALANCE_OFFSET + BINARY_TREE_BALANCE_BYTES_LENGTH,
260
+ )
261
+
262
+ const version = bytesToInt32(versionBytes)
263
+ const nonce = bytesToBigInt(nonceBytes)
264
+ const codeSize = bytesToInt32(codeSizeBytes)
265
+ const balance = bytesToBigInt(balanceBytes)
266
+
267
+ return { version, nonce, codeSize, balance }
268
+ }
269
+
270
+ /**
271
+ * This function takes a `BinaryTreeLeafBasicData` object and encodes its properties
272
+ * (version, nonce, code size, and balance) into a compact `Uint8Array` format. Each
273
+ * property is serialized and padded to match the required byte lengths defined by
274
+ * EIP-7864. Additionally, 4 bytes are reserved for future use as specified
275
+ * in EIP-7864.
276
+ * @param {Account} account - An object containing the version, nonce,
277
+ * code size, and balance to be encoded.
278
+ * @returns {Uint8Array} - A compact bytes representation of the account header basic data.
279
+ */
280
+ export function encodeBinaryTreeLeafBasicData(account: Account): Uint8Array {
281
+ const encodedVersion = setLengthLeft(
282
+ intToBytes(account.version),
283
+ BINARY_TREE_VERSION_BYTES_LENGTH,
284
+ )
285
+ // Per EIP-7864, bytes 1-4 are reserved for future use
286
+ const reservedBytes = new Uint8Array([0, 0, 0, 0])
287
+ const encodedNonce = setLengthLeft(bigIntToBytes(account.nonce), BINARY_TREE_NONCE_BYTES_LENGTH)
288
+ const encodedCodeSize = setLengthLeft(
289
+ intToBytes(account.codeSize),
290
+ BINARY_TREE_CODE_SIZE_BYTES_LENGTH,
291
+ )
292
+ const encodedBalance = setLengthLeft(
293
+ bigIntToBytes(account.balance),
294
+ BINARY_TREE_BALANCE_BYTES_LENGTH,
295
+ )
296
+ return concatBytes(encodedVersion, reservedBytes, encodedCodeSize, encodedNonce, encodedBalance)
297
+ }
298
+
299
+ /**
300
+ * Helper method to generate the suffixes for code chunks for putting code
301
+ * @param numChunks number of chunks to generate suffixes for
302
+ * @returns number[] - an array of numbers corresponding to the code chunks being put
303
+ */
304
+ export const generateBinaryTreeChunkSuffixes = (numChunks: number) => {
305
+ if (numChunks === 0) return []
306
+ const chunkSuffixes: number[] = new Array<number>(numChunks)
307
+ let currentSuffix = BINARY_TREE_CODE_OFFSET
308
+ for (let x = 0; x < numChunks; x++) {
309
+ chunkSuffixes[x] = currentSuffix
310
+ currentSuffix++
311
+ // Reset suffix to 0 if exceeds BINARY_TREE_NODE_WIDTH
312
+ if (currentSuffix >= BINARY_TREE_NODE_WIDTH) currentSuffix = 0
313
+ }
314
+
315
+ return chunkSuffixes
316
+ }
317
+
318
+ /**
319
+ * Helper method for generating the code stems necessary for putting code
320
+ * @param numChunks the number of code chunks to be put
321
+ * @param address the address of the account getting the code
322
+ * @param hashFunction an initialized {@link BinaryTreeCrypto} object
323
+ * @returns an array of stems for putting code
324
+ */
325
+ export function generateBinaryTreeCodeStems(
326
+ numChunks: number,
327
+ address: Address,
328
+ hashFunction: (input: Uint8Array) => Uint8Array,
329
+ ): Uint8Array[] {
330
+ // The maximum number of chunks is 793 (maxCodeSize - 24576) / (bytes per chunk 31) + (round up - 1)
331
+ // Code is stored in chunks starting at leaf index 128 of the leaf node corresponding to the stem of the code's address
332
+ // Code chunks beyond the initial 128 are stored in additional leaf nodes in batches up of up to 256 chunks per leaf node
333
+ // so the maximum number of leaf nodes that can hold contract code for a specific address is 4 leaf nodes (128 chunks in
334
+ // the first leaf node and 256 chunks in up to 3 additional leaf nodes)
335
+ // So, instead of computing every single leaf key (which is a heavy operation), we just compute the stem for the first
336
+ // chunk in each leaf node and can then know that the chunks in between have tree keys in monotonically increasing order
337
+ const numStems =
338
+ numChunks > BINARY_TREE_CODE_OFFSET ? Math.ceil(numChunks / BINARY_TREE_NODE_WIDTH) + 1 : 1
339
+ const chunkStems = new Array<Uint8Array>(numStems)
340
+ // Compute the stem for the initial set of code chunks
341
+ chunkStems[0] = getBinaryTreeKeyForCodeChunk(address, 0, hashFunction).slice(0, 31)
342
+
343
+ for (let stemNum = 0; stemNum < numStems - 1; stemNum++) {
344
+ // Generate additional stems
345
+ const firstChunkKey = getBinaryTreeKeyForCodeChunk(
346
+ address,
347
+ BINARY_TREE_CODE_OFFSET + stemNum * BINARY_TREE_NODE_WIDTH,
348
+ hashFunction,
349
+ )
350
+ chunkStems[stemNum + 1] = firstChunkKey.slice(0, 31)
351
+ }
352
+ return chunkStems
353
+ }
package/src/blobs.ts ADDED
@@ -0,0 +1,209 @@
1
+ import { sha256 } from '@noble/hashes/sha2.js'
2
+
3
+ import { bytesToHex, hexToBytes, utf8ToBytes } from './bytes.ts'
4
+
5
+ import type { KZG } from './kzg.ts'
6
+ import type { PrefixedHexString } from './types.ts'
7
+
8
+ /**
9
+ * These utilities for constructing blobs are borrowed from https://github.com/Inphi/eip4844-interop.git
10
+ */
11
+ const BYTES_PER_FIELD_ELEMENT = 32 // EIP-4844
12
+ const FIELD_ELEMENTS_PER_BLOB = 4096 // EIP-4844
13
+ const BLOB_SIZE = BYTES_PER_FIELD_ELEMENT * FIELD_ELEMENTS_PER_BLOB
14
+
15
+ const MAX_BLOBS_PER_TX = 6 // EIP-7691: Blob throughput increase, Pectra HF
16
+ const MAX_BLOB_BYTES_PER_TX = BLOB_SIZE * MAX_BLOBS_PER_TX - 1
17
+
18
+ export const CELLS_PER_EXT_BLOB = 128 // EIP-4844, Consensus Spec, 2 * FIELD_ELEMENTS_PER_BLOB // 64 (FIELD_ELEMENTS_PER_CELL)
19
+
20
+ /**
21
+ * Pads input data to blob boundaries with 0x80 marker and zeros.
22
+ * @param data Input data to pad
23
+ * @param blobs_len Number of blobs the data should span
24
+ * @returns Padded data aligned to blob boundaries
25
+ */
26
+ function getPadded(data: Uint8Array, blobs_len: number): Uint8Array {
27
+ const pData = new Uint8Array(blobs_len * BLOB_SIZE)
28
+ pData.set(data)
29
+ pData[data.byteLength] = 0x80
30
+ return pData
31
+ }
32
+
33
+ /**
34
+ * Converts arbitrary byte data into EIP-4844 blob format.
35
+ * Splits data into 4096 field elements of 32 bytes each, with proper alignment.
36
+ * @param data Input data (must be exactly BLOB_SIZE bytes)
37
+ * @returns Hex-prefixed blob string
38
+ */
39
+ export function getBlob(data: Uint8Array): PrefixedHexString {
40
+ const blob = new Uint8Array(BLOB_SIZE)
41
+ for (let i = 0; i < FIELD_ELEMENTS_PER_BLOB; i++) {
42
+ const chunk = new Uint8Array(32)
43
+ chunk.set(data.subarray(i * 31, (i + 1) * 31), 0)
44
+ blob.set(chunk, i * 32)
45
+ }
46
+
47
+ return bytesToHex(blob)
48
+ }
49
+
50
+ /**
51
+ * EIP-4844: Converts UTF-8 string(s) into EIP-4844 blob format.
52
+ *
53
+ * Each input string is converted to UTF-8 bytes, padded with 0x80 followed by zeros
54
+ * to align with blob boundaries, and encoded as one or more blobs depending on size.
55
+ * Multiple inputs are processed sequentially, with each input contributing its own blob(s).
56
+ *
57
+ * @param input Single UTF-8 string or array of UTF-8 strings to encode
58
+ * @throws Error with message 'invalid blob data' if any input string is empty
59
+ * @throws Error with message 'blob data is too large' if any single input exceeds MAX_USEFUL_BYTES_PER_TX
60
+ * @returns Array of hex-prefixed blob strings (0x...), one blob per 131,071 useful bytes per input
61
+ */
62
+ export const getBlobs = (input: string | string[]) => {
63
+ const inputArray = Array.isArray(input) ? input : [input]
64
+ const blobs: PrefixedHexString[] = []
65
+
66
+ for (const input of inputArray) {
67
+ const data = utf8ToBytes(input)
68
+ const len = data.byteLength
69
+ if (len === 0) {
70
+ throw Error('invalid blob data (0 bytes)')
71
+ }
72
+ if (len > MAX_BLOB_BYTES_PER_TX) {
73
+ throw Error(`blob data is too large (${len} bytes > ${MAX_BLOB_BYTES_PER_TX} bytes)`)
74
+ }
75
+
76
+ const blobs_len = Math.ceil(len / BLOB_SIZE)
77
+
78
+ const pData = getPadded(data, blobs_len)
79
+
80
+ for (let i = 0; i < blobs_len; i++) {
81
+ const chunk = pData.subarray(i * BLOB_SIZE, (i + 1) * BLOB_SIZE)
82
+ const blob = getBlob(chunk)
83
+ blobs.push(blob)
84
+ }
85
+ }
86
+
87
+ return blobs
88
+ }
89
+
90
+ /**
91
+ * EIP-4844: Computes KZG commitments for a set of blobs.
92
+ * @param kzg KZG implementation used to compute commitments
93
+ * @param blobs Array of blob data as hex-prefixed strings
94
+ * @returns Array of lowercase hex-prefixed KZG commitments (one per blob)
95
+ */
96
+ export const blobsToCommitments = (kzg: KZG, blobs: PrefixedHexString[]) => {
97
+ const commitments: PrefixedHexString[] = []
98
+ for (const blob of blobs) {
99
+ commitments.push(kzg.blobToKzgCommitment(blob).toLowerCase() as PrefixedHexString)
100
+ }
101
+ return commitments
102
+ }
103
+
104
+ /**
105
+ * EIP-4844: Computes KZG proofs for each blob/commitment pair.
106
+ * @param kzg KZG implementation used to compute proofs
107
+ * @param blobs Array of blob data as hex-prefixed strings
108
+ * @param commitments Array of corresponding blob commitments
109
+ * @returns Array of lowercase hex-prefixed proofs (aligned with input order)
110
+ */
111
+ export const blobsToProofs = (
112
+ kzg: KZG,
113
+ blobs: PrefixedHexString[],
114
+ commitments: PrefixedHexString[],
115
+ ) => {
116
+ const proofs = blobs.map((blob, ctx) =>
117
+ kzg.computeBlobProof(blob, commitments[ctx]).toLowerCase(),
118
+ ) as PrefixedHexString[]
119
+
120
+ return proofs
121
+ }
122
+
123
+ /**
124
+ * EIP-4844: Converts a vector commitment for a given data blob to its versioned hash. For 4844, this version
125
+ * number will be 0x01 for KZG vector commitments but could be different if future vector commitment
126
+ * types are introduced
127
+ * @param commitment a vector commitment to a blob
128
+ * @param blobCommitmentVersion the version number corresponding to the type of vector commitment
129
+ * @returns a versioned hash corresponding to a given blob vector commitment
130
+ */
131
+ export const computeVersionedHash = (
132
+ commitment: PrefixedHexString,
133
+ blobCommitmentVersion: number,
134
+ ) => {
135
+ const computedVersionedHash = new Uint8Array(32)
136
+ computedVersionedHash.set([blobCommitmentVersion], 0)
137
+ computedVersionedHash.set(sha256(hexToBytes(commitment)).subarray(1), 1)
138
+ return bytesToHex(computedVersionedHash)
139
+ }
140
+
141
+ /**
142
+ * EIP-4844: Generate an array of versioned hashes from corresponding kzg commitments
143
+ * @param commitments array of kzg commitments
144
+ * @returns array of versioned hashes
145
+ * Note: assumes KZG commitments (version 1 version hashes)
146
+ */
147
+ export const commitmentsToVersionedHashes = (commitments: PrefixedHexString[]) => {
148
+ const hashes: PrefixedHexString[] = []
149
+ for (const commitment of commitments) {
150
+ hashes.push(computeVersionedHash(commitment, 0x01))
151
+ }
152
+ return hashes
153
+ }
154
+
155
+ /**
156
+ * EIP-7594: Expands blobs into their extended cells using the provided KZG implementation.
157
+ * @param kzg KZG implementation capable of computing cells
158
+ * @param blobs Array of blob data as hex-prefixed strings
159
+ * @returns Tuple of [cells, indices], where cells are hex strings and indices are 0..127
160
+ */
161
+ export const blobsToCells = (
162
+ kzg: KZG,
163
+ blobs: PrefixedHexString[],
164
+ ): [PrefixedHexString[], number[]] => {
165
+ const cells = blobs.reduce((acc, elem) => {
166
+ return [...acc, ...(kzg.computeCells(elem) as PrefixedHexString[])]
167
+ }, [] as PrefixedHexString[])
168
+ const indices = Array.from({ length: CELLS_PER_EXT_BLOB }, (_, i) => i)
169
+
170
+ return [cells, indices]
171
+ }
172
+
173
+ /**
174
+ * EIP-7594: Computes extended cells and corresponding proofs for the given blobs.
175
+ * @param kzg KZG implementation capable of computing cells and proofs
176
+ * @param blobs Array of blob data as hex-prefixed strings
177
+ * @returns Tuple of [cells, proofs, indices]; indices are 0..127
178
+ */
179
+ export const blobsToCellsAndProofs = (
180
+ kzg: KZG,
181
+ blobs: PrefixedHexString[],
182
+ ): [PrefixedHexString[], PrefixedHexString[], number[]] => {
183
+ const blobsAndCells = blobs.reduce(
184
+ ([cellsAcc, proofsAcc], elem) => {
185
+ const blobCellsAndProofs = kzg.computeCellsAndProofs(elem) as [
186
+ PrefixedHexString[],
187
+ PrefixedHexString[],
188
+ ]
189
+ return [
190
+ [...cellsAcc, ...blobCellsAndProofs[0]],
191
+ [...proofsAcc, ...blobCellsAndProofs[1]],
192
+ ]
193
+ },
194
+ [[] as PrefixedHexString[], [] as PrefixedHexString[]],
195
+ )
196
+
197
+ const indices = Array.from({ length: CELLS_PER_EXT_BLOB }, (_, i) => i)
198
+ return [...blobsAndCells, indices] as [PrefixedHexString[], PrefixedHexString[], number[]]
199
+ }
200
+
201
+ /**
202
+ * EIP-7594: Computes cell proofs for the given blobs.
203
+ * @param kzg KZG implementation capable of computing cell proofs
204
+ * @param blobs Array of blob data as hex-prefixed strings
205
+ * @returns Array of lowercase hex-prefixed cell proofs (aligned with input order)
206
+ */
207
+ export const blobsToCellProofs = (kzg: KZG, blobs: PrefixedHexString[]): PrefixedHexString[] => {
208
+ return blobsToCellsAndProofs(kzg, blobs)[1] as PrefixedHexString[]
209
+ }