@prb/effect-evm 1.0.0-beta.8 → 1.0.0-beta.9

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.
@@ -1 +1 @@
1
- {"version":3,"file":"estimator.d.ts","sourceRoot":"","sources":["../../src/gas/estimator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACtE,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,qBAAqB,CAAC;AACpE,OAAO,EAAE,wBAAwB,EAAE,MAAM,qBAAqB,CAAC;AAE/D,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,UAAU,GAAG,MAAM,GAAG,SAAS,CAAC;AAEhE,MAAM,MAAM,WAAW,GAAG;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,oBAAoB,EAAE,MAAM,CAAC;CAC9B,CAAC;AAwEF,eAAO,MAAM,mBAAmB,GAC9B,qBAAqB,wBAAwB,EAC7C,SAAS,MAAM,KACd,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,wBAAwB,GAAG,mBAAmB,CAapE,CAAC;AAEL,eAAO,MAAM,sBAAsB,GACjC,qBAAqB,wBAAwB,EAC7C,SAAS,MAAM,KACd,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,EAAE,wBAAwB,GAAG,mBAAmB,CAuE1F,CAAC"}
1
+ {"version":3,"file":"estimator.d.ts","sourceRoot":"","sources":["../../src/gas/estimator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACtE,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,qBAAqB,CAAC;AACpE,OAAO,EAAE,wBAAwB,EAAE,MAAM,qBAAqB,CAAC;AAE/D,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,UAAU,GAAG,MAAM,GAAG,SAAS,CAAC;AAEhE,MAAM,MAAM,WAAW,GAAG;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,oBAAoB,EAAE,MAAM,CAAC;CAC9B,CAAC;AAgFF,eAAO,MAAM,mBAAmB,GAC9B,qBAAqB,wBAAwB,EAC7C,SAAS,MAAM,KACd,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,wBAAwB,GAAG,mBAAmB,CAapE,CAAC;AAEL,eAAO,MAAM,sBAAsB,GACjC,qBAAqB,wBAAwB,EAC7C,SAAS,MAAM,KACd,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,EAAE,wBAAwB,GAAG,mBAAmB,CAmF1F,CAAC"}
@@ -74,15 +74,19 @@ export const getAllFeeEstimatesImpl = (publicClientService, chainId) => Effect.g
74
74
  const client = yield* publicClientService.get(chainId);
75
75
  const supportsEip1559 = yield* supportsEip1559Impl(publicClientService, chainId);
76
76
  if (supportsEip1559) {
77
- const [block, maxPriorityFeePerGas] = yield* Effect.all([
78
- Effect.tryPromise({
79
- catch: (cause) => new GasPriceUnavailableError({
80
- cause,
81
- chainId,
82
- message: `Failed to get pending block: ${String(cause)}`,
83
- }),
84
- try: () => client.getBlock({ blockTag: "pending" }),
77
+ const getPendingOrLatestBlock = Effect.tryPromise({
78
+ catch: () => "pending-failed",
79
+ try: () => client.getBlock({ blockTag: "pending" }),
80
+ }).pipe(Effect.catchAll(() => Effect.tryPromise({
81
+ catch: (cause) => new GasPriceUnavailableError({
82
+ cause,
83
+ chainId,
84
+ message: `Failed to get block for fee estimation: ${String(cause)}`,
85
85
  }),
86
+ try: () => client.getBlock({ blockTag: "latest" }),
87
+ })));
88
+ const [block, maxPriorityFeePerGas] = yield* Effect.all([
89
+ getPendingOrLatestBlock,
86
90
  Effect.tryPromise({
87
91
  catch: (cause) => new GasPriceUnavailableError({
88
92
  cause,
@@ -1 +1 @@
1
- {"version":3,"file":"estimator.js","sourceRoot":"","sources":["../../src/gas/estimator.ts"],"names":[],"mappings":"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","sourcesContent":["import { Effect } from \"effect\";\nimport type { PublicClient } from \"viem\";\nimport type { ClientNotFoundError } from \"@/src/core/errors/index.js\";\nimport type { PublicClientServiceShape } from \"@/src/core/index.js\";\nimport { GasPriceUnavailableError } from \"@/src/gas/errors.js\";\n\nexport type GasSpeed = \"slow\" | \"standard\" | \"fast\" | \"instant\";\n\nexport type FeeEstimate = {\n confidence: number; // 0-100\n estimatedBaseFee: bigint;\n gasPrice?: bigint;\n maxFeePerGas: bigint;\n maxPriorityFeePerGas: bigint;\n};\n\n// Priority fee adjustments in gwei\nconst SPEED_ADJUSTMENTS: Record<GasSpeed, bigint> = {\n fast: 2_500_000_000n, // 2.5 gwei\n instant: 5_000_000_000n, // 5 gwei\n slow: 1_000_000_000n, // 1 gwei\n standard: 1_500_000_000n, // 1.5 gwei\n};\n\n// Confidence levels for each speed tier\nconst SPEED_CONFIDENCE: Record<GasSpeed, number> = {\n fast: 95,\n instant: 99,\n slow: 70,\n standard: 85,\n};\n\nfunction isBaseFeeMissing(baseFee: bigint | null | undefined): baseFee is null | undefined {\n return baseFee === null || baseFee === undefined;\n}\n\nfunction getLegacyFeeEstimates(\n client: PublicClient,\n chainId: number\n): Effect.Effect<Record<GasSpeed, FeeEstimate>, GasPriceUnavailableError> {\n return Effect.gen(function* () {\n const gasPrice = yield* Effect.tryPromise({\n catch: (cause) =>\n new GasPriceUnavailableError({\n cause,\n chainId,\n message: `Failed to get gas price: ${String(cause)}`,\n }),\n try: () => client.getGasPrice(),\n });\n\n const estimates: Record<GasSpeed, FeeEstimate> = {\n fast: {\n confidence: SPEED_CONFIDENCE.fast,\n estimatedBaseFee: 0n,\n gasPrice: (gasPrice * 125n) / 100n, // 1.25x\n maxFeePerGas: (gasPrice * 125n) / 100n,\n maxPriorityFeePerGas: 0n,\n },\n instant: {\n confidence: SPEED_CONFIDENCE.instant,\n estimatedBaseFee: 0n,\n gasPrice: (gasPrice * 150n) / 100n, // 1.5x\n maxFeePerGas: (gasPrice * 150n) / 100n,\n maxPriorityFeePerGas: 0n,\n },\n slow: {\n confidence: SPEED_CONFIDENCE.slow,\n estimatedBaseFee: 0n,\n gasPrice: (gasPrice * 90n) / 100n, // 0.9x\n maxFeePerGas: (gasPrice * 90n) / 100n,\n maxPriorityFeePerGas: 0n,\n },\n standard: {\n confidence: SPEED_CONFIDENCE.standard,\n estimatedBaseFee: 0n,\n gasPrice,\n maxFeePerGas: gasPrice,\n maxPriorityFeePerGas: 0n,\n },\n };\n\n return estimates;\n });\n}\n\nexport const supportsEip1559Impl = (\n publicClientService: PublicClientServiceShape,\n chainId: number\n): Effect.Effect<boolean, GasPriceUnavailableError | ClientNotFoundError> =>\n Effect.gen(function* () {\n const client = yield* publicClientService.get(chainId);\n const block = yield* Effect.tryPromise({\n catch: (cause) =>\n new GasPriceUnavailableError({\n cause,\n chainId,\n message: `Failed to check EIP-1559 support: ${String(cause)}`,\n }),\n try: () => client.getBlock({ blockTag: \"latest\" }),\n });\n return block.baseFeePerGas !== null && block.baseFeePerGas !== undefined;\n });\n\nexport const getAllFeeEstimatesImpl = (\n publicClientService: PublicClientServiceShape,\n chainId: number\n): Effect.Effect<Record<GasSpeed, FeeEstimate>, GasPriceUnavailableError | ClientNotFoundError> =>\n Effect.gen(function* () {\n const client = yield* publicClientService.get(chainId);\n const supportsEip1559 = yield* supportsEip1559Impl(publicClientService, chainId);\n\n if (supportsEip1559) {\n // EIP-1559 fee estimation\n const [block, maxPriorityFeePerGas] = yield* Effect.all(\n [\n Effect.tryPromise({\n catch: (cause) =>\n new GasPriceUnavailableError({\n cause,\n chainId,\n message: `Failed to get pending block: ${String(cause)}`,\n }),\n try: () => client.getBlock({ blockTag: \"pending\" }),\n }),\n Effect.tryPromise({\n catch: (cause) =>\n new GasPriceUnavailableError({\n cause,\n chainId,\n message: `Failed to estimate max priority fee: ${String(cause)}`,\n }),\n try: () => client.estimateMaxPriorityFeePerGas(),\n }),\n ],\n { concurrency: 2 }\n );\n\n let baseFee = block.baseFeePerGas;\n if (isBaseFeeMissing(baseFee)) {\n const latestBlock = yield* Effect.tryPromise({\n catch: (cause) =>\n new GasPriceUnavailableError({\n cause,\n chainId,\n message: `Failed to get latest block: ${String(cause)}`,\n }),\n try: () => client.getBlock({ blockTag: \"latest\" }),\n });\n baseFee = latestBlock.baseFeePerGas;\n }\n\n if (isBaseFeeMissing(baseFee)) {\n return yield* getLegacyFeeEstimates(client, chainId);\n }\n\n // Build estimates for each speed tier\n const makeEstimate = (speed: GasSpeed): FeeEstimate => {\n const priority = maxPriorityFeePerGas + SPEED_ADJUSTMENTS[speed];\n return {\n confidence: SPEED_CONFIDENCE[speed],\n estimatedBaseFee: baseFee,\n maxFeePerGas: baseFee * 2n + priority,\n maxPriorityFeePerGas: priority,\n };\n };\n\n const estimates: Record<GasSpeed, FeeEstimate> = {\n fast: makeEstimate(\"fast\"),\n instant: makeEstimate(\"instant\"),\n slow: makeEstimate(\"slow\"),\n standard: makeEstimate(\"standard\"),\n };\n\n return estimates;\n }\n\n return yield* getLegacyFeeEstimates(client, chainId);\n });\n"]}
1
+ {"version":3,"file":"estimator.js","sourceRoot":"","sources":["../../src/gas/estimator.ts"],"names":[],"mappings":"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","sourcesContent":["import { Effect } from \"effect\";\nimport type { PublicClient } from \"viem\";\nimport type { ClientNotFoundError } from \"@/src/core/errors/index.js\";\nimport type { PublicClientServiceShape } from \"@/src/core/index.js\";\nimport { GasPriceUnavailableError } from \"@/src/gas/errors.js\";\n\nexport type GasSpeed = \"slow\" | \"standard\" | \"fast\" | \"instant\";\n\nexport type FeeEstimate = {\n confidence: number; // 0-100\n estimatedBaseFee: bigint;\n gasPrice?: bigint;\n maxFeePerGas: bigint;\n maxPriorityFeePerGas: bigint;\n};\n\n// Priority fee adjustments in gwei\nconst SPEED_ADJUSTMENTS: Record<GasSpeed, bigint> = {\n fast: 2_500_000_000n, // 2.5 gwei\n instant: 5_000_000_000n, // 5 gwei\n slow: 1_000_000_000n, // 1 gwei\n standard: 1_500_000_000n, // 1.5 gwei\n};\n\n// Confidence levels for each speed tier\nconst SPEED_CONFIDENCE: Record<GasSpeed, number> = {\n fast: 95,\n instant: 99,\n slow: 70,\n standard: 85,\n};\n\n/**\n * Type guard for missing base fee. Some chains (e.g., BNB Chain) report EIP-1559 support\n * inconsistently - the latest block may have `baseFeePerGas` while pending blocks do not.\n */\nfunction isBaseFeeMissing(baseFee: bigint | null | undefined): baseFee is null | undefined {\n return baseFee === null || baseFee === undefined;\n}\n\n/**\n * Legacy fee estimation using `eth_gasPrice`. Used for chains without EIP-1559 support\n * (e.g., BNB Chain) or as a fallback when base fee is unavailable.\n */\nfunction getLegacyFeeEstimates(\n client: PublicClient,\n chainId: number\n): Effect.Effect<Record<GasSpeed, FeeEstimate>, GasPriceUnavailableError> {\n return Effect.gen(function* () {\n const gasPrice = yield* Effect.tryPromise({\n catch: (cause) =>\n new GasPriceUnavailableError({\n cause,\n chainId,\n message: `Failed to get gas price: ${String(cause)}`,\n }),\n try: () => client.getGasPrice(),\n });\n\n const estimates: Record<GasSpeed, FeeEstimate> = {\n fast: {\n confidence: SPEED_CONFIDENCE.fast,\n estimatedBaseFee: 0n,\n gasPrice: (gasPrice * 125n) / 100n, // 1.25x\n maxFeePerGas: (gasPrice * 125n) / 100n,\n maxPriorityFeePerGas: 0n,\n },\n instant: {\n confidence: SPEED_CONFIDENCE.instant,\n estimatedBaseFee: 0n,\n gasPrice: (gasPrice * 150n) / 100n, // 1.5x\n maxFeePerGas: (gasPrice * 150n) / 100n,\n maxPriorityFeePerGas: 0n,\n },\n slow: {\n confidence: SPEED_CONFIDENCE.slow,\n estimatedBaseFee: 0n,\n gasPrice: (gasPrice * 90n) / 100n, // 0.9x\n maxFeePerGas: (gasPrice * 90n) / 100n,\n maxPriorityFeePerGas: 0n,\n },\n standard: {\n confidence: SPEED_CONFIDENCE.standard,\n estimatedBaseFee: 0n,\n gasPrice,\n maxFeePerGas: gasPrice,\n maxPriorityFeePerGas: 0n,\n },\n };\n\n return estimates;\n });\n}\n\nexport const supportsEip1559Impl = (\n publicClientService: PublicClientServiceShape,\n chainId: number\n): Effect.Effect<boolean, GasPriceUnavailableError | ClientNotFoundError> =>\n Effect.gen(function* () {\n const client = yield* publicClientService.get(chainId);\n const block = yield* Effect.tryPromise({\n catch: (cause) =>\n new GasPriceUnavailableError({\n cause,\n chainId,\n message: `Failed to check EIP-1559 support: ${String(cause)}`,\n }),\n try: () => client.getBlock({ blockTag: \"latest\" }),\n });\n return block.baseFeePerGas !== null && block.baseFeePerGas !== undefined;\n });\n\nexport const getAllFeeEstimatesImpl = (\n publicClientService: PublicClientServiceShape,\n chainId: number\n): Effect.Effect<Record<GasSpeed, FeeEstimate>, GasPriceUnavailableError | ClientNotFoundError> =>\n Effect.gen(function* () {\n const client = yield* publicClientService.get(chainId);\n const supportsEip1559 = yield* supportsEip1559Impl(publicClientService, chainId);\n\n if (supportsEip1559) {\n // EIP-1559 fee estimation\n // Try pending block first, fall back to latest for chains that don't support pending (L2s)\n const getPendingOrLatestBlock = Effect.tryPromise({\n catch: () => \"pending-failed\" as const,\n try: () => client.getBlock({ blockTag: \"pending\" }),\n }).pipe(\n Effect.catchAll(() =>\n Effect.tryPromise({\n catch: (cause) =>\n new GasPriceUnavailableError({\n cause,\n chainId,\n message: `Failed to get block for fee estimation: ${String(cause)}`,\n }),\n try: () => client.getBlock({ blockTag: \"latest\" }),\n })\n )\n );\n\n const [block, maxPriorityFeePerGas] = yield* Effect.all(\n [\n getPendingOrLatestBlock,\n Effect.tryPromise({\n catch: (cause) =>\n new GasPriceUnavailableError({\n cause,\n chainId,\n message: `Failed to estimate max priority fee: ${String(cause)}`,\n }),\n try: () => client.estimateMaxPriorityFeePerGas(),\n }),\n ],\n { concurrency: 2 }\n );\n\n let baseFee = block.baseFeePerGas;\n if (isBaseFeeMissing(baseFee)) {\n const latestBlock = yield* Effect.tryPromise({\n catch: (cause) =>\n new GasPriceUnavailableError({\n cause,\n chainId,\n message: `Failed to get latest block: ${String(cause)}`,\n }),\n try: () => client.getBlock({ blockTag: \"latest\" }),\n });\n baseFee = latestBlock.baseFeePerGas;\n }\n\n // BNB Chain and similar networks may pass the EIP-1559 check but lack base fees\n // in practice. Fall back to legacy estimation when this occurs.\n if (isBaseFeeMissing(baseFee)) {\n return yield* getLegacyFeeEstimates(client, chainId);\n }\n\n // Build estimates for each speed tier\n const makeEstimate = (speed: GasSpeed): FeeEstimate => {\n const priority = maxPriorityFeePerGas + SPEED_ADJUSTMENTS[speed];\n return {\n confidence: SPEED_CONFIDENCE[speed],\n estimatedBaseFee: baseFee,\n maxFeePerGas: baseFee * 2n + priority,\n maxPriorityFeePerGas: priority,\n };\n };\n\n const estimates: Record<GasSpeed, FeeEstimate> = {\n fast: makeEstimate(\"fast\"),\n instant: makeEstimate(\"instant\"),\n slow: makeEstimate(\"slow\"),\n standard: makeEstimate(\"standard\"),\n };\n\n return estimates;\n }\n\n return yield* getLegacyFeeEstimates(client, chainId);\n });\n"]}
package/package.json CHANGED
@@ -6,7 +6,7 @@
6
6
  "sideEffects": false,
7
7
  "type": "module",
8
8
  "types": "./dist/index.d.ts",
9
- "version": "1.0.0-beta.8",
9
+ "version": "1.0.0-beta.9",
10
10
  "scripts": {
11
11
  "build": "just build",
12
12
  "prepack": "bun install --frozen-lockfile && just build"