@prb/effect-evm 1.0.0-beta.1 → 1.0.0-beta.3
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/abi/erc165.js.map +1 -1
- package/dist/abi/erc20-no-output.js.map +1 -1
- package/dist/abi/erc20.js.map +1 -1
- package/dist/abi/erc721.js.map +1 -1
- package/dist/abi/index.js.map +1 -1
- package/dist/balance/index.js.map +1 -1
- package/dist/balance/service.js.map +1 -1
- package/dist/balance/service.test.integration.d.ts +2 -0
- package/dist/balance/service.test.integration.d.ts.map +1 -0
- package/dist/balance/service.test.integration.js +289 -0
- package/dist/balance/service.test.integration.js.map +1 -0
- package/dist/balance/utils.js.map +1 -1
- package/dist/block/errors.js.map +1 -1
- package/dist/block/index.js.map +1 -1
- package/dist/block/service.js.map +1 -1
- package/dist/block/service.test.integration.d.ts +2 -0
- package/dist/block/service.test.integration.d.ts.map +1 -0
- package/dist/block/service.test.integration.js +190 -0
- package/dist/block/service.test.integration.js.map +1 -0
- package/dist/constants/index.js.map +1 -1
- package/dist/contract/cross-chain-reader.js.map +1 -1
- package/dist/contract/index.js.map +1 -1
- package/dist/contract/pipeline/index.js.map +1 -1
- package/dist/contract/pipeline/internal/core.js.map +1 -1
- package/dist/contract/pipeline/internal/helpers.js.map +1 -1
- package/dist/contract/pipeline/internal/nonce.js.map +1 -1
- package/dist/contract/pipeline/internal/prepare.js.map +1 -1
- package/dist/contract/pipeline/internal/receipt.js.map +1 -1
- package/dist/contract/pipeline/live.js.map +1 -1
- package/dist/contract/pipeline/service.js.map +1 -1
- package/dist/contract/pipeline/types.js.map +1 -1
- package/dist/contract/pipeline/write-and-track.js.map +1 -1
- package/dist/contract/pipeline/write-and-wait.js.map +1 -1
- package/dist/contract/pipeline.js.map +1 -1
- package/dist/contract/reader.js.map +1 -1
- package/dist/contract/typed-contract.js.map +1 -1
- package/dist/contract/writer.js.map +1 -1
- package/dist/core/clients/index.js.map +1 -1
- package/dist/core/clients/public-client.js.map +1 -1
- package/dist/core/clients/wallet-client.js.map +1 -1
- package/dist/core/errors/client.js.map +1 -1
- package/dist/core/errors/contract.js.map +1 -1
- package/dist/core/errors/erc20.js.map +1 -1
- package/dist/core/errors/event.js.map +1 -1
- package/dist/core/errors/index.js.map +1 -1
- package/dist/core/errors/predicates.js.map +1 -1
- package/dist/core/errors/transaction.js.map +1 -1
- package/dist/core/errors/viem-mapper.d.ts.map +1 -1
- package/dist/core/errors/viem-mapper.js +11 -2
- package/dist/core/errors/viem-mapper.js.map +1 -1
- package/dist/core/index.js.map +1 -1
- package/dist/deploy/errors.js.map +1 -1
- package/dist/deploy/index.js.map +1 -1
- package/dist/deploy/service.js.map +1 -1
- package/dist/eip7702/erc7579.js.map +1 -1
- package/dist/eip7702/errors.js.map +1 -1
- package/dist/eip7702/index.js.map +1 -1
- package/dist/eip7702/service.js.map +1 -1
- package/dist/ens/ens.js.map +1 -1
- package/dist/ens/errors.js.map +1 -1
- package/dist/ens/index.js.map +1 -1
- package/dist/erc20/allowance/core.js.map +1 -1
- package/dist/erc20/allowance/index.js.map +1 -1
- package/dist/erc20/allowance/no-output.js.map +1 -1
- package/dist/erc20/allowance/types.js.map +1 -1
- package/dist/erc20/index.d.ts +1 -0
- package/dist/erc20/index.d.ts.map +1 -1
- package/dist/erc20/index.js +1 -0
- package/dist/erc20/index.js.map +1 -1
- package/dist/erc20/metadata.d.ts +16 -0
- package/dist/erc20/metadata.d.ts.map +1 -0
- package/dist/erc20/metadata.js +67 -0
- package/dist/erc20/metadata.js.map +1 -0
- package/dist/erc721/errors.js.map +1 -1
- package/dist/erc721/helpers.js.map +1 -1
- package/dist/erc721/index.js.map +1 -1
- package/dist/erc721/metadata.js.map +1 -1
- package/dist/erc721/service.js.map +1 -1
- package/dist/events/backfill.js.map +1 -1
- package/dist/events/backfill.test.integration.d.ts +2 -0
- package/dist/events/backfill.test.integration.d.ts.map +1 -0
- package/dist/events/backfill.test.integration.js +112 -0
- package/dist/events/backfill.test.integration.js.map +1 -0
- package/dist/events/cursor.js.map +1 -1
- package/dist/events/decoder.js.map +1 -1
- package/dist/events/index.js.map +1 -1
- package/dist/events/reliable-stream-simple.test.integration.d.ts +2 -0
- package/dist/events/reliable-stream-simple.test.integration.d.ts.map +1 -0
- package/dist/events/reliable-stream-simple.test.integration.js +22 -0
- package/dist/events/reliable-stream-simple.test.integration.js.map +1 -0
- package/dist/events/reliable-stream.js.map +1 -1
- package/dist/events/reliable-stream.test.integration.d.ts +2 -0
- package/dist/events/reliable-stream.test.integration.d.ts.map +1 -0
- package/dist/events/reliable-stream.test.integration.js +327 -0
- package/dist/events/reliable-stream.test.integration.js.map +1 -0
- package/dist/events/stream.js.map +1 -1
- package/dist/events/stream.test.integration.d.ts +2 -0
- package/dist/events/stream.test.integration.d.ts.map +1 -0
- package/dist/events/stream.test.integration.js +120 -0
- package/dist/events/stream.test.integration.js.map +1 -0
- package/dist/gas/errors.js.map +1 -1
- package/dist/gas/estimator.js.map +1 -1
- package/dist/gas/index.js.map +1 -1
- package/dist/gas/service.js.map +1 -1
- package/dist/gas/service.test.integration.d.ts +2 -0
- package/dist/gas/service.test.integration.d.ts.map +1 -0
- package/dist/gas/service.test.integration.js +128 -0
- package/dist/gas/service.test.integration.js.map +1 -0
- package/dist/index.js.map +1 -1
- package/dist/integrations/react-hooks/convenience/index.js.map +1 -1
- package/dist/integrations/react-hooks/internal/error.js.map +1 -1
- package/dist/integrations/react-hooks/internal/is-dev.js.map +1 -1
- package/dist/integrations/react-hooks/internal/runtime.js.map +1 -1
- package/dist/integrations/react-hooks/internal/scoped-run.js.map +1 -1
- package/dist/integrations/react-hooks/internal/stable.js.map +1 -1
- package/dist/integrations/react-hooks/primitives/use-effect-memo-factory.js.map +1 -1
- package/dist/integrations/react-hooks/primitives/use-effect.js.map +1 -1
- package/dist/integrations/react-hooks/primitives/use-fork-effect.js.map +1 -1
- package/dist/integrations/react-hooks/primitives/use-stream.js.map +1 -1
- package/dist/integrations/react-hooks/primitives.js.map +1 -1
- package/dist/integrations/react-hooks/provider.js.map +1 -1
- package/dist/integrations/react-hooks/wagmi/index.js.map +1 -1
- package/dist/integrations/react-hooks/wallet-provider-ref.js.map +1 -1
- package/dist/integrations/wagmi/index.js.map +1 -1
- package/dist/integrations/wagmi/layers.js.map +1 -1
- package/dist/internal/index.js.map +1 -1
- package/dist/internal/numbers.js.map +1 -1
- package/dist/internal/schedule.js.map +1 -1
- package/dist/internal/stream-adapters.js.map +1 -1
- package/dist/internal/viem-effect.js.map +1 -1
- package/dist/nonce/index.js.map +1 -1
- package/dist/nonce/manager.js.map +1 -1
- package/dist/nonce/service.js.map +1 -1
- package/dist/nonce/service.test.integration.d.ts +2 -0
- package/dist/nonce/service.test.integration.d.ts.map +1 -0
- package/dist/nonce/service.test.integration.js +141 -0
- package/dist/nonce/service.test.integration.js.map +1 -0
- package/dist/platform/browser/cursor-store/index.js.map +1 -1
- package/dist/platform/browser/cursor-store/local-storage.js.map +1 -1
- package/dist/platform/browser/index.js.map +1 -1
- package/dist/platform/browser/layers.js.map +1 -1
- package/dist/platform/browser/storage/errors.js.map +1 -1
- package/dist/platform/browser/storage/index.js.map +1 -1
- package/dist/platform/browser/storage/local-storage.js.map +1 -1
- package/dist/platform/browser/tx-persistence/index.js.map +1 -1
- package/dist/platform/browser/tx-persistence/persistence.js.map +1 -1
- package/dist/platform/browser/tx-store/errors.js.map +1 -1
- package/dist/platform/browser/tx-store/index.js.map +1 -1
- package/dist/platform/browser/tx-store/local-storage.js.map +1 -1
- package/dist/platform/browser/tx-store/store.js.map +1 -1
- package/dist/platform/browser/tx-store/types.js.map +1 -1
- package/dist/presets/index.js.map +1 -1
- package/dist/presets/layers.js.map +1 -1
- package/dist/presets/transports.js.map +1 -1
- package/dist/query/chain-head.js.map +1 -1
- package/dist/query/client.js.map +1 -1
- package/dist/query/client.test.integration.d.ts +2 -0
- package/dist/query/client.test.integration.d.ts.map +1 -0
- package/dist/query/client.test.integration.js +94 -0
- package/dist/query/client.test.integration.js.map +1 -0
- package/dist/query/contract-query.js.map +1 -1
- package/dist/query/contract-query.test.integration.d.ts +2 -0
- package/dist/query/contract-query.test.integration.d.ts.map +1 -0
- package/dist/query/contract-query.test.integration.js +133 -0
- package/dist/query/contract-query.test.integration.js.map +1 -0
- package/dist/query/index.js.map +1 -1
- package/dist/query/multicall-batcher.js.map +1 -1
- package/dist/react-hooks/index.js.map +1 -1
- package/dist/react-hooks/use-is-safe-multisig.js.map +1 -1
- package/dist/react-hooks/use-safe-context.js.map +1 -1
- package/dist/react-hooks/wagmi/index.js.map +1 -1
- package/dist/rpc/cache.js.map +1 -1
- package/dist/rpc/circuit-breaker.js.map +1 -1
- package/dist/rpc/dedup.js.map +1 -1
- package/dist/rpc/index.js.map +1 -1
- package/dist/rpc/retry.js.map +1 -1
- package/dist/rpc/routemesh.js.map +1 -1
- package/dist/safe/adapter.js.map +1 -1
- package/dist/safe/detection.js.map +1 -1
- package/dist/safe/detection.test.integration.d.ts +2 -0
- package/dist/safe/detection.test.integration.d.ts.map +1 -0
- package/dist/safe/detection.test.integration.js +92 -0
- package/dist/safe/detection.test.integration.js.map +1 -0
- package/dist/safe/errors.js.map +1 -1
- package/dist/safe/index.js.map +1 -1
- package/dist/safe/live.js.map +1 -1
- package/dist/safe/service.js.map +1 -1
- package/dist/safe/service.test.integration.d.ts +2 -0
- package/dist/safe/service.test.integration.d.ts.map +1 -0
- package/dist/safe/service.test.integration.js +173 -0
- package/dist/safe/service.test.integration.js.map +1 -0
- package/dist/safe/simulation/abis.js.map +1 -1
- package/dist/safe/simulation/addresses.js.map +1 -1
- package/dist/safe/simulation/encoding.js.map +1 -1
- package/dist/safe/simulation/errors.d.ts +3 -3
- package/dist/safe/simulation/errors.js +1 -1
- package/dist/safe/simulation/errors.js.map +1 -1
- package/dist/safe/simulation/index.d.ts +1 -1
- package/dist/safe/simulation/index.js +1 -1
- package/dist/safe/simulation/index.js.map +1 -1
- package/dist/safe/simulation/service.d.ts +2 -2
- package/dist/safe/simulation/service.js +2 -2
- package/dist/safe/simulation/service.js.map +1 -1
- package/dist/safe/simulation/types.js.map +1 -1
- package/dist/safe/types.js.map +1 -1
- package/dist/signature/errors.js.map +1 -1
- package/dist/signature/index.js.map +1 -1
- package/dist/signature/service.js.map +1 -1
- package/dist/signature/service.test.integration.d.ts +2 -0
- package/dist/signature/service.test.integration.d.ts.map +1 -0
- package/dist/signature/service.test.integration.js +179 -0
- package/dist/signature/service.test.integration.js.map +1 -0
- package/dist/signature/utils.js.map +1 -1
- package/dist/simulation/errors.js.map +1 -1
- package/dist/simulation/index.js.map +1 -1
- package/dist/simulation/service.js.map +1 -1
- package/dist/simulation/tenderly.js.map +1 -1
- package/dist/simulation/tenderly.test.integration.d.ts +2 -0
- package/dist/simulation/tenderly.test.integration.d.ts.map +1 -0
- package/dist/simulation/tenderly.test.integration.js +104 -0
- package/dist/simulation/tenderly.test.integration.js.map +1 -0
- package/dist/simulation/types.js.map +1 -1
- package/dist/subscriptions/block-subscription.js.map +1 -1
- package/dist/subscriptions/errors.js.map +1 -1
- package/dist/subscriptions/index.js.map +1 -1
- package/dist/subscriptions/log-subscription.js.map +1 -1
- package/dist/subscriptions/pending-tx.js.map +1 -1
- package/dist/subscriptions/service.js.map +1 -1
- package/dist/telemetry/index.js.map +1 -1
- package/dist/telemetry/logger.js.map +1 -1
- package/dist/telemetry/tracer.js.map +1 -1
- package/dist/testing-kit/_fixtures/addresses.js.map +1 -1
- package/dist/testing-kit/_fixtures/receipts.js.map +1 -1
- package/dist/testing-kit/helpers.js.map +1 -1
- package/dist/testing-kit/index.js.map +1 -1
- package/dist/testing-kit/mock-balance-service.js.map +1 -1
- package/dist/testing-kit/mock-block-service.js.map +1 -1
- package/dist/testing-kit/mock-cross-chain-reader.js.map +1 -1
- package/dist/testing-kit/mock-deploy-service.js.map +1 -1
- package/dist/testing-kit/mock-erc721-service.js.map +1 -1
- package/dist/testing-kit/mock-gas-service.js.map +1 -1
- package/dist/testing-kit/mock-nonce-service.js.map +1 -1
- package/dist/testing-kit/mock-public-client.js.map +1 -1
- package/dist/testing-kit/mock-signature-service.js.map +1 -1
- package/dist/testing-kit/mock-simulation-service.js.map +1 -1
- package/dist/testing-kit/mock-subscription-service.js.map +1 -1
- package/dist/testing-kit/mock-transfer-service.js.map +1 -1
- package/dist/testing-kit/mock-wallet-client.js.map +1 -1
- package/dist/testing-kit/mock-wallet-provider.js.map +1 -1
- package/dist/testing-kit/test-layer.js.map +1 -1
- package/dist/transfer/index.js.map +1 -1
- package/dist/transfer/service.js.map +1 -1
- package/dist/tx/fees.js.map +1 -1
- package/dist/tx/index.js.map +1 -1
- package/dist/tx/manager.js.map +1 -1
- package/dist/tx/manager.test.integration.d.ts +2 -0
- package/dist/tx/manager.test.integration.d.ts.map +1 -0
- package/dist/tx/manager.test.integration.js +157 -0
- package/dist/tx/manager.test.integration.js.map +1 -0
- package/dist/tx/policy.js.map +1 -1
- package/dist/tx/replacement.js.map +1 -1
- package/dist/tx/tracker.js.map +1 -1
- package/dist/types/abi.js.map +1 -1
- package/dist/types/index.js.map +1 -1
- package/dist/types/params.js.map +1 -1
- package/dist/types/tx-overrides.js.map +1 -1
- package/dist/wagmi/index.js.map +1 -1
- package/dist/wagmi/layers.js.map +1 -1
- package/dist/wallet/errors.js.map +1 -1
- package/dist/wallet/index.js.map +1 -1
- package/dist/wallet/lifecycle.js.map +1 -1
- package/dist/wallet/operations.js.map +1 -1
- package/dist/wallet/provider-ref.js.map +1 -1
- package/dist/wallet/service.js.map +1 -1
- package/dist/wallet/types.js.map +1 -1
- package/package.json +25 -9
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { describe, expect, it } from "@effect/vitest";
|
|
2
|
+
import { Effect, Layer, Stream } from "effect";
|
|
3
|
+
import { erc20Abi } from "viem";
|
|
4
|
+
import { ContractReader } from "../contract/index.js";
|
|
5
|
+
import { ChainHead, ContractQuery, ContractQueryLive, MulticallBatcherLive, QueryClientLive, } from "../query/index.js";
|
|
6
|
+
import { makeRpcCacheLive, RequestDedupLive } from "../rpc/index.js";
|
|
7
|
+
import { TEST_ADDRESS, TEST_ADDRESS_2, TEST_CHAIN_ID } from "../testing-kit/index.js";
|
|
8
|
+
describe("ContractQuery", () => {
|
|
9
|
+
it.effect("batches concurrent reads into a single multicall", () => Effect.gen(function* () {
|
|
10
|
+
let multicallCount = 0;
|
|
11
|
+
let lastBatchSize = 0;
|
|
12
|
+
const contractReaderLayer = Layer.succeed(ContractReader, ContractReader.of({
|
|
13
|
+
multicall: (_chainId, calls) => {
|
|
14
|
+
multicallCount += 1;
|
|
15
|
+
lastBatchSize = calls.length;
|
|
16
|
+
return Effect.succeed(calls.map((_, i) => ({
|
|
17
|
+
result: BigInt(i + 1),
|
|
18
|
+
status: "success",
|
|
19
|
+
})));
|
|
20
|
+
},
|
|
21
|
+
read: () => Effect.succeed(0n),
|
|
22
|
+
}));
|
|
23
|
+
const chainHeadLayer = Layer.succeed(ChainHead, ChainHead.of({
|
|
24
|
+
current: () => Effect.succeed(1n),
|
|
25
|
+
watch: () => Effect.succeed(Stream.empty),
|
|
26
|
+
}));
|
|
27
|
+
const queryClientLayer = Layer.provideMerge(QueryClientLive, Layer.mergeAll(chainHeadLayer, makeRpcCacheLive({ ttl: 60_000 }), RequestDedupLive));
|
|
28
|
+
const multicallBatcherLayer = Layer.provideMerge(MulticallBatcherLive, contractReaderLayer);
|
|
29
|
+
const contractQueryLayer = Layer.provide(ContractQueryLive, Layer.mergeAll(queryClientLayer, multicallBatcherLayer));
|
|
30
|
+
const contractQuery = yield* ContractQuery.pipe(Effect.provide(contractQueryLayer));
|
|
31
|
+
const [r1, r2, r3] = yield* Effect.all([
|
|
32
|
+
contractQuery.read({
|
|
33
|
+
abi: erc20Abi,
|
|
34
|
+
address: TEST_ADDRESS,
|
|
35
|
+
args: [TEST_ADDRESS],
|
|
36
|
+
chainId: TEST_CHAIN_ID,
|
|
37
|
+
functionName: "balanceOf",
|
|
38
|
+
}),
|
|
39
|
+
contractQuery.read({
|
|
40
|
+
abi: erc20Abi,
|
|
41
|
+
address: TEST_ADDRESS,
|
|
42
|
+
args: [TEST_ADDRESS_2],
|
|
43
|
+
chainId: TEST_CHAIN_ID,
|
|
44
|
+
functionName: "balanceOf",
|
|
45
|
+
}),
|
|
46
|
+
contractQuery.read({
|
|
47
|
+
abi: erc20Abi,
|
|
48
|
+
address: TEST_ADDRESS,
|
|
49
|
+
chainId: TEST_CHAIN_ID,
|
|
50
|
+
functionName: "totalSupply",
|
|
51
|
+
}),
|
|
52
|
+
], { batching: true, concurrency: 3 });
|
|
53
|
+
expect(r1).toBe(1n);
|
|
54
|
+
expect(r2).toBe(2n);
|
|
55
|
+
expect(r3).toBe(3n);
|
|
56
|
+
expect(multicallCount).toBe(1);
|
|
57
|
+
expect(lastBatchSize).toBe(3);
|
|
58
|
+
}).pipe(Effect.scoped));
|
|
59
|
+
it.effect("caches identical reads (no additional multicall)", () => Effect.gen(function* () {
|
|
60
|
+
let multicallCount = 0;
|
|
61
|
+
const contractReaderLayer = Layer.succeed(ContractReader, ContractReader.of({
|
|
62
|
+
multicall: (_chainId, calls) => {
|
|
63
|
+
multicallCount += 1;
|
|
64
|
+
return Effect.succeed(calls.map(() => ({
|
|
65
|
+
result: 123n,
|
|
66
|
+
status: "success",
|
|
67
|
+
})));
|
|
68
|
+
},
|
|
69
|
+
read: () => Effect.succeed(0n),
|
|
70
|
+
}));
|
|
71
|
+
const chainHeadLayer = Layer.succeed(ChainHead, ChainHead.of({
|
|
72
|
+
current: () => Effect.succeed(1n),
|
|
73
|
+
watch: () => Effect.succeed(Stream.empty),
|
|
74
|
+
}));
|
|
75
|
+
const queryClientLayer = Layer.provideMerge(QueryClientLive, Layer.mergeAll(chainHeadLayer, makeRpcCacheLive({ ttl: 60_000 }), RequestDedupLive));
|
|
76
|
+
const multicallBatcherLayer = Layer.provideMerge(MulticallBatcherLive, contractReaderLayer);
|
|
77
|
+
const contractQueryLayer = Layer.provide(ContractQueryLive, Layer.mergeAll(queryClientLayer, multicallBatcherLayer));
|
|
78
|
+
const contractQuery = yield* ContractQuery.pipe(Effect.provide(contractQueryLayer));
|
|
79
|
+
const params = {
|
|
80
|
+
abi: erc20Abi,
|
|
81
|
+
address: TEST_ADDRESS,
|
|
82
|
+
args: [TEST_ADDRESS],
|
|
83
|
+
chainId: TEST_CHAIN_ID,
|
|
84
|
+
functionName: "balanceOf",
|
|
85
|
+
};
|
|
86
|
+
const r1 = yield* contractQuery.read(params);
|
|
87
|
+
const r2 = yield* contractQuery.read(params);
|
|
88
|
+
expect(r1).toBe(123n);
|
|
89
|
+
expect(r2).toBe(123n);
|
|
90
|
+
expect(multicallCount).toBe(1);
|
|
91
|
+
}).pipe(Effect.scoped));
|
|
92
|
+
it.effect("does not crash when args contain BigInt (cache key)", () => Effect.gen(function* () {
|
|
93
|
+
let multicallCount = 0;
|
|
94
|
+
const bigintArgAbi = [
|
|
95
|
+
{
|
|
96
|
+
inputs: [{ name: "x", type: "uint256" }],
|
|
97
|
+
name: "echo",
|
|
98
|
+
outputs: [{ name: "y", type: "uint256" }],
|
|
99
|
+
stateMutability: "view",
|
|
100
|
+
type: "function",
|
|
101
|
+
},
|
|
102
|
+
];
|
|
103
|
+
const contractReaderLayer = Layer.succeed(ContractReader, ContractReader.of({
|
|
104
|
+
multicall: (_chainId, calls) => {
|
|
105
|
+
multicallCount += 1;
|
|
106
|
+
expect(calls).toHaveLength(1);
|
|
107
|
+
return Effect.succeed([{ result: 456n, status: "success" }]);
|
|
108
|
+
},
|
|
109
|
+
read: () => Effect.succeed(0n),
|
|
110
|
+
}));
|
|
111
|
+
const chainHeadLayer = Layer.succeed(ChainHead, ChainHead.of({
|
|
112
|
+
current: () => Effect.succeed(1n),
|
|
113
|
+
watch: () => Effect.succeed(Stream.empty),
|
|
114
|
+
}));
|
|
115
|
+
const queryClientLayer = Layer.provideMerge(QueryClientLive, Layer.mergeAll(chainHeadLayer, makeRpcCacheLive({ ttl: 60_000 }), RequestDedupLive));
|
|
116
|
+
const multicallBatcherLayer = Layer.provideMerge(MulticallBatcherLive, contractReaderLayer);
|
|
117
|
+
const contractQueryLayer = Layer.provide(ContractQueryLive, Layer.mergeAll(queryClientLayer, multicallBatcherLayer));
|
|
118
|
+
const contractQuery = yield* ContractQuery.pipe(Effect.provide(contractQueryLayer));
|
|
119
|
+
const params = {
|
|
120
|
+
abi: bigintArgAbi,
|
|
121
|
+
address: TEST_ADDRESS,
|
|
122
|
+
args: [1n],
|
|
123
|
+
chainId: TEST_CHAIN_ID,
|
|
124
|
+
functionName: "echo",
|
|
125
|
+
};
|
|
126
|
+
const r1 = yield* contractQuery.read(params);
|
|
127
|
+
const r2 = yield* contractQuery.read(params);
|
|
128
|
+
expect(r1).toBe(456n);
|
|
129
|
+
expect(r2).toBe(456n);
|
|
130
|
+
expect(multicallCount).toBe(1);
|
|
131
|
+
}).pipe(Effect.scoped));
|
|
132
|
+
});
|
|
133
|
+
//# sourceMappingURL=contract-query.test.integration.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contract-query.test.integration.js","sourceRoot":"","sources":["../../src/query/contract-query.test.integration.ts"],"names":[],"mappings":"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","sourcesContent":["import { describe, expect, it } from \"@effect/vitest\";\nimport { Effect, Layer, Stream } from \"effect\";\nimport type { Abi } from \"viem\";\nimport { erc20Abi } from \"viem\";\nimport { ContractReader } from \"@/src/contract/index.js\";\nimport {\n ChainHead,\n ContractQuery,\n ContractQueryLive,\n MulticallBatcherLive,\n QueryClientLive,\n} from \"@/src/query/index.js\";\nimport { makeRpcCacheLive, RequestDedupLive } from \"@/src/rpc/index.js\";\nimport { TEST_ADDRESS, TEST_ADDRESS_2, TEST_CHAIN_ID } from \"@/src/testing-kit/index.js\";\n\ndescribe(\"ContractQuery\", () => {\n it.effect(\"batches concurrent reads into a single multicall\", () =>\n Effect.gen(function* () {\n let multicallCount = 0;\n let lastBatchSize = 0;\n\n const contractReaderLayer = Layer.succeed(\n ContractReader,\n ContractReader.of({\n multicall: (_chainId, calls) => {\n multicallCount += 1;\n lastBatchSize = calls.length;\n return Effect.succeed(\n calls.map((_, i) => ({\n result: BigInt(i + 1),\n status: \"success\" as const,\n })) as any\n );\n },\n read: () => Effect.succeed(0n as any),\n })\n );\n\n const chainHeadLayer = Layer.succeed(\n ChainHead,\n ChainHead.of({\n current: () => Effect.succeed(1n),\n watch: () => Effect.succeed(Stream.empty),\n })\n );\n\n const queryClientLayer = Layer.provideMerge(\n QueryClientLive,\n Layer.mergeAll(chainHeadLayer, makeRpcCacheLive({ ttl: 60_000 }), RequestDedupLive)\n );\n\n const multicallBatcherLayer = Layer.provideMerge(MulticallBatcherLive, contractReaderLayer);\n\n const contractQueryLayer = Layer.provide(\n ContractQueryLive,\n Layer.mergeAll(queryClientLayer, multicallBatcherLayer)\n );\n\n const contractQuery = yield* ContractQuery.pipe(Effect.provide(contractQueryLayer));\n\n // Use batching: true to enable request batching for concurrent effects\n const [r1, r2, r3] = yield* Effect.all(\n [\n contractQuery.read({\n abi: erc20Abi,\n address: TEST_ADDRESS,\n args: [TEST_ADDRESS] as const,\n chainId: TEST_CHAIN_ID,\n functionName: \"balanceOf\",\n }),\n contractQuery.read({\n abi: erc20Abi,\n address: TEST_ADDRESS,\n args: [TEST_ADDRESS_2] as const,\n chainId: TEST_CHAIN_ID,\n functionName: \"balanceOf\",\n }),\n contractQuery.read({\n abi: erc20Abi,\n address: TEST_ADDRESS,\n chainId: TEST_CHAIN_ID,\n functionName: \"totalSupply\",\n }),\n ],\n { batching: true, concurrency: 3 }\n );\n\n expect(r1).toBe(1n);\n expect(r2).toBe(2n);\n expect(r3).toBe(3n);\n expect(multicallCount).toBe(1);\n expect(lastBatchSize).toBe(3);\n }).pipe(Effect.scoped)\n );\n\n it.effect(\"caches identical reads (no additional multicall)\", () =>\n Effect.gen(function* () {\n let multicallCount = 0;\n\n const contractReaderLayer = Layer.succeed(\n ContractReader,\n ContractReader.of({\n multicall: (_chainId, calls) => {\n multicallCount += 1;\n return Effect.succeed(\n calls.map(() => ({\n result: 123n,\n status: \"success\" as const,\n })) as any\n );\n },\n read: () => Effect.succeed(0n as any),\n })\n );\n\n const chainHeadLayer = Layer.succeed(\n ChainHead,\n ChainHead.of({\n current: () => Effect.succeed(1n),\n watch: () => Effect.succeed(Stream.empty),\n })\n );\n\n const queryClientLayer = Layer.provideMerge(\n QueryClientLive,\n Layer.mergeAll(chainHeadLayer, makeRpcCacheLive({ ttl: 60_000 }), RequestDedupLive)\n );\n\n const multicallBatcherLayer = Layer.provideMerge(MulticallBatcherLive, contractReaderLayer);\n\n const contractQueryLayer = Layer.provide(\n ContractQueryLive,\n Layer.mergeAll(queryClientLayer, multicallBatcherLayer)\n );\n\n const contractQuery = yield* ContractQuery.pipe(Effect.provide(contractQueryLayer));\n\n const params = {\n abi: erc20Abi,\n address: TEST_ADDRESS,\n args: [TEST_ADDRESS] as const,\n chainId: TEST_CHAIN_ID,\n functionName: \"balanceOf\" as const,\n };\n\n const r1 = yield* contractQuery.read(params);\n const r2 = yield* contractQuery.read(params);\n\n expect(r1).toBe(123n);\n expect(r2).toBe(123n);\n expect(multicallCount).toBe(1);\n }).pipe(Effect.scoped)\n );\n\n it.effect(\"does not crash when args contain BigInt (cache key)\", () =>\n Effect.gen(function* () {\n let multicallCount = 0;\n\n const bigintArgAbi = [\n {\n inputs: [{ name: \"x\", type: \"uint256\" }],\n name: \"echo\",\n outputs: [{ name: \"y\", type: \"uint256\" }],\n stateMutability: \"view\",\n type: \"function\",\n },\n ] as const satisfies Abi;\n\n const contractReaderLayer = Layer.succeed(\n ContractReader,\n ContractReader.of({\n multicall: (_chainId, calls) => {\n multicallCount += 1;\n expect(calls).toHaveLength(1);\n return Effect.succeed([{ result: 456n, status: \"success\" as const }] as any);\n },\n read: () => Effect.succeed(0n as any),\n })\n );\n\n const chainHeadLayer = Layer.succeed(\n ChainHead,\n ChainHead.of({\n current: () => Effect.succeed(1n),\n watch: () => Effect.succeed(Stream.empty),\n })\n );\n\n const queryClientLayer = Layer.provideMerge(\n QueryClientLive,\n Layer.mergeAll(chainHeadLayer, makeRpcCacheLive({ ttl: 60_000 }), RequestDedupLive)\n );\n\n const multicallBatcherLayer = Layer.provideMerge(MulticallBatcherLive, contractReaderLayer);\n\n const contractQueryLayer = Layer.provide(\n ContractQueryLive,\n Layer.mergeAll(queryClientLayer, multicallBatcherLayer)\n );\n\n const contractQuery = yield* ContractQuery.pipe(Effect.provide(contractQueryLayer));\n\n const params = {\n abi: bigintArgAbi,\n address: TEST_ADDRESS,\n args: [1n] as const,\n chainId: TEST_CHAIN_ID,\n functionName: \"echo\" as const,\n };\n\n const r1 = yield* contractQuery.read(params);\n const r2 = yield* contractQuery.read(params);\n\n expect(r1).toBe(456n);\n expect(r2).toBe(456n);\n expect(multicallCount).toBe(1);\n }).pipe(Effect.scoped)\n );\n});\n"]}
|
package/dist/query/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/query/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,aAAa,CAAC;AAC5B,cAAc,qBAAqB,CAAC;AACpC,cAAc,wBAAwB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/query/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,aAAa,CAAC;AAC5B,cAAc,qBAAqB,CAAC;AACpC,cAAc,wBAAwB,CAAC","sourcesContent":["export * from \"./chain-head.js\";\nexport * from \"./client.js\";\nexport * from \"./contract-query.js\";\nexport * from \"./multicall-batcher.js\";\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"multicall-batcher.js","sourceRoot":"","sources":["../../src/query/multicall-batcher.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"multicall-batcher.js","sourceRoot":"","sources":["../../src/query/multicall-batcher.ts"],"names":[],"mappings":"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","sourcesContent":["import { Context, Effect, Layer, Request, RequestResolver } from \"effect\";\nimport type { ContractReaderShape } from \"@/src/contract/index.js\";\nimport { ContractReader } from \"@/src/contract/index.js\";\nimport type { MulticallCall } from \"@/src/types/index.js\";\n\nexport type MulticallBatchOptions = {\n readonly blockNumber?: bigint | undefined;\n readonly blockTag?: import(\"viem\").BlockTag | undefined;\n};\n\n/**\n * Request type for multicall batching.\n * Each request represents a single contract call to be batched.\n */\ninterface MulticallRequest extends Request.Request<unknown, Error> {\n readonly _tag: \"MulticallRequest\";\n readonly chainId: number;\n readonly call: MulticallCall;\n readonly options?: MulticallBatchOptions | undefined;\n}\n\nconst MulticallRequest = Request.tagged<MulticallRequest>(\"MulticallRequest\");\n\n/**\n * Generate a stable cache key for grouping requests by chainId and options.\n */\nconst stableStringify = (value: unknown): string =>\n JSON.stringify(value, (_, v) => (typeof v === \"bigint\" ? v.toString() : v));\n\nconst keyFor = (chainId: number, options?: MulticallBatchOptions | undefined): string =>\n `${chainId}:${stableStringify(options ?? {})}`;\n\ntype RequestGroup = {\n chainId: number;\n options?: MulticallBatchOptions | undefined;\n requests: readonly MulticallRequest[];\n};\n\n/**\n * Group requests by chainId and block options.\n */\nconst groupRequests = (requests: readonly MulticallRequest[]): Map<string, RequestGroup> => {\n const grouped = new Map<string, RequestGroup>();\n\n for (const req of requests) {\n const key = keyFor(req.chainId, req.options);\n const existing = grouped.get(key);\n if (existing) {\n grouped.set(key, {\n ...existing,\n requests: [...existing.requests, req],\n });\n } else {\n grouped.set(key, {\n chainId: req.chainId,\n options: req.options,\n requests: [req],\n });\n }\n }\n\n return grouped;\n};\n\n/**\n * Complete all requests in a group with a failure.\n */\nconst failGroup = (requests: readonly MulticallRequest[], error: Error) =>\n Effect.forEach(requests, (req) => Request.completeEffect(req, Effect.fail(error)), {\n discard: true,\n });\n\n/**\n * Complete all requests in a group with their corresponding results.\n */\nconst completeGroup = (\n requests: readonly MulticallRequest[],\n results: readonly {\n status: \"success\" | \"failure\";\n result?: unknown;\n error?: Error;\n }[]\n) =>\n Effect.forEach(\n requests,\n (req, i) => {\n const res = results[i];\n if (res?.status === \"success\") {\n return Request.completeEffect(req, Effect.succeed(res.result));\n }\n return Request.completeEffect(\n req,\n Effect.fail(res?.error ?? new Error(\"Unknown multicall error\"))\n );\n },\n { discard: true }\n );\n\n/**\n * Execute a single multicall group and complete all requests.\n */\nconst executeGroup = (contractReader: ContractReaderShape, group: RequestGroup) =>\n Effect.gen(function* () {\n const result = yield* contractReader\n .multicall(\n group.chainId,\n group.requests.map((r) => r.call),\n group.options\n )\n .pipe(Effect.either);\n\n if (result._tag === \"Left\") {\n const error = result.left instanceof Error ? result.left : new Error(String(result.left));\n yield* failGroup(group.requests, error);\n } else {\n yield* completeGroup(group.requests, result.right);\n }\n });\n\n/**\n * Creates a batched RequestResolver that groups multicall requests by chainId and options.\n */\nconst makeMulticallResolver = (\n contractReader: ContractReaderShape\n): RequestResolver.RequestResolver<MulticallRequest, never> =>\n RequestResolver.makeBatched((requests: readonly MulticallRequest[]) =>\n Effect.gen(function* () {\n const grouped = groupRequests(requests);\n\n // Execute groups in parallel (cross-chain requests can run concurrently)\n yield* Effect.all(\n [...grouped.values()].map((group) => executeGroup(contractReader, group)),\n { concurrency: \"unbounded\" }\n );\n })\n ).pipe(RequestResolver.batchN(100));\n\nexport type MulticallBatcherShape = {\n readonly enqueue: <A>(\n chainId: number,\n call: MulticallCall,\n options?: MulticallBatchOptions | undefined\n ) => Effect.Effect<A, Error>;\n};\n\nexport class MulticallBatcher extends Context.Tag(\"ew3/MulticallBatcher\")<\n MulticallBatcher,\n MulticallBatcherShape\n>() {}\n\n/**\n * Live implementation of MulticallBatcher using Effect's Request/RequestResolver.\n * Automatically batches and deduplicates multicall requests across concurrent fibers.\n */\nexport const MulticallBatcherLive = Layer.effect(\n MulticallBatcher,\n Effect.gen(function* () {\n const contractReader = yield* ContractReader;\n const resolver = makeMulticallResolver(contractReader);\n\n return MulticallBatcher.of({\n enqueue: <A>(chainId: number, call: MulticallCall, options?: MulticallBatchOptions) =>\n Effect.request(MulticallRequest({ call, chainId, options }), resolver) as Effect.Effect<\n A,\n Error\n >,\n });\n })\n);\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/react-hooks/index.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAOb,OAAO,EACL,aAAa,EACb,oBAAoB,EACpB,aAAa,EACb,aAAa,EACb,SAAS,EACT,eAAe,EACf,cAAc,EACd,kBAAkB,EAClB,uBAAuB,GACxB,MAAM,8CAA8C,CAAC;AAKtD,OAAO,EACL,sBAAsB,EACtB,iBAAiB,EACjB,qBAAqB,EACrB,iBAAiB,EACjB,mBAAmB,GACpB,MAAM,4CAA4C,CAAC;AAEpD,OAAO,EAAE,oBAAoB,EAAE,MAAM,uDAAuD,CAAC;AAC7F,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/react-hooks/index.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAOb,OAAO,EACL,aAAa,EACb,oBAAoB,EACpB,aAAa,EACb,aAAa,EACb,SAAS,EACT,eAAe,EACf,cAAc,EACd,kBAAkB,EAClB,uBAAuB,GACxB,MAAM,8CAA8C,CAAC;AAKtD,OAAO,EACL,sBAAsB,EACtB,iBAAiB,EACjB,qBAAqB,EACrB,iBAAiB,EACjB,mBAAmB,GACpB,MAAM,4CAA4C,CAAC;AAEpD,OAAO,EAAE,oBAAoB,EAAE,MAAM,uDAAuD,CAAC;AAC7F,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC","sourcesContent":["\"use client\";\n\nexport type {\n EffectMemoOptions,\n StreamState,\n UseEffectResult,\n} from \"@/src/integrations/react-hooks/primitives.js\";\nexport {\n useEffectMemo,\n useEffectMemoFactory,\n useEffectOnce,\n useForkEffect,\n useStream,\n useStreamEffect,\n useStreamValue,\n useSubscriptionRef,\n useSubscriptionRefValue,\n} from \"@/src/integrations/react-hooks/primitives.js\";\nexport type {\n EffectEvmLayerProviderProps,\n EffectEvmProviderProps,\n} from \"@/src/integrations/react-hooks/provider.js\";\nexport {\n EffectEvmLayerProvider,\n EffectEvmProvider,\n EffectEvmProviderSync,\n useEffectEvmLayer,\n useEffectEvmRuntime,\n} from \"@/src/integrations/react-hooks/provider.js\";\nexport type { WalletProviderRefActions } from \"@/src/integrations/react-hooks/wallet-provider-ref.js\";\nexport { useWalletProviderRef } from \"@/src/integrations/react-hooks/wallet-provider-ref.js\";\nexport { useIsSafeMultisig } from \"./use-is-safe-multisig.js\";\nexport { useSafeContext } from \"./use-safe-context.js\";\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-is-safe-multisig.js","sourceRoot":"","sources":["../../src/react-hooks/use-is-safe-multisig.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AACnC,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAMvD,MAAM,YAAY,GAAG;IAEnB,yBAAyB;IACzB,wBAAwB;IACxB,qBAAqB;IAErB,4BAA4B;IAC5B,yBAAyB;IACzB,2BAA2B;IAC3B,0BAA0B;CAClB,CAAC;AAYX,MAAM,UAAU,iBAAiB;IAC/B,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,GAAG,UAAU,EAAE,CAAC;IAChD,MAAM,aAAa,GAAG,cAAc,EAAE,CAAC;IAIvC,MAAM,CAAC,YAAY,EAAE,eAAe,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IACxD,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,MAAM,CAAC,MAAM,KAAK,MAAM,IAAI,iBAAiB,EAAE,EAAE,CAAC;YACpD,eAAe,CAAC,IAAI,CAAC,CAAC;QACxB,CAAC;IACH,CAAC,EAAE,EAAE,CAAC,CAAC;IAGP,IAAI,aAAa,EAAE,CAAC;QAClB,OAAO,IAAI,CAAC;IACd,CAAC;IAGD,IAAI,WAAW,IAAI,SAAS,EAAE,EAAE,KAAK,MAAM,EAAE,CAAC;QAC5C,OAAO,IAAI,CAAC;IACd,CAAC;IAGD,OAAO,YAAY,CAAC;AACtB,CAAC;AAMD,SAAS,iBAAiB;IACxB,IAAI,CAAC;QAEH,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC;QACnD,OAAO,YAAY,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,YAAY,KAAK,MAAM,CAAC,CAAC;IAChE,CAAC;IAAC,MAAM,CAAC;QAEP,IAAI,MAAM,CAAC,QAAQ,CAAC,eAAe,EAAE,MAAM,EAAE,CAAC;YAC5C,MAAM,cAAc,GAAG,MAAM,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;YAC1D,OAAO,YAAY,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,cAAc,KAAK,MAAM,CAAC,CAAC;QAClE,CAAC;QAED,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
|
|
1
|
+
{"version":3,"file":"use-is-safe-multisig.js","sourceRoot":"","sources":["../../src/react-hooks/use-is-safe-multisig.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AACnC,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAMvD,MAAM,YAAY,GAAG;IAEnB,yBAAyB;IACzB,wBAAwB;IACxB,qBAAqB;IAErB,4BAA4B;IAC5B,yBAAyB;IACzB,2BAA2B;IAC3B,0BAA0B;CAClB,CAAC;AAYX,MAAM,UAAU,iBAAiB;IAC/B,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,GAAG,UAAU,EAAE,CAAC;IAChD,MAAM,aAAa,GAAG,cAAc,EAAE,CAAC;IAIvC,MAAM,CAAC,YAAY,EAAE,eAAe,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IACxD,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,MAAM,CAAC,MAAM,KAAK,MAAM,IAAI,iBAAiB,EAAE,EAAE,CAAC;YACpD,eAAe,CAAC,IAAI,CAAC,CAAC;QACxB,CAAC;IACH,CAAC,EAAE,EAAE,CAAC,CAAC;IAGP,IAAI,aAAa,EAAE,CAAC;QAClB,OAAO,IAAI,CAAC;IACd,CAAC;IAGD,IAAI,WAAW,IAAI,SAAS,EAAE,EAAE,KAAK,MAAM,EAAE,CAAC;QAC5C,OAAO,IAAI,CAAC;IACd,CAAC;IAGD,OAAO,YAAY,CAAC;AACtB,CAAC;AAMD,SAAS,iBAAiB;IACxB,IAAI,CAAC;QAEH,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC;QACnD,OAAO,YAAY,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,YAAY,KAAK,MAAM,CAAC,CAAC;IAChE,CAAC;IAAC,MAAM,CAAC;QAEP,IAAI,MAAM,CAAC,QAAQ,CAAC,eAAe,EAAE,MAAM,EAAE,CAAC;YAC5C,MAAM,cAAc,GAAG,MAAM,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;YAC1D,OAAO,YAAY,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,cAAc,KAAK,MAAM,CAAC,CAAC;QAClE,CAAC;QAED,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC","sourcesContent":["\"use client\";\n\nimport { useEffect, useState } from \"react\";\nimport { useAccount } from \"wagmi\";\nimport { useSafeContext } from \"./use-safe-context.js\";\n\n/**\n * Known Safe wallet domains for iframe origin validation.\n * Includes the main Safe app and chain-specific Safe deployments.\n */\nconst SAFE_ORIGINS = [\n // Main Safe domains\n \"https://app.safe.global\",\n \"https://gnosis-safe.io\",\n \"https://safe.global\",\n // Chain-specific Safe deployments\n \"https://safe.berachain.com\",\n \"https://safe.chiliz.com\",\n \"https://safe.lightlink.io\",\n \"https://safe.optimism.io\",\n] as const;\n\n/**\n * Detect if the connected wallet is a Safe multisig.\n *\n * Detection strategy (in order of reliability):\n * 1. Safe Apps SDK detection via postMessage (most reliable, works cross-origin)\n * 2. Wagmi connector ID check\n * 3. Iframe origin validation (fallback, may fail cross-origin)\n *\n * @returns true if wallet is a Safe multisig\n */\nexport function useIsSafeMultisig(): boolean {\n const { connector, isConnected } = useAccount();\n const isSafeContext = useSafeContext();\n\n // Method 3: Iframe origin fallback (may fail cross-origin)\n // Deferred to useEffect to avoid SSR hydration mismatch\n const [isSafeIframe, setIsSafeIframe] = useState(false);\n useEffect(() => {\n if (window.parent !== window && isValidSafeOrigin()) {\n setIsSafeIframe(true);\n }\n }, []);\n\n // Method 1: Safe Apps SDK (most reliable - uses postMessage)\n if (isSafeContext) {\n return true;\n }\n\n // Method 2: Connected via Safe connector\n if (isConnected && connector?.id === \"safe\") {\n return true;\n }\n\n // Method 3: Fallback\n return isSafeIframe;\n}\n\n/**\n * Check if the parent window origin matches known Safe domains.\n * This prevents false positives from other iframe contexts.\n */\nfunction isValidSafeOrigin(): boolean {\n try {\n // Try to access parent origin (may throw SecurityError for cross-origin)\n const parentOrigin = window.parent.location.origin;\n return SAFE_ORIGINS.some((origin) => parentOrigin === origin);\n } catch {\n // Cross-origin access blocked - check ancestorOrigins if available\n if (window.location.ancestorOrigins?.length) {\n const ancestorOrigin = window.location.ancestorOrigins[0];\n return SAFE_ORIGINS.some((origin) => ancestorOrigin === origin);\n }\n // Cannot determine origin - default to false to avoid false positives\n return false;\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-safe-context.js","sourceRoot":"","sources":["../../src/react-hooks/use-safe-context.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAM5C,MAAM,gBAAgB,GAAG,IAAI,CAAC;AA0B9B,MAAM,UAAU,cAAc;IAC5B,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAE5C,SAAS,CAAC,GAAG,EAAE;QAEb,IAAI,OAAO,MAAM,KAAK,WAAW,EAAE,CAAC;YAClC,OAAO;QACT,CAAC;QAED,IAAI,SAAS,GAAG,KAAK,CAAC;QAGtB,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE;YAC9B,IAAI,CAAC,SAAS,EAAE,CAAC;gBACf,SAAS,CAAC,KAAK,CAAC,CAAC;YACnB,CAAC;QACH,CAAC,EAAE,gBAAgB,CAAC,CAAC;QAGrB,MAAM,CAAC,4BAA4B,CAAC;aACjC,IAAI,CAAC,CAAC,EAAE,OAAO,EAAE,WAAW,EAAE,EAAE,EAAE;YACjC,MAAM,GAAG,GAAG,IAAI,WAAW,EAAE,CAAC;YAC9B,OAAO,GAAG,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;QAC5B,CAAC,CAAC;aACD,IAAI,CAAC,GAAG,EAAE;YACT,IAAI,CAAC,SAAS,EAAE,CAAC;gBACf,SAAS,CAAC,IAAI,CAAC,CAAC;YAClB,CAAC;QACH,CAAC,CAAC;aACD,KAAK,CAAC,GAAG,EAAE;YACV,IAAI,CAAC,SAAS,EAAE,CAAC;gBACf,SAAS,CAAC,KAAK,CAAC,CAAC;YACnB,CAAC;QACH,CAAC,CAAC;aACD,OAAO,CAAC,GAAG,EAAE;YACZ,YAAY,CAAC,OAAO,CAAC,CAAC;QACxB,CAAC,CAAC,CAAC;QAEL,OAAO,GAAG,EAAE;YACV,SAAS,GAAG,IAAI,CAAC;YACjB,YAAY,CAAC,OAAO,CAAC,CAAC;QACxB,CAAC,CAAC;IACJ,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
1
|
+
{"version":3,"file":"use-safe-context.js","sourceRoot":"","sources":["../../src/react-hooks/use-safe-context.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAM5C,MAAM,gBAAgB,GAAG,IAAI,CAAC;AA0B9B,MAAM,UAAU,cAAc;IAC5B,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAE5C,SAAS,CAAC,GAAG,EAAE;QAEb,IAAI,OAAO,MAAM,KAAK,WAAW,EAAE,CAAC;YAClC,OAAO;QACT,CAAC;QAED,IAAI,SAAS,GAAG,KAAK,CAAC;QAGtB,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE;YAC9B,IAAI,CAAC,SAAS,EAAE,CAAC;gBACf,SAAS,CAAC,KAAK,CAAC,CAAC;YACnB,CAAC;QACH,CAAC,EAAE,gBAAgB,CAAC,CAAC;QAGrB,MAAM,CAAC,4BAA4B,CAAC;aACjC,IAAI,CAAC,CAAC,EAAE,OAAO,EAAE,WAAW,EAAE,EAAE,EAAE;YACjC,MAAM,GAAG,GAAG,IAAI,WAAW,EAAE,CAAC;YAC9B,OAAO,GAAG,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;QAC5B,CAAC,CAAC;aACD,IAAI,CAAC,GAAG,EAAE;YACT,IAAI,CAAC,SAAS,EAAE,CAAC;gBACf,SAAS,CAAC,IAAI,CAAC,CAAC;YAClB,CAAC;QACH,CAAC,CAAC;aACD,KAAK,CAAC,GAAG,EAAE;YACV,IAAI,CAAC,SAAS,EAAE,CAAC;gBACf,SAAS,CAAC,KAAK,CAAC,CAAC;YACnB,CAAC;QACH,CAAC,CAAC;aACD,OAAO,CAAC,GAAG,EAAE;YACZ,YAAY,CAAC,OAAO,CAAC,CAAC;QACxB,CAAC,CAAC,CAAC;QAEL,OAAO,GAAG,EAAE;YACV,SAAS,GAAG,IAAI,CAAC;YACjB,YAAY,CAAC,OAAO,CAAC,CAAC;QACxB,CAAC,CAAC;IACJ,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,OAAO,MAAM,CAAC;AAChB,CAAC","sourcesContent":["\"use client\";\n\nimport { useEffect, useState } from \"react\";\n\n/**\n * Timeout for Safe SDK detection in milliseconds.\n * Safe Apps SDK uses postMessage which can hang if not in Safe context.\n */\nconst SAFE_SDK_TIMEOUT = 3000;\n\n/**\n * Detect if the app is running in a Safe App context using the Safe Apps SDK.\n *\n * This hook asynchronously checks with the Safe Apps SDK to determine if\n * we're running inside a Safe App iframe. More reliable than iframe origin\n * detection because:\n * - Uses postMessage (works cross-origin)\n * - Gets definitive answer from Safe\n * - Includes timeout to prevent hangs\n *\n * @returns true if running in Safe App context, false otherwise\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const isSafeContext = useSafeContext();\n *\n * if (isSafeContext) {\n * return <p>Running in Safe App</p>;\n * }\n * return <p>Regular browser context</p>;\n * }\n * ```\n */\nexport function useSafeContext(): boolean {\n const [isSafe, setIsSafe] = useState(false);\n\n useEffect(() => {\n // SSR guard\n if (typeof window === \"undefined\") {\n return;\n }\n\n let cancelled = false;\n\n // Timeout fallback - resolve to false if SDK doesn't respond\n const timeout = setTimeout(() => {\n if (!cancelled) {\n setIsSafe(false);\n }\n }, SAFE_SDK_TIMEOUT);\n\n // Dynamically import SDK to keep it optional\n import(\"@safe-global/safe-apps-sdk\")\n .then(({ default: SafeAppsSDK }) => {\n const sdk = new SafeAppsSDK();\n return sdk.safe.getInfo();\n })\n .then(() => {\n if (!cancelled) {\n setIsSafe(true);\n }\n })\n .catch(() => {\n if (!cancelled) {\n setIsSafe(false);\n }\n })\n .finally(() => {\n clearTimeout(timeout);\n });\n\n return () => {\n cancelled = true;\n clearTimeout(timeout);\n };\n }, []);\n\n return isSafe;\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/react-hooks/wagmi/index.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,cAAc,+CAA+C,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/react-hooks/wagmi/index.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,cAAc,+CAA+C,CAAC","sourcesContent":["\"use client\";\n\nexport * from \"@/src/integrations/react-hooks/wagmi/index.js\";\n"]}
|
package/dist/rpc/cache.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cache.js","sourceRoot":"","sources":["../../src/rpc/cache.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"cache.js","sourceRoot":"","sources":["../../src/rpc/cache.ts"],"names":[],"mappings":"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","sourcesContent":["import { Clock, Context, Effect, Layer, Ref } from \"effect\";\n\nexport type CacheConfig = {\n ttl?: number; // default 12_000ms (1 block)\n maxSize?: number; // default 100 entries\n blockScoped?: boolean; // default true - invalidate on new block\n};\n\nexport type CacheEntry<T> = {\n value: T;\n timestamp: number;\n blockNumber?: bigint;\n ttl?: number;\n};\n\nexport type RpcCacheShape = {\n readonly get: <T>(key: string) => Effect.Effect<T | null>;\n readonly set: <T>(\n key: string,\n value: T,\n blockNumber?: bigint,\n ttl?: number\n ) => Effect.Effect<void>;\n readonly invalidate: (key: string) => Effect.Effect<void>;\n readonly invalidateBlock: (blockNumber: bigint) => Effect.Effect<void>;\n readonly clear: Effect.Effect<void>;\n};\n\nexport class RpcCache extends Context.Tag(\"ew3/RpcCache\")<RpcCache, RpcCacheShape>() {}\n\n/**\n * Create a cache layer with LRU eviction using Effect's Cache module\n */\nexport const makeRpcCacheLive = (config?: CacheConfig): Layer.Layer<RpcCache> => {\n const defaultTtl = config?.ttl ?? 12_000;\n const maxSize = config?.maxSize ?? 100;\n const blockScoped = config?.blockScoped ?? true;\n\n return Layer.effect(\n RpcCache,\n Effect.gen(function* () {\n // Store cache entries with timestamps and metadata\n const entriesRef = yield* Ref.make(new Map<string, CacheEntry<unknown>>());\n // Track access order for LRU eviction\n const accessOrderRef = yield* Ref.make(new Map<string, number>());\n const accessCounterRef = yield* Ref.make(0);\n\n // Evict the least recently used entry when at capacity\n const evictOldest = Effect.gen(function* () {\n const entries = yield* Ref.get(entriesRef);\n const accessOrder = yield* Ref.get(accessOrderRef);\n\n if (entries.size >= maxSize) {\n // Find the key with the lowest access counter (oldest)\n let oldestKey: string | null = null;\n let oldestAccess = Number.POSITIVE_INFINITY;\n\n for (const [key, access] of accessOrder.entries()) {\n if (access < oldestAccess) {\n oldestAccess = access;\n oldestKey = key;\n }\n }\n\n if (oldestKey) {\n const keyToEvict = oldestKey;\n yield* Ref.update(entriesRef, (e) => {\n const newEntries = new Map(e);\n newEntries.delete(keyToEvict);\n return newEntries;\n });\n yield* Ref.update(accessOrderRef, (o) => {\n const newAccessOrder = new Map(o);\n newAccessOrder.delete(keyToEvict);\n return newAccessOrder;\n });\n }\n }\n });\n\n const get = <T>(key: string): Effect.Effect<T | null> =>\n Effect.gen(function* () {\n const entries = yield* Ref.get(entriesRef);\n const entry = entries.get(key);\n\n if (!entry) {\n return null;\n }\n\n // Check TTL expiration\n const now = yield* Clock.currentTimeMillis;\n const entryTtl = entry.ttl ?? defaultTtl;\n\n if (now - entry.timestamp > entryTtl) {\n // Expired - remove it\n yield* Ref.update(entriesRef, (e) => {\n const newEntries = new Map(e);\n newEntries.delete(key);\n return newEntries;\n });\n yield* Ref.update(accessOrderRef, (o) => {\n const newAccessOrder = new Map(o);\n newAccessOrder.delete(key);\n return newAccessOrder;\n });\n return null;\n }\n\n // Update access order for LRU\n const accessCounter = yield* Ref.updateAndGet(accessCounterRef, (n) => n + 1);\n yield* Ref.update(accessOrderRef, (o) => {\n const newAccessOrder = new Map(o);\n newAccessOrder.set(key, accessCounter);\n return newAccessOrder;\n });\n\n return entry.value as T;\n });\n\n const set = <T>(\n key: string,\n value: T,\n blockNumber?: bigint,\n entryTtl?: number\n ): Effect.Effect<void> =>\n Effect.gen(function* () {\n const now = yield* Clock.currentTimeMillis;\n\n // Evict oldest entry if at capacity\n yield* evictOldest;\n\n // Store entry with timestamp\n yield* Ref.update(entriesRef, (entries) => {\n const newEntries = new Map(entries);\n newEntries.set(key, {\n blockNumber,\n timestamp: now,\n ttl: entryTtl,\n value,\n });\n return newEntries;\n });\n\n // Update access order for LRU\n const accessCounter = yield* Ref.updateAndGet(accessCounterRef, (n) => n + 1);\n yield* Ref.update(accessOrderRef, (o) => {\n const newAccessOrder = new Map(o);\n newAccessOrder.set(key, accessCounter);\n return newAccessOrder;\n });\n });\n\n const invalidate = (key: string): Effect.Effect<void> =>\n Effect.gen(function* () {\n yield* Ref.update(entriesRef, (entries) => {\n const newEntries = new Map(entries);\n newEntries.delete(key);\n return newEntries;\n });\n yield* Ref.update(accessOrderRef, (o) => {\n const newAccessOrder = new Map(o);\n newAccessOrder.delete(key);\n return newAccessOrder;\n });\n });\n\n const invalidateBlock = (blockNumber: bigint): Effect.Effect<void> =>\n Effect.gen(function* () {\n if (!blockScoped) {\n return;\n }\n\n const entries = yield* Ref.get(entriesRef);\n const keysToInvalidate: string[] = [];\n\n for (const [key, entry] of entries.entries()) {\n if (entry.blockNumber !== undefined && entry.blockNumber < blockNumber) {\n keysToInvalidate.push(key);\n }\n }\n\n // Invalidate all matching keys\n yield* Effect.all(\n keysToInvalidate.map((key) => invalidate(key)),\n { concurrency: \"unbounded\" }\n );\n });\n\n const clear: Effect.Effect<void> = Effect.gen(function* () {\n yield* Ref.set(entriesRef, new Map());\n yield* Ref.set(accessOrderRef, new Map());\n yield* Ref.set(accessCounterRef, 0);\n });\n\n return {\n clear,\n get,\n invalidate,\n invalidateBlock,\n set,\n } satisfies RpcCacheShape;\n })\n );\n};\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"circuit-breaker.js","sourceRoot":"","sources":["../../src/rpc/circuit-breaker.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"circuit-breaker.js","sourceRoot":"","sources":["../../src/rpc/circuit-breaker.ts"],"names":[],"mappings":"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","sourcesContent":["import { Clock, Config, Effect, Ref, Schema } from \"effect\";\nimport { DEFAULT_MAX_DELAY } from \"@/src/constants/index.js\";\n\nexport type CircuitState = \"closed\" | \"open\" | \"half-open\";\n\nexport type CircuitBreakerConfig = {\n /** Number of failures before opening the circuit (default: 5) */\n failureThreshold?: number;\n /** Time in milliseconds before attempting recovery (default: 30_000) */\n resetTimeout?: number;\n /** Number of successes needed to close from half-open (default: 2) */\n successThreshold?: number;\n};\n\n/**\n * Config-based circuit breaker configuration from environment variables.\n *\n * Environment variables (all optional, nested under `EW3_CIRCUIT_BREAKER_` prefix):\n * - `EW3_CIRCUIT_BREAKER_FAILURE_THRESHOLD`: Number of failures before opening circuit (default: 5)\n * - `EW3_CIRCUIT_BREAKER_SUCCESS_THRESHOLD`: Number of successes needed to close from half-open (default: 3)\n * - `EW3_CIRCUIT_BREAKER_RESET_TIMEOUT`: Time in ms before attempting recovery (default: 30_000)\n *\n * @example\n * ```typescript\n * import { Effect } from \"effect\";\n * import { CircuitBreakerConfigFromEnv } from \"effect-evm/rpc\";\n *\n * const program = Effect.gen(function* () {\n * const config = yield* CircuitBreakerConfigFromEnv;\n * // Use config for circuit breaker\n * });\n * ```\n */\nexport const CircuitBreakerConfigFromEnv = Config.all({\n failureThreshold: Config.number(\"FAILURE_THRESHOLD\").pipe(Config.withDefault(5)),\n resetTimeout: Config.number(\"RESET_TIMEOUT\").pipe(Config.withDefault(30_000)),\n successThreshold: Config.number(\"SUCCESS_THRESHOLD\").pipe(Config.withDefault(3)),\n}).pipe(Config.nested(\"EW3_CIRCUIT_BREAKER\"));\n\n/**\n * Error thrown when circuit breaker is open\n */\nexport class CircuitOpenError extends Schema.TaggedError<CircuitOpenError>()(\"CircuitOpenError\", {\n message: Schema.String,\n openedAt: Schema.Number,\n}) {}\n\n/**\n * Internal state tracking for circuit breaker\n */\ntype CircuitBreakerState = {\n state: CircuitState;\n failures: number;\n successes: number;\n lastFailureTime: number;\n};\n\n/**\n * Circuit breaker service definition\n */\nexport type CircuitBreaker = {\n /** Execute an effect with circuit breaker protection */\n readonly execute: <A, E, R>(\n effect: Effect.Effect<A, E, R>\n ) => Effect.Effect<A, E | CircuitOpenError, R>;\n /** Get current circuit state */\n readonly getState: Effect.Effect<CircuitState>;\n /** Manually reset the circuit to closed state */\n readonly reset: Effect.Effect<void>;\n};\n\n/**\n * Create a circuit breaker instance\n * Uses Ref for thread-safe state management\n *\n * @param config - Circuit breaker configuration options\n * @returns Effect that creates a new CircuitBreaker\n */\nexport const makeCircuitBreaker = (\n config?: CircuitBreakerConfig\n): Effect.Effect<CircuitBreaker> => {\n const {\n failureThreshold = 5,\n resetTimeout = DEFAULT_MAX_DELAY,\n successThreshold = 2,\n } = config ?? {};\n\n return Effect.gen(function* () {\n const stateRef = yield* Ref.make<CircuitBreakerState>({\n failures: 0,\n lastFailureTime: 0,\n state: \"closed\",\n successes: 0,\n });\n\n const recordSuccess = Effect.gen(function* () {\n yield* Ref.update(stateRef, (state) => {\n if (state.state === \"half-open\") {\n const newSuccesses = state.successes + 1;\n if (newSuccesses >= successThreshold) {\n // Close the circuit after enough successes\n return {\n failures: 0,\n lastFailureTime: 0,\n state: \"closed\" as const,\n successes: 0,\n };\n }\n return { ...state, successes: newSuccesses };\n }\n // Reset failure count on success in closed state\n return { ...state, failures: 0 };\n });\n });\n\n const recordFailure = Effect.gen(function* () {\n const now = yield* Clock.currentTimeMillis;\n yield* Ref.update(stateRef, (state) => {\n const newFailures = state.failures + 1;\n\n if (state.state === \"half-open\") {\n // Failure in half-open state reopens the circuit\n return {\n failures: newFailures,\n lastFailureTime: now,\n state: \"open\" as const,\n successes: 0,\n };\n }\n\n if (state.state === \"closed\" && newFailures >= failureThreshold) {\n // Open the circuit after threshold failures\n return {\n failures: newFailures,\n lastFailureTime: now,\n state: \"open\" as const,\n successes: 0,\n };\n }\n\n return { ...state, failures: newFailures, lastFailureTime: now };\n });\n });\n\n const execute = <A, E, R>(\n effect: Effect.Effect<A, E, R>\n ): Effect.Effect<A, E | CircuitOpenError, R> =>\n Effect.gen(function* () {\n const now = yield* Clock.currentTimeMillis;\n const currentState = yield* Ref.get(stateRef);\n\n // Check if we should attempt to recover\n if (currentState.state === \"open\" && now - currentState.lastFailureTime >= resetTimeout) {\n yield* Ref.update(stateRef, (s) => ({\n ...s,\n state: \"half-open\" as const,\n successes: 0,\n }));\n }\n\n const state = yield* Ref.get(stateRef);\n\n // Reject if circuit is open\n if (state.state === \"open\") {\n return yield* Effect.fail(\n new CircuitOpenError({\n message: \"Circuit breaker is open\",\n openedAt: state.lastFailureTime,\n })\n );\n }\n\n // Execute the effect and track success/failure\n const result = yield* Effect.matchEffect(effect, {\n onFailure: (error) =>\n Effect.gen(function* () {\n yield* recordFailure;\n return yield* Effect.fail(error);\n }),\n onSuccess: (value) =>\n Effect.gen(function* () {\n yield* recordSuccess;\n return value;\n }),\n });\n\n return result;\n });\n\n const getState = Effect.gen(function* () {\n const state = yield* Ref.get(stateRef);\n return state.state;\n });\n\n const reset = Ref.set(stateRef, {\n failures: 0,\n lastFailureTime: 0,\n state: \"closed\" as const,\n successes: 0,\n });\n\n return {\n execute,\n getState,\n reset,\n } satisfies CircuitBreaker;\n });\n};\n"]}
|
package/dist/rpc/dedup.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dedup.js","sourceRoot":"","sources":["../../src/rpc/dedup.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AAS1D,MAAM,OAAO,YAAa,SAAQ,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,EAG9D;CAAG;AAKN,MAAM,cAAc,GAAG,IAAI,GAAG,EAA+C,CAAC;AAK9E,MAAM,CAAC,MAAM,gBAAgB,GAA8B,KAAK,CAAC,OAAO,CAAC,YAAY,EAAE;IACrF,MAAM,EAAE,CAAU,GAAW,EAAE,MAA8B,EAA0B,EAAE,CAEvF,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE;QAElB,MAAM,QAAQ,GAAG,cAAc,CAAC,GAAG,CAAC,GAAG,CAAwC,CAAC;QAChF,IAAI,QAAQ,EAAE,CAAC;YACb,OAAO,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QAClC,CAAC;QAID,OAAO,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;YACzB,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,QAAQ,CAAC,IAAI,EAAQ,CAAC;YAG9C,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE;gBACjC,MAAM,OAAO,GAAG,cAAc,CAAC,GAAG,CAAC,GAAG,CAAwC,CAAC;gBAC/E,IAAI,OAAO,EAAE,CAAC;oBACZ,OAAO,EAAE,IAAI,EAAE,OAAgB,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC;gBACvD,CAAC;gBACD,cAAc,CAAC,GAAG,CAAC,GAAG,EAAE,QAA+C,CAAC,CAAC;gBACzE,OAAO,EAAE,IAAI,EAAE,OAAgB,EAAE,CAAC;YACpC,CAAC,CAAC,CAAC;YAEH,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,SAAS,CAAC;YAChC,IAAI,MAAM,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;gBAE5B,OAAO,KAAK,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;YAChD,CAAC;YAED,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE;gBAC/B,MAAM,OAAO,GAAG,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;gBACxC,IAAI,OAAO,KAAM,QAAgD,EAAE,CAAC;oBAClE,cAAc,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gBAC7B,CAAC;YACH,CAAC,CAAC,CAAC;YAGH,KAAK,CAAC,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAC,OAAO,EAAE,EAAE,CAC5C,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,QAAQ,CAAC,EAAE,OAAO,CAAC,CACzE,CAAC;YAEF,OAAO,KAAK,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QACzC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC;CACuB,CAAC,CAAC;AAM/B,MAAM,CAAC,MAAM,gBAAgB,GAAG,GAAS,EAAE;IACzC,cAAc,CAAC,KAAK,EAAE,CAAC;AACzB,CAAC,CAAC"}
|
|
1
|
+
{"version":3,"file":"dedup.js","sourceRoot":"","sources":["../../src/rpc/dedup.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AAS1D,MAAM,OAAO,YAAa,SAAQ,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,EAG9D;CAAG;AAKN,MAAM,cAAc,GAAG,IAAI,GAAG,EAA+C,CAAC;AAK9E,MAAM,CAAC,MAAM,gBAAgB,GAA8B,KAAK,CAAC,OAAO,CAAC,YAAY,EAAE;IACrF,MAAM,EAAE,CAAU,GAAW,EAAE,MAA8B,EAA0B,EAAE,CAEvF,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE;QAElB,MAAM,QAAQ,GAAG,cAAc,CAAC,GAAG,CAAC,GAAG,CAAwC,CAAC;QAChF,IAAI,QAAQ,EAAE,CAAC;YACb,OAAO,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QAClC,CAAC;QAID,OAAO,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;YACzB,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,QAAQ,CAAC,IAAI,EAAQ,CAAC;YAG9C,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE;gBACjC,MAAM,OAAO,GAAG,cAAc,CAAC,GAAG,CAAC,GAAG,CAAwC,CAAC;gBAC/E,IAAI,OAAO,EAAE,CAAC;oBACZ,OAAO,EAAE,IAAI,EAAE,OAAgB,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC;gBACvD,CAAC;gBACD,cAAc,CAAC,GAAG,CAAC,GAAG,EAAE,QAA+C,CAAC,CAAC;gBACzE,OAAO,EAAE,IAAI,EAAE,OAAgB,EAAE,CAAC;YACpC,CAAC,CAAC,CAAC;YAEH,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,SAAS,CAAC;YAChC,IAAI,MAAM,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;gBAE5B,OAAO,KAAK,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;YAChD,CAAC;YAED,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE;gBAC/B,MAAM,OAAO,GAAG,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;gBACxC,IAAI,OAAO,KAAM,QAAgD,EAAE,CAAC;oBAClE,cAAc,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gBAC7B,CAAC;YACH,CAAC,CAAC,CAAC;YAGH,KAAK,CAAC,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAC,OAAO,EAAE,EAAE,CAC5C,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,QAAQ,CAAC,EAAE,OAAO,CAAC,CACzE,CAAC;YAEF,OAAO,KAAK,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QACzC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC;CACuB,CAAC,CAAC;AAM/B,MAAM,CAAC,MAAM,gBAAgB,GAAG,GAAS,EAAE;IACzC,cAAc,CAAC,KAAK,EAAE,CAAC;AACzB,CAAC,CAAC","sourcesContent":["import { Context, Deferred, Effect, Layer } from \"effect\";\n\n/**\n * Deduplicates concurrent identical requests\n */\nexport type RequestDedupShape = {\n readonly dedupe: <A, E, R>(key: string, effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R>;\n};\n\nexport class RequestDedup extends Context.Tag(\"ew3/RequestDedup\")<\n RequestDedup,\n RequestDedupShape\n>() {}\n\n/**\n * Global mutable map - JavaScript Map is synchronous and truly shared\n */\nconst globalInflight = new Map<string, Deferred.Deferred<unknown, unknown>>();\n\n/**\n * Uses synchronous map access with Effect.suspend for atomic check-then-create\n */\nexport const RequestDedupLive: Layer.Layer<RequestDedup> = Layer.succeed(RequestDedup, {\n dedupe: <A, E, R>(key: string, effect: Effect.Effect<A, E, R>): Effect.Effect<A, E, R> =>\n // Use suspend to defer the entire check logic\n Effect.suspend(() => {\n // Synchronous check - if entry exists, return effect that waits on it\n const existing = globalInflight.get(key) as Deferred.Deferred<A, E> | undefined;\n if (existing) {\n return Deferred.await(existing);\n }\n\n // Need to create new entry - this is the critical section\n // Create the deferred, add to map, then run the effect\n return Effect.gen(function* () {\n const deferred = yield* Deferred.make<A, E>();\n\n // Synchronously add to map - check again in case of race\n const raceCheck = Effect.sync(() => {\n const current = globalInflight.get(key) as Deferred.Deferred<A, E> | undefined;\n if (current) {\n return { _tag: \"raced\" as const, existing: current };\n }\n globalInflight.set(key, deferred as Deferred.Deferred<unknown, unknown>);\n return { _tag: \"added\" as const };\n });\n\n const result = yield* raceCheck;\n if (result._tag === \"raced\") {\n // Another fiber beat us - wait on their deferred\n return yield* Deferred.await(result.existing);\n }\n\n const cleanup = Effect.sync(() => {\n const current = globalInflight.get(key);\n if (current === (deferred as Deferred.Deferred<unknown, unknown>)) {\n globalInflight.delete(key);\n }\n });\n\n // Run the effect and complete deferred with result\n yield* Effect.uninterruptibleMask((restore) =>\n Effect.ensuring(Effect.intoDeferred(restore(effect), deferred), cleanup)\n );\n\n return yield* Deferred.await(deferred);\n });\n }),\n} satisfies RequestDedupShape);\n\n/**\n * Reset global state (for testing)\n * @internal\n */\nexport const _resetDedupState = (): void => {\n globalInflight.clear();\n};\n"]}
|
package/dist/rpc/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/rpc/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,OAAO,EAGL,2BAA2B,EAC3B,gBAAgB,EAEhB,kBAAkB,GACnB,MAAM,sBAAsB,CAAC;AAC9B,cAAc,YAAY,CAAC;AAC3B,OAAO,EACL,sBAAsB,EACtB,iBAAiB,EAEjB,kBAAkB,EAClB,SAAS,GACV,MAAM,YAAY,CAAC;AACpB,cAAc,gBAAgB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/rpc/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,OAAO,EAGL,2BAA2B,EAC3B,gBAAgB,EAEhB,kBAAkB,GACnB,MAAM,sBAAsB,CAAC;AAC9B,cAAc,YAAY,CAAC;AAC3B,OAAO,EACL,sBAAsB,EACtB,iBAAiB,EAEjB,kBAAkB,EAClB,SAAS,GACV,MAAM,YAAY,CAAC;AACpB,cAAc,gBAAgB,CAAC","sourcesContent":["export * from \"./cache.js\";\nexport {\n type CircuitBreaker,\n type CircuitBreakerConfig,\n CircuitBreakerConfigFromEnv,\n CircuitOpenError,\n type CircuitState,\n makeCircuitBreaker,\n} from \"./circuit-breaker.js\";\nexport * from \"./dedup.js\";\nexport {\n defaultRetryableErrors,\n makeRetrySchedule,\n type RetryConfig,\n RetryConfigFromEnv,\n withRetry,\n} from \"./retry.js\";\nexport * from \"./routemesh.js\";\n"]}
|
package/dist/rpc/retry.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"retry.js","sourceRoot":"","sources":["../../src/rpc/retry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAElD,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AA2B9D,MAAM,CAAC,MAAM,kBAAkB,GAAG,MAAM,CAAC,GAAG,CAAC;IAC3C,SAAS,EAAE,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IACpE,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;IAC/D,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;IACrE,UAAU,EAAE,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;CACrE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC;AAMpC,MAAM,CAAC,MAAM,sBAAsB,GAAG;IACpC,YAAY;IACZ,SAAS;IACT,YAAY;IACZ,WAAW;IACX,KAAK;IACL,KAAK;IACL,KAAK;CACN,CAAC;AAKF,MAAM,gBAAgB,GAAG,CAAC,KAAc,EAAE,iBAA2B,EAAW,EAAE;IAChF,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;QAC3B,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;QAC5C,OAAO,iBAAiB,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;IACtF,CAAC;IACD,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,MAAM,OAAO,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC;QACpC,OAAO,iBAAiB,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;IACtF,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC,CAAC;AASF,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAI,MAAoB,EAAgC,EAAE;IACzF,MAAM,EAAE,eAAe,GAAG,sBAAsB,EAAE,GAAG,aAAa,EAAE,GAAG,MAAM,IAAI,EAAE,CAAC;IAEpF,OAAO,mBAAmB,CAAC,aAAa,CAAC,CAAC,IAAI,CAC5C,QAAQ,CAAC,UAAU,CAAI,CAAC,KAAK,EAAE,EAAE,CAAC,gBAAgB,CAAC,KAAK,EAAE,eAAe,CAAC,CAAC,CAC5E,CAAC;AACJ,CAAC,CAAC;AAUF,MAAM,CAAC,MAAM,SAAS,GACpB,CAAC,MAAoB,EAAE,EAAE,CACzB,CAAU,MAA8B,EAA0B,EAAE,CAClE,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,iBAAiB,CAAI,MAAM,CAAC,CAAC,CAAC"}
|
|
1
|
+
{"version":3,"file":"retry.js","sourceRoot":"","sources":["../../src/rpc/retry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAElD,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AA2B9D,MAAM,CAAC,MAAM,kBAAkB,GAAG,MAAM,CAAC,GAAG,CAAC;IAC3C,SAAS,EAAE,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IACpE,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;IAC/D,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;IACrE,UAAU,EAAE,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;CACrE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC;AAMpC,MAAM,CAAC,MAAM,sBAAsB,GAAG;IACpC,YAAY;IACZ,SAAS;IACT,YAAY;IACZ,WAAW;IACX,KAAK;IACL,KAAK;IACL,KAAK;CACN,CAAC;AAKF,MAAM,gBAAgB,GAAG,CAAC,KAAc,EAAE,iBAA2B,EAAW,EAAE;IAChF,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;QAC3B,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;QAC5C,OAAO,iBAAiB,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;IACtF,CAAC;IACD,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,MAAM,OAAO,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC;QACpC,OAAO,iBAAiB,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;IACtF,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC,CAAC;AASF,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAI,MAAoB,EAAgC,EAAE;IACzF,MAAM,EAAE,eAAe,GAAG,sBAAsB,EAAE,GAAG,aAAa,EAAE,GAAG,MAAM,IAAI,EAAE,CAAC;IAEpF,OAAO,mBAAmB,CAAC,aAAa,CAAC,CAAC,IAAI,CAC5C,QAAQ,CAAC,UAAU,CAAI,CAAC,KAAK,EAAE,EAAE,CAAC,gBAAgB,CAAC,KAAK,EAAE,eAAe,CAAC,CAAC,CAC5E,CAAC;AACJ,CAAC,CAAC;AAUF,MAAM,CAAC,MAAM,SAAS,GACpB,CAAC,MAAoB,EAAE,EAAE,CACzB,CAAU,MAA8B,EAA0B,EAAE,CAClE,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,iBAAiB,CAAI,MAAM,CAAC,CAAC,CAAC","sourcesContent":["import { Config, Effect, Schedule } from \"effect\";\nimport type { BackoffConfig } from \"@/src/internal/index.js\";\nimport { makeBackoffSchedule } from \"@/src/internal/index.js\";\n\nexport type RetryConfig = BackoffConfig & {\n /** Array of error message patterns that should trigger retries */\n retryableErrors?: string[];\n};\n\n/**\n * Config-based retry configuration from environment variables.\n *\n * Environment variables (all optional, nested under `EW3_RETRY_` prefix):\n * - `EW3_RETRY_MAX_RETRIES`: Maximum retry attempts (default: 3)\n * - `EW3_RETRY_BASE_DELAY`: Base delay in milliseconds (default: 100)\n * - `EW3_RETRY_MAX_DELAY`: Maximum delay cap in milliseconds (default: 10_000)\n * - `EW3_RETRY_JITTER`: Enable jitter for delays (default: true)\n *\n * @example\n * ```typescript\n * import { Effect } from \"effect\";\n * import { RetryConfigFromEnv } from \"effect-evm/rpc\";\n *\n * const program = Effect.gen(function* () {\n * const config = yield* RetryConfigFromEnv;\n * // Use config for retry logic\n * });\n * ```\n */\nexport const RetryConfigFromEnv = Config.all({\n baseDelay: Config.number(\"BASE_DELAY\").pipe(Config.withDefault(100)),\n jitter: Config.boolean(\"JITTER\").pipe(Config.withDefault(true)),\n maxDelay: Config.number(\"MAX_DELAY\").pipe(Config.withDefault(10_000)),\n maxRetries: Config.number(\"MAX_RETRIES\").pipe(Config.withDefault(3)),\n}).pipe(Config.nested(\"EW3_RETRY\"));\n\n/**\n * Default retryable error patterns for RPC calls\n * Includes rate limits, timeouts, network errors, and transient HTTP errors\n */\nexport const defaultRetryableErrors = [\n \"rate limit\",\n \"timeout\",\n \"ECONNRESET\",\n \"ETIMEDOUT\",\n \"503\",\n \"502\",\n \"429\",\n];\n\n/**\n * Check if an error should be retried based on its message\n */\nconst isRetryableError = (error: unknown, retryablePatterns: string[]): boolean => {\n if (error instanceof Error) {\n const message = error.message.toLowerCase();\n return retryablePatterns.some((pattern) => message.includes(pattern.toLowerCase()));\n }\n if (typeof error === \"string\") {\n const message = error.toLowerCase();\n return retryablePatterns.some((pattern) => message.includes(pattern.toLowerCase()));\n }\n return false;\n};\n\n/**\n * Create a retry schedule with exponential backoff\n * Only retries on errors matching the configured retryable patterns\n *\n * @param config - Retry configuration options\n * @returns Schedule that implements exponential backoff with jitter\n */\nexport const makeRetrySchedule = <E>(config?: RetryConfig): Schedule.Schedule<number, E> => {\n const { retryableErrors = defaultRetryableErrors, ...backoffConfig } = config ?? {};\n\n return makeBackoffSchedule(backoffConfig).pipe(\n Schedule.whileInput<E>((error) => isRetryableError(error, retryableErrors))\n );\n};\n\n/**\n * Apply retry logic to an Effect\n * Will retry the effect according to the configured schedule on retryable errors\n *\n * @param effect - The Effect to retry\n * @param config - Retry configuration options\n * @returns Effect that will be retried on transient failures\n */\nexport const withRetry =\n (config?: RetryConfig) =>\n <A, E, R>(effect: Effect.Effect<A, E, R>): Effect.Effect<A, E, R> =>\n Effect.retry(effect, makeRetrySchedule<E>(config));\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routemesh.js","sourceRoot":"","sources":["../../src/rpc/routemesh.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAIhC,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAI/D,MAAM,CAAC,MAAM,kBAAkB,GAAG,2BAA2B,CAAC;AA6B9D,MAAM,OAAO,2BAA4B,SAAQ,MAAM,CAAC,WAAW,EAA+B,CAChG,6BAA6B,EAC7B;IACE,OAAO,EAAE,MAAM,CAAC,MAAM;CACvB,CACF;CAAG;AAaJ,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,OAAe,EAAE,MAAc,EAAU,EAAE,CACtE,GAAG,kBAAkB,IAAI,OAAO,IAAI,MAAM,EAAE,CAAC;AAa/C,MAAM,CAAC,MAAM,YAAY,GACvB,CAAC,OAAe,EAAgC,EAAE,CAClD,CAAC,MAAM,EAAE,EAAE,CACT,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;AAwBlC,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,MAAuB,EAAiB,EAAE,CAChF,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IAC5B,KAAK,EAAE,KAAK,CAAC,KAAK;IAClB,OAAO,EAAE,KAAK,CAAC,OAAO;IACtB,OAAO,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;CACtD,CAAC,CAAC,CAAC;AAmBN,MAAM,CAAC,MAAM,qBAAqB,GAAG,CACnC,OAAe,EACf,MAAc,EACd,YAA+B,EACrB,EAAE,CAAC,CAAC,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,EAAE,GAAG,YAAY,CAAC,CAAC;AAsBhE,MAAM,CAAC,MAAM,uBAAuB,GAAG,CACrC,MAAc,EACd,MAA8C,EACnB,EAAE,CAC7B,MAAM,CAAC,MAAM,CACX,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE;IACb,MAAM,IAAI,GAAG,qBAAqB,CAAC,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,YAAY,IAAI,EAAE,CAAC,CAAC;IACpF,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,qBAAqB,CAAC,IAAI,CAAC,CAAC;IACjD,OAAO,GAAG,CAAC;AACb,CAAC,EACD,EAA+B,CAChC,CAAC"}
|
|
1
|
+
{"version":3,"file":"routemesh.js","sourceRoot":"","sources":["../../src/rpc/routemesh.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAIhC,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAI/D,MAAM,CAAC,MAAM,kBAAkB,GAAG,2BAA2B,CAAC;AA6B9D,MAAM,OAAO,2BAA4B,SAAQ,MAAM,CAAC,WAAW,EAA+B,CAChG,6BAA6B,EAC7B;IACE,OAAO,EAAE,MAAM,CAAC,MAAM;CACvB,CACF;CAAG;AAaJ,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,OAAe,EAAE,MAAc,EAAU,EAAE,CACtE,GAAG,kBAAkB,IAAI,OAAO,IAAI,MAAM,EAAE,CAAC;AAa/C,MAAM,CAAC,MAAM,YAAY,GACvB,CAAC,OAAe,EAAgC,EAAE,CAClD,CAAC,MAAM,EAAE,EAAE,CACT,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;AAwBlC,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,MAAuB,EAAiB,EAAE,CAChF,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IAC5B,KAAK,EAAE,KAAK,CAAC,KAAK;IAClB,OAAO,EAAE,KAAK,CAAC,OAAO;IACtB,OAAO,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;CACtD,CAAC,CAAC,CAAC;AAmBN,MAAM,CAAC,MAAM,qBAAqB,GAAG,CACnC,OAAe,EACf,MAAc,EACd,YAA+B,EACrB,EAAE,CAAC,CAAC,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,EAAE,GAAG,YAAY,CAAC,CAAC;AAsBhE,MAAM,CAAC,MAAM,uBAAuB,GAAG,CACrC,MAAc,EACd,MAA8C,EACnB,EAAE,CAC7B,MAAM,CAAC,MAAM,CACX,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE;IACb,MAAM,IAAI,GAAG,qBAAqB,CAAC,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,YAAY,IAAI,EAAE,CAAC,CAAC;IACpF,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,qBAAqB,CAAC,IAAI,CAAC,CAAC;IACjD,OAAO,GAAG,CAAC;AACb,CAAC,EACD,EAA+B,CAChC,CAAC","sourcesContent":["import { Schema } from \"effect\";\nimport type { Chain, Transport } from \"viem\";\n\nimport type { ChainConfig } from \"@/src/presets/index.js\";\nimport { makeFallbackTransport } from \"@/src/presets/index.js\";\n\n// === Constants ===\n\nexport const ROUTEMESH_BASE_URL = \"https://lb.routeme.sh/rpc\";\n\n// === Types ===\n\n/**\n * Configuration for a single chain using RouteMesh\n */\nexport type RouteMeshChainEntry = {\n readonly chainId: number;\n readonly chain: Chain;\n};\n\n/**\n * Full RouteMesh configuration with API key\n */\nexport type RouteMeshConfig = {\n readonly apiKey: string;\n readonly chains: readonly RouteMeshChainEntry[];\n};\n\n/**\n * Configuration for a chain with RouteMesh primary + optional fallback URLs\n */\nexport type RouteMeshFallbackChainEntry = RouteMeshChainEntry & {\n readonly fallbackUrls?: readonly string[];\n};\n\n// === Errors ===\n\nexport class RouteMeshApiKeyMissingError extends Schema.TaggedError<RouteMeshApiKeyMissingError>()(\n \"RouteMeshApiKeyMissingError\",\n {\n message: Schema.String,\n }\n) {}\n\n// === URL Generation ===\n\n/**\n * Generate a RouteMesh RPC URL for a specific chain\n *\n * @example\n * ```ts\n * const url = routemeshUrl(1, \"my-api-key\");\n * // => \"https://lb.routeme.sh/rpc/1/my-api-key\"\n * ```\n */\nexport const routemeshUrl = (chainId: number, apiKey: string): string =>\n `${ROUTEMESH_BASE_URL}/${chainId}/${apiKey}`;\n\n/**\n * Create a URL generator function for a specific chain.\n * Useful for deferred API key resolution.\n *\n * @example\n * ```ts\n * const mainnetRpc = routemeshRpc(1);\n * const url = mainnetRpc(\"my-api-key\");\n * // => \"https://lb.routeme.sh/rpc/1/my-api-key\"\n * ```\n */\nexport const routemeshRpc =\n (chainId: number): ((apiKey: string) => string) =>\n (apiKey) =>\n routemeshUrl(chainId, apiKey);\n\n// === ChainConfig Integration ===\n\n/**\n * Convert RouteMesh configuration to ChainConfig array.\n * Primary integration point with existing layer factories.\n *\n * @example\n * ```ts\n * import { mainnet, arbitrum } from \"viem/chains\";\n * import { makePublicClientLayer, routemeshToChainConfigs } from \"effect-evm\";\n *\n * const configs = routemeshToChainConfigs({\n * apiKey: \"my-api-key\",\n * chains: [\n * { chainId: mainnet.id, chain: mainnet },\n * { chainId: arbitrum.id, chain: arbitrum },\n * ],\n * });\n *\n * const layer = makePublicClientLayer(configs);\n * ```\n */\nexport const routemeshToChainConfigs = (config: RouteMeshConfig): ChainConfig[] =>\n config.chains.map((entry) => ({\n chain: entry.chain,\n chainId: entry.chainId,\n rpcUrls: [routemeshUrl(entry.chainId, config.apiKey)],\n }));\n\n// === Fallback Composition ===\n\n/**\n * Create fallback URLs combining RouteMesh with other providers.\n * RouteMesh URL is placed first (primary).\n *\n * @example\n * ```ts\n * import { mainnet } from \"viem/chains\";\n *\n * const urls = routemeshWithFallback(mainnet.id, \"api-key\", [\n * \"https://eth.llamarpc.com\",\n * \"https://rpc.ankr.com/eth\",\n * ]);\n * // => [\"https://lb.routeme.sh/rpc/1/api-key\", \"https://eth.llamarpc.com\", ...]\n * ```\n */\nexport const routemeshWithFallback = (\n chainId: number,\n apiKey: string,\n fallbackUrls: readonly string[]\n): string[] => [routemeshUrl(chainId, apiKey), ...fallbackUrls];\n\n/**\n * Create chain transports with RouteMesh as primary and optional fallbacks.\n *\n * @example\n * ```ts\n * import { mainnet, arbitrum } from \"viem/chains\";\n * import { makeRouteMeshTransports } from \"effect-evm\";\n *\n * const transports = makeRouteMeshTransports(\"my-api-key\", [\n * { chainId: mainnet.id, chain: mainnet, fallbackUrls: [\"https://eth.llamarpc.com\"] },\n * { chainId: arbitrum.id, chain: arbitrum },\n * ]);\n *\n * // Use with viem directly\n * const client = createPublicClient({\n * chain: mainnet,\n * transport: transports[mainnet.id],\n * });\n * ```\n */\nexport const makeRouteMeshTransports = (\n apiKey: string,\n chains: readonly RouteMeshFallbackChainEntry[]\n): Record<number, Transport> =>\n chains.reduce(\n (acc, entry) => {\n const urls = routemeshWithFallback(entry.chainId, apiKey, entry.fallbackUrls ?? []);\n acc[entry.chainId] = makeFallbackTransport(urls);\n return acc;\n },\n {} as Record<number, Transport>\n );\n"]}
|
package/dist/safe/adapter.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adapter.js","sourceRoot":"","sources":["../../src/safe/adapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAStD,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,MAA0B,EAAE,EAAE,CACxD,MAAM,CAAC,UAAU,CAAC;IAChB,KAAK,EAAE,CAAC,KAAK,EAAE,EAAE,CACf,IAAI,uBAAuB,CAAC;QAC1B,KAAK;QACL,OAAO,EACL,uGAAuG;KAC1G,CAAC;IACJ,GAAG,EAAE,KAAK,IAAI,EAAE;QACd,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,GAAG,MAAM,MAAM,CAAC,4BAA4B,CAAC,CAAC;QAC5E,OAAO,IAAI,WAAW,CAAC,MAAM,CAAC,CAAC;IACjC,CAAC;CACF,CAAC,CAAC"}
|
|
1
|
+
{"version":3,"file":"adapter.js","sourceRoot":"","sources":["../../src/safe/adapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAStD,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,MAA0B,EAAE,EAAE,CACxD,MAAM,CAAC,UAAU,CAAC;IAChB,KAAK,EAAE,CAAC,KAAK,EAAE,EAAE,CACf,IAAI,uBAAuB,CAAC;QAC1B,KAAK;QACL,OAAO,EACL,uGAAuG;KAC1G,CAAC;IACJ,GAAG,EAAE,KAAK,IAAI,EAAE;QACd,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,GAAG,MAAM,MAAM,CAAC,4BAA4B,CAAC,CAAC;QAC5E,OAAO,IAAI,WAAW,CAAC,MAAM,CAAC,CAAC;IACjC,CAAC;CACF,CAAC,CAAC","sourcesContent":["import { Effect } from \"effect\";\nimport { SafeSdkUnavailableError } from \"./errors.js\";\n\n/** Configuration for SDK initialization */\nexport type SafeAppsSdkConfig = {\n allowedDomains?: RegExp[];\n debug?: boolean;\n};\n\n/** Load SDK dynamically - keeps the dependency optional at runtime */\nexport const loadSafeSdk = (config?: SafeAppsSdkConfig) =>\n Effect.tryPromise({\n catch: (cause) =>\n new SafeSdkUnavailableError({\n cause,\n message:\n \"Failed to load @safe-global/safe-apps-sdk. Ensure it is installed: bun add @safe-global/safe-apps-sdk\",\n }),\n try: async () => {\n const { default: SafeAppsSDK } = await import(\"@safe-global/safe-apps-sdk\");\n return new SafeAppsSDK(config);\n },\n });\n\n/** Type for the loaded SDK instance - uses any due to optional SDK dependency */\n// biome-ignore lint/suspicious/noExplicitAny: SDK is optional dependency\nexport type SafeAppsSDKInstance = any;\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"detection.js","sourceRoot":"","sources":["../../src/safe/detection.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"detection.js","sourceRoot":"","sources":["../../src/safe/detection.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Safe multisig detection using EXTCODEHASH comparisons.\n *\n * Determines if an address is a Safe multisig by comparing bytecode hashes\n * against known Safe proxy and singleton hashes.\n *\n * @see https://github.com/safe-fndn/safe-smart-account/issues/714\n */\n\nimport { Effect, Schema } from \"effect\";\nimport type { Address, Hex } from \"viem\";\nimport { keccak256 } from \"viem\";\nimport type { ClientNotFoundError } from \"@/src/core/index.js\";\nimport { PublicClientService } from \"@/src/core/index.js\";\n\n// -----------------------------------------------------------------------------\n// Known Safe bytecode hashes\n// -----------------------------------------------------------------------------\n\n/**\n * Known Safe proxy bytecode hashes (keccak256 of deployed bytecode).\n *\n * These are the proxy contracts that delegate to Safe singletons.\n * All Safe accounts use one of these proxy implementations.\n *\n * @see https://github.com/safe-global/safe-deployments\n */\nconst KNOWN_SAFE_PROXY_HASHES: ReadonlySet<Hex> = new Set([\n // SafeProxy v1.3.0\n \"0xb89c1b3bdf2cf8827818646bce9a8f6e372885f8c55e5c07acbd307cb133b000\",\n // SafeProxy v1.4.1\n \"0xd7d408ebcd99b2b70be43e20253d6d92a8ea8fab29bd3be7f55b10032331fb4c\",\n] as Hex[]);\n\n/**\n * Known Safe singleton (implementation) bytecode hashes.\n *\n * These are the actual Safe contract implementations that proxies delegate to.\n *\n * Derivation: `cast keccak $(cast code <address> --rpc-url <mainnet>)`\n *\n * @see https://github.com/safe-global/safe-deployments\n */\nconst KNOWN_SAFE_SINGLETON_HASHES: ReadonlySet<Hex> = new Set([\n // Safe v1.0.0\n \"0xe1f1593df76e69abc2d692792c80f329457551d5e83dde597546a1d58764da80\",\n // Safe v1.1.1\n \"0x56b8be58b5ad629a621593a2e5e5e8e9a28408dc06e95597497b303902772e45\",\n // Safe v1.2.0\n \"0x2ae2d1231f0d754a7fa4f5e5d0e5554085e1b500d8e09f95aaaaa3f49c0db922\",\n // Safe v1.3.0\n \"0xbba688fbdb21ad2bb58bc320638b43d94e7d100f6f3ebaab0a4e4de6304b1c2e\",\n // Safe v1.3.0 L2\n \"0x21842597390c4c6e3c1239e434a682b054bd9548eee5e9b1d6a4482731023c0f\",\n // Safe v1.4.1\n \"0x1fe2df852ba3299d6534ef416eefa406e56ced995bca886ab7a553e6d0c5e1c4\",\n // Safe v1.4.1 L2\n \"0xb1f926978a0f44a2c0ec8fe822418ae969bd8c3f18d61e5103100339894f81ff\",\n // Safe v1.5.0\n \"0xdda019cbd7c867a533a2a86e5c53434fdc50b13122b5a5ddb4a8df61b31c20f2\",\n // Safe v1.5.0 L2\n \"0x180193227186ccb85316c94db1f0d156ed932b14712cfaac78901899178572dc\",\n] as Hex[]);\n\n// -----------------------------------------------------------------------------\n// Errors\n// -----------------------------------------------------------------------------\n\nexport class SafeDetectionError extends Schema.TaggedError<SafeDetectionError>()(\n \"SafeDetectionError\",\n {\n address: Schema.String,\n cause: Schema.optional(Schema.Unknown),\n message: Schema.String,\n }\n) {}\n\n// -----------------------------------------------------------------------------\n// ABI for masterCopy() call\n// -----------------------------------------------------------------------------\n\nconst masterCopyAbi = [\n {\n inputs: [],\n name: \"masterCopy\",\n outputs: [{ name: \"\", type: \"address\" }],\n stateMutability: \"view\",\n type: \"function\",\n },\n] as const;\n\n// -----------------------------------------------------------------------------\n// Detection function\n// -----------------------------------------------------------------------------\n\nexport type SafeDetectionParams = {\n /** The address to check */\n address: Address;\n /** The chain ID to query */\n chainId: number;\n};\n\nexport type SafeDetectionResult = {\n /** Whether the address appears to be a Safe multisig */\n isSafe: boolean;\n /** The proxy bytecode hash (if contract exists) */\n proxyHash: Hex | undefined;\n /** The singleton address (if Safe proxy detected) */\n singletonAddress: Address | undefined;\n /** The singleton bytecode hash (if singleton found) */\n singletonHash: Hex | undefined;\n};\n\n/**\n * Check if an address is a Safe multisig by comparing EXTCODEHASH values.\n *\n * This function:\n * 1. Gets the bytecode of the target address and computes its hash\n * 2. Checks if the hash matches a known Safe proxy\n * 3. If proxy matches, calls `masterCopy()` to get the singleton address\n * 4. Verifies the singleton's bytecode hash matches a known Safe singleton\n *\n * @example\n * ```typescript\n * const result = yield* isSafeMultisig({\n * address: \"0x...\",\n * chainId: 1,\n * });\n *\n * if (result.isSafe) {\n * console.log(\"This is a Safe multisig!\");\n * }\n * ```\n *\n * @remarks\n * This is a heuristic check, not a guarantee. Any contract can technically\n * deploy bytecode that matches Safe's, though this is extremely unlikely\n * in practice. For most use cases, this provides sufficient confidence.\n *\n * @see https://github.com/safe-fndn/safe-smart-account/issues/714\n */\nexport function isSafeMultisig(\n params: SafeDetectionParams\n): Effect.Effect<\n SafeDetectionResult,\n SafeDetectionError | ClientNotFoundError,\n PublicClientService\n> {\n return Effect.gen(function* () {\n const { address, chainId } = params;\n const publicClientService = yield* PublicClientService;\n const client = yield* publicClientService.get(chainId);\n\n // 1. Get proxy bytecode\n const proxyBytecode = yield* Effect.tryPromise({\n catch: (cause) =>\n new SafeDetectionError({\n address,\n cause,\n message: `Failed to get bytecode for ${address}`,\n }),\n try: () => client.getCode({ address }),\n });\n\n // No bytecode = EOA or empty contract\n if (!proxyBytecode || proxyBytecode === \"0x\") {\n return {\n isSafe: false,\n proxyHash: undefined,\n singletonAddress: undefined,\n singletonHash: undefined,\n };\n }\n\n // 2. Compute proxy hash\n const proxyHash = keccak256(proxyBytecode);\n\n // 3. Check if proxy hash matches known Safe proxies\n if (!KNOWN_SAFE_PROXY_HASHES.has(proxyHash)) {\n return {\n isSafe: false,\n proxyHash,\n singletonAddress: undefined,\n singletonHash: undefined,\n };\n }\n\n // 4. Call masterCopy() to get singleton address\n const singletonAddress = yield* Effect.tryPromise({\n catch: (cause) =>\n new SafeDetectionError({\n address,\n cause,\n message: `Failed to call masterCopy() on ${address}`,\n }),\n try: () =>\n client.readContract({\n abi: masterCopyAbi,\n address,\n functionName: \"masterCopy\",\n }),\n });\n\n // 5. Get singleton bytecode\n const singletonBytecode = yield* Effect.tryPromise({\n catch: (cause) =>\n new SafeDetectionError({\n address,\n cause,\n message: `Failed to get bytecode for singleton ${singletonAddress}`,\n }),\n try: () => client.getCode({ address: singletonAddress }),\n });\n\n if (!singletonBytecode || singletonBytecode === \"0x\") {\n return {\n isSafe: false,\n proxyHash,\n singletonAddress,\n singletonHash: undefined,\n };\n }\n\n // 6. Compute and check singleton hash\n const singletonHash = keccak256(singletonBytecode);\n const isSafe = KNOWN_SAFE_SINGLETON_HASHES.has(singletonHash);\n\n return {\n isSafe,\n proxyHash,\n singletonAddress,\n singletonHash,\n };\n });\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detection.test.integration.d.ts","sourceRoot":"","sources":["../../src/safe/detection.test.integration.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { describe, expect, it } from "@effect/vitest";
|
|
2
|
+
import { Effect } from "effect";
|
|
3
|
+
import { mainnet } from "viem/chains";
|
|
4
|
+
import { makePublicClientLayer } from "../presets/index.js";
|
|
5
|
+
import { isSafeMultisig } from "./detection.js";
|
|
6
|
+
const SAFE_V1_3_0_SINGLETON = "0xd9Db270c1B5E3Bd161E8c8503c55cEABeE709552";
|
|
7
|
+
const SAFE_V1_4_1_SINGLETON = "0x41675C099F32341bf84BFc5382aF534df5C7461a";
|
|
8
|
+
const testLayer = makePublicClientLayer([
|
|
9
|
+
{
|
|
10
|
+
chain: mainnet,
|
|
11
|
+
chainId: 1,
|
|
12
|
+
rpcUrls: ["https://eth.llamarpc.com"],
|
|
13
|
+
},
|
|
14
|
+
]);
|
|
15
|
+
describe("isSafeMultisig", () => {
|
|
16
|
+
describe("Positive Cases - Known Safe Wallets", () => {
|
|
17
|
+
it.effect("detects CoW DAO Safe (v1.3.0)", () => Effect.gen(function* () {
|
|
18
|
+
const result = yield* isSafeMultisig({
|
|
19
|
+
address: "0xcA771eda0c70aA7d053aB1B25004559B918FE662",
|
|
20
|
+
chainId: 1,
|
|
21
|
+
});
|
|
22
|
+
expect(result.isSafe).toBe(true);
|
|
23
|
+
expect(result.proxyHash).toBeDefined();
|
|
24
|
+
expect(result.singletonAddress).toBe(SAFE_V1_3_0_SINGLETON);
|
|
25
|
+
expect(result.singletonHash).toBeDefined();
|
|
26
|
+
}).pipe(Effect.provide(testLayer)));
|
|
27
|
+
it.effect("detects Gnosis DAO Safe (v1.3.0)", () => Effect.gen(function* () {
|
|
28
|
+
const result = yield* isSafeMultisig({
|
|
29
|
+
address: "0x849D52316331967b6fF1198e5E32A0eB168D039d",
|
|
30
|
+
chainId: 1,
|
|
31
|
+
});
|
|
32
|
+
expect(result.isSafe).toBe(true);
|
|
33
|
+
expect(result.proxyHash).toBeDefined();
|
|
34
|
+
expect(result.singletonAddress).toBe(SAFE_V1_3_0_SINGLETON);
|
|
35
|
+
expect(result.singletonHash).toBeDefined();
|
|
36
|
+
}).pipe(Effect.provide(testLayer)));
|
|
37
|
+
it.effect("detects v1.4.1 Safe", () => Effect.gen(function* () {
|
|
38
|
+
const result = yield* isSafeMultisig({
|
|
39
|
+
address: "0x843ed9137c60772b30a71a7fbdb7f302f336ace7",
|
|
40
|
+
chainId: 1,
|
|
41
|
+
});
|
|
42
|
+
expect(result.isSafe).toBe(true);
|
|
43
|
+
expect(result.proxyHash).toBeDefined();
|
|
44
|
+
expect(result.singletonAddress).toBe(SAFE_V1_4_1_SINGLETON);
|
|
45
|
+
expect(result.singletonHash).toBeDefined();
|
|
46
|
+
}).pipe(Effect.provide(testLayer)));
|
|
47
|
+
});
|
|
48
|
+
describe("Negative Cases - Non-Safe Contracts", () => {
|
|
49
|
+
it.effect("identifies non-Safe contract (vitalik.eth with EIP-7702) as non-Safe", () => Effect.gen(function* () {
|
|
50
|
+
const result = yield* isSafeMultisig({
|
|
51
|
+
address: "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
|
|
52
|
+
chainId: 1,
|
|
53
|
+
});
|
|
54
|
+
expect(result.isSafe).toBe(false);
|
|
55
|
+
expect(result.singletonAddress).toBeUndefined();
|
|
56
|
+
expect(result.singletonHash).toBeUndefined();
|
|
57
|
+
}).pipe(Effect.provide(testLayer)));
|
|
58
|
+
it.effect("identifies Uniswap V2 Router as non-Safe", () => Effect.gen(function* () {
|
|
59
|
+
const result = yield* isSafeMultisig({
|
|
60
|
+
address: "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D",
|
|
61
|
+
chainId: 1,
|
|
62
|
+
});
|
|
63
|
+
expect(result.isSafe).toBe(false);
|
|
64
|
+
expect(result.proxyHash).toBeDefined();
|
|
65
|
+
expect(result.singletonAddress).toBeUndefined();
|
|
66
|
+
expect(result.singletonHash).toBeUndefined();
|
|
67
|
+
}).pipe(Effect.provide(testLayer)));
|
|
68
|
+
it.effect("identifies USDC as non-Safe", () => Effect.gen(function* () {
|
|
69
|
+
const result = yield* isSafeMultisig({
|
|
70
|
+
address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
|
71
|
+
chainId: 1,
|
|
72
|
+
});
|
|
73
|
+
expect(result.isSafe).toBe(false);
|
|
74
|
+
expect(result.proxyHash).toBeDefined();
|
|
75
|
+
expect(result.singletonAddress).toBeUndefined();
|
|
76
|
+
expect(result.singletonHash).toBeUndefined();
|
|
77
|
+
}).pipe(Effect.provide(testLayer)));
|
|
78
|
+
});
|
|
79
|
+
describe("Edge Cases", () => {
|
|
80
|
+
it.effect("handles precompile address gracefully", () => Effect.gen(function* () {
|
|
81
|
+
const result = yield* isSafeMultisig({
|
|
82
|
+
address: "0x0000000000000000000000000000000000000001",
|
|
83
|
+
chainId: 1,
|
|
84
|
+
});
|
|
85
|
+
expect(result.isSafe).toBe(false);
|
|
86
|
+
expect(result.proxyHash).toBeUndefined();
|
|
87
|
+
expect(result.singletonAddress).toBeUndefined();
|
|
88
|
+
expect(result.singletonHash).toBeUndefined();
|
|
89
|
+
}).pipe(Effect.provide(testLayer)));
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
//# sourceMappingURL=detection.test.integration.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detection.test.integration.js","sourceRoot":"","sources":["../../src/safe/detection.test.integration.ts"],"names":[],"mappings":"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","sourcesContent":["import { describe, expect, it } from \"@effect/vitest\";\nimport { Effect } from \"effect\";\nimport type { Address } from \"viem\";\nimport { mainnet } from \"viem/chains\";\nimport { makePublicClientLayer } from \"@/src/presets/index.js\";\nimport { isSafeMultisig } from \"./detection.js\";\n\n// Known Safe singleton hashes for verification\nconst SAFE_V1_3_0_SINGLETON = \"0xd9Db270c1B5E3Bd161E8c8503c55cEABeE709552\" as Address;\nconst SAFE_V1_4_1_SINGLETON = \"0x41675C099F32341bf84BFc5382aF534df5C7461a\" as Address;\n\n// Test layer with Ethereum mainnet RPC\nconst testLayer = makePublicClientLayer([\n {\n chain: mainnet,\n chainId: 1,\n rpcUrls: [\"https://eth.llamarpc.com\"],\n },\n]);\n\ndescribe(\"isSafeMultisig\", () => {\n describe(\"Positive Cases - Known Safe Wallets\", () => {\n it.effect(\"detects CoW DAO Safe (v1.3.0)\", () =>\n Effect.gen(function* () {\n const result = yield* isSafeMultisig({\n address: \"0xcA771eda0c70aA7d053aB1B25004559B918FE662\",\n chainId: 1,\n });\n\n expect(result.isSafe).toBe(true);\n expect(result.proxyHash).toBeDefined();\n expect(result.singletonAddress).toBe(SAFE_V1_3_0_SINGLETON);\n expect(result.singletonHash).toBeDefined();\n }).pipe(Effect.provide(testLayer))\n );\n\n it.effect(\"detects Gnosis DAO Safe (v1.3.0)\", () =>\n Effect.gen(function* () {\n const result = yield* isSafeMultisig({\n address: \"0x849D52316331967b6fF1198e5E32A0eB168D039d\",\n chainId: 1,\n });\n\n expect(result.isSafe).toBe(true);\n expect(result.proxyHash).toBeDefined();\n expect(result.singletonAddress).toBe(SAFE_V1_3_0_SINGLETON);\n expect(result.singletonHash).toBeDefined();\n }).pipe(Effect.provide(testLayer))\n );\n\n it.effect(\"detects v1.4.1 Safe\", () =>\n Effect.gen(function* () {\n const result = yield* isSafeMultisig({\n address: \"0x843ed9137c60772b30a71a7fbdb7f302f336ace7\",\n chainId: 1,\n });\n\n expect(result.isSafe).toBe(true);\n expect(result.proxyHash).toBeDefined();\n expect(result.singletonAddress).toBe(SAFE_V1_4_1_SINGLETON);\n expect(result.singletonHash).toBeDefined();\n }).pipe(Effect.provide(testLayer))\n );\n });\n\n describe(\"Negative Cases - Non-Safe Contracts\", () => {\n it.effect(\"identifies non-Safe contract (vitalik.eth with EIP-7702) as non-Safe\", () =>\n Effect.gen(function* () {\n const result = yield* isSafeMultisig({\n address: \"0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045\",\n chainId: 1,\n });\n\n // vitalik.eth address has bytecode (EIP-7702 delegation) but is not a Safe multisig\n expect(result.isSafe).toBe(false);\n expect(result.singletonAddress).toBeUndefined();\n expect(result.singletonHash).toBeUndefined();\n }).pipe(Effect.provide(testLayer))\n );\n\n it.effect(\"identifies Uniswap V2 Router as non-Safe\", () =>\n Effect.gen(function* () {\n const result = yield* isSafeMultisig({\n address: \"0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D\",\n chainId: 1,\n });\n\n expect(result.isSafe).toBe(false);\n expect(result.proxyHash).toBeDefined();\n expect(result.singletonAddress).toBeUndefined();\n expect(result.singletonHash).toBeUndefined();\n }).pipe(Effect.provide(testLayer))\n );\n\n it.effect(\"identifies USDC as non-Safe\", () =>\n Effect.gen(function* () {\n const result = yield* isSafeMultisig({\n address: \"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48\",\n chainId: 1,\n });\n\n expect(result.isSafe).toBe(false);\n expect(result.proxyHash).toBeDefined();\n expect(result.singletonAddress).toBeUndefined();\n expect(result.singletonHash).toBeUndefined();\n }).pipe(Effect.provide(testLayer))\n );\n });\n\n describe(\"Edge Cases\", () => {\n it.effect(\"handles precompile address gracefully\", () =>\n Effect.gen(function* () {\n const result = yield* isSafeMultisig({\n address: \"0x0000000000000000000000000000000000000001\",\n chainId: 1,\n });\n\n expect(result.isSafe).toBe(false);\n expect(result.proxyHash).toBeUndefined();\n expect(result.singletonAddress).toBeUndefined();\n expect(result.singletonHash).toBeUndefined();\n }).pipe(Effect.provide(testLayer))\n );\n });\n});\n"]}
|
package/dist/safe/errors.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/safe/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAGhC,MAAM,OAAO,uBAAwB,SAAQ,MAAM,CAAC,WAAW,EAA2B,CACxF,yBAAyB,EACzB,EAAE,KAAK,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,CACnE;CAAG;AAEJ,MAAM,OAAO,wBAAyB,SAAQ,MAAM,CAAC,WAAW,EAA4B,CAC1F,0BAA0B,EAC1B,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,CAC3B;CAAG;AAGJ,MAAM,OAAO,wBAAyB,SAAQ,MAAM,CAAC,WAAW,EAA4B,CAC1F,0BAA0B,EAC1B,EAAE,KAAK,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,CACnE;CAAG;AAEJ,MAAM,OAAO,iBAAkB,SAAQ,MAAM,CAAC,WAAW,EAAqB,CAC5E,mBAAmB,EACnB,EAAE,KAAK,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,CACnE;CAAG;AAEJ,MAAM,OAAO,qBAAsB,SAAQ,MAAM,CAAC,WAAW,EAAyB,CACpF,uBAAuB,EACvB,EAAE,KAAK,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,CACnE;CAAG;AAEJ,MAAM,OAAO,iBAAkB,SAAQ,MAAM,CAAC,WAAW,EAAqB,CAC5E,mBAAmB,EACnB;IACE,KAAK,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC;IACtC,OAAO,EAAE,MAAM,CAAC,MAAM;IACtB,SAAS,EAAE,MAAM,CAAC,OAAO;IACzB,UAAU,EAAE,MAAM,CAAC,MAAM;CAC1B,CACF;CAAG;AAEJ,MAAM,OAAO,2BAA4B,SAAQ,MAAM,CAAC,WAAW,EAA+B,CAChG,6BAA6B,EAC7B;IACE,UAAU,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC;IAC1C,OAAO,EAAE,MAAM,CAAC,MAAM;IACtB,UAAU,EAAE,MAAM,CAAC,MAAM;IACzB,OAAO,EAAE,MAAM,CAAC,MAAM;CACvB,CACF;CAAG;AAGJ,MAAM,OAAO,kBAAmB,SAAQ,MAAM,CAAC,WAAW,EAAsB,CAC9E,oBAAoB,EACpB,EAAE,KAAK,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,CACnE;CAAG;AAEJ,MAAM,OAAO,6BAA8B,SAAQ,MAAM,CAAC,WAAW,EAAiC,CACpG,+BAA+B,EAC/B;IACE,OAAO,EAAE,MAAM,CAAC,MAAM;IACtB,WAAW,EAAE,MAAM,CAAC,MAAM;IAC1B,OAAO,EAAE,MAAM,CAAC,MAAM;CACvB,CACF;CAAG"}
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/safe/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAGhC,MAAM,OAAO,uBAAwB,SAAQ,MAAM,CAAC,WAAW,EAA2B,CACxF,yBAAyB,EACzB,EAAE,KAAK,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,CACnE;CAAG;AAEJ,MAAM,OAAO,wBAAyB,SAAQ,MAAM,CAAC,WAAW,EAA4B,CAC1F,0BAA0B,EAC1B,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,CAC3B;CAAG;AAGJ,MAAM,OAAO,wBAAyB,SAAQ,MAAM,CAAC,WAAW,EAA4B,CAC1F,0BAA0B,EAC1B,EAAE,KAAK,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,CACnE;CAAG;AAEJ,MAAM,OAAO,iBAAkB,SAAQ,MAAM,CAAC,WAAW,EAAqB,CAC5E,mBAAmB,EACnB,EAAE,KAAK,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,CACnE;CAAG;AAEJ,MAAM,OAAO,qBAAsB,SAAQ,MAAM,CAAC,WAAW,EAAyB,CACpF,uBAAuB,EACvB,EAAE,KAAK,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,CACnE;CAAG;AAEJ,MAAM,OAAO,iBAAkB,SAAQ,MAAM,CAAC,WAAW,EAAqB,CAC5E,mBAAmB,EACnB;IACE,KAAK,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC;IACtC,OAAO,EAAE,MAAM,CAAC,MAAM;IACtB,SAAS,EAAE,MAAM,CAAC,OAAO;IACzB,UAAU,EAAE,MAAM,CAAC,MAAM;CAC1B,CACF;CAAG;AAEJ,MAAM,OAAO,2BAA4B,SAAQ,MAAM,CAAC,WAAW,EAA+B,CAChG,6BAA6B,EAC7B;IACE,UAAU,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC;IAC1C,OAAO,EAAE,MAAM,CAAC,MAAM;IACtB,UAAU,EAAE,MAAM,CAAC,MAAM;IACzB,OAAO,EAAE,MAAM,CAAC,MAAM;CACvB,CACF;CAAG;AAGJ,MAAM,OAAO,kBAAmB,SAAQ,MAAM,CAAC,WAAW,EAAsB,CAC9E,oBAAoB,EACpB,EAAE,KAAK,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,CACnE;CAAG;AAEJ,MAAM,OAAO,6BAA8B,SAAQ,MAAM,CAAC,WAAW,EAAiC,CACpG,+BAA+B,EAC/B;IACE,OAAO,EAAE,MAAM,CAAC,MAAM;IACtB,WAAW,EAAE,MAAM,CAAC,MAAM;IAC1B,OAAO,EAAE,MAAM,CAAC,MAAM;CACvB,CACF;CAAG","sourcesContent":["import { Schema } from \"effect\";\n\n// SDK availability errors\nexport class SafeSdkUnavailableError extends Schema.TaggedError<SafeSdkUnavailableError>()(\n \"SafeSdkUnavailableError\",\n { cause: Schema.optional(Schema.Unknown), message: Schema.String }\n) {}\n\nexport class NotInSafeAppContextError extends Schema.TaggedError<NotInSafeAppContextError>()(\n \"NotInSafeAppContextError\",\n { message: Schema.String }\n) {}\n\n// Safe operation errors\nexport class SafeInfoUnavailableError extends Schema.TaggedError<SafeInfoUnavailableError>()(\n \"SafeInfoUnavailableError\",\n { cause: Schema.optional(Schema.Unknown), message: Schema.String }\n) {}\n\nexport class SafeSettingsError extends Schema.TaggedError<SafeSettingsError>()(\n \"SafeSettingsError\",\n { cause: Schema.optional(Schema.Unknown), message: Schema.String }\n) {}\n\nexport class SafeTxSubmissionError extends Schema.TaggedError<SafeTxSubmissionError>()(\n \"SafeTxSubmissionError\",\n { cause: Schema.optional(Schema.Unknown), message: Schema.String }\n) {}\n\nexport class SafeTxLookupError extends Schema.TaggedError<SafeTxLookupError>()(\n \"SafeTxLookupError\",\n {\n cause: Schema.optional(Schema.Unknown),\n message: Schema.String,\n retryable: Schema.Boolean,\n safeTxHash: Schema.String,\n }\n) {}\n\nexport class SafeTxExecutionTimeoutError extends Schema.TaggedError<SafeTxExecutionTimeoutError>()(\n \"SafeTxExecutionTimeoutError\",\n {\n lastStatus: Schema.optional(Schema.String),\n message: Schema.String,\n safeTxHash: Schema.String,\n timeout: Schema.Number,\n }\n) {}\n\n// Signing errors\nexport class SignTypedDataError extends Schema.TaggedError<SignTypedDataError>()(\n \"SignTypedDataError\",\n { cause: Schema.optional(Schema.Unknown), message: Schema.String }\n) {}\n\nexport class OffchainSignatureTimeoutError extends Schema.TaggedError<OffchainSignatureTimeoutError>()(\n \"OffchainSignatureTimeoutError\",\n {\n message: Schema.String,\n messageHash: Schema.String,\n timeout: Schema.Number,\n }\n) {}\n"]}
|
package/dist/safe/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/safe/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAGpE,OAAO,EACL,wBAAwB,EACxB,6BAA6B,EAC7B,wBAAwB,EACxB,uBAAuB,EACvB,iBAAiB,EACjB,2BAA2B,EAC3B,iBAAiB,EACjB,qBAAqB,EACrB,kBAAkB,GACnB,MAAM,aAAa,CAAC;AACrB,OAAO,EAA8B,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAC5E,OAAO,EAAE,eAAe,EAA6B,MAAM,cAAc,CAAC;AAE1E,cAAc,uBAAuB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/safe/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAGpE,OAAO,EACL,wBAAwB,EACxB,6BAA6B,EAC7B,wBAAwB,EACxB,uBAAuB,EACvB,iBAAiB,EACjB,2BAA2B,EAC3B,iBAAiB,EACjB,qBAAqB,EACrB,kBAAkB,GACnB,MAAM,aAAa,CAAC;AACrB,OAAO,EAA8B,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAC5E,OAAO,EAAE,eAAe,EAA6B,MAAM,cAAc,CAAC;AAE1E,cAAc,uBAAuB,CAAC","sourcesContent":["// Service and layer\n\nexport type { SafeDetectionParams, SafeDetectionResult } from \"./detection.js\";\n// Detection\nexport { isSafeMultisig, SafeDetectionError } from \"./detection.js\";\n\n// Errors\nexport {\n NotInSafeAppContextError,\n OffchainSignatureTimeoutError,\n SafeInfoUnavailableError,\n SafeSdkUnavailableError,\n SafeSettingsError,\n SafeTxExecutionTimeoutError,\n SafeTxLookupError,\n SafeTxSubmissionError,\n SignTypedDataError,\n} from \"./errors.js\";\nexport { type SafeAppsServiceConfig, SafeAppsServiceLive } from \"./live.js\";\nexport { SafeAppsService, type SafeAppsServiceShape } from \"./service.js\";\n// Simulation\nexport * from \"./simulation/index.js\";\n// Types\nexport type {\n EIP712TypedData,\n OffchainSignaturePolicy,\n OffchainSignatureResult,\n SafeInfo,\n SafeTransaction,\n SafeTxResult,\n SafeTxSubmission,\n SafeWaitPolicy,\n SignTypedDataResult,\n} from \"./types.js\";\n"]}
|