voltaire-effect 0.2.23 → 0.2.24

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 (264) hide show
  1. package/dist/KZGService-B7PJerOb.d.ts +146 -0
  2. package/dist/{X25519Test-DGsk1V9o.d.ts → X25519Test-C8Cicdd_.d.ts} +2 -139
  3. package/dist/crypto/index.d.ts +3 -2
  4. package/dist/{index-IgkEHjBe.d.ts → index-DsFjN_a3.d.ts} +17633 -11961
  5. package/dist/index.d.ts +3104 -938
  6. package/dist/index.js +4467 -2446
  7. package/dist/native/index.d.ts +14 -5
  8. package/dist/native/index.js +4489 -2468
  9. package/dist/primitives/index.d.ts +12 -4
  10. package/dist/primitives/index.js +3980 -2411
  11. package/package.json +2 -2
  12. package/src/crypto/Keccak256/index.ts +1 -0
  13. package/src/index.ts +2 -2
  14. package/src/primitives/Abi/decode.test.ts +38 -0
  15. package/src/primitives/Abi/decode.ts +67 -0
  16. package/src/primitives/Abi/decodeData.test.ts +37 -0
  17. package/src/primitives/Abi/decodeData.ts +77 -0
  18. package/src/primitives/Abi/decodeLog.test.ts +32 -0
  19. package/src/primitives/Abi/decodeLog.ts +81 -0
  20. package/src/primitives/Abi/decodeWrappedError.test.ts +41 -0
  21. package/src/primitives/Abi/decodeWrappedError.ts +68 -0
  22. package/src/primitives/Abi/encode.test.ts +43 -0
  23. package/src/primitives/Abi/encode.ts +67 -0
  24. package/src/primitives/Abi/encodePacked.test.ts +35 -0
  25. package/src/primitives/Abi/encodePacked.ts +62 -0
  26. package/src/primitives/Abi/encodeWrappedError.test.ts +21 -0
  27. package/src/primitives/Abi/encodeWrappedError.ts +64 -0
  28. package/src/primitives/Abi/findSelectorCollisions.test.ts +50 -0
  29. package/src/primitives/Abi/findSelectorCollisions.ts +83 -0
  30. package/src/primitives/Abi/index.ts +33 -7
  31. package/src/primitives/Abi/parseLogs.test.ts +37 -0
  32. package/src/primitives/Abi/parseLogs.ts +62 -0
  33. package/src/primitives/AccessList/AccessList.test.ts +229 -0
  34. package/src/primitives/AccessList/AccessListTypeSchema.ts +16 -0
  35. package/src/primitives/AccessList/addressCount.ts +21 -0
  36. package/src/primitives/AccessList/assertValid.ts +37 -0
  37. package/src/primitives/AccessList/create.ts +19 -0
  38. package/src/primitives/AccessList/deduplicate.ts +23 -0
  39. package/src/primitives/AccessList/from.ts +39 -0
  40. package/src/primitives/AccessList/fromBytes.ts +36 -0
  41. package/src/primitives/AccessList/gasCost.ts +22 -0
  42. package/src/primitives/AccessList/gasSavings.ts +26 -0
  43. package/src/primitives/AccessList/hasSavings.ts +23 -0
  44. package/src/primitives/AccessList/includesAddress.ts +25 -0
  45. package/src/primitives/AccessList/includesStorageKey.ts +28 -0
  46. package/src/primitives/AccessList/index.ts +99 -19
  47. package/src/primitives/AccessList/is.ts +23 -0
  48. package/src/primitives/AccessList/isEmpty.ts +23 -0
  49. package/src/primitives/AccessList/isItem.ts +22 -0
  50. package/src/primitives/AccessList/keysFor.ts +29 -0
  51. package/src/primitives/AccessList/merge.ts +24 -0
  52. package/src/primitives/AccessList/storageKeyCount.ts +21 -0
  53. package/src/primitives/AccessList/toBytes.ts +23 -0
  54. package/src/primitives/AccessList/withAddress.ts +27 -0
  55. package/src/primitives/AccessList/withStorageKey.ts +30 -0
  56. package/src/primitives/Address/Address.test.ts +146 -0
  57. package/src/primitives/Address/assert.ts +51 -0
  58. package/src/primitives/Address/calculateCreate2Address.ts +33 -0
  59. package/src/primitives/Address/calculateCreateAddress.ts +30 -0
  60. package/src/primitives/Address/deduplicateAddresses.ts +20 -0
  61. package/src/primitives/Address/from.ts +41 -0
  62. package/src/primitives/Address/fromAbiEncoded.ts +35 -0
  63. package/src/primitives/Address/fromBase64.ts +25 -0
  64. package/src/primitives/Address/fromBytes.ts +25 -0
  65. package/src/primitives/Address/fromHex.ts +31 -0
  66. package/src/primitives/Address/fromNumber.ts +25 -0
  67. package/src/primitives/Address/fromPrivateKey.ts +25 -0
  68. package/src/primitives/Address/fromPublicKey.ts +56 -0
  69. package/src/primitives/Address/index.ts +99 -35
  70. package/src/primitives/Address/is.ts +20 -0
  71. package/src/primitives/Address/isAddress.ts +22 -0
  72. package/src/primitives/Address/sortAddresses.ts +19 -0
  73. package/src/primitives/Address/toChecksummed.ts +32 -0
  74. package/src/primitives/Address/toHex.ts +18 -0
  75. package/src/primitives/Address/zero.ts +18 -0
  76. package/src/primitives/Base64/Base64.test.ts +75 -0
  77. package/src/primitives/Base64/convert.ts +37 -0
  78. package/src/primitives/Base64/decode.ts +59 -0
  79. package/src/primitives/Base64/encode.ts +42 -0
  80. package/src/primitives/Base64/from.ts +39 -0
  81. package/src/primitives/Base64/index.ts +81 -1
  82. package/src/primitives/Base64/size.ts +16 -0
  83. package/src/primitives/Base64/validation.ts +16 -0
  84. package/src/primitives/Blob/Blob.test.ts +292 -0
  85. package/src/primitives/Blob/calculateGas.ts +30 -0
  86. package/src/primitives/Blob/estimateBlobCount.ts +30 -0
  87. package/src/primitives/Blob/from.ts +38 -0
  88. package/src/primitives/Blob/fromData.ts +36 -0
  89. package/src/primitives/Blob/index.ts +99 -12
  90. package/src/primitives/Blob/isValidVersion.ts +27 -0
  91. package/src/primitives/Blob/joinData.ts +43 -0
  92. package/src/primitives/Blob/splitData.ts +36 -0
  93. package/src/primitives/Blob/toCommitment.ts +43 -0
  94. package/src/primitives/Blob/toProof.ts +50 -0
  95. package/src/primitives/Blob/toVersionedHash.ts +35 -0
  96. package/src/primitives/Blob/verify.ts +49 -0
  97. package/src/primitives/Blob/verifyBatch.ts +119 -0
  98. package/src/primitives/BloomFilter/BloomFilter.test.ts +138 -0
  99. package/src/primitives/BloomFilter/add.ts +23 -0
  100. package/src/primitives/BloomFilter/combine.ts +21 -0
  101. package/src/primitives/BloomFilter/contains.ts +26 -0
  102. package/src/primitives/BloomFilter/create.ts +35 -0
  103. package/src/primitives/BloomFilter/density.ts +22 -0
  104. package/src/primitives/BloomFilter/expectedFalsePositiveRate.ts +25 -0
  105. package/src/primitives/BloomFilter/fromHex.ts +37 -0
  106. package/src/primitives/BloomFilter/hash.ts +43 -0
  107. package/src/primitives/BloomFilter/index.ts +59 -37
  108. package/src/primitives/BloomFilter/isEmpty.ts +22 -0
  109. package/src/primitives/BloomFilter/merge.ts +24 -0
  110. package/src/primitives/BloomFilter/toHex.ts +22 -0
  111. package/src/primitives/Bytecode/analyze.ts +58 -0
  112. package/src/primitives/Bytecode/detectFusions.ts +10 -0
  113. package/src/primitives/Bytecode/equals.ts +10 -0
  114. package/src/primitives/Bytecode/extractRuntime.ts +12 -0
  115. package/src/primitives/Bytecode/format.ts +16 -0
  116. package/src/primitives/Bytecode/from.ts +16 -0
  117. package/src/primitives/Bytecode/fromHex.ts +14 -0
  118. package/src/primitives/Bytecode/getBlock.ts +12 -0
  119. package/src/primitives/Bytecode/getNextPc.ts +12 -0
  120. package/src/primitives/Bytecode/getPushSize.ts +8 -0
  121. package/src/primitives/Bytecode/hasMetadata.ts +10 -0
  122. package/src/primitives/Bytecode/hash.ts +9 -0
  123. package/src/primitives/Bytecode/index.ts +103 -13
  124. package/src/primitives/Bytecode/isPush.ts +8 -0
  125. package/src/primitives/Bytecode/isTerminator.ts +8 -0
  126. package/src/primitives/Bytecode/isValidJumpDest.ts +12 -0
  127. package/src/primitives/Bytecode/parseInstructions.ts +10 -0
  128. package/src/primitives/Bytecode/prettyPrint.ts +12 -0
  129. package/src/primitives/Bytecode/scan.ts +20 -0
  130. package/src/primitives/Bytecode/size.ts +9 -0
  131. package/src/primitives/Bytecode/stripMetadata.ts +10 -0
  132. package/src/primitives/Bytecode/toAbi.ts +10 -0
  133. package/src/primitives/Bytecode/toHex.ts +10 -0
  134. package/src/primitives/Bytecode/types.ts +23 -0
  135. package/src/primitives/Bytecode/validate.ts +9 -0
  136. package/src/primitives/Ens/Ens.test.ts +71 -0
  137. package/src/primitives/Ens/convert.ts +13 -0
  138. package/src/primitives/Ens/from.ts +32 -0
  139. package/src/primitives/Ens/hash.ts +46 -0
  140. package/src/primitives/Ens/index.ts +86 -4
  141. package/src/primitives/Ens/normalize.ts +45 -0
  142. package/src/primitives/Ens/validation.ts +38 -0
  143. package/src/primitives/EventLog/accessors.ts +32 -0
  144. package/src/primitives/EventLog/clone.ts +17 -0
  145. package/src/primitives/EventLog/create.ts +46 -0
  146. package/src/primitives/EventLog/filtering.ts +48 -0
  147. package/src/primitives/EventLog/index.ts +96 -6
  148. package/src/primitives/EventLog/status.ts +17 -0
  149. package/src/primitives/EventLog/toRpc.ts +49 -0
  150. package/src/primitives/Hardfork/HardforkSchema.ts +3 -3
  151. package/src/primitives/Hardfork/allIds.ts +13 -0
  152. package/src/primitives/Hardfork/allNames.ts +13 -0
  153. package/src/primitives/Hardfork/compare.ts +17 -0
  154. package/src/primitives/Hardfork/comparisons.ts +45 -0
  155. package/src/primitives/Hardfork/equals.ts +17 -0
  156. package/src/primitives/Hardfork/features.ts +61 -0
  157. package/src/primitives/Hardfork/fromString.ts +16 -0
  158. package/src/primitives/Hardfork/index.ts +128 -18
  159. package/src/primitives/Hardfork/isValidName.ts +14 -0
  160. package/src/primitives/Hardfork/minMax.ts +23 -0
  161. package/src/primitives/Hardfork/range.ts +19 -0
  162. package/src/primitives/Hardfork/toString.ts +16 -0
  163. package/src/primitives/Hash/Hash.test.ts +104 -0
  164. package/src/primitives/Hash/from.ts +47 -0
  165. package/src/primitives/Hash/fromBytes.ts +46 -0
  166. package/src/primitives/Hash/fromHex.ts +44 -0
  167. package/src/primitives/Hash/index.ts +45 -8
  168. package/src/primitives/Hash/isHash.ts +31 -0
  169. package/src/primitives/Hash/toHex.ts +29 -0
  170. package/src/primitives/Hex/Hex.test.ts +266 -155
  171. package/src/primitives/Hex/assertSize.ts +41 -0
  172. package/src/primitives/Hex/concat.ts +37 -0
  173. package/src/primitives/Hex/from.ts +38 -0
  174. package/src/primitives/Hex/fromBigInt.ts +40 -0
  175. package/src/primitives/Hex/fromBoolean.ts +29 -0
  176. package/src/primitives/Hex/fromNumber.ts +41 -0
  177. package/src/primitives/Hex/fromString.ts +28 -0
  178. package/src/primitives/Hex/index.ts +68 -37
  179. package/src/primitives/Hex/pad.ts +40 -0
  180. package/src/primitives/Hex/padRight.ts +39 -0
  181. package/src/primitives/Hex/size.ts +29 -0
  182. package/src/primitives/Hex/slice.ts +42 -0
  183. package/src/primitives/Hex/toBigInt.ts +27 -0
  184. package/src/primitives/Hex/toBoolean.ts +38 -0
  185. package/src/primitives/Hex/toNumber.ts +37 -0
  186. package/src/primitives/Hex/toStringHex.ts +39 -0
  187. package/src/primitives/Hex/trim.ts +27 -0
  188. package/src/primitives/Hex/validate.ts +37 -0
  189. package/src/primitives/Hex/xor.ts +39 -0
  190. package/src/primitives/Opcode/OpcodeSchema.ts +1 -1
  191. package/src/primitives/Opcode/disassemble.ts +15 -0
  192. package/src/primitives/Opcode/dupPosition.ts +15 -0
  193. package/src/primitives/Opcode/format.ts +15 -0
  194. package/src/primitives/Opcode/getters.ts +54 -0
  195. package/src/primitives/Opcode/index.ts +301 -11
  196. package/src/primitives/Opcode/info.ts +18 -0
  197. package/src/primitives/Opcode/jumpDests.ts +15 -0
  198. package/src/primitives/Opcode/logTopics.ts +15 -0
  199. package/src/primitives/Opcode/name.ts +15 -0
  200. package/src/primitives/Opcode/parse.ts +15 -0
  201. package/src/primitives/Opcode/predicates.ts +72 -0
  202. package/src/primitives/Opcode/pushBytes.ts +15 -0
  203. package/src/primitives/Opcode/pushOpcode.ts +15 -0
  204. package/src/primitives/Opcode/swapPosition.ts +15 -0
  205. package/src/primitives/Rlp/decodeBatch.ts +46 -0
  206. package/src/primitives/Rlp/decodeObject.ts +46 -0
  207. package/src/primitives/Rlp/decodeValue.ts +51 -0
  208. package/src/primitives/Rlp/encodeBatch.ts +50 -0
  209. package/src/primitives/Rlp/encodeObject.ts +48 -0
  210. package/src/primitives/Rlp/encodeVariadic.ts +49 -0
  211. package/src/primitives/Rlp/equals.ts +22 -0
  212. package/src/primitives/Rlp/from.ts +44 -0
  213. package/src/primitives/Rlp/fromJSON.ts +45 -0
  214. package/src/primitives/Rlp/getEncodedLength.ts +47 -0
  215. package/src/primitives/Rlp/getLength.ts +44 -0
  216. package/src/primitives/Rlp/index.ts +67 -14
  217. package/src/primitives/Rlp/isBytesData.ts +21 -0
  218. package/src/primitives/Rlp/isCanonical.ts +32 -0
  219. package/src/primitives/Rlp/isData.ts +21 -0
  220. package/src/primitives/Rlp/isList.ts +46 -0
  221. package/src/primitives/Rlp/isListData.ts +21 -0
  222. package/src/primitives/Rlp/isString.ts +46 -0
  223. package/src/primitives/Rlp/toJSON.ts +20 -0
  224. package/src/primitives/Rlp/toRaw.ts +31 -0
  225. package/src/primitives/Signature/Signature.test.ts +217 -0
  226. package/src/primitives/Signature/from.ts +38 -0
  227. package/src/primitives/Signature/fromBytes.ts +31 -0
  228. package/src/primitives/Signature/fromCompact.ts +33 -0
  229. package/src/primitives/Signature/fromDER.ts +35 -0
  230. package/src/primitives/Signature/fromEd25519.ts +24 -0
  231. package/src/primitives/Signature/fromHex.ts +29 -0
  232. package/src/primitives/Signature/fromP256.ts +25 -0
  233. package/src/primitives/Signature/fromRpc.ts +38 -0
  234. package/src/primitives/Signature/fromSecp256k1.ts +29 -0
  235. package/src/primitives/Signature/fromTuple.ts +33 -0
  236. package/src/primitives/Signature/getR.ts +24 -0
  237. package/src/primitives/Signature/getS.ts +24 -0
  238. package/src/primitives/Signature/getV.ts +24 -0
  239. package/src/primitives/Signature/index.ts +61 -11
  240. package/src/primitives/Signature/toDER.ts +24 -0
  241. package/src/primitives/Signature/toHex.ts +24 -0
  242. package/src/primitives/Signature/toRpc.ts +35 -0
  243. package/src/primitives/Signature/toTuple.ts +29 -0
  244. package/src/primitives/Signature/verify.ts +31 -0
  245. package/src/primitives/Siwe/create.ts +56 -0
  246. package/src/primitives/Siwe/hash.ts +27 -0
  247. package/src/primitives/Siwe/index.ts +57 -21
  248. package/src/primitives/Siwe/parse.ts +24 -0
  249. package/src/primitives/Siwe/verify.ts +47 -0
  250. package/src/primitives/Transaction/index.ts +467 -2
  251. package/src/primitives/Uint/Uint.test.ts +200 -0
  252. package/src/primitives/Uint/dividedBy.ts +34 -0
  253. package/src/primitives/Uint/from.ts +35 -0
  254. package/src/primitives/Uint/fromAbiEncoded.ts +29 -0
  255. package/src/primitives/Uint/fromBigInt.ts +30 -0
  256. package/src/primitives/Uint/fromBytes.ts +32 -0
  257. package/src/primitives/Uint/fromHex.ts +32 -0
  258. package/src/primitives/Uint/fromNumber.ts +30 -0
  259. package/src/primitives/Uint/index.ts +90 -45
  260. package/src/primitives/Uint/isUint256.ts +25 -0
  261. package/src/primitives/Uint/isValid.ts +25 -0
  262. package/src/primitives/Uint/modulo.ts +34 -0
  263. package/src/primitives/Uint/toHex.ts +31 -0
  264. package/src/primitives/Uint/tryFrom.ts +30 -0
