FRE-600: Fix code review blockers

- Consolidated duplicate UndoManagers to single instance
- Fixed connection promise to only resolve on 'connected' status
- Fixed WebSocketProvider import (WebsocketProvider)
- Added proper doc.destroy() cleanup
- Renamed isPresenceInitialized property to avoid conflict

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
2026-04-25 00:08:01 -04:00
parent 65b552bb08
commit 7c684a42cc
48450 changed files with 5679671 additions and 383 deletions

View File

@@ -0,0 +1,29 @@
import type { Address } from '../../../accounts/index.js'
import { pad, toHex } from '../../../utils/index.js'
import { addressModulo, l1ToL2AliasOffset } from '../../constants/address.js'
/**
* Converts the address that submitted a transaction to the inbox on L1 to the `msg.sender` viewed on L2.
* Returns the `msg.sender` of the `L1->L2` transaction as the address of the contract that initiated the transaction.
*
* All available cases:
* - During a normal transaction, if contract `A` calls contract `B`, the `msg.sender` is `A`.
* - During `L1->L2` communication, if an EOA `X` calls contract `B`, the `msg.sender` is `X`.
* - During `L1->L2` communication, if a contract `A` calls contract `B`, the `msg.sender` is `applyL1ToL2Alias(A)`.
*
* @param address - The address of the contract.
* @returns address - The transformed address representing the `msg.sender` on L2.
*
* @example
* import { applyL1ToL2Alias } from 'viem/zksync'
*
* const l1ContractAddress = "0x702942B8205E5dEdCD3374E5f4419843adA76Eeb";
* const l2ContractAddress = utils.applyL1ToL2Alias(l1ContractAddress);
* // l2ContractAddress = "0x813A42B8205E5DedCd3374e5f4419843ADa77FFC"
*/
export function applyL1ToL2Alias(address: Address): Address {
return pad(
toHex((BigInt(address) + BigInt(l1ToL2AliasOffset)) % addressModulo),
{ size: 20 },
)
}

View File

@@ -0,0 +1,63 @@
import type { Address } from 'abitype'
import type { Hash } from '../../../types/misc.js'
import type { TransactionReceipt } from '../../../types/transaction.js'
import { decodeEventLog, isAddressEqual } from '../../../utils/index.js'
import { zksyncAbi } from '../../constants/abis.js'
import {
TxHashNotFoundInLogsError,
type TxHashNotFoundInLogsErrorType,
} from '../../errors/bridge.js'
export type GetL2HashFromPriorityOpErrorType = TxHashNotFoundInLogsErrorType
/**
* Returns the hash of the L2 priority operation from a given L1 transaction receipt.
*
* @param receipt - The L1 transaction receipt.
* @param zksync - The address of the ZKsync Era main contract.
* @returns hash - The hash of the L2 priority operation.
*
* @example
* import { createPublicClient, http } from 'viem'
* import { zksync, mainnet } from 'viem/chains'
* import { publicActionsL2, getL2HashFromPriorityOp } from 'viem/zksync'
*
* const client = createPublicClient({
* chain: mainnet,
* transport: http(),
* })
*
* const zksyncClient = const client = createPublicClient({
* chain: zksync,
* transport: http(),
* })
*
* const receipt = await client.waitForTransactionReceipt({hash: '0x...'})
* const l2Hash = getL2HashFromPriorityOp(
* receipt,
* await zksyncClient.getMainContractAddress()
* )
*/
export function getL2HashFromPriorityOp(
receipt: TransactionReceipt,
zksync: Address,
): Address {
let hash: Hash | null = null
for (const log of receipt.logs) {
if (!isAddressEqual(log.address, zksync)) continue
try {
const priorityQueueLog = decodeEventLog({
abi: zksyncAbi,
data: log.data,
topics: log.topics,
})
if (priorityQueueLog && (priorityQueueLog.args as any).txHash !== null)
hash = (priorityQueueLog.args as any).txHash
} catch (_e) {}
}
if (!hash) {
throw new TxHashNotFoundInLogsError()
}
return hash
}

View File

