voltaire-effect 0.3.0 → 1.0.1
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.
- package/dist/{X25519Test-D5Q-5fL9.d.ts → X25519Test-avt1DUgp.d.ts} +231 -6
- package/dist/crypto/index.d.ts +2 -2
- package/dist/crypto/index.js +72 -2
- package/dist/{index-3UKSP3cd.d.ts → index-DxwZo3xo.d.ts} +7781 -5513
- package/dist/index.d.ts +990 -3096
- package/dist/index.js +2374 -1652
- package/dist/native/index.d.ts +6 -6
- package/dist/native/index.js +2399 -1677
- package/dist/primitives/index.d.ts +7 -6
- package/dist/primitives/index.js +2966 -2361
- package/dist/services/index.d.ts +1631 -1255
- package/dist/services/index.js +4493 -3977
- package/package.json +7 -3
- package/src/crypto/Signers/SignersService.ts +1 -1
- package/src/crypto/Signers/errors.ts +29 -0
- package/src/crypto/Signers/index.ts +1 -0
- package/src/crypto/Signers/operations.ts +26 -8
- package/src/crypto/index.ts +10 -11
- package/src/index.ts +1 -2
- package/src/jsonrpc/Anvil.ts +13 -8
- package/src/jsonrpc/Eth.ts +13 -8
- package/src/jsonrpc/Hardhat.ts +13 -8
- package/src/jsonrpc/IdCounter.ts +21 -5
- package/src/jsonrpc/JsonRpc.test.ts +126 -61
- package/src/jsonrpc/Net.ts +13 -8
- package/src/jsonrpc/Request.ts +16 -8
- package/src/jsonrpc/Txpool.ts +13 -8
- package/src/jsonrpc/Wallet.ts +13 -8
- package/src/jsonrpc/Web3.ts +13 -8
- package/src/jsonrpc/index.ts +1 -1
- package/src/primitives/Abi/AbiSchema.ts +3 -4
- package/src/primitives/Abi/fromBytecode.test.ts +47 -0
- package/src/primitives/Abi/fromBytecode.ts +81 -0
- package/src/primitives/Abi/index.ts +3 -0
- package/src/primitives/AccessList/from.ts +12 -9
- package/src/primitives/Address/Checksummed.ts +21 -27
- package/src/primitives/Address/from.ts +12 -15
- package/src/primitives/Address/toHex.ts +2 -1
- package/src/primitives/Base64/from.ts +21 -4
- package/src/primitives/Blob/from.ts +12 -4
- package/src/primitives/BlockHash/index.ts +2 -2
- package/src/primitives/BlockNumber/index.ts +3 -3
- package/src/primitives/Bytecode/from.ts +11 -2
- package/src/primitives/ContractSignature/verifySignature.ts +3 -5
- package/src/primitives/Ens/from.ts +12 -11
- package/src/primitives/Hex/from.ts +12 -4
- package/src/primitives/Signature/from.ts +11 -2
- package/src/primitives/Transaction/EIP2930/index.ts +12 -12
- package/src/primitives/Transaction/EIP4844/index.ts +14 -14
- package/src/primitives/Transaction/EIP7702/index.ts +13 -13
- package/src/primitives/Transaction/Legacy/index.ts +13 -13
- package/src/primitives/TransactionHash/index.ts +3 -2
- package/src/primitives/TransactionIndex/index.ts +2 -2
- package/src/primitives/Trie/Trie.test.ts +70 -0
- package/src/primitives/Trie/TrieSchema.ts +26 -0
- package/src/primitives/Trie/clear.ts +16 -0
- package/src/primitives/Trie/del.ts +18 -0
- package/src/primitives/Trie/get.ts +18 -0
- package/src/primitives/Trie/index.ts +30 -0
- package/src/primitives/Trie/init.ts +13 -0
- package/src/primitives/Trie/prove.ts +19 -0
- package/src/primitives/Trie/put.ts +20 -0
- package/src/primitives/Trie/rootHash.ts +14 -0
- package/src/primitives/Trie/verify.ts +18 -0
- package/src/primitives/Uint/from.ts +11 -2
- package/src/primitives/Uint16/index.ts +5 -4
- package/src/primitives/Uint64/index.ts +5 -4
- package/src/primitives/Uint8/index.ts +5 -4
- package/src/primitives/index.ts +3 -2
- package/src/services/BlockExplorerApi/BlockExplorerApi.test.ts +789 -0
- package/src/services/BlockExplorerApi/BlockExplorerApi.ts +797 -0
- package/src/services/BlockExplorerApi/BlockExplorerApiErrors.ts +176 -0
- package/src/services/BlockExplorerApi/BlockExplorerApiService.ts +60 -0
- package/src/services/BlockExplorerApi/BlockExplorerApiTypes.ts +225 -0
- package/src/services/BlockExplorerApi/index.ts +42 -0
- package/src/services/Contract/Contract.test.ts +2 -6
- package/src/services/Contract/ContractTypes.ts +26 -8
- package/src/services/Contract/estimateGas.test.ts +4 -7
- package/src/services/Provider/actions/multicall.ts +28 -9
- package/src/services/Provider/actions/readContract.test.ts +8 -11
- package/src/services/Provider/actions/readContract.ts +28 -9
- package/src/services/Provider/functions/getBlock.ts +2 -1
- package/src/services/Provider/functions/getBlockReceipts.ts +2 -1
- package/src/services/Provider/functions/getBlockTransactionCount.ts +2 -1
- package/src/services/Provider/functions/getUncle.ts +2 -1
- package/src/services/Provider/functions/getUncleCount.ts +2 -1
- package/src/services/Signer/actions/deployContract.ts +1 -1
- package/src/services/index.ts +25 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "voltaire-effect",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "Effect-TS integration for Voltaire Ethereum primitives library",
|
|
5
5
|
"author": "TEVM",
|
|
6
6
|
"license": "MIT",
|
|
@@ -80,7 +80,7 @@
|
|
|
80
80
|
"peerDependencies": {
|
|
81
81
|
"@effect/platform": "^0.94.0",
|
|
82
82
|
"effect": "^3.19.0",
|
|
83
|
-
"@tevm/voltaire": "0.
|
|
83
|
+
"@tevm/voltaire": "0.4.0"
|
|
84
84
|
},
|
|
85
85
|
"optionalDependencies": {
|
|
86
86
|
"@effect/platform-browser": "^0.74.0",
|
|
@@ -91,12 +91,16 @@
|
|
|
91
91
|
"@effect/platform": "^0.94.0",
|
|
92
92
|
"@effect/platform-node": "^0.104.0",
|
|
93
93
|
"@effect/vitest": "^0.27.0",
|
|
94
|
-
"
|
|
94
|
+
"@types/node": "^22.0.0",
|
|
95
95
|
"astro": "^5.0.0",
|
|
96
|
+
"effect": "^3.19.0",
|
|
96
97
|
"tsup": "^8.4.0",
|
|
97
98
|
"typescript": "^5.9.3",
|
|
98
99
|
"vitest": "^2.1.8"
|
|
99
100
|
},
|
|
101
|
+
"dependencies": {
|
|
102
|
+
"@shazow/whatsabi": "^0.25.0"
|
|
103
|
+
},
|
|
100
104
|
"scripts": {
|
|
101
105
|
"build": "tsup",
|
|
102
106
|
"test": "vitest",
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* @since 0.0.1
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import type { CryptoError, InvalidPrivateKeyError } from "
|
|
7
|
+
import type { CryptoError, InvalidPrivateKeyError } from "./errors.js";
|
|
8
8
|
import * as Context from "effect/Context";
|
|
9
9
|
import type * as Effect from "effect/Effect";
|
|
10
10
|
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Error types for Signers module using Effect TaggedError.
|
|
3
|
+
* @module Signers/errors
|
|
4
|
+
* @since 0.0.1
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import * as Data from "effect/Data";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* General cryptographic error during signing operations.
|
|
11
|
+
*
|
|
12
|
+
* @since 0.0.1
|
|
13
|
+
*/
|
|
14
|
+
export class CryptoError extends Data.TaggedError("CryptoError")<{
|
|
15
|
+
readonly message: string;
|
|
16
|
+
readonly cause?: unknown;
|
|
17
|
+
}> {}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Invalid private key format or value.
|
|
21
|
+
*
|
|
22
|
+
* @since 0.0.1
|
|
23
|
+
*/
|
|
24
|
+
export class InvalidPrivateKeyError extends Data.TaggedError(
|
|
25
|
+
"InvalidPrivateKeyError",
|
|
26
|
+
)<{
|
|
27
|
+
readonly message: string;
|
|
28
|
+
readonly cause?: unknown;
|
|
29
|
+
}> {}
|
|
@@ -6,11 +6,9 @@
|
|
|
6
6
|
|
|
7
7
|
import { Signers } from "@tevm/voltaire";
|
|
8
8
|
import * as Effect from "effect/Effect";
|
|
9
|
+
import { CryptoError, InvalidPrivateKeyError } from "./errors.js";
|
|
9
10
|
import type { Signer } from "./SignersService.js";
|
|
10
11
|
|
|
11
|
-
type CryptoError = Error;
|
|
12
|
-
type InvalidPrivateKeyError = Error & { code: "INVALID_PRIVATE_KEY" };
|
|
13
|
-
|
|
14
12
|
/**
|
|
15
13
|
* Creates a signer from a private key.
|
|
16
14
|
*
|
|
@@ -49,21 +47,37 @@ export const fromPrivateKey = (
|
|
|
49
47
|
signMessage: (message: string | Uint8Array) =>
|
|
50
48
|
Effect.tryPromise({
|
|
51
49
|
try: () => impl.signMessage(message),
|
|
52
|
-
catch: (e) =>
|
|
50
|
+
catch: (e) =>
|
|
51
|
+
new CryptoError({
|
|
52
|
+
message: e instanceof Error ? e.message : String(e),
|
|
53
|
+
cause: e,
|
|
54
|
+
}),
|
|
53
55
|
}),
|
|
54
56
|
signTransaction: (transaction: unknown) =>
|
|
55
57
|
Effect.tryPromise({
|
|
56
58
|
try: () => impl.signTransaction(transaction),
|
|
57
|
-
catch: (e) =>
|
|
59
|
+
catch: (e) =>
|
|
60
|
+
new CryptoError({
|
|
61
|
+
message: e instanceof Error ? e.message : String(e),
|
|
62
|
+
cause: e,
|
|
63
|
+
}),
|
|
58
64
|
}),
|
|
59
65
|
signTypedData: (typedData: unknown) =>
|
|
60
66
|
Effect.tryPromise({
|
|
61
67
|
try: () => impl.signTypedData(typedData),
|
|
62
|
-
catch: (e) =>
|
|
68
|
+
catch: (e) =>
|
|
69
|
+
new CryptoError({
|
|
70
|
+
message: e instanceof Error ? e.message : String(e),
|
|
71
|
+
cause: e,
|
|
72
|
+
}),
|
|
63
73
|
}),
|
|
64
74
|
} as Signer;
|
|
65
75
|
},
|
|
66
|
-
catch: (e) =>
|
|
76
|
+
catch: (e) =>
|
|
77
|
+
new InvalidPrivateKeyError({
|
|
78
|
+
message: e instanceof Error ? e.message : String(e),
|
|
79
|
+
cause: e,
|
|
80
|
+
}),
|
|
67
81
|
});
|
|
68
82
|
|
|
69
83
|
/**
|
|
@@ -119,5 +133,9 @@ export const recoverTransactionAddress = (
|
|
|
119
133
|
): Effect.Effect<string, CryptoError> =>
|
|
120
134
|
Effect.tryPromise({
|
|
121
135
|
try: () => Signers.recoverTransactionAddress(transaction),
|
|
122
|
-
catch: (e) =>
|
|
136
|
+
catch: (e) =>
|
|
137
|
+
new CryptoError({
|
|
138
|
+
message: e instanceof Error ? e.message : String(e),
|
|
139
|
+
cause: e,
|
|
140
|
+
}),
|
|
123
141
|
});
|
package/src/crypto/index.ts
CHANGED
|
@@ -217,17 +217,16 @@ export {
|
|
|
217
217
|
verifyMessage,
|
|
218
218
|
verifyTypedData as verifyTypedDataSignature,
|
|
219
219
|
} from "./Signature/index.js";
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
// } from "./Signers/index.js";
|
|
220
|
+
export {
|
|
221
|
+
fromPrivateKey,
|
|
222
|
+
getAddress as signersGetAddress,
|
|
223
|
+
recoverTransactionAddress,
|
|
224
|
+
type Signer,
|
|
225
|
+
SignersLive,
|
|
226
|
+
SignersService,
|
|
227
|
+
type SignersServiceShape,
|
|
228
|
+
SignersTest,
|
|
229
|
+
} from "./Signers/index.js";
|
|
231
230
|
export {
|
|
232
231
|
computeSecret as x25519ComputeSecret,
|
|
233
232
|
generateKeyPair as x25519GenerateKeyPair,
|
package/src/index.ts
CHANGED
|
@@ -70,8 +70,7 @@ export * as P256 from "./crypto/P256/index.js";
|
|
|
70
70
|
export * as Ripemd160 from "./crypto/Ripemd160/index.js";
|
|
71
71
|
export * as Secp256k1 from "./crypto/Secp256k1/index.js";
|
|
72
72
|
export * as SHA256 from "./crypto/SHA256/index.js";
|
|
73
|
-
|
|
74
|
-
// export * as Signers from "./crypto/Signers/index.js";
|
|
73
|
+
export * as Signers from "./crypto/Signers/index.js";
|
|
75
74
|
export * as X25519 from "./crypto/X25519/index.js";
|
|
76
75
|
// JSON-RPC module
|
|
77
76
|
export * as JsonRpc from "./jsonrpc/index.js";
|
package/src/jsonrpc/Anvil.ts
CHANGED
|
@@ -1,16 +1,21 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as Effect from "effect/Effect";
|
|
2
|
+
import { IdCounterService } from "./IdCounter.js";
|
|
2
3
|
import type { JsonRpcRequestType } from "./Request.js";
|
|
3
4
|
|
|
4
5
|
function makeRequest(
|
|
5
6
|
method: string,
|
|
6
7
|
params: unknown[] = [],
|
|
7
|
-
): JsonRpcRequestType {
|
|
8
|
-
return {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
8
|
+
): Effect.Effect<JsonRpcRequestType, never, IdCounterService> {
|
|
9
|
+
return Effect.gen(function* () {
|
|
10
|
+
const counter = yield* IdCounterService;
|
|
11
|
+
const id = yield* counter.next();
|
|
12
|
+
return {
|
|
13
|
+
jsonrpc: "2.0",
|
|
14
|
+
method,
|
|
15
|
+
params,
|
|
16
|
+
id,
|
|
17
|
+
};
|
|
18
|
+
});
|
|
14
19
|
}
|
|
15
20
|
|
|
16
21
|
export const MineRequest = (blocks?: number, interval?: number) =>
|
package/src/jsonrpc/Eth.ts
CHANGED
|
@@ -1,16 +1,21 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as Effect from "effect/Effect";
|
|
2
|
+
import { IdCounterService } from "./IdCounter.js";
|
|
2
3
|
import type { JsonRpcRequestType } from "./Request.js";
|
|
3
4
|
|
|
4
5
|
function makeRequest(
|
|
5
6
|
method: string,
|
|
6
7
|
params: unknown[] = [],
|
|
7
|
-
): JsonRpcRequestType {
|
|
8
|
-
return {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
8
|
+
): Effect.Effect<JsonRpcRequestType, never, IdCounterService> {
|
|
9
|
+
return Effect.gen(function* () {
|
|
10
|
+
const counter = yield* IdCounterService;
|
|
11
|
+
const id = yield* counter.next();
|
|
12
|
+
return {
|
|
13
|
+
jsonrpc: "2.0",
|
|
14
|
+
method,
|
|
15
|
+
params,
|
|
16
|
+
id,
|
|
17
|
+
};
|
|
18
|
+
});
|
|
14
19
|
}
|
|
15
20
|
|
|
16
21
|
export const AccountsRequest = () => makeRequest("eth_accounts");
|
package/src/jsonrpc/Hardhat.ts
CHANGED
|
@@ -1,16 +1,21 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as Effect from "effect/Effect";
|
|
2
|
+
import { IdCounterService } from "./IdCounter.js";
|
|
2
3
|
import type { JsonRpcRequestType } from "./Request.js";
|
|
3
4
|
|
|
4
5
|
function makeRequest(
|
|
5
6
|
method: string,
|
|
6
7
|
params: unknown[] = [],
|
|
7
|
-
): JsonRpcRequestType {
|
|
8
|
-
return {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
8
|
+
): Effect.Effect<JsonRpcRequestType, never, IdCounterService> {
|
|
9
|
+
return Effect.gen(function* () {
|
|
10
|
+
const counter = yield* IdCounterService;
|
|
11
|
+
const id = yield* counter.next();
|
|
12
|
+
return {
|
|
13
|
+
jsonrpc: "2.0",
|
|
14
|
+
method,
|
|
15
|
+
params,
|
|
16
|
+
id,
|
|
17
|
+
};
|
|
18
|
+
});
|
|
14
19
|
}
|
|
15
20
|
|
|
16
21
|
export const ResetRequest = (options?: {
|
package/src/jsonrpc/IdCounter.ts
CHANGED
|
@@ -1,7 +1,23 @@
|
|
|
1
|
-
|
|
1
|
+
import * as Context from "effect/Context";
|
|
2
|
+
import * as Effect from "effect/Effect";
|
|
3
|
+
import * as Layer from "effect/Layer";
|
|
4
|
+
import * as Ref from "effect/Ref";
|
|
2
5
|
|
|
3
|
-
export
|
|
4
|
-
|
|
5
|
-
export const resetId = (): void => {
|
|
6
|
-
idCounter = 0;
|
|
6
|
+
export type IdCounterShape = {
|
|
7
|
+
readonly next: () => Effect.Effect<number>;
|
|
7
8
|
};
|
|
9
|
+
|
|
10
|
+
export class IdCounterService extends Context.Tag("IdCounterService")<
|
|
11
|
+
IdCounterService,
|
|
12
|
+
IdCounterShape
|
|
13
|
+
>() {}
|
|
14
|
+
|
|
15
|
+
export const IdCounterLive: Layer.Layer<IdCounterService> = Layer.effect(
|
|
16
|
+
IdCounterService,
|
|
17
|
+
Effect.gen(function* () {
|
|
18
|
+
const ref = yield* Ref.make(0);
|
|
19
|
+
return {
|
|
20
|
+
next: () => Ref.updateAndGet(ref, (n) => n + 1),
|
|
21
|
+
};
|
|
22
|
+
}),
|
|
23
|
+
);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as Effect from "effect/Effect";
|
|
2
|
-
import {
|
|
2
|
+
import { describe, expect, it } from "vitest";
|
|
3
3
|
import {
|
|
4
4
|
Anvil,
|
|
5
5
|
BatchRequest,
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
EXECUTION_REVERTED,
|
|
11
11
|
ExecutionRevertedError,
|
|
12
12
|
Hardhat,
|
|
13
|
+
IdCounterLive,
|
|
13
14
|
INSUFFICIENT_FUNDS,
|
|
14
15
|
InsufficientFundsError,
|
|
15
16
|
isDisconnected,
|
|
@@ -28,7 +29,6 @@ import {
|
|
|
28
29
|
parseErrorCode,
|
|
29
30
|
Request,
|
|
30
31
|
Response,
|
|
31
|
-
resetId,
|
|
32
32
|
Txpool,
|
|
33
33
|
USER_REJECTED_REQUEST,
|
|
34
34
|
Wallet,
|
|
@@ -66,10 +66,13 @@ describe("JsonRpc", () => {
|
|
|
66
66
|
expect(Request.isNotification(req)).toBe(false);
|
|
67
67
|
});
|
|
68
68
|
|
|
69
|
-
it("withParams adds parameters to request", () => {
|
|
69
|
+
it("withParams adds parameters to request", async () => {
|
|
70
70
|
const base = Request.from({ method: "eth_getBalance", id: 1 });
|
|
71
71
|
const addParams = Request.withParams<[string, string]>(base);
|
|
72
|
-
const
|
|
72
|
+
const program = addParams(["0x1234", "latest"]).pipe(
|
|
73
|
+
Effect.provide(IdCounterLive),
|
|
74
|
+
);
|
|
75
|
+
const req = await Effect.runPromise(program);
|
|
73
76
|
expect(req.params).toEqual(["0x1234", "latest"]);
|
|
74
77
|
});
|
|
75
78
|
|
|
@@ -98,10 +101,13 @@ describe("JsonRpc", () => {
|
|
|
98
101
|
expect(Request.isNotification(req)).toBe(false);
|
|
99
102
|
});
|
|
100
103
|
|
|
101
|
-
it("withParams auto-assigns id when undefined", () => {
|
|
104
|
+
it("withParams auto-assigns id when undefined", async () => {
|
|
102
105
|
const base = Request.from({ method: "eth_getBalance" });
|
|
103
106
|
const addParams = Request.withParams<[string, string]>(base);
|
|
104
|
-
const
|
|
107
|
+
const program = addParams(["0x1234", "latest"]).pipe(
|
|
108
|
+
Effect.provide(IdCounterLive),
|
|
109
|
+
);
|
|
110
|
+
const req = await Effect.runPromise(program);
|
|
105
111
|
expect(req.id).toBeDefined();
|
|
106
112
|
expect(typeof req.id).toBe("number");
|
|
107
113
|
});
|
|
@@ -478,84 +484,123 @@ describe("JsonRpc", () => {
|
|
|
478
484
|
});
|
|
479
485
|
|
|
480
486
|
describe("Eth namespace", () => {
|
|
481
|
-
it("creates GetBalanceRequest", () => {
|
|
482
|
-
const
|
|
487
|
+
it("creates GetBalanceRequest", async () => {
|
|
488
|
+
const program = Eth.GetBalanceRequest("0x1234", "latest").pipe(
|
|
489
|
+
Effect.provide(IdCounterLive),
|
|
490
|
+
);
|
|
491
|
+
const req = await Effect.runPromise(program);
|
|
483
492
|
expect(req.method).toBe("eth_getBalance");
|
|
484
493
|
expect(req.params).toEqual(["0x1234", "latest"]);
|
|
485
494
|
});
|
|
486
495
|
|
|
487
|
-
it("creates BlockNumberRequest", () => {
|
|
488
|
-
const
|
|
496
|
+
it("creates BlockNumberRequest", async () => {
|
|
497
|
+
const program = Eth.BlockNumberRequest().pipe(
|
|
498
|
+
Effect.provide(IdCounterLive),
|
|
499
|
+
);
|
|
500
|
+
const req = await Effect.runPromise(program);
|
|
489
501
|
expect(req.method).toBe("eth_blockNumber");
|
|
490
502
|
});
|
|
491
503
|
|
|
492
|
-
it("creates ChainIdRequest", () => {
|
|
493
|
-
const
|
|
504
|
+
it("creates ChainIdRequest", async () => {
|
|
505
|
+
const program = Eth.ChainIdRequest().pipe(Effect.provide(IdCounterLive));
|
|
506
|
+
const req = await Effect.runPromise(program);
|
|
494
507
|
expect(req.method).toBe("eth_chainId");
|
|
495
508
|
});
|
|
496
509
|
|
|
497
|
-
it("creates CallRequest", () => {
|
|
498
|
-
const
|
|
510
|
+
it("creates CallRequest", async () => {
|
|
511
|
+
const program = Eth.CallRequest(
|
|
512
|
+
{ to: "0xabc", data: "0x123" },
|
|
513
|
+
"latest",
|
|
514
|
+
).pipe(Effect.provide(IdCounterLive));
|
|
515
|
+
const req = await Effect.runPromise(program);
|
|
499
516
|
expect(req.method).toBe("eth_call");
|
|
500
517
|
});
|
|
501
518
|
|
|
502
|
-
it("creates GetBlockByNumberRequest", () => {
|
|
503
|
-
const
|
|
519
|
+
it("creates GetBlockByNumberRequest", async () => {
|
|
520
|
+
const program = Eth.GetBlockByNumberRequest("0x1", false).pipe(
|
|
521
|
+
Effect.provide(IdCounterLive),
|
|
522
|
+
);
|
|
523
|
+
const req = await Effect.runPromise(program);
|
|
504
524
|
expect(req.method).toBe("eth_getBlockByNumber");
|
|
505
525
|
expect(req.params).toEqual(["0x1", false]);
|
|
506
526
|
});
|
|
507
527
|
});
|
|
508
528
|
|
|
509
529
|
describe("Wallet namespace", () => {
|
|
510
|
-
it("creates SwitchEthereumChainRequest", () => {
|
|
511
|
-
const
|
|
530
|
+
it("creates SwitchEthereumChainRequest", async () => {
|
|
531
|
+
const program = Wallet.SwitchEthereumChainRequest("0x1").pipe(
|
|
532
|
+
Effect.provide(IdCounterLive),
|
|
533
|
+
);
|
|
534
|
+
const req = await Effect.runPromise(program);
|
|
512
535
|
expect(req.method).toBe("wallet_switchEthereumChain");
|
|
513
536
|
});
|
|
514
537
|
});
|
|
515
538
|
|
|
516
539
|
describe("Net namespace", () => {
|
|
517
|
-
it("creates VersionRequest", () => {
|
|
518
|
-
const
|
|
540
|
+
it("creates VersionRequest", async () => {
|
|
541
|
+
const program = Net.VersionRequest().pipe(Effect.provide(IdCounterLive));
|
|
542
|
+
const req = await Effect.runPromise(program);
|
|
519
543
|
expect(req.method).toBe("net_version");
|
|
520
544
|
});
|
|
521
545
|
|
|
522
|
-
it("creates ListeningRequest", () => {
|
|
523
|
-
const
|
|
546
|
+
it("creates ListeningRequest", async () => {
|
|
547
|
+
const program = Net.ListeningRequest().pipe(
|
|
548
|
+
Effect.provide(IdCounterLive),
|
|
549
|
+
);
|
|
550
|
+
const req = await Effect.runPromise(program);
|
|
524
551
|
expect(req.method).toBe("net_listening");
|
|
525
552
|
});
|
|
526
553
|
|
|
527
|
-
it("creates PeerCountRequest", () => {
|
|
528
|
-
const
|
|
554
|
+
it("creates PeerCountRequest", async () => {
|
|
555
|
+
const program = Net.PeerCountRequest().pipe(
|
|
556
|
+
Effect.provide(IdCounterLive),
|
|
557
|
+
);
|
|
558
|
+
const req = await Effect.runPromise(program);
|
|
529
559
|
expect(req.method).toBe("net_peerCount");
|
|
530
560
|
});
|
|
531
561
|
});
|
|
532
562
|
|
|
533
563
|
describe("Web3 namespace", () => {
|
|
534
|
-
it("creates ClientVersionRequest", () => {
|
|
535
|
-
const
|
|
564
|
+
it("creates ClientVersionRequest", async () => {
|
|
565
|
+
const program = Web3.ClientVersionRequest().pipe(
|
|
566
|
+
Effect.provide(IdCounterLive),
|
|
567
|
+
);
|
|
568
|
+
const req = await Effect.runPromise(program);
|
|
536
569
|
expect(req.method).toBe("web3_clientVersion");
|
|
537
570
|
});
|
|
538
571
|
|
|
539
|
-
it("creates Sha3Request", () => {
|
|
540
|
-
const
|
|
572
|
+
it("creates Sha3Request", async () => {
|
|
573
|
+
const program = Web3.Sha3Request("0x68656c6c6f").pipe(
|
|
574
|
+
Effect.provide(IdCounterLive),
|
|
575
|
+
);
|
|
576
|
+
const req = await Effect.runPromise(program);
|
|
541
577
|
expect(req.method).toBe("web3_sha3");
|
|
542
578
|
expect(req.params).toEqual(["0x68656c6c6f"]);
|
|
543
579
|
});
|
|
544
580
|
});
|
|
545
581
|
|
|
546
582
|
describe("Txpool namespace", () => {
|
|
547
|
-
it("creates StatusRequest", () => {
|
|
548
|
-
const
|
|
583
|
+
it("creates StatusRequest", async () => {
|
|
584
|
+
const program = Txpool.StatusRequest().pipe(
|
|
585
|
+
Effect.provide(IdCounterLive),
|
|
586
|
+
);
|
|
587
|
+
const req = await Effect.runPromise(program);
|
|
549
588
|
expect(req.method).toBe("txpool_status");
|
|
550
589
|
});
|
|
551
590
|
|
|
552
|
-
it("creates ContentRequest", () => {
|
|
553
|
-
const
|
|
591
|
+
it("creates ContentRequest", async () => {
|
|
592
|
+
const program = Txpool.ContentRequest().pipe(
|
|
593
|
+
Effect.provide(IdCounterLive),
|
|
594
|
+
);
|
|
595
|
+
const req = await Effect.runPromise(program);
|
|
554
596
|
expect(req.method).toBe("txpool_content");
|
|
555
597
|
});
|
|
556
598
|
|
|
557
|
-
it("creates InspectRequest", () => {
|
|
558
|
-
const
|
|
599
|
+
it("creates InspectRequest", async () => {
|
|
600
|
+
const program = Txpool.InspectRequest().pipe(
|
|
601
|
+
Effect.provide(IdCounterLive),
|
|
602
|
+
);
|
|
603
|
+
const req = await Effect.runPromise(program);
|
|
559
604
|
expect(req.method).toBe("txpool_inspect");
|
|
560
605
|
});
|
|
561
606
|
});
|
|
@@ -569,41 +614,61 @@ describe("JsonRpc", () => {
|
|
|
569
614
|
});
|
|
570
615
|
|
|
571
616
|
describe("ID Counter", () => {
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
617
|
+
it("generates unique IDs across namespaces", async () => {
|
|
618
|
+
const program = Effect.gen(function* () {
|
|
619
|
+
const ids = new Set<number>();
|
|
620
|
+
|
|
621
|
+
// Generate requests from multiple namespaces
|
|
622
|
+
const req1 = yield* Eth.BlockNumberRequest();
|
|
623
|
+
ids.add(req1.id as number);
|
|
624
|
+
const req2 = yield* Eth.ChainIdRequest();
|
|
625
|
+
ids.add(req2.id as number);
|
|
626
|
+
const req3 = yield* Net.VersionRequest();
|
|
627
|
+
ids.add(req3.id as number);
|
|
628
|
+
const req4 = yield* Web3.ClientVersionRequest();
|
|
629
|
+
ids.add(req4.id as number);
|
|
630
|
+
const req5 = yield* Txpool.StatusRequest();
|
|
631
|
+
ids.add(req5.id as number);
|
|
632
|
+
const req6 = yield* Wallet.GetPermissionsRequest();
|
|
633
|
+
ids.add(req6.id as number);
|
|
634
|
+
const req7 = yield* Anvil.GetAutomineRequest();
|
|
635
|
+
ids.add(req7.id as number);
|
|
636
|
+
const req8 = yield* Hardhat.MineRequest();
|
|
637
|
+
ids.add(req8.id as number);
|
|
638
|
+
|
|
639
|
+
return ids;
|
|
640
|
+
}).pipe(Effect.provide(IdCounterLive));
|
|
641
|
+
|
|
642
|
+
const ids = await Effect.runPromise(program);
|
|
589
643
|
// All 8 IDs should be unique
|
|
590
644
|
expect(ids.size).toBe(8);
|
|
591
645
|
});
|
|
592
646
|
|
|
593
|
-
it("increments IDs sequentially", () => {
|
|
594
|
-
const
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
647
|
+
it("increments IDs sequentially", async () => {
|
|
648
|
+
const program = Effect.gen(function* () {
|
|
649
|
+
const req1 = yield* Eth.BlockNumberRequest();
|
|
650
|
+
const req2 = yield* Net.VersionRequest();
|
|
651
|
+
const req3 = yield* Web3.ClientVersionRequest();
|
|
652
|
+
|
|
653
|
+
return {
|
|
654
|
+
id1: req1.id as number,
|
|
655
|
+
id2: req2.id as number,
|
|
656
|
+
id3: req3.id as number,
|
|
657
|
+
};
|
|
658
|
+
}).pipe(Effect.provide(IdCounterLive));
|
|
659
|
+
|
|
660
|
+
const { id1, id2, id3 } = await Effect.runPromise(program);
|
|
598
661
|
expect(id2).toBe(id1 + 1);
|
|
599
662
|
expect(id3).toBe(id2 + 1);
|
|
600
663
|
});
|
|
601
664
|
|
|
602
|
-
it("
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
665
|
+
it("isolated counter starts fresh", async () => {
|
|
666
|
+
const program = Effect.gen(function* () {
|
|
667
|
+
const req = yield* Eth.BlockNumberRequest();
|
|
668
|
+
return req.id as number;
|
|
669
|
+
}).pipe(Effect.provide(IdCounterLive));
|
|
670
|
+
|
|
671
|
+
const id = await Effect.runPromise(program);
|
|
607
672
|
expect(id).toBe(1);
|
|
608
673
|
});
|
|
609
674
|
});
|
package/src/jsonrpc/Net.ts
CHANGED
|
@@ -1,16 +1,21 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as Effect from "effect/Effect";
|
|
2
|
+
import { IdCounterService } from "./IdCounter.js";
|
|
2
3
|
import type { JsonRpcRequestType } from "./Request.js";
|
|
3
4
|
|
|
4
5
|
function makeRequest(
|
|
5
6
|
method: string,
|
|
6
7
|
params: unknown[] = [],
|
|
7
|
-
): JsonRpcRequestType {
|
|
8
|
-
return {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
8
|
+
): Effect.Effect<JsonRpcRequestType, never, IdCounterService> {
|
|
9
|
+
return Effect.gen(function* () {
|
|
10
|
+
const counter = yield* IdCounterService;
|
|
11
|
+
const id = yield* counter.next();
|
|
12
|
+
return {
|
|
13
|
+
jsonrpc: "2.0",
|
|
14
|
+
method,
|
|
15
|
+
params,
|
|
16
|
+
id,
|
|
17
|
+
};
|
|
18
|
+
});
|
|
14
19
|
}
|
|
15
20
|
|
|
16
21
|
export const VersionRequest = () => makeRequest("net_version");
|
package/src/jsonrpc/Request.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as Effect from "effect/Effect";
|
|
2
|
+
import { IdCounterService } from "./IdCounter.js";
|
|
2
3
|
|
|
3
4
|
export type JsonRpcIdType = number | string | null;
|
|
4
5
|
|
|
@@ -28,13 +29,20 @@ export function isNotification(request: JsonRpcRequestType): boolean {
|
|
|
28
29
|
|
|
29
30
|
export function withParams<TParams>(
|
|
30
31
|
request: JsonRpcRequestType,
|
|
31
|
-
): (
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
32
|
+
): (
|
|
33
|
+
params: TParams,
|
|
34
|
+
) => Effect.Effect<JsonRpcRequestType<TParams>, never, IdCounterService> {
|
|
35
|
+
return (params: TParams) =>
|
|
36
|
+
Effect.gen(function* () {
|
|
37
|
+
const counter = yield* IdCounterService;
|
|
38
|
+
const id = request.id ?? (yield* counter.next());
|
|
39
|
+
return {
|
|
40
|
+
jsonrpc: "2.0",
|
|
41
|
+
method: request.method,
|
|
42
|
+
params,
|
|
43
|
+
id,
|
|
44
|
+
};
|
|
45
|
+
});
|
|
38
46
|
}
|
|
39
47
|
|
|
40
48
|
export const Request = {
|