@@ -0,0 +1,62 @@
1
+ /**
2
+ * @fileoverview ABI encodePacked - compact encoding without padding.
3
+ * Provides Effect-based wrapper for packed encoding.
4
+ *
5
+ * @module Abi/encodePacked
6
+ * @since 0.0.1
7
+ */
8
+
9
+ import {
10
+ AbiEncodingError as AbiEncodingErrorClass,
11
+ type AbiEncodingError,
12
+ type AbiParameterMismatchError,
13
+ encodePacked as _encodePacked,
14
+ } from "@tevm/voltaire/Abi";
15
+ import type { HexType } from "@tevm/voltaire/Hex";
16
+ import * as Effect from "effect/Effect";
17
+
18
+ type EncodePackedErrorType = AbiParameterMismatchError | AbiEncodingError;
19
+
20
+ const isAbiError = (e: unknown): e is EncodePackedErrorType =>
21
+ e !== null &&
22
+ typeof e === "object" &&
23
+ "name" in e &&
24
+ (e.name === "AbiParameterMismatchError" || e.name === "AbiEncodingError");
25
+
26
+ /**
27
+ * Encodes values in packed format (no padding).
28
+ *
29
+ * @description
30
+ * Performs ABI encoding without padding, used for creating hashes
31
+ * where standard ABI encoding would waste space.
32
+ *
33
+ * @param {readonly string[]} types - Array of Solidity type strings.
34
+ * @param {readonly unknown[]} values - Array of values to encode.
35
+ * @returns {Effect.Effect<HexType, AbiParameterMismatchError | AbiEncodingError>}
36
+ * Effect yielding encoded hex string.
37
+ *
38
+ * @example
39
+ * ```typescript
40
+ * import * as Effect from 'effect/Effect'
41
+ * import { encodePacked } from 'voltaire-effect/primitives/Abi'
42
+ *
43
+ * const encoded = await Effect.runPromise(
44
+ * encodePacked(['address', 'uint256'], [address, amount])
45
+ * )
46
+ * ```
47
+ *
48
+ * @since 0.0.1
49
+ */
50
+ export const encodePacked = (
51
+ types: readonly string[],
52
+ values: readonly unknown[],
53
+ ): Effect.Effect<HexType, AbiParameterMismatchError | AbiEncodingError> =>
54
+ Effect.try({
55
+ try: () => _encodePacked(types, values),
56
+ catch: (e) =>
57
+ isAbiError(e)
58
+ ? e
59
+ : new AbiEncodingErrorClass("Failed to encode packed", {
60
+ cause: e instanceof Error ? e : undefined,
61
+ }),
62
+ });
@@ -0,0 +1,21 @@
1
+ import { describe, expect, it } from "@effect/vitest";
2
+ import { Address, Bytes, Selector } from "@tevm/voltaire";
3
+ import * as Effect from "effect/Effect";
4
+ import { encodeWrappedError } from "./encodeWrappedError.js";
5
+
6
+ describe("encodeWrappedError", () => {
7
+ describe("success cases", () => {
8
+ it.effect("encodes wrapped error", () =>
9
+ Effect.gen(function* () {
10
+ const encoded = yield* encodeWrappedError({
11
+ target: Address.from("0x742d35Cc6634C0532925a3b844Bc9e7595f251e3"),
12
+ selector: Selector.fromHex("0xa9059cbb"),
13
+ reason: Bytes.from(new Uint8Array([1, 2, 3])),
14
+ details: Bytes.from(new Uint8Array([4, 5, 6])),
15
+ });
16
+ expect(encoded).toBeInstanceOf(Uint8Array);
17
+ expect(encoded.length).toBeGreaterThan(4);
18
+ }),
19
+ );
20
+ });
21
+ });
@@ -0,0 +1,64 @@
1
+ /**
2
+ * @fileoverview Encodes ERC-7751 wrapped error data.
3
+ * Provides Effect-based wrapper for wrapped error encoding.
4
+ *
5
+ * @module Abi/encodeWrappedError
6
+ * @since 0.0.1
7
+ */
8
+
9
+ import {
10
+ AbiEncodingError as AbiEncodingErrorClass,
11
+ type AbiEncodingError,
12
+ type WrappedErrorType,
13
+ encodeWrappedError as _encodeWrappedError,
14
+ } from "@tevm/voltaire/Abi";
15
+ import * as Effect from "effect/Effect";
16
+
17
+ /**
18
+ * Wrapped error input structure (ERC-7751).
19
+ */
20
+ export type WrappedErrorInput = WrappedErrorType;
21
+
22
+ /**
23
+ * Encodes ERC-7751 wrapped error data.
24
+ *
25
+ * @description
26
+ * Creates encoded error data following the ERC-7751 specification:
27
+ * `error WrappedError(address target, bytes4 selector, bytes reason, bytes details)`
28
+ *
29
+ * @param {WrappedErrorInput} wrappedError - Wrapped error data.
30
+ * @returns {Effect.Effect<Uint8Array, AbiEncodingError>}
31
+ * Effect yielding encoded error data (selector + ABI-encoded params).
32
+ *
33
+ * @example
34
+ * ```typescript
35
+ * import * as Effect from 'effect/Effect'
36
+ * import { encodeWrappedError } from 'voltaire-effect/primitives/Abi'
37
+ * import * as Address from '@tevm/voltaire/Address'
38
+ * import * as Selector from '@tevm/voltaire/Selector'
39
+ *
40
+ * const encoded = await Effect.runPromise(
41
+ * encodeWrappedError({
42
+ * target: Address.from('0x1234...'),
43
+ * selector: Selector.fromHex('0xabcd1234'),
44
+ * reason: new Uint8Array([...]),
45
+ * details: new Uint8Array([...])
46
+ * })
47
+ * )
48
+ * ```
49
+ *
50
+ * @see https://eips.ethereum.org/EIPS/eip-7751
51
+ * @since 0.0.1
52
+ */
53
+ export const encodeWrappedError = (
54
+ wrappedError: WrappedErrorInput,
55
+ ): Effect.Effect<Uint8Array, AbiEncodingError> =>
56
+ Effect.try({
57
+ try: () => _encodeWrappedError(wrappedError),
58
+ catch: (e) =>
59
+ e instanceof AbiEncodingErrorClass
60
+ ? e
61
+ : new AbiEncodingErrorClass("Failed to encode wrapped error", {
62
+ cause: e instanceof Error ? e : undefined,
63
+ }),
64
+ });
@@ -0,0 +1,50 @@
1
+ import { describe, expect, it } from "@effect/vitest";
2
+ import * as Effect from "effect/Effect";
3
+ import * as S from "effect/Schema";
4
+ import { fromArray } from "./AbiSchema.js";
5
+ import {
6
+ findSelectorCollisions,
7
+ hasSelectorCollisions,
8
+ } from "./findSelectorCollisions.js";
9
+
10
+ const normalAbi = S.decodeUnknownSync(fromArray)([
11
+ {
12
+ type: "function",
13
+ name: "transfer",
14
+ stateMutability: "nonpayable",
15
+ inputs: [
16
+ { name: "to", type: "address" },
17
+ { name: "amount", type: "uint256" },
18
+ ],
19
+ outputs: [{ type: "bool" }],
20
+ },
21
+ {
22
+ type: "function",
23
+ name: "balanceOf",
24
+ stateMutability: "view",
25
+ inputs: [{ name: "account", type: "address" }],
26
+ outputs: [{ type: "uint256" }],
27
+ },
28
+ ]);
29
+
30
+ describe("findSelectorCollisions", () => {
31
+ describe("success cases", () => {
32
+ it.effect("returns empty array for normal ABI", () =>
33
+ Effect.gen(function* () {
34
+ const collisions = yield* findSelectorCollisions(normalAbi);
35
+ expect(collisions).toEqual([]);
36
+ }),
37
+ );
38
+ });
39
+ });
40
+
41
+ describe("hasSelectorCollisions", () => {
42
+ describe("success cases", () => {
43
+ it.effect("returns false for normal ABI", () =>
44
+ Effect.gen(function* () {
45
+ const hasCollisions = yield* hasSelectorCollisions(normalAbi);
46
+ expect(hasCollisions).toBe(false);
47
+ }),
48
+ );
49
+ });
50
+ });
@@ -0,0 +1,83 @@
1
+ /**
2
+ * @fileoverview Finds function selector collisions in an ABI.
3
+ * Provides Effect-based wrapper for collision detection.
4
+ *
5
+ * @module Abi/findSelectorCollisions
6
+ * @since 0.0.1
7
+ */
8
+
9
+ import {
10
+ type ItemType,
11
+ findSelectorCollisions as _findSelectorCollisions,
12
+ hasSelectorCollisions as _hasSelectorCollisions,
13
+ } from "@tevm/voltaire/Abi";
14
+ import type { HexType } from "@tevm/voltaire/Hex";
15
+ import * as Effect from "effect/Effect";
16
+
17
+ type AbiInput = readonly ItemType[];
18
+
19
+ /**
20
+ * Selector collision information.
21
+ */
22
+ export interface SelectorCollision {
23
+ selector: HexType;
24
+ functions: readonly ItemType[];
25
+ }
26
+
27
+ /**
28
+ * Finds function selector collisions in an ABI.
29
+ *
30
+ * @description
31
+ * Detects when multiple functions in an ABI share the same 4-byte selector.
32
+ * This can happen due to the birthday paradox with 4-byte hashes.
33
+ *
34
+ * @param {AbiInput} abi - The contract ABI to check.
35
+ * @returns {Effect.Effect<readonly SelectorCollision[], never>}
36
+ * Effect yielding array of collisions (empty if none).
37
+ *
38
+ * @example
39
+ * ```typescript
40
+ * import * as Effect from 'effect/Effect'
41
+ * import { findSelectorCollisions } from 'voltaire-effect/primitives/Abi'
42
+ *
43
+ * const collisions = await Effect.runPromise(
44
+ * findSelectorCollisions(abi)
45
+ * )
46
+ * if (collisions.length > 0) {
47
+ * console.warn('Selector collisions detected:', collisions)
48
+ * }
49
+ * ```
50
+ *
51
+ * @since 0.0.1
52
+ */
53
+ export const findSelectorCollisions = (
54
+ abi: AbiInput,
55
+ ): Effect.Effect<readonly SelectorCollision[], never> =>
56
+ Effect.sync(() => _findSelectorCollisions([...abi]) as SelectorCollision[]);
57
+
58
+ /**
59
+ * Checks if an ABI has any function selector collisions.
60
+ *
61
+ * @description
62
+ * Quick check for the presence of selector collisions.
63
+ *
64
+ * @param {AbiInput} abi - The contract ABI to check.
65
+ * @returns {Effect.Effect<boolean, never>}
66
+ * Effect yielding true if collisions exist.
67
+ *
68
+ * @example
69
+ * ```typescript
70
+ * import * as Effect from 'effect/Effect'
71
+ * import { hasSelectorCollisions } from 'voltaire-effect/primitives/Abi'
72
+ *
73
+ * const hasCollisions = await Effect.runPromise(
74
+ * hasSelectorCollisions(abi)
75
+ * )
76
+ * ```
77
+ *
78
+ * @since 0.0.1
79
+ */
80
+ export const hasSelectorCollisions = (
81
+ abi: AbiInput,
82
+ ): Effect.Effect<boolean, never> =>
83
+ Effect.sync(() => _hasSelectorCollisions([...abi]));
@@ -21,33 +21,59 @@ export {
21
21
  ReceiveSchema,
22
22
  StateMutabilitySchema,
23
23
  } from "./AbiSchema.js";