@@ -0,0 +1,47 @@
import type { Address } from 'abitype'
import type { Account } from '../../../accounts/index.js'
import { getTransactionReceipt } from '../../../actions/index.js'
import type { Client } from '../../../clients/createClient.js'
import type { Transport } from '../../../clients/transports/createTransport.js'
import type { Chain } from '../../../types/chain.js'
import type { Hash } from '../../../types/misc.js'
import { isAddressEqual } from '../../../utils/index.js'
import { l1MessengerAddress } from '../../constants/address.js'
import type { ZksyncL2ToL1Log } from '../../types/log.js'
import type { ZksyncTransactionReceipt } from '../../types/transaction.js'
export type GetWithdrawalL2ToL1LogParameters = {
/** Hash of the L2 transaction where the withdrawal was initiated. */
hash: Hash
/** In case there were multiple withdrawals in one transaction, you may pass an index of the
withdrawal you want to finalize. */
index?: number | undefined
}
export type GetWithdrawalL2ToL1LogReturnType = {
l2ToL1LogIndex: number | null
l2ToL1Log: ZksyncL2ToL1Log
}
/** @internal */
export async function getWithdrawalL2ToL1Log<
chain extends Chain | undefined,
account extends Account | undefined,
>(
client: Client<Transport, chain, account>,
parameters: GetWithdrawalL2ToL1LogParameters,
): Promise<GetWithdrawalL2ToL1LogReturnType> {
const { hash, index = 0 } = parameters
const receipt = (await getTransactionReceipt(client, {
hash,
})) as ZksyncTransactionReceipt
const messages = Array.from(receipt.l2ToL1Logs.entries()).filter(([, log]) =>
isAddressEqual(log.sender as Address, l1MessengerAddress),
)
const [l2ToL1LogIndex, l2ToL1Log] = messages[index]
return {
l2ToL1LogIndex,
l2ToL1Log,
}
}

View File

@@ -0,0 +1,47 @@
import type { Account } from '../../../accounts/types.js'
import { getTransactionReceipt } from '../../../actions/index.js'
import type { Client } from '../../../clients/createClient.js'
import type { Transport } from '../../../clients/transports/createTransport.js'
import type { Chain } from '../../../types/chain.js'
import type { Hash } from '../../../types/misc.js'
import { isAddressEqual, toFunctionHash } from '../../../utils/index.js'
import { l1MessengerAddress } from '../../constants/address.js'
import type { ZksyncLog } from '../../types/log.js'
import type { ZksyncTransactionReceipt } from '../../types/transaction.js'
export type GetWithdrawalLogParameters = {
/** Hash of the L2 transaction where the withdrawal was initiated. */
hash: Hash
/** In case there were multiple withdrawals in one transaction, you may pass an index of the
withdrawal you want to finalize. */
index?: number | undefined
}
export type GetWithdrawalLogReturnType = {
log: ZksyncLog
l1BatchTxId: bigint | null
}
/** @internal */
export async function getWithdrawalLog<
chain extends Chain | undefined,
account extends Account | undefined,
>(
client: Client<Transport, chain, account>,
parameters: GetWithdrawalLogParameters,
): Promise<GetWithdrawalLogReturnType> {
const { hash, index = 0 } = parameters
const receipt = (await getTransactionReceipt(client, {
hash,
})) as ZksyncTransactionReceipt
const log = receipt.logs.filter(
(log) =>
isAddressEqual(log.address, l1MessengerAddress) &&
log.topics[0] === toFunctionHash('L1MessageSent(address,bytes32,bytes)'),
)[index]
return {
log,
l1BatchTxId: receipt.l1BatchTxIndex,
}
}

View File

@@ -0,0 +1,22 @@
import type { Address } from '../../../accounts/index.js'
import { pad, toHex } from '../../../utils/index.js'
import { addressModulo, l1ToL2AliasOffset } from '../../constants/address.js'
/**
* Converts and returns the `msg.sender` viewed on L2 to the address that submitted a transaction to the inbox on L1.
*
* @param address - The sender address viewed on L2.
* @returns address - The hash of the L2 priority operation.
*
* @example
* import { undoL1ToL2Alias } from 'viem/zksync'
*
* const l2ContractAddress = "0x813A42B8205E5DedCd3374e5f4419843ADa77FFC";
* const l1ContractAddress = utils.undoL1ToL2Alias(l2ContractAddress);
* // const l1ContractAddress = "0x702942B8205E5dEdCD3374E5f4419843adA76Eeb"
*/
export function undoL1ToL2Alias(address: Address): Address {
let result = BigInt(address) - BigInt(l1ToL2AliasOffset)
if (result < 0n) result += addressModulo
return pad(toHex(result), { size: 20 })
}