@prb/effect-evm 1.0.0-beta.6 → 1.0.0-beta.7

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.
@@ -4,7 +4,7 @@ export const MIN_TX_GAS = 21000n;
4
4
  export const DEFAULT_MAX_DELAY = Duration.toMillis("30 seconds");
5
5
  export const DEFAULT_RECEIPT_TIMEOUT = Duration.toMillis("2 minutes");
6
6
  export const DEFAULT_REQUEST_TIMEOUT = Duration.toMillis("10 seconds");
7
- export const DEFAULT_STUCK_TX_MS = Duration.toMillis("45 seconds");
7
+ export const DEFAULT_STUCK_TX_MS = Duration.toMillis("60 minutes");
8
8
  export const DEFAULT_BLOCK_WAIT_TIMEOUT = Duration.toMillis("60 seconds");
9
9
  export const DEFAULT_POLLING_INTERVAL = Duration.toMillis("4 seconds");
10
10
  export const DEFAULT_RETRY_DELAY = Duration.toMillis("150 millis");
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/constants/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAOlC,MAAM,CAAC,MAAM,4BAA4B,GAAG,GAAG,CAAC;AAMhD,MAAM,CAAC,MAAM,UAAU,GAAG,MAAM,CAAC;AAOjC,MAAM,CAAC,MAAM,iBAAiB,GAAG,QAAQ,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;AAGjE,MAAM,CAAC,MAAM,uBAAuB,GAAG,QAAQ,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;AAGtE,MAAM,CAAC,MAAM,uBAAuB,GAAG,QAAQ,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;AAGvE,MAAM,CAAC,MAAM,mBAAmB,GAAG,QAAQ,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;AAGnE,MAAM,CAAC,MAAM,0BAA0B,GAAG,QAAQ,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;AAG1E,MAAM,CAAC,MAAM,wBAAwB,GAAG,QAAQ,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;AAGvE,MAAM,CAAC,MAAM,mBAAmB,GAAG,QAAQ,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;AAGnE,MAAM,CAAC,MAAM,+BAA+B,GAAG,QAAQ,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;AAG/E,MAAM,CAAC,MAAM,0BAA0B,GAAG,YAAY,CAAC","sourcesContent":["/**\n * Shared constants used across the codebase.\n */\n\nimport { Duration } from \"effect\";\n\n// =============================================================================\n// Gas Constants\n// =============================================================================\n\n/** Default multiplier for estimated gas limits (10% safety margin). */\nexport const DEFAULT_GAS_LIMIT_MULTIPLIER = 1.1;\n\n/**\n * Minimum gas required for a basic Ethereum transaction (21,000 gas units).\n * @see https://ethereum.stackexchange.com/q/34674/24693\n */\nexport const MIN_TX_GAS = 21000n;\n\n// =============================================================================\n// Timing Constants (milliseconds)\n// =============================================================================\n\n/** Default maximum delay for circuit breakers and subscriptions. */\nexport const DEFAULT_MAX_DELAY = Duration.toMillis(\"30 seconds\");\n\n/** Default timeout for waiting on a transaction receipt. */\nexport const DEFAULT_RECEIPT_TIMEOUT = Duration.toMillis(\"2 minutes\");\n\n/** Default timeout for RPC requests. */\nexport const DEFAULT_REQUEST_TIMEOUT = Duration.toMillis(\"10 seconds\");\n\n/** Default time before a transaction is considered stuck. */\nexport const DEFAULT_STUCK_TX_MS = Duration.toMillis(\"45 seconds\");\n\n/** Default timeout for waiting on a specific block. */\nexport const DEFAULT_BLOCK_WAIT_TIMEOUT = Duration.toMillis(\"60 seconds\");\n\n/** Default polling interval for transaction receipt and confirmation checks. */\nexport const DEFAULT_POLLING_INTERVAL = Duration.toMillis(\"4 seconds\");\n\n/** Default delay between RPC retries. */\nexport const DEFAULT_RETRY_DELAY = Duration.toMillis(\"150 millis\");\n\n/** Default base delay for subscription exponential backoff. */\nexport const DEFAULT_SUBSCRIPTION_BASE_DELAY = Duration.toMillis(\"500 millis\");\n\n/** Default debounce delay for cursor store flush operations. */\nexport const DEFAULT_CURSOR_FLUSH_DELAY = \"250 millis\";\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/constants/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAOlC,MAAM,CAAC,MAAM,4BAA4B,GAAG,GAAG,CAAC;AAMhD,MAAM,CAAC,MAAM,UAAU,GAAG,MAAM,CAAC;AAOjC,MAAM,CAAC,MAAM,iBAAiB,GAAG,QAAQ,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;AAGjE,MAAM,CAAC,MAAM,uBAAuB,GAAG,QAAQ,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;AAGtE,MAAM,CAAC,MAAM,uBAAuB,GAAG,QAAQ,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;AAGvE,MAAM,CAAC,MAAM,mBAAmB,GAAG,QAAQ,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;AAGnE,MAAM,CAAC,MAAM,0BAA0B,GAAG,QAAQ,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;AAG1E,MAAM,CAAC,MAAM,wBAAwB,GAAG,QAAQ,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;AAGvE,MAAM,CAAC,MAAM,mBAAmB,GAAG,QAAQ,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;AAGnE,MAAM,CAAC,MAAM,+BAA+B,GAAG,QAAQ,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;AAG/E,MAAM,CAAC,MAAM,0BAA0B,GAAG,YAAY,CAAC","sourcesContent":["/**\n * Shared constants used across the codebase.\n */\n\nimport { Duration } from \"effect\";\n\n// =============================================================================\n// Gas Constants\n// =============================================================================\n\n/** Default multiplier for estimated gas limits (10% safety margin). */\nexport const DEFAULT_GAS_LIMIT_MULTIPLIER = 1.1;\n\n/**\n * Minimum gas required for a basic Ethereum transaction (21,000 gas units).\n * @see https://ethereum.stackexchange.com/q/34674/24693\n */\nexport const MIN_TX_GAS = 21000n;\n\n// =============================================================================\n// Timing Constants (milliseconds)\n// =============================================================================\n\n/** Default maximum delay for circuit breakers and subscriptions. */\nexport const DEFAULT_MAX_DELAY = Duration.toMillis(\"30 seconds\");\n\n/** Default timeout for waiting on a transaction receipt. */\nexport const DEFAULT_RECEIPT_TIMEOUT = Duration.toMillis(\"2 minutes\");\n\n/** Default timeout for RPC requests. */\nexport const DEFAULT_REQUEST_TIMEOUT = Duration.toMillis(\"10 seconds\");\n\n/** Default time before a transaction is considered stuck. */\nexport const DEFAULT_STUCK_TX_MS = Duration.toMillis(\"60 minutes\");\n\n/** Default timeout for waiting on a specific block. */\nexport const DEFAULT_BLOCK_WAIT_TIMEOUT = Duration.toMillis(\"60 seconds\");\n\n/** Default polling interval for transaction receipt and confirmation checks. */\nexport const DEFAULT_POLLING_INTERVAL = Duration.toMillis(\"4 seconds\");\n\n/** Default delay between RPC retries. */\nexport const DEFAULT_RETRY_DELAY = Duration.toMillis(\"150 millis\");\n\n/** Default base delay for subscription exponential backoff. */\nexport const DEFAULT_SUBSCRIPTION_BASE_DELAY = Duration.toMillis(\"500 millis\");\n\n/** Default debounce delay for cursor store flush operations. */\nexport const DEFAULT_CURSOR_FLUSH_DELAY = \"250 millis\";\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"write-and-track.d.ts","sourceRoot":"","sources":["../../../src/contract/pipeline/write-and-track.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,MAAM,EAAsB,MAAM,QAAQ,CAAC;AACrE,OAAO,KAAK,EAAE,GAAG,EAAsB,MAAM,MAAM,CAAC;AAEpD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AACnE,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,qBAAqB,CAAC;AACpE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,KAAK,EAAE,cAAc,EAAE,QAAQ,EAAE,kBAAkB,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAE/F,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAIjE,OAAO,KAAK,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAK/F,MAAM,MAAM,iBAAiB,GAAG;IAC9B,QAAQ,CAAC,MAAM,EAAE,mBAAmB,CAAC;IACrC,QAAQ,CAAC,SAAS,EAAE,cAAc,CAAC;IACnC,QAAQ,CAAC,WAAW,EAAE,gBAAgB,CAAC;IACvC,QAAQ,CAAC,YAAY,EAAE,iBAAiB,CAAC;IACzC,QAAQ,CAAC,aAAa,EAAE,kBAAkB,CAAC;IAC3C,QAAQ,CAAC,mBAAmB,EAAE,wBAAwB,CAAC;IACvD,QAAQ,CAAC,UAAU,EAAE,eAAe,CAAC;CACtC,CAAC;AAKF,eAAO,MAAM,iBAAiB,GAAI,MAAM,iBAAiB,MAErD,IAAI,SAAS,GAAG,EAChB,aAAa;;kCA+SiB,QAAQ;mCAoCP,QAAQ;;;;uCAuCvC,CAAC"}
1
+ {"version":3,"file":"write-and-track.d.ts","sourceRoot":"","sources":["../../../src/contract/pipeline/write-and-track.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,MAAM,EAAsB,MAAM,QAAQ,CAAC;AACrE,OAAO,KAAK,EAAE,GAAG,EAAsB,MAAM,MAAM,CAAC;AAEpD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AACnE,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,qBAAqB,CAAC;AACpE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,KAAK,EAAE,cAAc,EAAE,QAAQ,EAAE,kBAAkB,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAE/F,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAIjE,OAAO,KAAK,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAK/F,MAAM,MAAM,iBAAiB,GAAG;IAC9B,QAAQ,CAAC,MAAM,EAAE,mBAAmB,CAAC;IACrC,QAAQ,CAAC,SAAS,EAAE,cAAc,CAAC;IACnC,QAAQ,CAAC,WAAW,EAAE,gBAAgB,CAAC;IACvC,QAAQ,CAAC,YAAY,EAAE,iBAAiB,CAAC;IACzC,QAAQ,CAAC,aAAa,EAAE,kBAAkB,CAAC;IAC3C,QAAQ,CAAC,mBAAmB,EAAE,wBAAwB,CAAC;IACvD,QAAQ,CAAC,UAAU,EAAE,eAAe,CAAC;CACtC,CAAC;AAKF,eAAO,MAAM,iBAAiB,GAAI,MAAM,iBAAiB,MAErD,IAAI,SAAS,GAAG,EAChB,aAAa;;kCA8SiB,QAAQ;mCAoCP,QAAQ;;;;uCAuCvC,CAAC"}
@@ -68,7 +68,6 @@ export const makeWriteAndTrack = (deps) => Effect.fn("ContractPipeline.writeAndT
68
68
  yield* tracker.update((prev) => ({ hash, status: "submitted", tx: prev.tx }));
69
69
  const publicClient = yield* publicClientService.get(params.chainId);
70
70
  const replacementStrategy = policy.replacement?.strategy ?? policy.replacementStrategy ?? "none";
71
- const stuckBlocks = policy.replacement?.stuckBlocks ?? 3;
72
71
  const stuckMs = policy.replacement?.stuckMs ?? DEFAULT_STUCK_TX_MS;
73
72
  const maxAttempts = policy.replacement?.maxAttempts ?? 1;
74
73
  const updatePendingState = (currentHash) => Effect.gen(function* () {
@@ -112,7 +111,7 @@ export const makeWriteAndTrack = (deps) => Effect.fn("ContractPipeline.writeAndT
112
111
  })),
113
112
  ]).pipe(Effect.asVoid);
114
113
  }))));
115
- const autoReplaceIfStuck = (currentHash, blocksElapsed) => {
114
+ const autoReplaceIfStuck = (currentHash) => {
116
115
  if (replacementStrategy === "none") {
117
116
  return Effect.void;
118
117
  }
@@ -123,7 +122,7 @@ export const makeWriteAndTrack = (deps) => Effect.fn("ContractPipeline.writeAndT
123
122
  startedAt: Ref.get(startedAtMsRef),
124
123
  }).pipe(Effect.flatMap(({ alreadyReplacing, attempts, now, startedAt }) => {
125
124
  const elapsed = startedAt > 0 ? now - startedAt : 0;
126
- const stuck = blocksElapsed >= stuckBlocks || elapsed >= stuckMs;
125
+ const stuck = elapsed >= stuckMs;
127
126
  const allowed = attempts < maxAttempts && !alreadyReplacing;
128
127
  return stuck && allowed ? performAutoReplacement(currentHash, now) : Effect.void;
129
128
  }));
@@ -133,8 +132,8 @@ export const makeWriteAndTrack = (deps) => Effect.fn("ContractPipeline.writeAndT
133
132
  if (!currentHash) {
134
133
  return;
135
134
  }
136
- const blocksElapsed = yield* updatePendingState(currentHash);
137
- yield* autoReplaceIfStuck(currentHash, blocksElapsed);
135
+ yield* updatePendingState(currentHash);
136
+ yield* autoReplaceIfStuck(currentHash);
138
137
  });