24
- export { decodeError } from "./decodeError.js";
25
- export { decodeEventLog } from "./decodeEventLog.js";
26
- export { decodeFunction } from "./decodeFunction.js";
27
- export { decodeFunctionData } from "./decodeFunctionData.js";
28
- export { decodeFunctionResult } from "./decodeFunctionResult.js";
24
+
25
+ // Core encoding
26
+ export { encode } from "./encode.js";
27
+ export { encodePacked } from "./encodePacked.js";
28
+ export { encodeWrappedError, type WrappedErrorInput } from "./encodeWrappedError.js";
29
+
30
+ // Core decoding
31
+ export { decode } from "./decode.js";
32
+ export { decodeData } from "./decodeData.js";
33
+ export { decodeLog, type LogInput } from "./decodeLog.js";
34
+ export { decodeWrappedError, type WrappedErrorResult } from "./decodeWrappedError.js";
35
+
29
36
  // Error encoding/decoding
37
+ export { decodeError } from "./decodeError.js";
30
38
  export { encodeError } from "./encodeError.js";
39
+
31
40
  // Event encoding/decoding
41
+ export { decodeEventLog } from "./decodeEventLog.js";
32
42
  export { encodeEventLog } from "./encodeEventLog.js";
43
+
33
44
  // Function encoding/decoding
