diff --git a/docs/src/sdk-reference/ethers/deposits.md b/docs/src/sdk-reference/ethers/deposits.md index 98d7388..f5fed16 100644 --- a/docs/src/sdk-reference/ethers/deposits.md +++ b/docs/src/sdk-reference/ethers/deposits.md @@ -162,6 +162,21 @@ Result-style `wait`. --- +## Utility Helpers + +### `getL2TransactionHashFromLogs(logs) → Hex | null` + +Extracts the L2 transaction hash from L1 logs emitted by `Bridgehub` during deposit. Returns `null` if not found. + +```ts +import { getL2TransactionHashFromLogs } from '@matterlabs/zksync-js/ethers'; + +const l1Receipt = await client.l1.waitForTransaction(l1TxHash); +const l2TxHash = l1Receipt ? getL2TransactionHashFromLogs(l1Receipt.logs) : null; +``` + +--- + ## Types (Overview) ### Deposit Params diff --git a/docs/src/sdk-reference/viem/deposits.md b/docs/src/sdk-reference/viem/deposits.md index 00d4679..320edca 100644 --- a/docs/src/sdk-reference/viem/deposits.md +++ b/docs/src/sdk-reference/viem/deposits.md @@ -160,6 +160,23 @@ Result-style `wait`. {{#include ../../../snippets/viem/reference/deposits.test.ts:create-token-deposit}} ``` +--- + +## Utility Helpers + +### `getL2TransactionHashFromLogs(logs) → Hex | null` + +Extracts the L2 transaction hash from L1 logs emitted by `Bridgehub` during deposit. Returns `null` if not found. + +```ts +import { getL2TransactionHashFromLogs } from '@matterlabs/zksync-js/viem'; + +const l1Receipt = await client.l1.waitForTransactionReceipt({ hash: l1TxHash }); +const l2TxHash = getL2TransactionHashFromLogs(l1Receipt.logs); +``` + +--- + ## Types (Overview) ### Deposit Params diff --git a/src/adapters/ethers/index.ts b/src/adapters/ethers/index.ts index 992e933..32ecc0c 100644 --- a/src/adapters/ethers/index.ts +++ b/src/adapters/ethers/index.ts @@ -7,6 +7,7 @@ export * from './sdk'; export * from './resources/utils'; export { createDepositsResource } from './resources/deposits'; export type { DepositsResource } from './resources/deposits'; +export { getL2TransactionHashFromLogs } from './resources/deposits/services/verification'; export { createWithdrawalsResource } from './resources/withdrawals'; export { createFinalizationServices } from './resources/withdrawals'; export type { WithdrawalsResource, FinalizationServices } from './resources/withdrawals'; diff --git a/src/adapters/ethers/resources/deposits/index.ts b/src/adapters/ethers/resources/deposits/index.ts index f88a5cb..c6544d8 100644 --- a/src/adapters/ethers/resources/deposits/index.ts +++ b/src/adapters/ethers/resources/deposits/index.ts @@ -10,7 +10,10 @@ import type { DepositStatus, } from '../../../../core/types/flows/deposits.ts'; import type { Address, Hex } from '../../../../core/types/primitives.ts'; -import { extractL2TxHashFromL1Logs, waitForL2ExecutionFromL1Tx } from './services/verification.ts'; +import { + getL2TransactionHashFromLogs, + waitForL2ExecutionFromL1Tx, +} from './services/verification.ts'; import { Contract, type TransactionRequest, type TransactionReceipt, NonceManager } from 'ethers'; import { IERC20ABI } from '../../../../core/abi.ts'; @@ -321,14 +324,14 @@ export function createDepositsResource( let l2TxHash: Hex | undefined; try { - l2TxHash = extractL2TxHashFromL1Logs(l1Rcpt.logs) ?? undefined; + l2TxHash = getL2TransactionHashFromLogs(l1Rcpt.logs) ?? undefined; } catch (e) { throw toZKsyncError( 'INTERNAL', { resource: 'deposits', - operation: 'deposits.status.extractL2TxHashFromL1Logs', - context: { where: 'extractL2TxHashFromL1Logs', l1TxHash }, + operation: 'deposits.status.getL2TransactionHashFromLogs', + context: { where: 'getL2TransactionHashFromLogs', l1TxHash }, message: 'Failed to derive L2 transaction hash from L1 logs.', }, e, diff --git a/src/adapters/ethers/resources/deposits/services/__tests__/verification.test.ts b/src/adapters/ethers/resources/deposits/services/__tests__/verification.test.ts index 576c211..b0a5c2d 100644 --- a/src/adapters/ethers/resources/deposits/services/__tests__/verification.test.ts +++ b/src/adapters/ethers/resources/deposits/services/__tests__/verification.test.ts @@ -3,7 +3,7 @@ import { describe, it, expect } from 'bun:test'; import { type Log } from 'ethers'; import { - extractL2TxHashFromL1Logs, + getL2TransactionHashFromLogs, waitForL2ExecutionFromL1Tx, I_BRIDGEHUB, TOPIC_BRIDGEHUB_NPR, @@ -68,23 +68,23 @@ function makeTopicOnlyLog(topic0: string, extraTopics: string[] = []): Log { } as unknown as Log; } -describe('services/verification.extractL2TxHashFromL1Logs', () => { +describe('services/verification.getL2TransactionHashFromLogs', () => { it('extracts from Bridgehub.NewPriorityRequest', () => { const target = H.l2tx as `0x${string}`; const log = makeNprLog({ txHash: target }); - const out = extractL2TxHashFromL1Logs([log]); + const out = getL2TransactionHashFromLogs([log]); expect(out).toBe(target); }); it('falls back to TOPIC_CANONICAL_ASSIGNED (hash at topic[2])', () => { const assigned = makeTopicOnlyLog(TOPIC_CANONICAL_ASSIGNED, ['0x', H.l2tx, '0xdead']); - const out = extractL2TxHashFromL1Logs([assigned]); + const out = getL2TransactionHashFromLogs([assigned]); expect(out).toBe(H.l2tx); }); it('falls back to TOPIC_CANONICAL_SUCCESS (hash at topic[3])', () => { const success = makeTopicOnlyLog(TOPIC_CANONICAL_SUCCESS, ['0x1', '0x2', H.l2tx]); - const out = extractL2TxHashFromL1Logs([success]); + const out = getL2TransactionHashFromLogs([success]); expect(out).toBe(H.l2tx); }); @@ -94,12 +94,12 @@ describe('services/verification.extractL2TxHashFromL1Logs', () => { data: '0x1234', } as Log; const success = makeTopicOnlyLog(TOPIC_CANONICAL_SUCCESS, ['0x1', '0x2', H.l2tx]); - const out = extractL2TxHashFromL1Logs([badNpr, success]); + const out = getL2TransactionHashFromLogs([badNpr, success]); expect(out).toBe(H.l2tx); }); it('returns null when no recognizable logs exist', () => { - const out = extractL2TxHashFromL1Logs([]); + const out = getL2TransactionHashFromLogs([]); expect(out).toBeNull(); }); }); diff --git a/src/adapters/ethers/resources/deposits/services/verification.ts b/src/adapters/ethers/resources/deposits/services/verification.ts index 0c6033f..0c1af3e 100644 --- a/src/adapters/ethers/resources/deposits/services/verification.ts +++ b/src/adapters/ethers/resources/deposits/services/verification.ts @@ -14,7 +14,7 @@ export const TOPIC_BRIDGEHUB_NPR = I_BRIDGEHUB.getEvent('NewPriorityRequest')!.t // Extracts the L2 transaction hash from L1 logs emitted by Bridgehub during deposit // Returns null if not found -export function extractL2TxHashFromL1Logs(logs: ReadonlyArray): Hex | null { +export function getL2TransactionHashFromLogs(logs: ReadonlyArray): Hex | null { for (const lg of logs) { if ((lg.topics?.[0] ?? '').toLowerCase() === TOPIC_BRIDGEHUB_NPR.toLowerCase()) { try { @@ -52,7 +52,7 @@ export async function waitForL2ExecutionFromL1Tx( const l1Receipt = await l1.waitForTransaction(l1TxHash); if (!l1Receipt) throw new Error('No L1 receipt found'); - const l2TxHash = extractL2TxHashFromL1Logs(l1Receipt.logs); + const l2TxHash = getL2TransactionHashFromLogs(l1Receipt.logs); if (!l2TxHash) { throw createError('VERIFICATION', { message: 'Failed to extract L2 transaction hash from L1 logs', diff --git a/src/adapters/ethers/resources/interop/resolvers.ts b/src/adapters/ethers/resources/interop/resolvers.ts index 7ccabc3..dfadff2 100644 --- a/src/adapters/ethers/resources/interop/resolvers.ts +++ b/src/adapters/ethers/resources/interop/resolvers.ts @@ -1,4 +1,4 @@ -import { AbstractProvider, JsonRpcProvider } from 'ethers'; +import { type AbstractProvider, JsonRpcProvider } from 'ethers'; import type { InteropWaitable as InteropWaitableBase } from '../../../../core/types/flows/interop'; import type { DstChain, InteropWaitable, InteropHandle } from './types'; diff --git a/src/adapters/viem/index.ts b/src/adapters/viem/index.ts index 4888be7..c4d8f12 100644 --- a/src/adapters/viem/index.ts +++ b/src/adapters/viem/index.ts @@ -5,6 +5,7 @@ export * from './sdk'; export * from './resources/utils'; export { createDepositsResource } from './resources/deposits'; export type { DepositsResource } from './resources/deposits'; +export { getL2TransactionHashFromLogs } from './resources/deposits/services/verification'; export { createWithdrawalsResource } from './resources/withdrawals'; export { createFinalizationServices } from './resources/withdrawals'; export type { WithdrawalsResource, FinalizationServices } from './resources/withdrawals'; diff --git a/src/adapters/viem/resources/deposits/index.ts b/src/adapters/viem/resources/deposits/index.ts index af74709..6cd54d5 100644 --- a/src/adapters/viem/resources/deposits/index.ts +++ b/src/adapters/viem/resources/deposits/index.ts @@ -26,7 +26,7 @@ import { routeEthNonBase } from './routes/eth-nonbase'; import { routeErc20Base } from './routes/erc20-base'; import type { DepositRouteStrategy, ViemPlanWriteRequest } from './routes/types'; -import { extractL2TxHashFromL1Logs, waitForL2ExecutionFromL1Tx } from './services/verification'; +import { getL2TransactionHashFromLogs, waitForL2ExecutionFromL1Tx } from './services/verification'; import { isZKsyncError, isReceiptNotFound, OP_DEPOSITS } from '../../../../core/types/errors'; import { createError } from '../../../../core/errors/factory'; import { toZKsyncError, createErrorHandlers } from '../../errors/error-ops'; @@ -382,14 +382,14 @@ export function createDepositsResource( let l2TxHash: Hex | undefined; try { - l2TxHash = extractL2TxHashFromL1Logs(l1Rcpt.logs) ?? undefined; + l2TxHash = getL2TransactionHashFromLogs(l1Rcpt.logs) ?? undefined; } catch (e) { throw toZKsyncError( 'INTERNAL', { resource: 'deposits', - operation: 'deposits.status.extractL2TxHashFromL1Logs', - context: { where: 'extractL2TxHashFromL1Logs', l1TxHash }, + operation: 'deposits.status.getL2TransactionHashFromLogs', + context: { where: 'getL2TransactionHashFromLogs', l1TxHash }, message: 'Failed to derive L2 transaction hash from L1 logs.', }, e, diff --git a/src/adapters/viem/resources/deposits/services/verification.ts b/src/adapters/viem/resources/deposits/services/verification.ts index 2b241a0..bf2986a 100644 --- a/src/adapters/viem/resources/deposits/services/verification.ts +++ b/src/adapters/viem/resources/deposits/services/verification.ts @@ -22,7 +22,7 @@ const I_BRIDGEHUB_NEW_PRIORITY_REQUEST = { // Extracts the L2 transaction hash from L1 logs emitted by Bridgehub during deposit // Returns null if not found -export function extractL2TxHashFromL1Logs(logs: ReadonlyArray): Hex | null { +export function getL2TransactionHashFromLogs(logs: ReadonlyArray): Hex | null { for (const lg of logs) { try { const parsed = decodeEventLog({ @@ -69,7 +69,7 @@ export async function waitForL2ExecutionFromL1Tx( if (!l1Receipt) throw new Error('No L1 receipt found'); // Extract L2 tx hash from logs - const l2TxHash = extractL2TxHashFromL1Logs(l1Receipt.logs as ReadonlyArray); + const l2TxHash = getL2TransactionHashFromLogs(l1Receipt.logs as ReadonlyArray); if (!l2TxHash) { throw createError('VERIFICATION', { message: 'Failed to extract L2 transaction hash from L1 logs',