139
138
  const pendingFiber = yield* Stream.runForEach(Stream.async((emit) => {
140
139
  const unwatch = publicClient.watchBlockNumber({
@@ -1 +1 @@
1
- {"version":3,"file":"write-and-track.js","sourceRoot":"","sources":["../../../src/contract/pipeline/write-and-track.ts"],"names":[],"mappings":"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","sourcesContent":["import { Clock, Deferred, Effect, Fiber, Ref, Stream } from \"effect\";\nimport type { Abi, Hash, PublicClient } from \"viem\";\nimport { DEFAULT_STUCK_TX_MS } from \"@/src/constants/index.js\";\nimport type { ContractWriterShape } from \"@/src/contract/index.js\";\nimport type { PublicClientServiceShape } from \"@/src/core/index.js\";\nimport type { EventStreamShape } from \"@/src/events/index.js\";\nimport type { GasServiceShape } from \"@/src/gas/index.js\";\nimport type { NonceServiceShape } from \"@/src/nonce/index.js\";\nimport type { TxManagerShape, TxPolicy, TxReplacementShape, TxState } from \"@/src/tx/index.js\";\nimport { defaultPolicy, makeTxTracker } from \"@/src/tx/index.js\";\nimport type { ContractFunctionName } from \"@/src/types/index.js\";\nimport { applyGasLimitMultiplier, nonceToBigInt } from \"./internal/helpers.js\";\nimport { withNonceReservation } from \"./internal/nonce.js\";\nimport { deriveBaseOverrides } from \"./internal/prepare.js\";\nimport type { WriteAndTrackError, WriteAndTrackParams, WriteAndTrackResult } from \"./types.js\";\n\n/**\n * Dependencies required by writeAndTrack\n */\nexport type WriteAndTrackDeps = {\n readonly writer: ContractWriterShape;\n readonly txManager: TxManagerShape;\n readonly eventStream: EventStreamShape;\n readonly nonceService: NonceServiceShape;\n readonly txReplacement: TxReplacementShape;\n readonly publicClientService: PublicClientServiceShape;\n readonly gasService: GasServiceShape;\n};\n\n/**\n * Create the writeAndTrack implementation with full tracking orchestration\n */\nexport const makeWriteAndTrack = (deps: WriteAndTrackDeps) =>\n Effect.fn(\"ContractPipeline.writeAndTrack\")(function* <\n TAbi extends Abi,\n TFunctionName extends ContractFunctionName<TAbi, \"nonpayable\" | \"payable\">,\n >(params: WriteAndTrackParams<TAbi, TFunctionName>) {\n const {\n writer,\n txManager,\n eventStream,\n nonceService,\n txReplacement,\n publicClientService,\n gasService,\n } = deps;\n\n const tracker = yield* makeTxTracker;\n const policy = params.policy ?? defaultPolicy;\n const currentHashRef = yield* Ref.make<Hash | null>(null);\n const blocksElapsedRef = yield* Ref.make(0);\n const startedAtMsRef = yield* Ref.make(0);\n const autoAttemptsRef = yield* Ref.make(0);\n const autoReplacingRef = yield* Ref.make(false);\n\n const resultDeferred = yield* Deferred.make<WriteAndTrackResult<TAbi>, WriteAndTrackError>();\n\n const run = Effect.gen(function* () {\n // Step 1: Derive base overrides\n const baseOverrides = yield* deriveBaseOverrides(gasService, {\n chainId: params.chainId,\n policy,\n userOverrides: params.overrides,\n });\n\n // Step 2: Estimate gas first to provide a reasonable limit for simulation.\n // Some RPC nodes default to max uint64 when no gas limit is provided,\n // causing \"insufficient funds\" errors during the balance check.\n const estimatedGas = yield* writer.estimateGas({\n ...params,\n overrides: baseOverrides,\n });\n // Apply multiplier to add safety margin; this buffered value is used for\n // both simulation (balance check) and the final transaction.\n const derivedGas = applyGasLimitMultiplier(estimatedGas, policy.gasLimitMultiplier);\n\n const explicitGas = params.overrides?.gas ?? params.gas;\n const finalGas = explicitGas ?? derivedGas;\n\n // Step 3: Simulate with the gas limit to ensure proper balance checks\n yield* tracker.set({ status: \"simulating\" });\n yield* writer.simulate({ ...params, overrides: { ...baseOverrides, gas: finalGas } });\n const explicitNonce = params.overrides?.nonce;\n\n // Step 4: Reserve nonce\n const nonceReservation = yield* withNonceReservation(nonceService, {\n account: params.account,\n chainId: params.chainId,\n explicitNonce,\n });\n\n const nonce = nonceReservation.nonce;\n\n const overridesWithGasAndNonce = {\n ...baseOverrides,\n gas: finalGas,\n nonce,\n };\n\n yield* tracker.set({\n gas: finalGas,\n status: \"estimated\",\n tx: {\n accessList: overridesWithGasAndNonce.accessList,\n gas: finalGas,\n gasPrice: overridesWithGasAndNonce.gasPrice,\n maxFeePerGas: overridesWithGasAndNonce.maxFeePerGas,\n maxPriorityFeePerGas: overridesWithGasAndNonce.maxPriorityFeePerGas,\n nonce,\n type: overridesWithGasAndNonce.type,\n },\n });\n\n // Step 5: Signing\n yield* tracker.update((prev) => ({ status: \"signing\", tx: prev.tx }) as TxState);\n\n // Step 6: Write transaction\n const hash = yield* writer.write({\n ...params,\n overrides: overridesWithGasAndNonce,\n });\n yield* nonceReservation.markSubmitted;\n yield* Ref.set(currentHashRef, hash);\n yield* Ref.set(blocksElapsedRef, 0);\n yield* Ref.set(autoAttemptsRef, 0);\n yield* Ref.set(autoReplacingRef, false);\n yield* Ref.set(startedAtMsRef, yield* Clock.currentTimeMillis);\n yield* tracker.update((prev) => ({ hash, status: \"submitted\", tx: prev.tx }) as TxState);\n\n // Set up block watcher for pending state updates\n const publicClient: PublicClient = yield* publicClientService.get(params.chainId);\n const replacementStrategy =\n policy.replacement?.strategy ?? policy.replacementStrategy ?? \"none\";\n const stuckBlocks = policy.replacement?.stuckBlocks ?? 3;\n const stuckMs = policy.replacement?.stuckMs ?? DEFAULT_STUCK_TX_MS;\n const maxAttempts = policy.replacement?.maxAttempts ?? 1;\n\n const updatePendingState = (currentHash: Hash) =>\n Effect.gen(function* () {\n const blocksElapsed = yield* Ref.modify(blocksElapsedRef, (n) => [n + 1, n + 1] as const);\n\n yield* tracker.update((prev) => {\n if (prev.status === \"mined\" || prev.status === \"failed\") {\n return prev;\n }\n return {\n confirmations: blocksElapsed,\n hash: currentHash,\n status: \"pending\",\n tx: prev.tx,\n } as TxState;\n });\n\n return blocksElapsed;\n });\n\n const performAutoReplacement = (currentHash: Hash, now: number) =>\n Ref.set(autoReplacingRef, true).pipe(\n Effect.zipRight(\n (replacementStrategy === \"cancel\"\n ? txReplacement.cancel(params.chainId, currentHash, policy)\n : txReplacement.speedup(params.chainId, currentHash, policy)\n ).pipe(\n Effect.either,\n Effect.ensuring(Ref.set(autoReplacingRef, false)),\n Effect.flatMap((replaced) => {\n if (replaced._tag === \"Left\") {\n return Effect.void;\n }\n\n const newHash = replaced.right;\n return Effect.all([\n Ref.set(currentHashRef, newHash),\n Ref.set(blocksElapsedRef, 0),\n Ref.set(startedAtMsRef, now),\n Ref.update(autoAttemptsRef, (n) => n + 1),\n tracker.update(\n (prev) =>\n ({\n newHash,\n oldHash: currentHash,\n reason: replacementStrategy === \"cancel\" ? \"cancelled\" : \"repriced\",\n status: \"replaced\",\n tx: prev.tx,\n }) as TxState\n ),\n tracker.update(\n (prev) =>\n ({\n hash: newHash,\n status: \"submitted\",\n tx: prev.tx,\n }) as TxState\n ),\n ]).pipe(Effect.asVoid);\n })\n )\n )\n );\n\n const autoReplaceIfStuck = (currentHash: Hash, blocksElapsed: number) => {\n if (replacementStrategy === \"none\") {\n return Effect.void;\n }\n\n return Effect.all({\n alreadyReplacing: Ref.get(autoReplacingRef),\n attempts: Ref.get(autoAttemptsRef),\n now: Clock.currentTimeMillis,\n startedAt: Ref.get(startedAtMsRef),\n }).pipe(\n Effect.flatMap(({ alreadyReplacing, attempts, now, startedAt }) => {\n const elapsed = startedAt > 0 ? now - startedAt : 0;\n const stuck = blocksElapsed >= stuckBlocks || elapsed >= stuckMs;\n const allowed = attempts < maxAttempts && !alreadyReplacing;\n return stuck && allowed ? performAutoReplacement(currentHash, now) : Effect.void;\n })\n );\n };\n\n const onPendingBlock = Effect.gen(function* () {\n const currentHash = yield* Ref.get(currentHashRef);\n if (!currentHash) {\n return;\n }\n\n const blocksElapsed = yield* updatePendingState(currentHash);\n yield* autoReplaceIfStuck(currentHash, blocksElapsed);\n });\n\n const pendingFiber = yield* Stream.runForEach(\n Stream.async<bigint, unknown>((emit) => {\n const unwatch = publicClient.watchBlockNumber({\n onBlockNumber: (blockNumber: bigint) => emit.single(blockNumber),\n onError: (error) => emit.fail(error as unknown),\n pollingInterval: policy.pollingInterval,\n });\n\n return Effect.sync(() => {\n unwatch();\n });\n }),\n () => onPendingBlock\n ).pipe(Effect.forkScoped);\n\n // Step 7: Wait for receipt (follow replacements)\n const receipt = yield* Effect.gen(function* () {\n let waitHash = hash;\n\n while (true) {\n const exit = yield* txManager\n .waitForReceipt(params.chainId, waitHash, policy)\n .pipe(Effect.either);\n\n if (exit._tag === \"Right\") {\n return exit.right;\n }\n\n const error = exit.left;\n if (error._tag === \"TxReplacedError\") {\n const newHash = error.newHash as Hash;\n const now = yield* Clock.currentTimeMillis;\n\n yield* Ref.set(currentHashRef, newHash);\n yield* Ref.set(blocksElapsedRef, 0);\n yield* Ref.set(startedAtMsRef, now);\n yield* tracker.update(\n (prev) =>\n ({\n newHash,\n oldHash: error.oldHash as Hash,\n reason: error.reason,\n status: \"replaced\",\n tx: prev.tx,\n }) as TxState\n );\n yield* tracker.update(\n (prev) =>\n ({\n hash: newHash,\n status: \"submitted\",\n tx: prev.tx,\n }) as TxState\n );\n\n waitHash = newHash;\n continue;\n }\n\n return yield* Effect.fail(error);\n }\n }).pipe(Effect.ensuring(Fiber.interrupt(pendingFiber)));\n\n // Step 8: Update to mined state\n yield* tracker.update(\n (prev) =>\n ({\n effectiveGasPrice: receipt.effectiveGasPrice,\n hash: receipt.transactionHash as Hash,\n receipt,\n status: \"mined\",\n tx: prev.tx,\n }) as TxState\n );\n\n if (nonceReservation.reserved) {\n yield* nonceService.confirm({\n address: params.account,\n chainId: params.chainId,\n nonce: nonceToBigInt(nonceReservation.nonce),\n });\n }\n\n // Step 9: Decode events\n const events = (yield* eventStream.decodeReceipt(\n receipt,\n params.abi\n )) as WriteAndTrackResult<TAbi>[\"events\"];\n\n return {\n events,\n hash: receipt.transactionHash as Hash,\n receipt,\n } as WriteAndTrackResult<TAbi>;\n });\n\n yield* run.pipe(\n Effect.either,\n Effect.flatMap((either) =>\n either._tag === \"Right\"\n ? Deferred.succeed(resultDeferred, either.right)\n : Deferred.fail(resultDeferred, either.left)\n ),\n Effect.forkScoped\n );\n\n return {\n actions: {\n cancel: (overridePolicy?: TxPolicy) =>\n Effect.gen(function* () {\n const currentHash = yield* Ref.get(currentHashRef);\n if (!currentHash) {\n return yield* Effect.fail(new Error(\"Transaction not yet submitted\"));\n }\n\n const nextPolicy = overridePolicy ?? policy;\n const newHash = yield* txReplacement.cancel(params.chainId, currentHash, nextPolicy);\n const now = yield* Clock.currentTimeMillis;\n\n yield* Ref.set(currentHashRef, newHash);\n yield* Ref.set(blocksElapsedRef, 0);\n yield* Ref.set(startedAtMsRef, now);\n yield* tracker.update(\n (prev) =>\n ({\n newHash,\n oldHash: currentHash,\n reason: \"cancelled\",\n status: \"replaced\",\n tx: prev.tx,\n }) as TxState\n );\n yield* tracker.update(\n (prev) =>\n ({\n hash: newHash,\n status: \"submitted\",\n tx: prev.tx,\n }) as TxState\n );\n\n return newHash;\n }),\n\n speedup: (overridePolicy?: TxPolicy) =>\n Effect.gen(function* () {\n const currentHash = yield* Ref.get(currentHashRef);\n if (!currentHash) {\n return yield* Effect.fail(new Error(\"Transaction not yet submitted\"));\n }\n\n const nextPolicy = overridePolicy ?? policy;\n const newHash = yield* txReplacement.speedup(params.chainId, currentHash, nextPolicy);\n const now = yield* Clock.currentTimeMillis;\n\n yield* Ref.set(currentHashRef, newHash);\n yield* Ref.set(blocksElapsedRef, 0);\n yield* Ref.set(startedAtMsRef, now);\n yield* tracker.update(\n (prev) =>\n ({\n newHash,\n oldHash: currentHash,\n reason: \"repriced\",\n status: \"replaced\",\n tx: prev.tx,\n }) as TxState\n );\n yield* tracker.update(\n (prev) =>\n ({\n hash: newHash,\n status: \"submitted\",\n tx: prev.tx,\n }) as TxState\n );\n\n return newHash;\n }),\n },\n result: Deferred.await(resultDeferred),\n stateRef: tracker.ref,\n };\n });\n"]}
1
+ {"version":3,"file":"write-and-track.js","sourceRoot":"","sources":["../../../src/contract/pipeline/write-and-track.ts"],"names":[],"mappings":"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","sourcesContent":["import { Clock, Deferred, Effect, Fiber, Ref, Stream } from \"effect\";\nimport type { Abi, Hash, PublicClient } from \"viem\";\nimport { DEFAULT_STUCK_TX_MS } from \"@/src/constants/index.js\";\nimport type { ContractWriterShape } from \"@/src/contract/index.js\";\nimport type { PublicClientServiceShape } from \"@/src/core/index.js\";\nimport type { EventStreamShape } from \"@/src/events/index.js\";\nimport type { GasServiceShape } from \"@/src/gas/index.js\";\nimport type { NonceServiceShape } from \"@/src/nonce/index.js\";\nimport type { TxManagerShape, TxPolicy, TxReplacementShape, TxState } from \"@/src/tx/index.js\";\nimport { defaultPolicy, makeTxTracker } from \"@/src/tx/index.js\";\nimport type { ContractFunctionName } from \"@/src/types/index.js\";\nimport { applyGasLimitMultiplier, nonceToBigInt } from \"./internal/helpers.js\";\nimport { withNonceReservation } from \"./internal/nonce.js\";\nimport { deriveBaseOverrides } from \"./internal/prepare.js\";\nimport type { WriteAndTrackError, WriteAndTrackParams, WriteAndTrackResult } from \"./types.js\";\n\n/**\n * Dependencies required by writeAndTrack\n */\nexport type WriteAndTrackDeps = {\n readonly writer: ContractWriterShape;\n readonly txManager: TxManagerShape;\n readonly eventStream: EventStreamShape;\n readonly nonceService: NonceServiceShape;\n readonly txReplacement: TxReplacementShape;\n readonly publicClientService: PublicClientServiceShape;\n readonly gasService: GasServiceShape;\n};\n\n/**\n * Create the writeAndTrack implementation with full tracking orchestration\n */\nexport const makeWriteAndTrack = (deps: WriteAndTrackDeps) =>\n Effect.fn(\"ContractPipeline.writeAndTrack\")(function* <\n TAbi extends Abi,\n TFunctionName extends ContractFunctionName<TAbi, \"nonpayable\" | \"payable\">,\n >(params: WriteAndTrackParams<TAbi, TFunctionName>) {\n const {\n writer,\n txManager,\n eventStream,\n nonceService,\n txReplacement,\n publicClientService,\n gasService,\n } = deps;\n\n const tracker = yield* makeTxTracker;\n const policy = params.policy ?? defaultPolicy;\n const currentHashRef = yield* Ref.make<Hash | null>(null);\n const blocksElapsedRef = yield* Ref.make(0);\n const startedAtMsRef = yield* Ref.make(0);\n const autoAttemptsRef = yield* Ref.make(0);\n const autoReplacingRef = yield* Ref.make(false);\n\n const resultDeferred = yield* Deferred.make<WriteAndTrackResult<TAbi>, WriteAndTrackError>();\n\n const run = Effect.gen(function* () {\n // Step 1: Derive base overrides\n const baseOverrides = yield* deriveBaseOverrides(gasService, {\n chainId: params.chainId,\n policy,\n userOverrides: params.overrides,\n });\n\n // Step 2: Estimate gas first to provide a reasonable limit for simulation.\n // Some RPC nodes default to max uint64 when no gas limit is provided,\n // causing \"insufficient funds\" errors during the balance check.\n const estimatedGas = yield* writer.estimateGas({\n ...params,\n overrides: baseOverrides,\n });\n // Apply multiplier to add safety margin; this buffered value is used for\n // both simulation (balance check) and the final transaction.\n const derivedGas = applyGasLimitMultiplier(estimatedGas, policy.gasLimitMultiplier);\n\n const explicitGas = params.overrides?.gas ?? params.gas;\n const finalGas = explicitGas ?? derivedGas;\n\n // Step 3: Simulate with the gas limit to ensure proper balance checks\n yield* tracker.set({ status: \"simulating\" });\n yield* writer.simulate({ ...params, overrides: { ...baseOverrides, gas: finalGas } });\n const explicitNonce = params.overrides?.nonce;\n\n // Step 4: Reserve nonce\n const nonceReservation = yield* withNonceReservation(nonceService, {\n account: params.account,\n chainId: params.chainId,\n explicitNonce,\n });\n\n const nonce = nonceReservation.nonce;\n\n const overridesWithGasAndNonce = {\n ...baseOverrides,\n gas: finalGas,\n nonce,\n };\n\n yield* tracker.set({\n gas: finalGas,\n status: \"estimated\",\n tx: {\n accessList: overridesWithGasAndNonce.accessList,\n gas: finalGas,\n gasPrice: overridesWithGasAndNonce.gasPrice,\n maxFeePerGas: overridesWithGasAndNonce.maxFeePerGas,\n maxPriorityFeePerGas: overridesWithGasAndNonce.maxPriorityFeePerGas,\n nonce,\n type: overridesWithGasAndNonce.type,\n },\n });\n\n // Step 5: Signing\n yield* tracker.update((prev) => ({ status: \"signing\", tx: prev.tx }) as TxState);\n\n // Step 6: Write transaction\n const hash = yield* writer.write({\n ...params,\n overrides: overridesWithGasAndNonce,\n });\n yield* nonceReservation.markSubmitted;\n yield* Ref.set(currentHashRef, hash);\n yield* Ref.set(blocksElapsedRef, 0);\n yield* Ref.set(autoAttemptsRef, 0);\n yield* Ref.set(autoReplacingRef, false);\n yield* Ref.set(startedAtMsRef, yield* Clock.currentTimeMillis);\n yield* tracker.update((prev) => ({ hash, status: \"submitted\", tx: prev.tx }) as TxState);\n\n // Set up block watcher for pending state updates\n const publicClient: PublicClient = yield* publicClientService.get(params.chainId);\n const replacementStrategy =\n policy.replacement?.strategy ?? policy.replacementStrategy ?? \"none\";\n const stuckMs = policy.replacement?.stuckMs ?? DEFAULT_STUCK_TX_MS;\n const maxAttempts = policy.replacement?.maxAttempts ?? 1;\n\n const updatePendingState = (currentHash: Hash) =>\n Effect.gen(function* () {\n const blocksElapsed = yield* Ref.modify(blocksElapsedRef, (n) => [n + 1, n + 1] as const);\n\n yield* tracker.update((prev) => {\n if (prev.status === \"mined\" || prev.status === \"failed\") {\n return prev;\n }\n return {\n confirmations: blocksElapsed,\n hash: currentHash,\n status: \"pending\",\n tx: prev.tx,\n } as TxState;\n });\n\n return blocksElapsed;\n });\n\n const performAutoReplacement = (currentHash: Hash, now: number) =>\n Ref.set(autoReplacingRef, true).pipe(\n Effect.zipRight(\n (replacementStrategy === \"cancel\"\n ? txReplacement.cancel(params.chainId, currentHash, policy)\n : txReplacement.speedup(params.chainId, currentHash, policy)\n ).pipe(\n Effect.either,\n Effect.ensuring(Ref.set(autoReplacingRef, false)),\n Effect.flatMap((replaced) => {\n if (replaced._tag === \"Left\") {\n return Effect.void;\n }\n\n const newHash = replaced.right;\n return Effect.all([\n Ref.set(currentHashRef, newHash),\n Ref.set(blocksElapsedRef, 0),\n Ref.set(startedAtMsRef, now),\n Ref.update(autoAttemptsRef, (n) => n + 1),\n tracker.update(\n (prev) =>\n ({\n newHash,\n oldHash: currentHash,\n reason: replacementStrategy === \"cancel\" ? \"cancelled\" : \"repriced\",\n status: \"replaced\",\n tx: prev.tx,\n }) as TxState\n ),\n tracker.update(\n (prev) =>\n ({\n hash: newHash,\n status: \"submitted\",\n tx: prev.tx,\n }) as TxState\n ),\n ]).pipe(Effect.asVoid);\n })\n )\n )\n );\n\n const autoReplaceIfStuck = (currentHash: Hash) => {\n if (replacementStrategy === \"none\") {\n return Effect.void;\n }\n\n return Effect.all({\n alreadyReplacing: Ref.get(autoReplacingRef),\n attempts: Ref.get(autoAttemptsRef),\n now: Clock.currentTimeMillis,\n startedAt: Ref.get(startedAtMsRef),\n }).pipe(\n Effect.flatMap(({ alreadyReplacing, attempts, now, startedAt }) => {\n const elapsed = startedAt > 0 ? now - startedAt : 0;\n const stuck = elapsed >= stuckMs;\n const allowed = attempts < maxAttempts && !alreadyReplacing;\n return stuck && allowed ? performAutoReplacement(currentHash, now) : Effect.void;\n })\n );\n };\n\n const onPendingBlock = Effect.gen(function* () {\n const currentHash = yield* Ref.get(currentHashRef);\n if (!currentHash) {\n return;\n }\n\n yield* updatePendingState(currentHash);\n yield* autoReplaceIfStuck(currentHash);\n });\n\n const pendingFiber = yield* Stream.runForEach(\n Stream.async<bigint, unknown>((emit) => {\n const unwatch = publicClient.watchBlockNumber({\n onBlockNumber: (blockNumber: bigint) => emit.single(blockNumber),\n onError: (error) => emit.fail(error as unknown),\n pollingInterval: policy.pollingInterval,\n });\n\n return Effect.sync(() => {\n unwatch();\n });\n }),\n () => onPendingBlock\n ).pipe(Effect.forkScoped);\n\n // Step 7: Wait for receipt (follow replacements)\n const receipt = yield* Effect.gen(function* () {\n let waitHash = hash;\n\n while (true) {\n const exit = yield* txManager\n .waitForReceipt(params.chainId, waitHash, policy)\n .pipe(Effect.either);\n\n if (exit._tag === \"Right\") {\n return exit.right;\n }\n\n const error = exit.left;\n if (error._tag === \"TxReplacedError\") {\n const newHash = error.newHash as Hash;\n const now = yield* Clock.currentTimeMillis;\n\n yield* Ref.set(currentHashRef, newHash);\n yield* Ref.set(blocksElapsedRef, 0);\n yield* Ref.set(startedAtMsRef, now);\n yield* tracker.update(\n (prev) =>\n ({\n newHash,\n oldHash: error.oldHash as Hash,\n reason: error.reason,\n status: \"replaced\",\n tx: prev.tx,\n }) as TxState\n );\n yield* tracker.update(\n (prev) =>\n ({\n hash: newHash,\n status: \"submitted\",\n tx: prev.tx,\n }) as TxState\n );\n\n waitHash = newHash;\n continue;\n }\n\n return yield* Effect.fail(error);\n }\n }).pipe(Effect.ensuring(Fiber.interrupt(pendingFiber)));\n\n // Step 8: Update to mined state\n yield* tracker.update(\n (prev) =>\n ({\n effectiveGasPrice: receipt.effectiveGasPrice,\n hash: receipt.transactionHash as Hash,\n receipt,\n status: \"mined\",\n tx: prev.tx,\n }) as TxState\n );\n\n if (nonceReservation.reserved) {\n yield* nonceService.confirm({\n address: params.account,\n chainId: params.chainId,\n nonce: nonceToBigInt(nonceReservation.nonce),\n });\n }\n\n // Step 9: Decode events\n const events = (yield* eventStream.decodeReceipt(\n receipt,\n params.abi\n )) as WriteAndTrackResult<TAbi>[\"events\"];\n\n return {\n events,\n hash: receipt.transactionHash as Hash,\n receipt,\n } as WriteAndTrackResult<TAbi>;\n });\n\n yield* run.pipe(\n Effect.either,\n Effect.flatMap((either) =>\n either._tag === \"Right\"\n ? Deferred.succeed(resultDeferred, either.right)\n : Deferred.fail(resultDeferred, either.left)\n ),\n Effect.forkScoped\n );\n\n return {\n actions: {\n cancel: (overridePolicy?: TxPolicy) =>\n Effect.gen(function* () {\n const currentHash = yield* Ref.get(currentHashRef);\n if (!currentHash) {\n return yield* Effect.fail(new Error(\"Transaction not yet submitted\"));\n }\n\n const nextPolicy = overridePolicy ?? policy;\n const newHash = yield* txReplacement.cancel(params.chainId, currentHash, nextPolicy);\n const now = yield* Clock.currentTimeMillis;\n\n yield* Ref.set(currentHashRef, newHash);\n yield* Ref.set(blocksElapsedRef, 0);\n yield* Ref.set(startedAtMsRef, now);\n yield* tracker.update(\n (prev) =>\n ({\n newHash,\n oldHash: currentHash,\n reason: \"cancelled\",\n status: \"replaced\",\n tx: prev.tx,\n }) as TxState\n );\n yield* tracker.update(\n (prev) =>\n ({\n hash: newHash,\n status: \"submitted\",\n tx: prev.tx,\n }) as TxState\n );\n\n return newHash;\n }),\n\n speedup: (overridePolicy?: TxPolicy) =>\n Effect.gen(function* () {\n const currentHash = yield* Ref.get(currentHashRef);\n if (!currentHash) {\n return yield* Effect.fail(new Error(\"Transaction not yet submitted\"));\n }\n\n const nextPolicy = overridePolicy ?? policy;\n const newHash = yield* txReplacement.speedup(params.chainId, currentHash, nextPolicy);\n const now = yield* Clock.currentTimeMillis;\n\n yield* Ref.set(currentHashRef, newHash);\n yield* Ref.set(blocksElapsedRef, 0);\n yield* Ref.set(startedAtMsRef, now);\n yield* tracker.update(\n (prev) =>\n ({\n newHash,\n oldHash: currentHash,\n reason: \"repriced\",\n status: \"replaced\",\n tx: prev.tx,\n }) as TxState\n );\n yield* tracker.update(\n (prev) =>\n ({\n hash: newHash,\n status: \"submitted\",\n tx: prev.tx,\n }) as TxState\n );\n\n return newHash;\n }),\n },\n result: Deferred.await(resultDeferred),\n stateRef: tracker.ref,\n };\n });\n"]}
@@ -18,6 +18,7 @@ export type TxManagerShape = {
18
18
  declare const TxManager_base: Context.TagClass<TxManager, "ew3/TxManager", TxManagerShape>;
19
19
  export declare class TxManager extends TxManager_base {
20
20
  }
21
+ export declare function makeTxManagerLive(layerPolicy?: TxPolicy): Layer.Layer<TxManager, never, PublicClientService | TxReplacement>;
21
22
  export declare const TxManagerLive: Layer.Layer<TxManager, never, PublicClientService | TxReplacement>;
22
23
  export {};
23
24
  //# sourceMappingURL=manager.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../src/tx/manager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,eAAe,EAAE,MAAM,QAAQ,CAAC;AACrD,OAAO,EAAS,OAAO,EAAE,MAAM,EAAS,KAAK,EAAe,MAAM,QAAQ,CAAC;AAC3E,OAAO,KAAK,EAAE,IAAI,EAAE,kBAAkB,EAAE,MAAM,MAAM,CAAC;AAGrD,OAAO,KAAK,EAAE,mBAAmB,EAAuB,MAAM,qBAAqB,CAAC;AACpF,OAAO,EACL,mBAAmB,EACnB,mBAAmB,EACnB,cAAc,EACd,aAAa,EACb,eAAe,EAChB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE5C,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAG5C,MAAM,MAAM,cAAc,GAAG;IAI3B,QAAQ,CAAC,KAAK,EAAE,CACd,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,IAAI,EACV,MAAM,CAAC,EAAE,QAAQ,KACd,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,eAAe,CAAC,OAAO,CAAC,EAAE,mBAAmB,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;IAK/F,QAAQ,CAAC,cAAc,EAAE,CACvB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,IAAI,EACV,eAAe,CAAC,EAAE,MAAM,GAAG,QAAQ,KAChC,MAAM,CAAC,MAAM,CAChB,kBAAkB,EAClB,aAAa,GAAG,mBAAmB,GAAG,eAAe,GAAG,mBAAmB,CAC5E,CAAC;IAKF,QAAQ,CAAC,gBAAgB,EAAE,CACzB,OAAO,EAAE,MAAM,EACf,MAAM,EAAE;QAAE,IAAI,EAAE,IAAI,CAAA;KAAE,GAAG;QAAE,kBAAkB,EAAE,kBAAkB,CAAA;KAAE,KAChE,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,mBAAmB,GAAG,cAAc,CAAC,CAAC;CAClE,CAAC;;AAEF,qBAAa,SAAU,SAAQ,cAAyD;CAAG;AAE3F,eAAO,MAAM,aAAa,oEAoTzB,CAAC"}
1
+ {"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../src/tx/manager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,eAAe,EAAE,MAAM,QAAQ,CAAC;AACrD,OAAO,EAAS,OAAO,EAAE,MAAM,EAAS,KAAK,EAAe,MAAM,QAAQ,CAAC;AAC3E,OAAO,KAAK,EAAE,IAAI,EAAE,kBAAkB,EAAE,MAAM,MAAM,CAAC;AAGrD,OAAO,KAAK,EAAE,mBAAmB,EAAuB,MAAM,qBAAqB,CAAC;AACpF,OAAO,EACL,mBAAmB,EACnB,mBAAmB,EACnB,cAAc,EACd,aAAa,EACb,eAAe,EAChB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE5C,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAG5C,MAAM,MAAM,cAAc,GAAG;IAI3B,QAAQ,CAAC,KAAK,EAAE,CACd,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,IAAI,EACV,MAAM,CAAC,EAAE,QAAQ,KACd,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,eAAe,CAAC,OAAO,CAAC,EAAE,mBAAmB,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;IAK/F,QAAQ,CAAC,cAAc,EAAE,CACvB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,IAAI,EACV,eAAe,CAAC,EAAE,MAAM,GAAG,QAAQ,KAChC,MAAM,CAAC,MAAM,CAChB,kBAAkB,EAClB,aAAa,GAAG,mBAAmB,GAAG,eAAe,GAAG,mBAAmB,CAC5E,CAAC;IAKF,QAAQ,CAAC,gBAAgB,EAAE,CACzB,OAAO,EAAE,MAAM,EACf,MAAM,EAAE;QAAE,IAAI,EAAE,IAAI,CAAA;KAAE,GAAG;QAAE,kBAAkB,EAAE,kBAAkB,CAAA;KAAE,KAChE,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,mBAAmB,GAAG,cAAc,CAAC,CAAC;CAClE,CAAC;;AAEF,qBAAa,SAAU,SAAQ,cAAyD;CAAG;AAE3F,wBAAgB,iBAAiB,CAC/B,WAAW,CAAC,EAAE,QAAQ,GACrB,KAAK,CAAC,KAAK,CAAC,SAAS,EAAE,KAAK,EAAE,mBAAmB,GAAG,aAAa,CAAC,CAqUpE;AAED,eAAO,MAAM,aAAa,oEAAsB,CAAC"}
@@ -8,233 +8,249 @@ import { TxReplacement } from "./replacement.js";
8
8
  import { makeTxTracker } from "./tracker.js";
9
9
  export class TxManager extends Context.Tag("ew3/TxManager")() {
10
10
  }
11
- export const TxManagerLive = Layer.effect(TxManager, Effect.gen(function* () {
12
- const publicClientService = yield* PublicClientService;
13
- const txReplacement = yield* TxReplacement;
14
- return {
15
- getConfirmations: Effect.fn("TxManager.getConfirmations")(function* (chainId, params) {
16
- const client = yield* publicClientService.get(chainId);
17
- return yield* Effect.tryPromise({
18
- catch: (cause) => new TransportError({
19
- cause,
20
- message: cause instanceof Error ? cause.message : "Failed to get transaction confirmations",
21
- url: client.transport.url ?? "",
22
- }),
23
- try: () => client.getTransactionConfirmations(params),
24
- }).pipe(Effect.withSpan(SpanNames.TX_GET_CONFIRMATIONS, {
25
- attributes: {
26
- chainId,
27
- hash: "hash" in params ? params.hash : params.transactionReceipt.transactionHash,
28
- },
29
- }));
30
- }),
31
- track: Effect.fn("TxManager.track")(function* (chainId, hash, providedPolicy) {
32
- const tracker = yield* makeTxTracker;
33
- const client = yield* publicClientService.get(chainId);
34
- const policy = {
35
- ...defaultPolicy,
36
- ...providedPolicy,
37
- replacement: {
38
- ...(defaultPolicy.replacement ?? {}),
39
- ...(providedPolicy?.replacement ?? {}),
40
- },
41
- };
42
- yield* tracker.set({ hash, status: "submitted" });
43
- yield* Effect.forkScoped(Effect.gen(function* () {
44
- const currentHashRef = yield* Ref.make(hash);
45
- const confirmationsRef = yield* Ref.make(0);
46
- const startedAtMsRef = yield* Ref.make(yield* Clock.currentTimeMillis);
47
- const autoAttemptsRef = yield* Ref.make(0);
48
- const autoReplacingRef = yield* Ref.make(false);
49
- const replacementStrategy = policy.replacement?.strategy ?? policy.replacementStrategy ?? "none";
50
- const stuckBlocks = policy.replacement?.stuckBlocks ?? 3;
51
- const stuckMs = policy.replacement?.stuckMs ?? DEFAULT_STUCK_TX_MS;
52
- const maxAttempts = policy.replacement?.maxAttempts ?? 1;
53
- const updatePendingState = (currentHash) => Effect.gen(function* () {
54
- const confirmations = yield* Ref.modify(confirmationsRef, (n) => [n + 1, n + 1]);
55
- yield* tracker.set({
56
- confirmations,
57
- hash: currentHash,
58
- status: "pending",
59
- });
60
- return confirmations;
61
- });
62
- const performAutoReplacement = (currentHash, now) => Ref.set(autoReplacingRef, true).pipe(Effect.zipRight((replacementStrategy === "cancel"
63
- ? txReplacement.cancel(chainId, currentHash, policy)
64
- : txReplacement.speedup(chainId, currentHash, policy)).pipe(Effect.either, Effect.ensuring(Ref.set(autoReplacingRef, false)), Effect.flatMap((replaced) => {
65
- if (replaced._tag === "Left") {
66
- return Effect.void;
67
- }
68
- const newHash = replaced.right;
69
- return Effect.all([
70
- Ref.set(currentHashRef, newHash),
71
- Ref.set(confirmationsRef, 0),
72
- Ref.set(startedAtMsRef, now),
73
- Ref.update(autoAttemptsRef, (n) => n + 1),
74
- tracker.set({
75
- newHash,
76
- oldHash: currentHash,
77
- reason: replacementStrategy === "cancel" ? "cancelled" : "repriced",
78
- status: "replaced",
79
- }),
80
- tracker.set({ hash: newHash, status: "submitted" }),
81
- ]).pipe(Effect.asVoid);
82
- }))));
83
- const autoReplaceIfStuck = (currentHash, confirmations) => {
84
- if (replacementStrategy === "none") {
85
- return Effect.void;
86
- }
87
- return Effect.all({
88
- alreadyReplacing: Ref.get(autoReplacingRef),
89
- attempts: Ref.get(autoAttemptsRef),
90
- now: Clock.currentTimeMillis,
91
- startedAt: Ref.get(startedAtMsRef),
92
- }).pipe(Effect.flatMap(({ alreadyReplacing, attempts, now, startedAt }) => {
93
- const elapsed = startedAt > 0 ? now - startedAt : 0;
94
- const stuck = confirmations >= stuckBlocks || elapsed >= stuckMs;
95
- const allowed = attempts < maxAttempts && !alreadyReplacing;
96
- return stuck && allowed ? performAutoReplacement(currentHash, now) : Effect.void;
97
- }));
11
+ export function makeTxManagerLive(layerPolicy) {
12
+ const layerDefault = {
13
+ ...defaultPolicy,
14
+ ...layerPolicy,
15
+ replacement: {
16
+ ...(defaultPolicy.replacement ?? {}),
17
+ ...(layerPolicy?.replacement ?? {}),
18
+ },
19
+ };
20
+ return Layer.effect(TxManager, Effect.gen(function* () {
21
+ const publicClientService = yield* PublicClientService;
22
+ const txReplacement = yield* TxReplacement;
23
+ return {
24
+ getConfirmations: Effect.fn("TxManager.getConfirmations")(function* (chainId, params) {
25
+ const client = yield* publicClientService.get(chainId);
26
+ return yield* Effect.tryPromise({
27
+ catch: (cause) => new TransportError({
28
+ cause,
29
+ message: cause instanceof Error
30
+ ? cause.message
31
+ : "Failed to get transaction confirmations",
32
+ url: client.transport.url ?? "",
33
+ }),
34
+ try: () => client.getTransactionConfirmations(params),
35
+ }).pipe(Effect.withSpan(SpanNames.TX_GET_CONFIRMATIONS, {
36
+ attributes: {
37
+ chainId,
38
+ hash: "hash" in params ? params.hash : params.transactionReceipt.transactionHash,
39
+ },
40
+ }));
41
+ }),
42
+ track: Effect.fn("TxManager.track")(function* (chainId, hash, providedPolicy) {
43
+ const tracker = yield* makeTxTracker;
44
+ const client = yield* publicClientService.get(chainId);
45
+ const policy = {
46
+ ...layerDefault,
47
+ ...providedPolicy,
48
+ replacement: {
49
+ ...(layerDefault.replacement ?? {}),
50
+ ...(providedPolicy?.replacement ?? {}),
51
+ },
98
52
  };
99
- const onPendingBlock = Effect.gen(function* () {
100
- const currentHash = yield* Ref.get(currentHashRef);
101
- const confirmations = yield* updatePendingState(currentHash);
102
- yield* autoReplaceIfStuck(currentHash, confirmations);
103
- });
104
- const pendingFiber = yield* Stream.runForEach(Stream.async((emit) => {
105
- const unwatch = client.watchBlockNumber({
106
- onBlockNumber: (blockNumber) => emit.single(blockNumber),
107
- onError: (error) => emit.fail(error),
108
- pollingInterval: policy.pollingInterval,
53
+ yield* tracker.set({ hash, status: "submitted" });
54
+ yield* Effect.forkScoped(Effect.gen(function* () {
55
+ const currentHashRef = yield* Ref.make(hash);
56
+ const confirmationsRef = yield* Ref.make(0);
57
+ const startedAtMsRef = yield* Ref.make(yield* Clock.currentTimeMillis);
58
+ const autoAttemptsRef = yield* Ref.make(0);
59
+ const autoReplacingRef = yield* Ref.make(false);
60
+ const replacementStrategy = policy.replacement?.strategy ?? policy.replacementStrategy ?? "none";
61
+ const stuckMs = policy.replacement?.stuckMs ?? DEFAULT_STUCK_TX_MS;
62
+ const maxAttempts = policy.replacement?.maxAttempts ?? 1;
63
+ const updatePendingState = (currentHash) => Effect.gen(function* () {
64
+ const confirmations = yield* Ref.modify(confirmationsRef, (n) => [n + 1, n + 1]);
65
+ yield* tracker.set({
66
+ confirmations,
67
+ hash: currentHash,
68
+ status: "pending",
69
+ });
70
+ return confirmations;
109
71
  });
110
- return Effect.sync(() => {
111
- unwatch();
72
+ const performAutoReplacement = (currentHash, now) => Ref.set(autoReplacingRef, true).pipe(Effect.zipRight((replacementStrategy === "cancel"
73
+ ? txReplacement.cancel(chainId, currentHash, policy)
74
+ : txReplacement.speedup(chainId, currentHash, policy)).pipe(Effect.either, Effect.ensuring(Ref.set(autoReplacingRef, false)), Effect.flatMap((replaced) => {
75
+ if (replaced._tag === "Left") {
76
+ return Effect.void;
77
+ }
78
+ const newHash = replaced.right;
79
+ return Effect.all([
80
+ Ref.set(currentHashRef, newHash),
81
+ Ref.set(confirmationsRef, 0),
82
+ Ref.set(startedAtMsRef, now),
83
+ Ref.update(autoAttemptsRef, (n) => n + 1),
84
+ tracker.set({
85
+ newHash,
86
+ oldHash: currentHash,
87
+ reason: replacementStrategy === "cancel" ? "cancelled" : "repriced",
88
+ status: "replaced",
89
+ }),
90
+ tracker.set({ hash: newHash, status: "submitted" }),
91
+ ]).pipe(Effect.asVoid);
92
+ }))));
93
+ const autoReplaceIfStuck = (currentHash) => {
94
+ if (replacementStrategy === "none") {
95
+ return Effect.void;
96
+ }
97
+ return Effect.all({
98
+ alreadyReplacing: Ref.get(autoReplacingRef),
99
+ attempts: Ref.get(autoAttemptsRef),
100
+ now: Clock.currentTimeMillis,
101
+ startedAt: Ref.get(startedAtMsRef),
102
+ }).pipe(Effect.flatMap(({ alreadyReplacing, attempts, now, startedAt }) => {
103
+ const elapsed = startedAt > 0 ? now - startedAt : 0;
104
+ const stuck = elapsed >= stuckMs;
105
+ const allowed = attempts < maxAttempts && !alreadyReplacing;
106
+ return stuck && allowed
107
+ ? performAutoReplacement(currentHash, now)
108
+ : Effect.void;
109
+ }));
110
+ };
111
+ const onPendingBlock = Effect.gen(function* () {
112
+ const currentHash = yield* Ref.get(currentHashRef);
113
+ yield* updatePendingState(currentHash);
114
+ yield* autoReplaceIfStuck(currentHash);
112
115
  });
113
- }), () => onPendingBlock).pipe(Effect.forkScoped);
114
- let replacement;
115
- const receiptResult = yield* Effect.either(Effect.tryPromise({
116
- catch: (e) => e,
117
- try: () => client.waitForTransactionReceipt({
118
- hash,
119
- onReplaced: (info) => {
120
- replacement = {
121
- newHash: info.transaction.hash,
122
- oldHash: info.replacedTransaction.hash,
123
- reason: info.reason,
124
- };
125
- },
126
- pollingInterval: policy.pollingInterval,
127
- timeout: policy.receiptTimeout,
128
- }),
129
- })).pipe(Effect.ensuring(Fiber.interrupt(pendingFiber)));
130
- if (receiptResult._tag === "Left") {
131
- const cause = receiptResult.left;
132
- const timeout = policy.receiptTimeout ?? DEFAULT_RECEIPT_TIMEOUT;
133
- const failure = cause instanceof WaitForTransactionReceiptTimeoutError
134
- ? new ReceiptTimeoutError({
135
- hash,
136
- message: cause.message,
137
- timeout,
138
- })
139
- : cause;
140
- yield* tracker.set({
141
- error: new TxFailedError({
142
- cause: failure,
116
+ const pendingFiber = yield* Stream.runForEach(Stream.async((emit) => {
117
+ const unwatch = client.watchBlockNumber({
118
+ onBlockNumber: (blockNumber) => emit.single(blockNumber),
119
+ onError: (error) => emit.fail(error),
120
+ pollingInterval: policy.pollingInterval,
121
+ });
122
+ return Effect.sync(() => {
123
+ unwatch();
124
+ });
125
+ }), () => onPendingBlock).pipe(Effect.forkScoped);
126
+ let replacement;
127
+ const receiptResult = yield* Effect.either(Effect.tryPromise({
128
+ catch: (e) => e,
129
+ try: () => client.waitForTransactionReceipt({
143
130
  hash,
144
- message: failure instanceof Error ? failure.message : String(failure),
131
+ onReplaced: (info) => {
132
+ replacement = {
133
+ newHash: info.transaction.hash,
134
+ oldHash: info.replacedTransaction.hash,
135
+ reason: info.reason,
136
+ };
137
+ },
138
+ pollingInterval: policy.pollingInterval,
139
+ timeout: policy.receiptTimeout,
145
140
  }),
146
- status: "failed",
147
- });
148
- return;
149
- }
150
- const receipt = receiptResult.right;
151
- if (replacement) {
152
- yield* Ref.set(currentHashRef, replacement.newHash);
153
- yield* tracker.set({
154
- newHash: replacement.newHash,
155
- oldHash: replacement.oldHash,
156
- reason: replacement.reason,
157
- status: "replaced",
158
- });
141
+ })).pipe(Effect.ensuring(Fiber.interrupt(pendingFiber)));
142
+ if (receiptResult._tag === "Left") {
143
+ const cause = receiptResult.left;
144
+ const timeout = policy.receiptTimeout ?? DEFAULT_RECEIPT_TIMEOUT;
145
+ const failure = cause instanceof WaitForTransactionReceiptTimeoutError
146
+ ? new ReceiptTimeoutError({
147
+ hash,
148
+ message: cause.message,
149
+ timeout,
150
+ })
151
+ : cause;
152
+ yield* tracker.set({
153
+ error: new TxFailedError({
154
+ cause: failure,
155
+ hash,
156
+ message: failure instanceof Error ? failure.message : String(failure),
157
+ }),
158
+ status: "failed",
159
+ });
160
+ return;
161
+ }
162
+ const receipt = receiptResult.right;
163
+ if (replacement) {
164
+ yield* Ref.set(currentHashRef, replacement.newHash);
165
+ yield* tracker.set({
166
+ newHash: replacement.newHash,
167
+ oldHash: replacement.oldHash,
168
+ reason: replacement.reason,
169
+ status: "replaced",
170
+ });
171
+ yield* tracker.set({
172
+ hash: replacement.newHash,
173
+ status: "submitted",
174
+ });
175
+ }
159
176
  yield* tracker.set({
160
- hash: replacement.newHash,
161
- status: "submitted",
177
+ effectiveGasPrice: receipt.effectiveGasPrice,
178
+ hash: receipt.transactionHash,
179
+ receipt,
180
+ status: "mined",
162
181
  });
163
- }
164
- yield* tracker.set({
165
- effectiveGasPrice: receipt.effectiveGasPrice,
166
- hash: receipt.transactionHash,
167
- receipt,
168
- status: "mined",
169
- });
170
- }));
171
- return tracker.ref;
172
- }),
173
- waitForReceipt: Effect.fn("TxManager.waitForReceipt")(function* (chainId, hash, timeoutOrPolicy) {
174
- const client = yield* publicClientService.get(chainId);
175
- const policy = typeof timeoutOrPolicy === "object" && timeoutOrPolicy !== null
176
- ? timeoutOrPolicy
177
- : undefined;
178
- const timeout = typeof timeoutOrPolicy === "number"
179
- ? timeoutOrPolicy
180
- : (policy?.receiptTimeout ?? defaultPolicy.receiptTimeout ?? DEFAULT_RECEIPT_TIMEOUT);
181
- const pollingInterval = policy?.pollingInterval ?? defaultPolicy.pollingInterval;
182
- return yield* Effect.tryPromise({
183
- catch: (cause) => {
184
- if (cause instanceof TxReplacedError) {
185
- return cause;
186
- }
187
- if (cause instanceof WaitForTransactionReceiptTimeoutError) {
188
- return new ReceiptTimeoutError({
182
+ }));
183
+ return tracker.ref;
184
+ }),
185
+ waitForReceipt: Effect.fn("TxManager.waitForReceipt")(function* (chainId, hash, timeoutOrPolicy) {
186
+ const client = yield* publicClientService.get(chainId);
187
+ const policy = typeof timeoutOrPolicy === "object" && timeoutOrPolicy !== null
188
+ ? timeoutOrPolicy
189
+ : undefined;
190
+ const timeout = typeof timeoutOrPolicy === "number"
191
+ ? timeoutOrPolicy
192
+ : (policy?.receiptTimeout ??
193
+ layerDefault.receiptTimeout ??
194
+ DEFAULT_RECEIPT_TIMEOUT);
195
+ const pollingInterval = policy?.pollingInterval ?? layerDefault.pollingInterval;
196
+ return yield* Effect.tryPromise({
197
+ catch: (cause) => {
198
+ if (cause instanceof TxReplacedError) {
199
+ return cause;
200
+ }
201
+ if (cause instanceof WaitForTransactionReceiptTimeoutError) {
202
+ return new ReceiptTimeoutError({
203
+ hash,
204
+ message: cause.message,
205
+ timeout,
206
+ });
207
+ }
208
+ if (cause instanceof Error && cause.message.toLowerCase().includes("timeout")) {
209
+ return new ReceiptTimeoutError({
210
+ hash,
211
+ message: cause.message,
212
+ timeout,
213
+ });
214
+ }
215
+ return new TxFailedError({
216
+ cause,
189
217
  hash,
190
- message: cause.message,
191
- timeout,
218
+ message: `Failed to get receipt for ${hash}`,
192
219
  });
193
- }
194
- if (cause instanceof Error && cause.message.toLowerCase().includes("timeout")) {
195
- return new ReceiptTimeoutError({
220
+ },
221
+ try: async () => {
222
+ let replacement;
223
+ const receipt = await client.waitForTransactionReceipt({
196
224
  hash,
197
- message: cause.message,
225
+ onReplaced: (info) => {
226
+ replacement = {
227
+ newHash: info.transaction.hash,
228
+ reason: info.reason,
229
+ };
230
+ },
231
+ pollingInterval,
198
232
  timeout,
199
233
  });
200
- }
201
- return new TxFailedError({
202
- cause,
203
- hash,
204
- message: `Failed to get receipt for ${hash}`,
205
- });
206
- },
207
- try: async () => {
208
- let replacement;
209
- const receipt = await client.waitForTransactionReceipt({
234
+ if (replacement && replacement.newHash !== hash) {
235
+ throw new TxReplacedError({
236
+ message: `Transaction ${hash} was ${replacement.reason} with ${replacement.newHash}`,
237
+ newHash: replacement.newHash,
238
+ oldHash: hash,
239
+ reason: replacement.reason,
240
+ });
241
+ }
242
+ return receipt;
243
+ },
244
+ }).pipe(Effect.withSpan(SpanNames.TX_WAIT, {
245
+ attributes: {
246
+ chainId,
210
247
  hash,
211
- onReplaced: (info) => {
212
- replacement = {
213
- newHash: info.transaction.hash,
214
- reason: info.reason,
215
- };
216
- },
217
- pollingInterval,
218
248
  timeout,
219
- });
220
- if (replacement && replacement.newHash !== hash) {
221
- throw new TxReplacedError({
222
- message: `Transaction ${hash} was ${replacement.reason} with ${replacement.newHash}`,
223
- newHash: replacement.newHash,
224
- oldHash: hash,
225
- reason: replacement.reason,
226
- });
227
- }
228
- return receipt;
229
- },
230
- }).pipe(Effect.withSpan(SpanNames.TX_WAIT, {
231
- attributes: {
232
- chainId,
233
- hash,
234
- timeout,
235
- },
236
- }));
237
- }),
238
- };
239
- }));
249
+ },
250
+ }));
251
+ }),
252
+ };
253
+ }));
254
+ }
255
+ export const TxManagerLive = makeTxManagerLive();
240
256
  //# sourceMappingURL=manager.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"manager.js","sourceRoot":"","sources":["../../src/tx/manager.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Scope, SubscriptionRef } from \"effect\";\nimport { Clock, Context, Effect, Fiber, Layer, Ref, Stream } from \"effect\";\nimport type { Hash, TransactionReceipt } from \"viem\";\nimport { WaitForTransactionReceiptTimeoutError } from \"viem\";\nimport { DEFAULT_RECEIPT_TIMEOUT, DEFAULT_STUCK_TX_MS } from \"@/src/constants/index.js\";\nimport type { ClientNotFoundError, TxReplacementReason } from \"@/src/core/index.js\";\nimport {\n PublicClientService,\n ReceiptTimeoutError,\n TransportError,\n TxFailedError,\n TxReplacedError,\n} from \"@/src/core/index.js\";\nimport { SpanNames } from \"@/src/telemetry/index.js\";\nimport type { TxPolicy } from \"./policy.js\";\nimport { defaultPolicy } from \"./policy.js\";\nimport { TxReplacement } from \"./replacement.js\";\nimport type { TxState } from \"./tracker.js\";\nimport { makeTxTracker } from \"./tracker.js\";\n\nexport type TxManagerShape = {\n /**\n * Track an existing transaction hash and return a SubscriptionRef for state updates\n */\n readonly track: (\n chainId: number,\n hash: Hash,\n policy?: TxPolicy\n ) => Effect.Effect<SubscriptionRef.SubscriptionRef<TxState>, ClientNotFoundError, Scope.Scope>;\n\n /**\n * Wait for transaction receipt with timeout\n */\n readonly waitForReceipt: (\n chainId: number,\n hash: Hash,\n timeoutOrPolicy?: number | TxPolicy\n ) => Effect.Effect<\n TransactionReceipt,\n TxFailedError | ReceiptTimeoutError | TxReplacedError | ClientNotFoundError\n >;\n\n /**\n * Get the number of confirmations for a transaction\n */\n readonly getConfirmations: (\n chainId: number,\n params: { hash: Hash } | { transactionReceipt: TransactionReceipt }\n ) => Effect.Effect<bigint, ClientNotFoundError | TransportError>;\n};\n\nexport class TxManager extends Context.Tag(\"ew3/TxManager\")<TxManager, TxManagerShape>() {}\n\nexport const TxManagerLive = Layer.effect(\n TxManager,\n Effect.gen(function* () {\n const publicClientService = yield* PublicClientService;\n const txReplacement = yield* TxReplacement;\n\n return {\n getConfirmations: Effect.fn(\"TxManager.getConfirmations\")(function* (chainId, params) {\n const client = yield* publicClientService.get(chainId);\n\n return yield* Effect.tryPromise({\n catch: (cause) =>\n new TransportError({\n cause,\n message:\n cause instanceof Error ? cause.message : \"Failed to get transaction confirmations\",\n url: client.transport.url ?? \"\",\n }),\n try: () => client.getTransactionConfirmations(params),\n }).pipe(\n Effect.withSpan(SpanNames.TX_GET_CONFIRMATIONS, {\n attributes: {\n chainId,\n hash: \"hash\" in params ? params.hash : params.transactionReceipt.transactionHash,\n },\n })\n );\n }),\n track: Effect.fn(\"TxManager.track\")(function* (chainId, hash, providedPolicy) {\n const tracker = yield* makeTxTracker;\n const client = yield* publicClientService.get(chainId);\n const policy: TxPolicy = {\n ...defaultPolicy,\n ...providedPolicy,\n replacement: {\n ...(defaultPolicy.replacement ?? {}),\n ...(providedPolicy?.replacement ?? {}),\n },\n };\n\n // Set initial state\n yield* tracker.set({ hash, status: \"submitted\" });\n\n // Start tracking in background\n yield* Effect.forkScoped(\n Effect.gen(function* () {\n const currentHashRef = yield* Ref.make<Hash>(hash);\n const confirmationsRef = yield* Ref.make(0);\n const startedAtMsRef = yield* Ref.make(yield* Clock.currentTimeMillis);\n const autoAttemptsRef = yield* Ref.make(0);\n const autoReplacingRef = yield* Ref.make(false);\n\n const replacementStrategy =\n policy.replacement?.strategy ?? policy.replacementStrategy ?? \"none\";\n const stuckBlocks = policy.replacement?.stuckBlocks ?? 3;\n const stuckMs = policy.replacement?.stuckMs ?? DEFAULT_STUCK_TX_MS;\n const maxAttempts = policy.replacement?.maxAttempts ?? 1;\n\n const updatePendingState = (currentHash: Hash) =>\n Effect.gen(function* () {\n const confirmations = yield* Ref.modify(\n confirmationsRef,\n (n) => [n + 1, n + 1] as const\n );\n\n yield* tracker.set({\n confirmations,\n hash: currentHash,\n status: \"pending\",\n });\n return confirmations;\n });\n\n const performAutoReplacement = (currentHash: Hash, now: number) =>\n Ref.set(autoReplacingRef, true).pipe(\n Effect.zipRight(\n (replacementStrategy === \"cancel\"\n ? txReplacement.cancel(chainId, currentHash, policy)\n : txReplacement.speedup(chainId, currentHash, policy)\n ).pipe(\n Effect.either,\n Effect.ensuring(Ref.set(autoReplacingRef, false)),\n Effect.flatMap((replaced) => {\n if (replaced._tag === \"Left\") {\n return Effect.void;\n }\n\n const newHash = replaced.right;\n return Effect.all([\n Ref.set(currentHashRef, newHash),\n Ref.set(confirmationsRef, 0),\n Ref.set(startedAtMsRef, now),\n Ref.update(autoAttemptsRef, (n) => n + 1),\n tracker.set({\n newHash,\n oldHash: currentHash,\n reason: replacementStrategy === \"cancel\" ? \"cancelled\" : \"repriced\",\n status: \"replaced\",\n }),\n tracker.set({ hash: newHash, status: \"submitted\" }),\n ]).pipe(Effect.asVoid);\n })\n )\n )\n );\n\n const autoReplaceIfStuck = (currentHash: Hash, confirmations: number) => {\n if (replacementStrategy === \"none\") {\n return Effect.void;\n }\n\n return Effect.all({\n alreadyReplacing: Ref.get(autoReplacingRef),\n attempts: Ref.get(autoAttemptsRef),\n now: Clock.currentTimeMillis,\n startedAt: Ref.get(startedAtMsRef),\n }).pipe(\n Effect.flatMap(({ alreadyReplacing, attempts, now, startedAt }) => {\n const elapsed = startedAt > 0 ? now - startedAt : 0;\n const stuck = confirmations >= stuckBlocks || elapsed >= stuckMs;\n const allowed = attempts < maxAttempts && !alreadyReplacing;\n return stuck && allowed ? performAutoReplacement(currentHash, now) : Effect.void;\n })\n );\n };\n\n const onPendingBlock = Effect.gen(function* () {\n const currentHash = yield* Ref.get(currentHashRef);\n const confirmations = yield* updatePendingState(currentHash);\n yield* autoReplaceIfStuck(currentHash, confirmations);\n });\n\n const pendingFiber = yield* Stream.runForEach(\n Stream.async<bigint, unknown>((emit) => {\n const unwatch = client.watchBlockNumber({\n onBlockNumber: (blockNumber: bigint) => emit.single(blockNumber),\n onError: (error) => emit.fail(error as unknown),\n pollingInterval: policy.pollingInterval,\n });\n\n return Effect.sync(() => {\n unwatch();\n });\n }),\n () => onPendingBlock\n ).pipe(Effect.forkScoped);\n\n let replacement:\n | {\n oldHash: Hash;\n newHash: Hash;\n reason: TxReplacementReason;\n }\n | undefined;\n\n const receiptResult = yield* Effect.either(\n Effect.tryPromise({\n catch: (e) => e,\n try: () =>\n client.waitForTransactionReceipt({\n hash,\n onReplaced: (info) => {\n replacement = {\n newHash: info.transaction.hash,\n oldHash: info.replacedTransaction.hash,\n reason: info.reason,\n };\n },\n pollingInterval: policy.pollingInterval,\n timeout: policy.receiptTimeout,\n }),\n })\n ).pipe(Effect.ensuring(Fiber.interrupt(pendingFiber)));\n\n if (receiptResult._tag === \"Left\") {\n const cause = receiptResult.left;\n const timeout = policy.receiptTimeout ?? DEFAULT_RECEIPT_TIMEOUT;\n\n const failure =\n cause instanceof WaitForTransactionReceiptTimeoutError\n ? new ReceiptTimeoutError({\n hash,\n message: cause.message,\n timeout,\n })\n : cause;\n\n yield* tracker.set({\n error: new TxFailedError({\n cause: failure,\n hash,\n message: failure instanceof Error ? failure.message : String(failure),\n }),\n status: \"failed\",\n });\n\n return;\n }\n\n const receipt = receiptResult.right;\n\n if (replacement) {\n yield* Ref.set(currentHashRef, replacement.newHash);\n yield* tracker.set({\n newHash: replacement.newHash,\n oldHash: replacement.oldHash,\n reason: replacement.reason,\n status: \"replaced\",\n });\n yield* tracker.set({\n hash: replacement.newHash,\n status: \"submitted\",\n });\n }\n\n yield* tracker.set({\n effectiveGasPrice: receipt.effectiveGasPrice,\n hash: receipt.transactionHash,\n receipt,\n status: \"mined\",\n });\n })\n );\n\n return tracker.ref;\n }),\n\n waitForReceipt: Effect.fn(\"TxManager.waitForReceipt\")(\n function* (chainId, hash, timeoutOrPolicy) {\n const client = yield* publicClientService.get(chainId);\n const policy =\n typeof timeoutOrPolicy === \"object\" && timeoutOrPolicy !== null\n ? timeoutOrPolicy\n : undefined;\n const timeout =\n typeof timeoutOrPolicy === \"number\"\n ? timeoutOrPolicy\n : (policy?.receiptTimeout ?? defaultPolicy.receiptTimeout ?? DEFAULT_RECEIPT_TIMEOUT);\n const pollingInterval = policy?.pollingInterval ?? defaultPolicy.pollingInterval;\n\n return yield* Effect.tryPromise({\n catch: (cause) => {\n if (cause instanceof TxReplacedError) {\n return cause;\n }\n\n if (cause instanceof WaitForTransactionReceiptTimeoutError) {\n return new ReceiptTimeoutError({\n hash,\n message: cause.message,\n timeout,\n });\n }\n\n if (cause instanceof Error && cause.message.toLowerCase().includes(\"timeout\")) {\n return new ReceiptTimeoutError({\n hash,\n message: cause.message,\n timeout,\n });\n }\n\n return new TxFailedError({\n cause,\n hash,\n message: `Failed to get receipt for ${hash}`,\n });\n },\n try: async () => {\n let replacement: { newHash: Hash; reason: TxReplacementReason } | undefined;\n\n const receipt = await client.waitForTransactionReceipt({\n hash,\n onReplaced: (info) => {\n replacement = {\n newHash: info.transaction.hash,\n reason: info.reason,\n };\n },\n pollingInterval,\n timeout,\n });\n\n // Only throw if there's an actual replacement (different hash)\n if (replacement && replacement.newHash !== hash) {\n throw new TxReplacedError({\n message: `Transaction ${hash} was ${replacement.reason} with ${replacement.newHash}`,\n newHash: replacement.newHash,\n oldHash: hash,\n reason: replacement.reason,\n });\n }\n\n return receipt;\n },\n }).pipe(\n Effect.withSpan(SpanNames.TX_WAIT, {\n attributes: {\n chainId,\n hash,\n timeout,\n },\n })\n );\n }\n ),\n };\n })\n);\n"]}
1
+ {"version":3,"file":"manager.js","sourceRoot":"","sources":["../../src/tx/manager.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Scope, SubscriptionRef } from \"effect\";\nimport { Clock, Context, Effect, Fiber, Layer, Ref, Stream } from \"effect\";\nimport type { Hash, TransactionReceipt } from \"viem\";\nimport { WaitForTransactionReceiptTimeoutError } from \"viem\";\nimport { DEFAULT_RECEIPT_TIMEOUT, DEFAULT_STUCK_TX_MS } from \"@/src/constants/index.js\";\nimport type { ClientNotFoundError, TxReplacementReason } from \"@/src/core/index.js\";\nimport {\n PublicClientService,\n ReceiptTimeoutError,\n TransportError,\n TxFailedError,\n TxReplacedError,\n} from \"@/src/core/index.js\";\nimport { SpanNames } from \"@/src/telemetry/index.js\";\nimport type { TxPolicy } from \"./policy.js\";\nimport { defaultPolicy } from \"./policy.js\";\nimport { TxReplacement } from \"./replacement.js\";\nimport type { TxState } from \"./tracker.js\";\nimport { makeTxTracker } from \"./tracker.js\";\n\nexport type TxManagerShape = {\n /**\n * Track an existing transaction hash and return a SubscriptionRef for state updates\n */\n readonly track: (\n chainId: number,\n hash: Hash,\n policy?: TxPolicy\n ) => Effect.Effect<SubscriptionRef.SubscriptionRef<TxState>, ClientNotFoundError, Scope.Scope>;\n\n /**\n * Wait for transaction receipt with timeout\n */\n readonly waitForReceipt: (\n chainId: number,\n hash: Hash,\n timeoutOrPolicy?: number | TxPolicy\n ) => Effect.Effect<\n TransactionReceipt,\n TxFailedError | ReceiptTimeoutError | TxReplacedError | ClientNotFoundError\n >;\n\n /**\n * Get the number of confirmations for a transaction\n */\n readonly getConfirmations: (\n chainId: number,\n params: { hash: Hash } | { transactionReceipt: TransactionReceipt }\n ) => Effect.Effect<bigint, ClientNotFoundError | TransportError>;\n};\n\nexport class TxManager extends Context.Tag(\"ew3/TxManager\")<TxManager, TxManagerShape>() {}\n\nexport function makeTxManagerLive(\n layerPolicy?: TxPolicy\n): Layer.Layer<TxManager, never, PublicClientService | TxReplacement> {\n const layerDefault: TxPolicy = {\n ...defaultPolicy,\n ...layerPolicy,\n replacement: {\n ...(defaultPolicy.replacement ?? {}),\n ...(layerPolicy?.replacement ?? {}),\n },\n };\n\n return Layer.effect(\n TxManager,\n Effect.gen(function* () {\n const publicClientService = yield* PublicClientService;\n const txReplacement = yield* TxReplacement;\n\n return {\n getConfirmations: Effect.fn(\"TxManager.getConfirmations\")(function* (chainId, params) {\n const client = yield* publicClientService.get(chainId);\n\n return yield* Effect.tryPromise({\n catch: (cause) =>\n new TransportError({\n cause,\n message:\n cause instanceof Error\n ? cause.message\n : \"Failed to get transaction confirmations\",\n url: client.transport.url ?? \"\",\n }),\n try: () => client.getTransactionConfirmations(params),\n }).pipe(\n Effect.withSpan(SpanNames.TX_GET_CONFIRMATIONS, {\n attributes: {\n chainId,\n hash: \"hash\" in params ? params.hash : params.transactionReceipt.transactionHash,\n },\n })\n );\n }),\n track: Effect.fn(\"TxManager.track\")(function* (chainId, hash, providedPolicy) {\n const tracker = yield* makeTxTracker;\n const client = yield* publicClientService.get(chainId);\n const policy: TxPolicy = {\n ...layerDefault,\n ...providedPolicy,\n replacement: {\n ...(layerDefault.replacement ?? {}),\n ...(providedPolicy?.replacement ?? {}),\n },\n };\n\n // Set initial state\n yield* tracker.set({ hash, status: \"submitted\" });\n\n // Start tracking in background\n yield* Effect.forkScoped(\n // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: tracking orchestration is inherently complex\n Effect.gen(function* () {\n const currentHashRef = yield* Ref.make<Hash>(hash);\n const confirmationsRef = yield* Ref.make(0);\n const startedAtMsRef = yield* Ref.make(yield* Clock.currentTimeMillis);\n const autoAttemptsRef = yield* Ref.make(0);\n const autoReplacingRef = yield* Ref.make(false);\n\n const replacementStrategy =\n policy.replacement?.strategy ?? policy.replacementStrategy ?? \"none\";\n const stuckMs = policy.replacement?.stuckMs ?? DEFAULT_STUCK_TX_MS;\n const maxAttempts = policy.replacement?.maxAttempts ?? 1;\n\n const updatePendingState = (currentHash: Hash) =>\n Effect.gen(function* () {\n const confirmations = yield* Ref.modify(\n confirmationsRef,\n (n) => [n + 1, n + 1] as const\n );\n\n yield* tracker.set({\n confirmations,\n hash: currentHash,\n status: \"pending\",\n });\n return confirmations;\n });\n\n const performAutoReplacement = (currentHash: Hash, now: number) =>\n Ref.set(autoReplacingRef, true).pipe(\n Effect.zipRight(\n (replacementStrategy === \"cancel\"\n ? txReplacement.cancel(chainId, currentHash, policy)\n : txReplacement.speedup(chainId, currentHash, policy)\n ).pipe(\n Effect.either,\n Effect.ensuring(Ref.set(autoReplacingRef, false)),\n Effect.flatMap((replaced) => {\n if (replaced._tag === \"Left\") {\n return Effect.void;\n }\n\n const newHash = replaced.right;\n return Effect.all([\n Ref.set(currentHashRef, newHash),\n Ref.set(confirmationsRef, 0),\n Ref.set(startedAtMsRef, now),\n Ref.update(autoAttemptsRef, (n) => n + 1),\n tracker.set({\n newHash,\n oldHash: currentHash,\n reason: replacementStrategy === \"cancel\" ? \"cancelled\" : \"repriced\",\n status: \"replaced\",\n }),\n tracker.set({ hash: newHash, status: \"submitted\" }),\n ]).pipe(Effect.asVoid);\n })\n )\n )\n );\n\n const autoReplaceIfStuck = (currentHash: Hash) => {\n if (replacementStrategy === \"none\") {\n return Effect.void;\n }\n\n return Effect.all({\n alreadyReplacing: Ref.get(autoReplacingRef),\n attempts: Ref.get(autoAttemptsRef),\n now: Clock.currentTimeMillis,\n startedAt: Ref.get(startedAtMsRef),\n }).pipe(\n Effect.flatMap(({ alreadyReplacing, attempts, now, startedAt }) => {\n const elapsed = startedAt > 0 ? now - startedAt : 0;\n const stuck = elapsed >= stuckMs;\n const allowed = attempts < maxAttempts && !alreadyReplacing;\n return stuck && allowed\n ? performAutoReplacement(currentHash, now)\n : Effect.void;\n })\n );\n };\n\n const onPendingBlock = Effect.gen(function* () {\n const currentHash = yield* Ref.get(currentHashRef);\n yield* updatePendingState(currentHash);\n yield* autoReplaceIfStuck(currentHash);\n });\n\n const pendingFiber = yield* Stream.runForEach(\n Stream.async<bigint, unknown>((emit) => {\n const unwatch = client.watchBlockNumber({\n onBlockNumber: (blockNumber: bigint) => emit.single(blockNumber),\n onError: (error) => emit.fail(error as unknown),\n pollingInterval: policy.pollingInterval,\n });\n\n return Effect.sync(() => {\n unwatch();\n });\n }),\n () => onPendingBlock\n ).pipe(Effect.forkScoped);\n\n let replacement:\n | {\n oldHash: Hash;\n newHash: Hash;\n reason: TxReplacementReason;\n }\n | undefined;\n\n const receiptResult = yield* Effect.either(\n Effect.tryPromise({\n catch: (e) => e,\n try: () =>\n client.waitForTransactionReceipt({\n hash,\n onReplaced: (info) => {\n replacement = {\n newHash: info.transaction.hash,\n oldHash: info.replacedTransaction.hash,\n reason: info.reason,\n };\n },\n pollingInterval: policy.pollingInterval,\n timeout: policy.receiptTimeout,\n }),\n })\n ).pipe(Effect.ensuring(Fiber.interrupt(pendingFiber)));\n\n if (receiptResult._tag === \"Left\") {\n const cause = receiptResult.left;\n const timeout = policy.receiptTimeout ?? DEFAULT_RECEIPT_TIMEOUT;\n\n const failure =\n cause instanceof WaitForTransactionReceiptTimeoutError\n ? new ReceiptTimeoutError({\n hash,\n message: cause.message,\n timeout,\n })\n : cause;\n\n yield* tracker.set({\n error: new TxFailedError({\n cause: failure,\n hash,\n message: failure instanceof Error ? failure.message : String(failure),\n }),\n status: \"failed\",\n });\n\n return;\n }\n\n const receipt = receiptResult.right;\n\n if (replacement) {\n yield* Ref.set(currentHashRef, replacement.newHash);\n yield* tracker.set({\n newHash: replacement.newHash,\n oldHash: replacement.oldHash,\n reason: replacement.reason,\n status: \"replaced\",\n });\n yield* tracker.set({\n hash: replacement.newHash,\n status: \"submitted\",\n });\n }\n\n yield* tracker.set({\n effectiveGasPrice: receipt.effectiveGasPrice,\n hash: receipt.transactionHash,\n receipt,\n status: \"mined\",\n });\n })\n );\n\n return tracker.ref;\n }),\n\n waitForReceipt: Effect.fn(\"TxManager.waitForReceipt\")(\n function* (chainId, hash, timeoutOrPolicy) {\n const client = yield* publicClientService.get(chainId);\n const policy =\n typeof timeoutOrPolicy === \"object\" && timeoutOrPolicy !== null\n ? timeoutOrPolicy\n : undefined;\n const timeout =\n typeof timeoutOrPolicy === \"number\"\n ? timeoutOrPolicy\n : (policy?.receiptTimeout ??\n layerDefault.receiptTimeout ??\n DEFAULT_RECEIPT_TIMEOUT);\n const pollingInterval = policy?.pollingInterval ?? layerDefault.pollingInterval;\n\n return yield* Effect.tryPromise({\n catch: (cause) => {\n if (cause instanceof TxReplacedError) {\n return cause;\n }\n\n if (cause instanceof WaitForTransactionReceiptTimeoutError) {\n return new ReceiptTimeoutError({\n hash,\n message: cause.message,\n timeout,\n });\n }\n\n if (cause instanceof Error && cause.message.toLowerCase().includes(\"timeout\")) {\n return new ReceiptTimeoutError({\n hash,\n message: cause.message,\n timeout,\n });\n }\n\n return new TxFailedError({\n cause,\n hash,\n message: `Failed to get receipt for ${hash}`,\n });\n },\n try: async () => {\n let replacement: { newHash: Hash; reason: TxReplacementReason } | undefined;\n\n const receipt = await client.waitForTransactionReceipt({\n hash,\n onReplaced: (info) => {\n replacement = {\n newHash: info.transaction.hash,\n reason: info.reason,\n };\n },\n pollingInterval,\n timeout,\n });\n\n // Only throw if there's an actual replacement (different hash)\n if (replacement && replacement.newHash !== hash) {\n throw new TxReplacedError({\n message: `Transaction ${hash} was ${replacement.reason} with ${replacement.newHash}`,\n newHash: replacement.newHash,\n oldHash: hash,\n reason: replacement.reason,\n });\n }\n\n return receipt;\n },\n }).pipe(\n Effect.withSpan(SpanNames.TX_WAIT, {\n attributes: {\n chainId,\n hash,\n timeout,\n },\n })\n );\n }\n ),\n };\n })\n );\n}\n\nexport const TxManagerLive = makeTxManagerLive();\n"]}
@@ -2,7 +2,7 @@ import { describe, expect, it } from "@effect/vitest";
2
2
  import { Effect, Either, Exit, Layer } from "effect";
3
3
  import { MIN_TX_GAS } from "../constants/index.js";
4
4
  import { makeMockPublicClientLayer, TEST_CHAIN_ID, TEST_TX_HASH } from "../testing-kit/index.js";
5
- import { TxManager, TxManagerLive, TxReplacement } from "../tx/index.js";
5
+ import { makeTxManagerLive, TxManager, TxManagerLive, TxReplacement } from "../tx/index.js";
6
6
  const txReplacementLayer = Layer.succeed(TxReplacement, TxReplacement.of({
7
7
  cancel: () => Effect.succeed(TEST_TX_HASH),
8
8
  speedup: () => Effect.succeed(TEST_TX_HASH),
@@ -124,6 +124,26 @@ describe("TxManager", () => {
124
124
  }),
125
125
  }), txReplacementLayer))), Effect.scoped));
126
126
  });
127
+ describe("makeTxManagerLive", () => {
128
+ it.effect("applies custom layer policy as base for waitForReceipt", () => Effect.gen(function* () {
129
+ const manager = yield* TxManager;
130
+ const exit = yield* manager.waitForReceipt(TEST_CHAIN_ID, TEST_TX_HASH).pipe(Effect.exit);
131
+ expect(Exit.isFailure(exit)).toBe(true);
132
+ }).pipe(Effect.provide(Layer.provide(makeTxManagerLive({ receiptTimeout: 100 }), Layer.mergeAll(makeMockPublicClientLayer({
133
+ waitForTransactionReceipt: () => new Promise((_resolve, reject) => {
134
+ setTimeout(() => reject(new Error("timeout waiting for transaction")), 200);
135
+ }),
136
+ }), txReplacementLayer)))));
137
+ it.effect("per-call policy overrides layer policy", () => Effect.gen(function* () {
138
+ const manager = yield* TxManager;
139
+ const receipt = yield* manager.waitForReceipt(TEST_CHAIN_ID, TEST_TX_HASH, {
140
+ receiptTimeout: 5000,
141
+ });
142
+ expect(receipt.transactionHash).toBe(TEST_TX_HASH);
143
+ }).pipe(Effect.provide(Layer.provide(makeTxManagerLive({ receiptTimeout: 100 }), Layer.mergeAll(makeMockPublicClientLayer({
144
+ waitForTransactionReceipt: async () => TEST_RECEIPT,
145
+ }), txReplacementLayer)))));
146
+ });
127
147
  describe("getConfirmations", () => {
128
148
  it.effect("returns confirmations when called with hash param", () => Effect.gen(function* () {
129
149
  const manager = yield* TxManager;
@@ -1 +1 @@
1
- {"version":3,"file":"manager.test.integration.js","sourceRoot":"","sources":["../../src/tx/manager.test.integration.ts"],"names":[],"mappings":"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","sourcesContent":["import { describe, expect, it } from \"@effect/vitest\";\nimport { Effect, Either, Exit, Layer } from \"effect\";\nimport type { TransactionReceipt } from \"viem\";\nimport { MIN_TX_GAS } from \"@/src/constants/index.js\";\nimport { makeMockPublicClientLayer, TEST_CHAIN_ID, TEST_TX_HASH } from \"@/src/testing-kit/index.js\";\nimport { TxManager, TxManagerLive, TxReplacement } from \"@/src/tx/index.js\";\n\nconst txReplacementLayer = Layer.succeed(\n TxReplacement,\n TxReplacement.of({\n cancel: () => Effect.succeed(TEST_TX_HASH),\n speedup: () => Effect.succeed(TEST_TX_HASH),\n })\n);\n\nconst TEST_RECEIPT: TransactionReceipt = {\n blockHash: \"0xblock\",\n blockNumber: 123n,\n contractAddress: null,\n cumulativeGasUsed: MIN_TX_GAS,\n effectiveGasPrice: 1n,\n from: \"0xfrom\",\n gasUsed: MIN_TX_GAS,\n logs: [],\n logsBloom: \"0x\",\n status: \"success\",\n to: \"0xto\",\n transactionHash: TEST_TX_HASH,\n transactionIndex: 0,\n type: \"0x2\",\n};\n\ndescribe(\"TxManager\", () => {\n describe(\"waitForReceipt\", () => {\n it.effect(\"returns receipt on success\", () =>\n Effect.gen(function* () {\n const manager = yield* TxManager;\n const receipt = yield* manager.waitForReceipt(TEST_CHAIN_ID, TEST_TX_HASH);\n\n expect(receipt.transactionHash).toBe(TEST_TX_HASH);\n expect(receipt.status).toBe(\"success\");\n }).pipe(\n Effect.provide(\n Layer.provide(\n TxManagerLive,\n Layer.mergeAll(\n makeMockPublicClientLayer({\n waitForTransactionReceipt: async () => TEST_RECEIPT,\n }),\n txReplacementLayer\n )\n )\n )\n )\n );\n\n it.effect(\"returns TxFailedError on failure\", () =>\n Effect.gen(function* () {\n const manager = yield* TxManager;\n const exit = yield* manager.waitForReceipt(TEST_CHAIN_ID, TEST_TX_HASH).pipe(Effect.exit);\n\n expect(Exit.isFailure(exit)).toBe(true);\n }).pipe(\n Effect.provide(\n Layer.provide(\n TxManagerLive,\n Layer.mergeAll(\n makeMockPublicClientLayer({\n waitForTransactionReceipt: () => Promise.reject(new Error(\"Transaction reverted\")),\n }),\n txReplacementLayer\n )\n )\n )\n )\n );\n\n it.effect(\"returns ReceiptTimeoutError when error message contains timeout\", () =>\n Effect.gen(function* () {\n const manager = yield* TxManager;\n const exit = yield* manager\n .waitForReceipt(TEST_CHAIN_ID, TEST_TX_HASH, 5000)\n .pipe(Effect.exit);\n\n expect(Exit.isFailure(exit)).toBe(true);\n }).pipe(\n Effect.provide(\n Layer.provide(\n TxManagerLive,\n Layer.mergeAll(\n makeMockPublicClientLayer({\n waitForTransactionReceipt: () =>\n Promise.reject(new Error(\"timeout waiting for transaction\")),\n }),\n txReplacementLayer\n )\n )\n )\n )\n );\n\n it.effect(\"returns TxReplacedError when transaction is replaced\", () =>\n Effect.gen(function* () {\n const manager = yield* TxManager;\n const result = yield* manager\n .waitForReceipt(TEST_CHAIN_ID, TEST_TX_HASH)\n .pipe(Effect.either);\n\n Either.match(result, {\n onLeft: (error) => {\n expect(error._tag).toBe(\"TxReplacedError\");\n if (error._tag === \"TxReplacedError\") {\n expect(error.oldHash).toBe(TEST_TX_HASH);\n expect(error.newHash).toBe(\n \"0x9999999999999999999999999999999999999999999999999999999999999999\"\n );\n expect(error.reason).toBe(\"replaced\");\n }\n },\n onRight: () => {\n throw new Error(\"Expected failure (Left), got success (Right)\");\n },\n });\n }).pipe(\n Effect.provide(\n Layer.provide(\n TxManagerLive,\n Layer.mergeAll(\n makeMockPublicClientLayer({\n waitForTransactionReceipt: (params: unknown) => {\n type ReplacementInfo = {\n reason: \"cancelled\" | \"replaced\" | \"repriced\";\n transaction: { hash: string };\n };\n type WaitForTransactionReceiptParams = {\n hash: string;\n onReplaced?: (info: ReplacementInfo) => void;\n };\n\n const { onReplaced } = params as WaitForTransactionReceiptParams;\n\n onReplaced?.({\n reason: \"replaced\",\n transaction: {\n hash: \"0x9999999999999999999999999999999999999999999999999999999999999999\",\n },\n });\n\n return Promise.resolve({\n ...TEST_RECEIPT,\n transactionHash:\n \"0x9999999999999999999999999999999999999999999999999999999999999999\",\n } as TransactionReceipt);\n },\n }),\n txReplacementLayer\n )\n )\n )\n )\n );\n\n it.effect(\"returns receipt when onReplaced fires with same hash (no actual replacement)\", () =>\n Effect.gen(function* () {\n const manager = yield* TxManager;\n const result = yield* manager\n .waitForReceipt(TEST_CHAIN_ID, TEST_TX_HASH)\n .pipe(Effect.either);\n\n Either.match(result, {\n onLeft: (error) => {\n throw new Error(`Expected success (Right), got error (Left): ${error._tag}`);\n },\n onRight: (receipt) => {\n expect(receipt.transactionHash).toBe(TEST_TX_HASH);\n expect(receipt.status).toBe(\"success\");\n },\n });\n }).pipe(\n Effect.provide(\n Layer.provide(\n TxManagerLive,\n Layer.mergeAll(\n makeMockPublicClientLayer({\n waitForTransactionReceipt: (params: unknown) => {\n type ReplacementInfo = {\n reason: \"cancelled\" | \"replaced\" | \"repriced\";\n transaction: { hash: string };\n };\n type WaitForTransactionReceiptParams = {\n hash: string;\n onReplaced?: (info: ReplacementInfo) => void;\n };\n\n const { onReplaced, hash } = params as WaitForTransactionReceiptParams;\n\n // Simulate viem calling onReplaced with same hash (edge case)\n onReplaced?.({\n reason: \"repriced\",\n transaction: { hash }, // Same hash as original!\n });\n\n return Promise.resolve({\n ...TEST_RECEIPT,\n transactionHash: hash, // Same hash\n } as TransactionReceipt);\n },\n }),\n txReplacementLayer\n )\n )\n )\n )\n );\n });\n\n describe(\"track\", () => {\n it.effect(\"returns SubscriptionRef with initial submitted state\", () =>\n Effect.gen(function* () {\n const manager = yield* TxManager;\n const ref = yield* manager.track(TEST_CHAIN_ID, TEST_TX_HASH);\n const state = yield* ref.get;\n\n expect(state.status).toBe(\"submitted\");\n if (state.status === \"submitted\") {\n expect(state.hash).toBe(TEST_TX_HASH);\n }\n }).pipe(\n Effect.provide(\n Layer.provide(\n TxManagerLive,\n Layer.mergeAll(\n makeMockPublicClientLayer({\n waitForTransactionReceipt: async () =>\n new Promise<never>(() => {\n // Intentionally never resolves.\n }),\n }),\n txReplacementLayer\n )\n )\n ),\n Effect.scoped\n )\n );\n\n // Note: Testing background state updates in a scoped fork is complex\n // These tests verify that track() returns a proper SubscriptionRef\n // Integration tests should verify the full async behavior\n });\n\n describe(\"getConfirmations\", () => {\n it.effect(\"returns confirmations when called with hash param\", () =>\n Effect.gen(function* () {\n const manager = yield* TxManager;\n const confirmations = yield* manager.getConfirmations(TEST_CHAIN_ID, {\n hash: TEST_TX_HASH,\n });\n\n expect(confirmations).toBe(5n);\n }).pipe(\n Effect.provide(\n Layer.provide(\n TxManagerLive,\n Layer.mergeAll(\n makeMockPublicClientLayer({\n getTransactionConfirmations: async () => 5n,\n }),\n txReplacementLayer\n )\n )\n )\n )\n );\n\n it.effect(\"returns confirmations when called with transactionReceipt param\", () =>\n Effect.gen(function* () {\n const manager = yield* TxManager;\n\n const confirmations = yield* manager.getConfirmations(TEST_CHAIN_ID, {\n transactionReceipt: TEST_RECEIPT,\n });\n\n expect(confirmations).toBe(10n);\n }).pipe(\n Effect.provide(\n Layer.provide(\n TxManagerLive,\n Layer.mergeAll(\n makeMockPublicClientLayer({\n getTransactionConfirmations: async () => 10n,\n }),\n txReplacementLayer\n )\n )\n )\n )\n );\n\n it.effect(\"returns TransportError on failure\", () =>\n Effect.gen(function* () {\n const manager = yield* TxManager;\n const exit = yield* manager\n .getConfirmations(TEST_CHAIN_ID, { hash: TEST_TX_HASH })\n .pipe(Effect.exit);\n\n expect(Exit.isFailure(exit)).toBe(true);\n }).pipe(\n Effect.provide(\n Layer.provide(\n TxManagerLive,\n Layer.mergeAll(\n makeMockPublicClientLayer({\n getTransactionConfirmations: () => Promise.reject(new Error(\"RPC error\")),\n }),\n txReplacementLayer\n )\n )\n )\n )\n );\n });\n});\n"]}
1
+ {"version":3,"file":"manager.test.integration.js","sourceRoot":"","sources":["../../src/tx/manager.test.integration.ts"],"names":[],"mappings":"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","sourcesContent":["import { describe, expect, it } from \"@effect/vitest\";\nimport { Effect, Either, Exit, Layer } from \"effect\";\nimport type { TransactionReceipt } from \"viem\";\nimport { MIN_TX_GAS } from \"@/src/constants/index.js\";\nimport { makeMockPublicClientLayer, TEST_CHAIN_ID, TEST_TX_HASH } from \"@/src/testing-kit/index.js\";\nimport { makeTxManagerLive, TxManager, TxManagerLive, TxReplacement } from \"@/src/tx/index.js\";\n\nconst txReplacementLayer = Layer.succeed(\n TxReplacement,\n TxReplacement.of({\n cancel: () => Effect.succeed(TEST_TX_HASH),\n speedup: () => Effect.succeed(TEST_TX_HASH),\n })\n);\n\nconst TEST_RECEIPT: TransactionReceipt = {\n blockHash: \"0xblock\",\n blockNumber: 123n,\n contractAddress: null,\n cumulativeGasUsed: MIN_TX_GAS,\n effectiveGasPrice: 1n,\n from: \"0xfrom\",\n gasUsed: MIN_TX_GAS,\n logs: [],\n logsBloom: \"0x\",\n status: \"success\",\n to: \"0xto\",\n transactionHash: TEST_TX_HASH,\n transactionIndex: 0,\n type: \"0x2\",\n};\n\ndescribe(\"TxManager\", () => {\n describe(\"waitForReceipt\", () => {\n it.effect(\"returns receipt on success\", () =>\n Effect.gen(function* () {\n const manager = yield* TxManager;\n const receipt = yield* manager.waitForReceipt(TEST_CHAIN_ID, TEST_TX_HASH);\n\n expect(receipt.transactionHash).toBe(TEST_TX_HASH);\n expect(receipt.status).toBe(\"success\");\n }).pipe(\n Effect.provide(\n Layer.provide(\n TxManagerLive,\n Layer.mergeAll(\n makeMockPublicClientLayer({\n waitForTransactionReceipt: async () => TEST_RECEIPT,\n }),\n txReplacementLayer\n )\n )\n )\n )\n );\n\n it.effect(\"returns TxFailedError on failure\", () =>\n Effect.gen(function* () {\n const manager = yield* TxManager;\n const exit = yield* manager.waitForReceipt(TEST_CHAIN_ID, TEST_TX_HASH).pipe(Effect.exit);\n\n expect(Exit.isFailure(exit)).toBe(true);\n }).pipe(\n Effect.provide(\n Layer.provide(\n TxManagerLive,\n Layer.mergeAll(\n makeMockPublicClientLayer({\n waitForTransactionReceipt: () => Promise.reject(new Error(\"Transaction reverted\")),\n }),\n txReplacementLayer\n )\n )\n )\n )\n );\n\n it.effect(\"returns ReceiptTimeoutError when error message contains timeout\", () =>\n Effect.gen(function* () {\n const manager = yield* TxManager;\n const exit = yield* manager\n .waitForReceipt(TEST_CHAIN_ID, TEST_TX_HASH, 5000)\n .pipe(Effect.exit);\n\n expect(Exit.isFailure(exit)).toBe(true);\n }).pipe(\n Effect.provide(\n Layer.provide(\n TxManagerLive,\n Layer.mergeAll(\n makeMockPublicClientLayer({\n waitForTransactionReceipt: () =>\n Promise.reject(new Error(\"timeout waiting for transaction\")),\n }),\n txReplacementLayer\n )\n )\n )\n )\n );\n\n it.effect(\"returns TxReplacedError when transaction is replaced\", () =>\n Effect.gen(function* () {\n const manager = yield* TxManager;\n const result = yield* manager\n .waitForReceipt(TEST_CHAIN_ID, TEST_TX_HASH)\n .pipe(Effect.either);\n\n Either.match(result, {\n onLeft: (error) => {\n expect(error._tag).toBe(\"TxReplacedError\");\n if (error._tag === \"TxReplacedError\") {\n expect(error.oldHash).toBe(TEST_TX_HASH);\n expect(error.newHash).toBe(\n \"0x9999999999999999999999999999999999999999999999999999999999999999\"\n );\n expect(error.reason).toBe(\"replaced\");\n }\n },\n onRight: () => {\n throw new Error(\"Expected failure (Left), got success (Right)\");\n },\n });\n }).pipe(\n Effect.provide(\n Layer.provide(\n TxManagerLive,\n Layer.mergeAll(\n makeMockPublicClientLayer({\n waitForTransactionReceipt: (params: unknown) => {\n type ReplacementInfo = {\n reason: \"cancelled\" | \"replaced\" | \"repriced\";\n transaction: { hash: string };\n };\n type WaitForTransactionReceiptParams = {\n hash: string;\n onReplaced?: (info: ReplacementInfo) => void;\n };\n\n const { onReplaced } = params as WaitForTransactionReceiptParams;\n\n onReplaced?.({\n reason: \"replaced\",\n transaction: {\n hash: \"0x9999999999999999999999999999999999999999999999999999999999999999\",\n },\n });\n\n return Promise.resolve({\n ...TEST_RECEIPT,\n transactionHash:\n \"0x9999999999999999999999999999999999999999999999999999999999999999\",\n } as TransactionReceipt);\n },\n }),\n txReplacementLayer\n )\n )\n )\n )\n );\n\n it.effect(\"returns receipt when onReplaced fires with same hash (no actual replacement)\", () =>\n Effect.gen(function* () {\n const manager = yield* TxManager;\n const result = yield* manager\n .waitForReceipt(TEST_CHAIN_ID, TEST_TX_HASH)\n .pipe(Effect.either);\n\n Either.match(result, {\n onLeft: (error) => {\n throw new Error(`Expected success (Right), got error (Left): ${error._tag}`);\n },\n onRight: (receipt) => {\n expect(receipt.transactionHash).toBe(TEST_TX_HASH);\n expect(receipt.status).toBe(\"success\");\n },\n });\n }).pipe(\n Effect.provide(\n Layer.provide(\n TxManagerLive,\n Layer.mergeAll(\n makeMockPublicClientLayer({\n waitForTransactionReceipt: (params: unknown) => {\n type ReplacementInfo = {\n reason: \"cancelled\" | \"replaced\" | \"repriced\";\n transaction: { hash: string };\n };\n type WaitForTransactionReceiptParams = {\n hash: string;\n onReplaced?: (info: ReplacementInfo) => void;\n };\n\n const { onReplaced, hash } = params as WaitForTransactionReceiptParams;\n\n // Simulate viem calling onReplaced with same hash (edge case)\n onReplaced?.({\n reason: \"repriced\",\n transaction: { hash }, // Same hash as original!\n });\n\n return Promise.resolve({\n ...TEST_RECEIPT,\n transactionHash: hash, // Same hash\n } as TransactionReceipt);\n },\n }),\n txReplacementLayer\n )\n )\n )\n )\n );\n });\n\n describe(\"track\", () => {\n it.effect(\"returns SubscriptionRef with initial submitted state\", () =>\n Effect.gen(function* () {\n const manager = yield* TxManager;\n const ref = yield* manager.track(TEST_CHAIN_ID, TEST_TX_HASH);\n const state = yield* ref.get;\n\n expect(state.status).toBe(\"submitted\");\n if (state.status === \"submitted\") {\n expect(state.hash).toBe(TEST_TX_HASH);\n }\n }).pipe(\n Effect.provide(\n Layer.provide(\n TxManagerLive,\n Layer.mergeAll(\n makeMockPublicClientLayer({\n waitForTransactionReceipt: async () =>\n new Promise<never>(() => {\n // Intentionally never resolves.\n }),\n }),\n txReplacementLayer\n )\n )\n ),\n Effect.scoped\n )\n );\n\n // Note: Testing background state updates in a scoped fork is complex\n // These tests verify that track() returns a proper SubscriptionRef\n // Integration tests should verify the full async behavior\n });\n\n describe(\"makeTxManagerLive\", () => {\n it.effect(\"applies custom layer policy as base for waitForReceipt\", () =>\n Effect.gen(function* () {\n const manager = yield* TxManager;\n\n // The custom layer policy sets a short timeout (100ms).\n // The mock delays 200ms, so the receipt should timeout.\n const exit = yield* manager.waitForReceipt(TEST_CHAIN_ID, TEST_TX_HASH).pipe(Effect.exit);\n\n expect(Exit.isFailure(exit)).toBe(true);\n }).pipe(\n Effect.provide(\n Layer.provide(\n makeTxManagerLive({ receiptTimeout: 100 }),\n Layer.mergeAll(\n makeMockPublicClientLayer({\n waitForTransactionReceipt: () =>\n new Promise<never>((_resolve, reject) => {\n setTimeout(() => reject(new Error(\"timeout waiting for transaction\")), 200);\n }),\n }),\n txReplacementLayer\n )\n )\n )\n )\n );\n\n it.effect(\"per-call policy overrides layer policy\", () =>\n Effect.gen(function* () {\n const manager = yield* TxManager;\n\n // Layer policy has 100ms timeout, but per-call overrides to 5000ms.\n // The mock resolves immediately, so it should succeed.\n const receipt = yield* manager.waitForReceipt(TEST_CHAIN_ID, TEST_TX_HASH, {\n receiptTimeout: 5000,\n });\n\n expect(receipt.transactionHash).toBe(TEST_TX_HASH);\n }).pipe(\n Effect.provide(\n Layer.provide(\n makeTxManagerLive({ receiptTimeout: 100 }),\n Layer.mergeAll(\n makeMockPublicClientLayer({\n waitForTransactionReceipt: async () => TEST_RECEIPT,\n }),\n txReplacementLayer\n )\n )\n )\n )\n );\n });\n\n describe(\"getConfirmations\", () => {\n it.effect(\"returns confirmations when called with hash param\", () =>\n Effect.gen(function* () {\n const manager = yield* TxManager;\n const confirmations = yield* manager.getConfirmations(TEST_CHAIN_ID, {\n hash: TEST_TX_HASH,\n });\n\n expect(confirmations).toBe(5n);\n }).pipe(\n Effect.provide(\n Layer.provide(\n TxManagerLive,\n Layer.mergeAll(\n makeMockPublicClientLayer({\n getTransactionConfirmations: async () => 5n,\n }),\n txReplacementLayer\n )\n )\n )\n )\n );\n\n it.effect(\"returns confirmations when called with transactionReceipt param\", () =>\n Effect.gen(function* () {\n const manager = yield* TxManager;\n\n const confirmations = yield* manager.getConfirmations(TEST_CHAIN_ID, {\n transactionReceipt: TEST_RECEIPT,\n });\n\n expect(confirmations).toBe(10n);\n }).pipe(\n Effect.provide(\n Layer.provide(\n TxManagerLive,\n Layer.mergeAll(\n makeMockPublicClientLayer({\n getTransactionConfirmations: async () => 10n,\n }),\n txReplacementLayer\n )\n )\n )\n )\n );\n\n it.effect(\"returns TransportError on failure\", () =>\n Effect.gen(function* () {\n const manager = yield* TxManager;\n const exit = yield* manager\n .getConfirmations(TEST_CHAIN_ID, { hash: TEST_TX_HASH })\n .pipe(Effect.exit);\n\n expect(Exit.isFailure(exit)).toBe(true);\n }).pipe(\n Effect.provide(\n Layer.provide(\n TxManagerLive,\n Layer.mergeAll(\n makeMockPublicClientLayer({\n getTransactionConfirmations: () => Promise.reject(new Error(\"RPC error\")),\n }),\n txReplacementLayer\n )\n )\n )\n )\n );\n });\n});\n"]}
@@ -9,7 +9,6 @@ export type TxPolicy = {
9
9
  replacementStrategy?: "speedup" | "cancel" | "none";
10
10
  replacement?: {
11
11
  strategy?: "speedup" | "cancel" | "none";
12
- stuckBlocks?: number;
13
12
  stuckMs?: number;
14
13
  maxAttempts?: number;
15
14
  };
@@ -1 +1 @@
1
- {"version":3,"file":"policy.d.ts","sourceRoot":"","sources":["../../src/tx/policy.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAEnD,MAAM,MAAM,QAAQ,GAAG;IAErB,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAE9B,QAAQ,CAAC,EAAE,QAAQ,CAAC;IAEpB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAE5B,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB,mBAAmB,CAAC,EAAE,SAAS,GAAG,QAAQ,GAAG,MAAM,CAAC;IAEpD,WAAW,CAAC,EAAE;QACZ,QAAQ,CAAC,EAAE,SAAS,GAAG,QAAQ,GAAG,MAAM,CAAC;QAEzC,WAAW,CAAC,EAAE,MAAM,CAAC;QAErB,OAAO,CAAC,EAAE,MAAM,CAAC;QAEjB,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,CAAC;CACH,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,QAM3B,CAAC"}
1
+ {"version":3,"file":"policy.d.ts","sourceRoot":"","sources":["../../src/tx/policy.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAEnD,MAAM,MAAM,QAAQ,GAAG;IAErB,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAE9B,QAAQ,CAAC,EAAE,QAAQ,CAAC;IAEpB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAE5B,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB,mBAAmB,CAAC,EAAE,SAAS,GAAG,QAAQ,GAAG,MAAM,CAAC;IAEpD,WAAW,CAAC,EAAE;QACZ,QAAQ,CAAC,EAAE,SAAS,GAAG,QAAQ,GAAG,MAAM,CAAC;QAEzC,OAAO,CAAC,EAAE,MAAM,CAAC;QAEjB,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,CAAC;CACH,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,QAM3B,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"policy.js","sourceRoot":"","sources":["../../src/tx/policy.ts"],"names":[],"mappings":"AACA,OAAO,EACL,4BAA4B,EAC5B,wBAAwB,EACxB,uBAAuB,GACxB,MAAM,0BAA0B,CAAC;AA8BlC,MAAM,CAAC,MAAM,aAAa,GAAa;IACrC,QAAQ,EAAE,UAAU;IACpB,kBAAkB,EAAE,4BAA4B;IAChD,eAAe,EAAE,wBAAwB;IACzC,cAAc,EAAE,uBAAuB;IACvC,mBAAmB,EAAE,MAAM;CAC5B,CAAC","sourcesContent":["/** Transaction execution policy */\nimport {\n DEFAULT_GAS_LIMIT_MULTIPLIER,\n DEFAULT_POLLING_INTERVAL,\n DEFAULT_RECEIPT_TIMEOUT,\n} from \"@/src/constants/index.js\";\nimport type { GasSpeed } from \"@/src/gas/index.js\";\n\nexport type TxPolicy = {\n /** Max fee per gas in wei (optional cap) */\n maxFeePerGas?: bigint;\n /** Max priority fee per gas in wei */\n maxPriorityFeePerGas?: bigint;\n /** Fee estimation speed tier */\n feeSpeed?: GasSpeed;\n /** Gas limit multiplier applied to estimates */\n gasLimitMultiplier?: number;\n /** Timeout in milliseconds for receipt polling */\n receiptTimeout?: number;\n /** Polling interval in milliseconds */\n pollingInterval?: number;\n /** Replacement strategy when stuck */\n replacementStrategy?: \"speedup\" | \"cancel\" | \"none\";\n /** Replacement behavior (preferred) */\n replacement?: {\n strategy?: \"speedup\" | \"cancel\" | \"none\";\n /** Consider tx stuck after N blocks */\n stuckBlocks?: number;\n /** Consider tx stuck after N milliseconds */\n stuckMs?: number;\n /** Maximum automatic replacement attempts */\n maxAttempts?: number;\n };\n};\n\nexport const defaultPolicy: TxPolicy = {\n feeSpeed: \"standard\",\n gasLimitMultiplier: DEFAULT_GAS_LIMIT_MULTIPLIER,\n pollingInterval: DEFAULT_POLLING_INTERVAL,\n receiptTimeout: DEFAULT_RECEIPT_TIMEOUT,\n replacementStrategy: \"none\",\n};\n"]}
1
+ {"version":3,"file":"policy.js","sourceRoot":"","sources":["../../src/tx/policy.ts"],"names":[],"mappings":"AACA,OAAO,EACL,4BAA4B,EAC5B,wBAAwB,EACxB,uBAAuB,GACxB,MAAM,0BAA0B,CAAC;AA4BlC,MAAM,CAAC,MAAM,aAAa,GAAa;IACrC,QAAQ,EAAE,UAAU;IACpB,kBAAkB,EAAE,4BAA4B;IAChD,eAAe,EAAE,wBAAwB;IACzC,cAAc,EAAE,uBAAuB;IACvC,mBAAmB,EAAE,MAAM;CAC5B,CAAC","sourcesContent":["/** Transaction execution policy */\nimport {\n DEFAULT_GAS_LIMIT_MULTIPLIER,\n DEFAULT_POLLING_INTERVAL,\n DEFAULT_RECEIPT_TIMEOUT,\n} from \"@/src/constants/index.js\";\nimport type { GasSpeed } from \"@/src/gas/index.js\";\n\nexport type TxPolicy = {\n /** Max fee per gas in wei (optional cap) */\n maxFeePerGas?: bigint;\n /** Max priority fee per gas in wei */\n maxPriorityFeePerGas?: bigint;\n /** Fee estimation speed tier */\n feeSpeed?: GasSpeed;\n /** Gas limit multiplier applied to estimates */\n gasLimitMultiplier?: number;\n /** Timeout in milliseconds for receipt polling */\n receiptTimeout?: number;\n /** Polling interval in milliseconds */\n pollingInterval?: number;\n /** Replacement strategy when stuck */\n replacementStrategy?: \"speedup\" | \"cancel\" | \"none\";\n /** Replacement behavior (preferred) */\n replacement?: {\n strategy?: \"speedup\" | \"cancel\" | \"none\";\n /** Consider tx stuck after N milliseconds */\n stuckMs?: number;\n /** Maximum automatic replacement attempts */\n maxAttempts?: number;\n };\n};\n\nexport const defaultPolicy: TxPolicy = {\n feeSpeed: \"standard\",\n gasLimitMultiplier: DEFAULT_GAS_LIMIT_MULTIPLIER,\n pollingInterval: DEFAULT_POLLING_INTERVAL,\n receiptTimeout: DEFAULT_RECEIPT_TIMEOUT,\n replacementStrategy: \"none\",\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.6",
9
+ "version": "1.0.0-beta.7",
10
10
  "scripts": {
11
11
  "build": "just build",
12
12
  "prepack": "bun install --frozen-lockfile && just build"