45
+ export { decodeFunction } from "./decodeFunction.js";
46
+ export { decodeFunctionData } from "./decodeFunctionData.js";
47
+ export { decodeFunctionResult } from "./decodeFunctionResult.js";
34
48
  export { encodeFunction } from "./encodeFunction.js";
35
49
  export { encodeFunctionData } from "./encodeFunctionData.js";
36
50
  export { encodeFunctionResult } from "./encodeFunctionResult.js";
51
+
52
+ // Lookup functions
37
53
  export { findError } from "./findError.js";
38
54
  export { findEvent } from "./findEvent.js";
39
- // Lookup functions
40
55
  export { findFunction } from "./findFunction.js";
56
+
57
+ // Selector collision detection
58
+ export {
59
+ findSelectorCollisions,
60
+ hasSelectorCollisions,
61
+ type SelectorCollision,
62
+ } from "./findSelectorCollisions.js";
63
+
41
64
  // Formatting
42
65
  export { format } from "./format.js";
43
66
  export { formatWithArgs } from "./formatWithArgs.js";
67
+
68
+ // Getters
44
69
  export { getErrorSignature } from "./getErrorSignature.js";
45
70
  export { getEvent } from "./getEvent.js";
46
71
  export { getEventSignature } from "./getEventSignature.js";
47
72
  export { getFunction } from "./getFunction.js";
48
73
  export { getFunctionSignature } from "./getFunctionSignature.js";
49
- // Selectors and signatures
50
74
  export { getSelector } from "./getSelector.js";
75
+
51
76
  // Parsing
52
77
  export { AbiParseError, parse } from "./parse.js";
53
78
  export { AbiItemParseError, parseItem } from "./parseItem.js";
79
+ export { parseLogs, type ParsedLog, type ParseLogsInput } from "./parseLogs.js";
@@ -0,0 +1,37 @@
1
+ import { describe, expect, it } from "@effect/vitest";
2
+ import * as Effect from "effect/Effect";
3
+ import * as S from "effect/Schema";
4
+ import { fromArray } from "./AbiSchema.js";
5
+ import { parseLogs } from "./parseLogs.js";
6
+
7
+ const erc20Abi = S.decodeUnknownSync(fromArray)([
8
+ {
9
+ type: "event",
10
+ name: "Transfer",
11
+ inputs: [
12
+ { name: "from", type: "address", indexed: true },
13
+ { name: "to", type: "address", indexed: true },
14
+ { name: "value", type: "uint256", indexed: false },
15
+ ],
16
+ },
17
+ ]);
18
+
19
+ describe("parseLogs", () => {
20
+ describe("success cases", () => {
21
+ it.effect("returns empty array for no matching logs", () =>
22
+ Effect.gen(function* () {
23
+ const parsed = yield* parseLogs(erc20Abi, [
24
+ { data: new Uint8Array(32), topics: [new Uint8Array(32)] },
25
+ ]);
26
+ expect(parsed).toEqual([]);
27
+ }),
28
+ );
29
+
30
+ it.effect("returns empty array for empty logs", () =>
31
+ Effect.gen(function* () {
32
+ const parsed = yield* parseLogs(erc20Abi, []);
33
+ expect(parsed).toEqual([]);
34
+ }),
35
+ );
36
+ });
37
+ });
@@ -0,0 +1,62 @@
1
+ /**
2
+ * @fileoverview Parses multiple event logs using ABI.
3
+ * Provides Effect-based wrapper for batch log parsing.
4
+ *
5
+ * @module Abi/parseLogs
6
+ * @since 0.0.1
7
+ */
8
+
9
+ import { type Abi, type ItemType } from "@tevm/voltaire/Abi";
10
+ import type { HexType } from "@tevm/voltaire/Hex";
11
+ import * as Effect from "effect/Effect";
12
+
13
+ type AbiInput = readonly ItemType[];
14
+
15
+ const toAbi = (input: AbiInput): Abi => input as unknown as Abi;
16
+
17
+ /**
18
+ * Log input structure for parseLogs.
19
+ */
20
+ export interface ParseLogsInput {
21
+ data: Uint8Array | string;
22
+ topics: readonly (Uint8Array | string)[];
23
+ }
24
+
25
+ /**
26
+ * Parsed log result.
27
+ */
28
+ export interface ParsedLog {
29
+ eventName: string;
30
+ args: Record<string, unknown>;
31
+ }
32
+
33
+ /**
34
+ * Parses multiple event logs using ABI.
35
+ *
36
+ * @description
37
+ * Parses an array of log entries, returning successfully decoded logs.
38
+ * Logs that don't match any event in the ABI are silently filtered out.
39
+ *
40
+ * @param {AbiInput} abi - The contract ABI.
41
+ * @param {readonly ParseLogsInput[]} logs - Array of log objects.
42
+ * @returns {Effect.Effect<readonly ParsedLog[], never>}
43
+ * Effect yielding array of parsed logs (never fails).
44
+ *
45
+ * @example
46
+ * ```typescript
47
+ * import * as Effect from 'effect/Effect'
48
+ * import { parseLogs } from 'voltaire-effect/primitives/Abi'
49
+ *
50
+ * const parsed = await Effect.runPromise(
51
+ * parseLogs(abi, logs)
52
+ * )
53
+ * // [{ eventName: 'Transfer', args: { from, to, value } }]
54
+ * ```
55
+ *
56
+ * @since 0.0.1
57
+ */
58
+ export const parseLogs = (
59
+ abi: AbiInput,
60
+ logs: readonly ParseLogsInput[],
61
+ ): Effect.Effect<readonly ParsedLog[], never> =>
62
+ Effect.sync(() => toAbi(abi).parseLogs(logs));
@@ -0,0 +1,229 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { Effect } from "effect";
3
+ import * as S from "effect/Schema";
4
+ import * as AccessList from "./index.js";
5
+
6
+ const makeAddress = (byte: number): Uint8Array & { readonly __brand?: symbol } =>
7
+ new Uint8Array(20).fill(byte) as Uint8Array & { readonly __brand?: symbol };
8
+
9
+ const makeHash = (byte: number): Uint8Array & { readonly __brand?: symbol } =>
10
+ new Uint8Array(32).fill(byte) as Uint8Array & { readonly __brand?: symbol };
11
+
12
+ describe("AccessList", () => {
13
+ describe("create", () => {
14
+ it("creates empty access list", () => {
15
+ const list = AccessList.create();
16
+ expect(AccessList.isEmpty(list)).toBe(true);
17
+ expect(AccessList.addressCount(list)).toBe(0);
18
+ });
19
+ });
20
+
21
+ describe("from", () => {
22
+ it("creates from items", async () => {
23
+ const addr = makeAddress(0x42);
24
+ const key = makeHash(0x01);
25
+ const list = await Effect.runPromise(
26
+ AccessList.from([{ address: addr, storageKeys: [key] }])
27
+ );
28
+ expect(AccessList.addressCount(list)).toBe(1);
29
+ expect(AccessList.storageKeyCount(list)).toBe(1);
30
+ });
31
+ });
32
+
33
+ describe("type guards", () => {
34
+ it("is() validates access list", () => {
35
+ const list = AccessList.create();
36
+ expect(AccessList.is(list)).toBe(true);
37
+ expect(AccessList.is([])).toBe(true);
38
+ expect(AccessList.is("not a list")).toBe(false);
39
+ expect(AccessList.is([{ invalid: true }])).toBe(false);
40
+ });
41
+
42
+ it("isItem() validates items", () => {
43
+ const addr = makeAddress(0x42);
44
+ const key = makeHash(0x01);
45
+ expect(AccessList.isItem({ address: addr, storageKeys: [key] })).toBe(true);
46
+ expect(AccessList.isItem({ address: addr, storageKeys: [] })).toBe(true);
47
+ expect(AccessList.isItem({ address: "0x123", storageKeys: [] })).toBe(false);
48
+ expect(AccessList.isItem(null)).toBe(false);
49
+ });
50
+ });
51
+
52
+ describe("queries", () => {
53
+ it("isEmpty", () => {
54
+ expect(AccessList.isEmpty(AccessList.create())).toBe(true);
55
+ });
56
+
57
+ it("addressCount", () => {
58
+ const addr1 = makeAddress(0x01);
59
+ const addr2 = makeAddress(0x02);
60
+ let list = AccessList.create();
61
+ list = AccessList.withAddress(list, addr1);
62
+ list = AccessList.withAddress(list, addr2);
63
+ expect(AccessList.addressCount(list)).toBe(2);
64
+ });
65
+
66
+ it("storageKeyCount", () => {
67
+ const addr = makeAddress(0x42);
68
+ const key1 = makeHash(0x01);
69
+ const key2 = makeHash(0x02);
70
+ let list = AccessList.create();
71
+ list = AccessList.withStorageKey(list, addr, key1);
72
+ list = AccessList.withStorageKey(list, addr, key2);
73
+ expect(AccessList.storageKeyCount(list)).toBe(2);
74
+ });
75
+
76
+ it("includesAddress", () => {
77
+ const addr = makeAddress(0x42);
78
+ const other = makeAddress(0x43);
79
+ let list = AccessList.create();
80
+ list = AccessList.withAddress(list, addr);
81
+ expect(AccessList.includesAddress(list, addr)).toBe(true);
82
+ expect(AccessList.includesAddress(list, other)).toBe(false);
83
+ });
84
+
85
+ it("includesStorageKey", () => {
86
+ const addr = makeAddress(0x42);
87
+ const key = makeHash(0x01);
88
+ const other = makeHash(0x02);
89
+ let list = AccessList.create();
90
+ list = AccessList.withStorageKey(list, addr, key);
91
+ expect(AccessList.includesStorageKey(list, addr, key)).toBe(true);
92
+ expect(AccessList.includesStorageKey(list, addr, other)).toBe(false);
93
+ });
94
+
95
+ it("keysFor", () => {
96
+ const addr = makeAddress(0x42);
97
+ const key = makeHash(0x01);
98
+ let list = AccessList.create();
99
+ list = AccessList.withStorageKey(list, addr, key);
100
+ const keys = AccessList.keysFor(list, addr);
101
+ expect(keys).toBeDefined();
102
+ expect(keys?.length).toBe(1);
103
+ expect(AccessList.keysFor(list, makeAddress(0x99))).toBeUndefined();
104
+ });
105
+ });
106
+
107
+ describe("gas calculations", () => {
108
+ it("gasCost", () => {
109
+ const addr = makeAddress(0x42);
110
+ const key = makeHash(0x01);
111
+ let list = AccessList.create();
112
+ list = AccessList.withStorageKey(list, addr, key);
113
+ const cost = AccessList.gasCost(list);
114
+ expect(cost).toBe(AccessList.ADDRESS_COST + AccessList.STORAGE_KEY_COST);
115
+ });
116
+
117
+ it("gasSavings", () => {
118
+ const addr = makeAddress(0x42);
119
+ let list = AccessList.create();
120
+ list = AccessList.withAddress(list, addr);
121
+ const savings = AccessList.gasSavings(list);
122
+ expect(savings).toBe(AccessList.COLD_ACCOUNT_ACCESS_COST - AccessList.ADDRESS_COST);
123
+ });
124
+
125
+ it("hasSavings", () => {
126
+ const addr = makeAddress(0x42);
127
+ let list = AccessList.create();
128
+ list = AccessList.withAddress(list, addr);
129
+ expect(AccessList.hasSavings(list)).toBe(true);
130
+ });
131
+ });
132
+
133
+ describe("transformations", () => {
134
+ it("withAddress adds new address", () => {
135
+ const addr = makeAddress(0x42);
136
+ let list = AccessList.create();
137
+ list = AccessList.withAddress(list, addr);
138
+ expect(AccessList.includesAddress(list, addr)).toBe(true);
139
+ });
140
+
141
+ it("withAddress is idempotent", () => {
142
+ const addr = makeAddress(0x42);
143
+ let list = AccessList.create();
144
+ list = AccessList.withAddress(list, addr);
145
+ const list2 = AccessList.withAddress(list, addr);
146
+ expect(AccessList.addressCount(list2)).toBe(1);
147
+ });
148
+
149
+ it("withStorageKey adds key", () => {
150
+ const addr = makeAddress(0x42);
151
+ const key = makeHash(0x01);
152
+ let list = AccessList.create();
153
+ list = AccessList.withStorageKey(list, addr, key);
154
+ expect(AccessList.includesStorageKey(list, addr, key)).toBe(true);
155
+ });
156
+
157
+ it("deduplicate merges duplicate addresses", () => {
158
+ const addr = makeAddress(0x42);
159
+ const key1 = makeHash(0x01);
160
+ const key2 = makeHash(0x02);
161
+ const list = [
162
+ { address: addr, storageKeys: [key1] },
163
+ { address: addr, storageKeys: [key2, key1] },
164
+ ] as AccessList.BrandedAccessList;
165
+ const deduped = AccessList.deduplicate(list);
166
+ expect(AccessList.addressCount(deduped)).toBe(1);
167
+ expect(AccessList.storageKeyCount(deduped)).toBe(2);
168
+ });
169
+
170
+ it("merge combines lists", () => {
171
+ const addr1 = makeAddress(0x01);
172
+ const addr2 = makeAddress(0x02);
173
+ const list1 = AccessList.withAddress(AccessList.create(), addr1);
174
+ const list2 = AccessList.withAddress(AccessList.create(), addr2);
175
+ const merged = AccessList.merge(list1, list2);
176
+ expect(AccessList.addressCount(merged)).toBe(2);
177
+ });
178
+
179
+ it("toBytes encodes to RLP", () => {
180
+ const list = AccessList.create();
181
+ const bytes = AccessList.toBytes(list);
182
+ expect(bytes).toBeInstanceOf(Uint8Array);
183
+ });
184
+ });
185
+
186
+ describe("assertValid", () => {
187
+ it("succeeds for valid list", async () => {
188
+ const list = AccessList.create();
189
+ await Effect.runPromise(AccessList.assertValid(list));
190
+ });
191
+ });
192
+
193
+ describe("Rpc schema", () => {
194
+ it("decodes from JSON-RPC format", () => {
195
+ const input = [
196
+ {
197
+ address: "0x742d35Cc6634C0532925a3b844Bc9e7595f251e3",
198
+ storageKeys: [
199
+ "0x0000000000000000000000000000000000000000000000000000000000000001",
200
+ ],
201
+ },
202
+ ];
203
+ const list = S.decodeSync(AccessList.Rpc)(input);
204
+ expect(AccessList.addressCount(list)).toBe(1);
205
+ expect(AccessList.storageKeyCount(list)).toBe(1);
206
+ });
207
+
208
+ it("encodes to JSON-RPC format", () => {
209
+ const addr = makeAddress(0x42);
210
+ const key = makeHash(0x01);
211
+ let list = AccessList.create();
212
+ list = AccessList.withStorageKey(list, addr, key);
213
+ const json = S.encodeSync(AccessList.Rpc)(list);
214
+ expect(json).toHaveLength(1);
215
+ expect(json[0].address).toMatch(/^0x[0-9a-f]{40}$/);
216
+ expect(json[0].storageKeys).toHaveLength(1);
217
+ });
218
+ });
219
+
220
+ describe("constants", () => {
221
+ it("exports gas constants", () => {
222
+ expect(AccessList.ADDRESS_COST).toBe(2400n);
223
+ expect(AccessList.STORAGE_KEY_COST).toBe(1900n);
224
+ expect(AccessList.COLD_ACCOUNT_ACCESS_COST).toBe(2600n);
225
+ expect(AccessList.COLD_STORAGE_ACCESS_COST).toBe(2100n);
226
+ expect(AccessList.WARM_STORAGE_ACCESS_COST).toBe(100n);
227
+ });
228
+ });
229
+ });
@@ -0,0 +1,16 @@
1
+ /**
2
+ * @module AccessListTypeSchema
3
+ * @description Effect Schema declaration for BrandedAccessList type
4
+ * @since 0.1.0
5
+ */
6
+ import { AccessList, type BrandedAccessList } from "@tevm/voltaire/AccessList";
7
+ import * as S from "effect/Schema";
8
+
9
+ /**
10
+ * Schema declaration for the BrandedAccessList type
11
+ * @since 0.1.0
12
+ */
13
+ export const AccessListTypeSchema = S.declare<BrandedAccessList>(
14
+ (u): u is BrandedAccessList => AccessList.is(u),
15
+ { identifier: "AccessList" },
16
+ );