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

318
node_modules/viem/zksync/actions/claimFailedDeposit.ts generated vendored Normal file
View File

@@ -0,0 +1,318 @@
import { type Address, parseAbi } from 'abitype'
import type { Account } from '../../accounts/types.js'
import { getTransaction } from '../../actions/public/getTransaction.js'
import { getTransactionReceipt } from '../../actions/public/getTransactionReceipt.js'
import { readContract } from '../../actions/public/readContract.js'
import {
type SendTransactionErrorType,
type SendTransactionParameters,
type SendTransactionReturnType,
sendTransaction,
} from '../../actions/wallet/sendTransaction.js'
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import { zeroHash } from '../../constants/bytes.js'
import { AccountNotFoundError } from '../../errors/account.js'
import { ClientChainNotConfiguredError } from '../../errors/chain.js'
import type { TransactionReceiptNotFoundErrorType } from '../../errors/transaction.js'
import type { GetAccountParameter } from '../../types/account.js'
import type {
Chain,
DeriveChain,
GetChainParameter,
} from '../../types/chain.js'
import type { Hash, Hex } from '../../types/misc.js'
import type { UnionEvaluate, UnionOmit } from '../../types/utils.js'
import {
decodeAbiParameters,
decodeFunctionData,
encodeAbiParameters,
encodeFunctionData,
type FormattedTransactionRequest,
isAddressEqual,
parseAccount,
} from '../../utils/index.js'
import { bootloaderFormalAddress } from '../constants/address.js'
import {
CannotClaimSuccessfulDepositError,
type CannotClaimSuccessfulDepositErrorType,
L2BridgeNotFoundError,
type L2BridgeNotFoundErrorType,
LogProofNotFoundError,
type LogProofNotFoundErrorType,
} from '../errors/bridge.js'
import type { ChainEIP712 } from '../types/chain.js'
import type { BridgeContractAddresses } from '../types/contract.js'
import type { ZksyncTransactionReceipt } from '../types/transaction.js'
import { undoL1ToL2Alias } from '../utils/bridge/undoL1ToL2Alias.js'
import { getDefaultBridgeAddresses } from './getDefaultBridgeAddresses.js'
import { getLogProof } from './getLogProof.js'
export type ClaimFailedDepositParameters<
chain extends Chain | undefined = Chain | undefined,
account extends Account | undefined = Account | undefined,
chainOverride extends Chain | undefined = Chain | undefined,
chainL2 extends ChainEIP712 | undefined = ChainEIP712 | undefined,
accountL2 extends Account | undefined = Account | undefined,
_derivedChain extends Chain | undefined = DeriveChain<chain, chainOverride>,
> = UnionEvaluate<
UnionOmit<FormattedTransactionRequest<_derivedChain>, 'data' | 'to' | 'from'>
> &
Partial<GetChainParameter<chain, chainOverride>> &
Partial<GetAccountParameter<account>> & {
/** L2 client. */
client: Client<Transport, chainL2, accountL2>
/** The L2 transaction hash of the failed deposit. */
depositHash: Hash
}
export type ClaimFailedDepositReturnType = SendTransactionReturnType
export type ClaimFailedDepositErrorType =
| SendTransactionErrorType
| TransactionReceiptNotFoundErrorType
| CannotClaimSuccessfulDepositErrorType
| LogProofNotFoundErrorType
| L2BridgeNotFoundErrorType
/**
* Withdraws funds from the initiated deposit, which failed when finalizing on L2.
* If the deposit L2 transaction has failed, it sends an L1 transaction calling `claimFailedDeposit` method of the
* L1 bridge, which results in returning L1 tokens back to the depositor.
*
* @param client - Client to use
* @param parameters - {@link ClaimFailedDepositParameters}
* @returns hash - The [Transaction](https://viem.sh/docs/glossary/terms#transaction) hash. {@link ClaimFailedDepositReturnType}
*
* @example
* import { createPublicClient, http } from 'viem'
* import { privateKeyToAccount } from 'viem/accounts'
* import { zksync, mainnet } from 'viem/chains'
* import { claimFailedDeposit, publicActionsL2 } from 'viem/zksync'
*
* const client = createPublicClient({
* chain: mainnet,
* transport: http(),
* })
*
* const clientL2 = createPublicClient({
* chain: zksync,
* transport: http(),
* }).extend(publicActionsL2())
*
* const account = privateKeyToAccount('0x…')
*
* const hash = await claimFailedDeposit(client, {
* client: clientL2,
* account,
* depositHash: <L2_HASH_OF_FAILED_DEPOSIT>,
* })
*
* @example Account Hoisting
* import { createPublicClient, createWalletClient, http } from 'viem'
* import { privateKeyToAccount } from 'viem/accounts'
* import { zksync, mainnet } from 'viem/chains'
* import { publicActionsL2 } from 'viem/zksync'
*
* const walletClient = createWalletClient({
* chain: mainnet,
* transport: http(),
* account: privateKeyToAccount('0x…'),
* })
*
* const clientL2 = createPublicClient({
* chain: zksync,
* transport: http(),
* }).extend(publicActionsL2())
*
* const hash = await claimFailedDeposit(walletClient, {
* client: clientL2,
* depositHash: <L2_HASH_OF_FAILED_DEPOSIT>,
* })
*/
export async function claimFailedDeposit<
chain extends Chain | undefined,
account extends Account | undefined,
chainOverride extends Chain | undefined = Chain | undefined,
chainL2 extends ChainEIP712 | undefined = ChainEIP712 | undefined,
accountL2 extends Account | undefined = Account | undefined,
_derivedChain extends Chain | undefined = DeriveChain<chain, chainOverride>,
>(
client: Client<Transport, chain, account>,
parameters: ClaimFailedDepositParameters<
chain,
account,
chainOverride,
chainL2,
accountL2
>,
): Promise<ClaimFailedDepositReturnType> {
const {
account: account_ = client.account,
chain: chain_ = client.chain,
client: l2Client,
depositHash,
...rest
} = parameters
const account = account_ ? parseAccount(account_) : client.account
if (!account)
throw new AccountNotFoundError({
docsPath: '/docs/actions/wallet/sendTransaction',
})
if (!l2Client.chain) throw new ClientChainNotConfiguredError()
const receipt = <ZksyncTransactionReceipt>(
await getTransactionReceipt(l2Client, { hash: depositHash })
)
const successL2ToL1LogIndex = receipt.l2ToL1Logs.findIndex(
(l2ToL1log) =>
isAddressEqual(<Hex>l2ToL1log.sender, bootloaderFormalAddress) &&
l2ToL1log.key === depositHash,
)
const successL2ToL1Log = receipt.l2ToL1Logs[successL2ToL1LogIndex]
if (successL2ToL1Log?.value !== zeroHash)
throw new CannotClaimSuccessfulDepositError({ hash: depositHash })
const tx = await getTransaction(l2Client, { hash: depositHash })
// Undo the aliasing, since the Mailbox contract set it as for contract address.
const l1BridgeAddress = undoL1ToL2Alias(receipt.from)
const l2BridgeAddress = receipt.to
if (!l2BridgeAddress) throw new L2BridgeNotFoundError()
const l1NativeTokenVault = (await getBridgeAddresses(client, l2Client))
.l1NativeTokenVault
let depositSender: Hex
let assetId: Hex
let assetData: Hex
try {
const { args } = decodeFunctionData({
abi: parseAbi([
'function finalizeDeposit(address _l1Sender, address _l2Receiver, address _l1Token, uint256 _amount, bytes _data)',
]),
data: tx.input,
})
assetData = encodeAbiParameters(
[{ type: 'uint256' }, { type: 'address' }, { type: 'address' }],
[args[3], args[1], args[2]],
)
assetId = await readContract(client, {
address: l1NativeTokenVault,
abi: parseAbi(['function assetId(address token) view returns (bytes32)']),
functionName: 'assetId',
args: [args[2]],
})
depositSender = args[0]
if (assetId === zeroHash)
throw new Error(`Token ${args[2]} not registered in NTV`)
} catch (_e) {
const { args } = decodeFunctionData({
abi: parseAbi([
'function finalizeDeposit(uint256 _chainId, bytes32 _assetId, bytes _transferData)',
]),
data: tx.input,
})
assetId = args[1]
const transferData = args[2]
const l1TokenAddress = await readContract(client, {
address: l1NativeTokenVault,
abi: parseAbi([
'function tokenAddress(bytes32 assetId) view returns (address)',
]),
functionName: 'tokenAddress',
args: [assetId],
})
const transferDataDecoded = decodeAbiParameters(
[
{ type: 'address' },
{ type: 'address' },
{ type: 'address' },
{ type: 'uint256' },
{ type: 'bytes' },
],
transferData,
)
assetData = encodeAbiParameters(
[{ type: 'uint256' }, { type: 'address' }, { type: 'address' }],
[transferDataDecoded[3], transferDataDecoded[1], l1TokenAddress],
)
depositSender = transferDataDecoded[0]
}
const proof = await getLogProof(l2Client, {
txHash: depositHash,
index: successL2ToL1LogIndex,
})
if (!proof)
throw new LogProofNotFoundError({
hash: depositHash,
index: successL2ToL1LogIndex,
})
const data = encodeFunctionData({
abi: parseAbi([
'function bridgeRecoverFailedTransfer(uint256 _chainId, address _depositSender, bytes32 _assetId, bytes _assetData, bytes32 _l2TxHash, uint256 _l2BatchNumber, uint256 _l2MessageIndex, uint16 _l2TxNumberInBatch, bytes32[] _merkleProof)',
]),
functionName: 'bridgeRecoverFailedTransfer',
args: [
BigInt(l2Client.chain.id),
depositSender,
assetId,
assetData,
depositHash,
receipt.l1BatchNumber!,
BigInt(proof.id),
Number(receipt.l1BatchTxIndex),
proof.proof,
],
})
return await sendTransaction(client, {
chain: chain_,
account,
to: l1BridgeAddress,
data,
...rest,
} as SendTransactionParameters)
}
async function getBridgeAddresses<
chain extends Chain | undefined,
chainL2 extends ChainEIP712 | undefined,
>(
client: Client<Transport, chain>,
l2Client: Client<Transport, chainL2>,
): Promise<
BridgeContractAddresses & {
l1Nullifier: Address
l1NativeTokenVault: Address
}
> {
const addresses = await getDefaultBridgeAddresses(l2Client)
let l1Nullifier = addresses.l1Nullifier
let l1NativeTokenVault = addresses.l1NativeTokenVault
if (!l1Nullifier)
l1Nullifier = await readContract(client, {
address: addresses.sharedL1,
abi: parseAbi(['function L1_NULLIFIER() view returns (address)']),
functionName: 'L1_NULLIFIER',
args: [],
})
if (!l1NativeTokenVault)
l1NativeTokenVault = await readContract(client, {
address: addresses.sharedL1,
abi: parseAbi(['function nativeTokenVault() view returns (address)']),
functionName: 'nativeTokenVault',
args: [],
})
return {
...addresses,
l1Nullifier,
l1NativeTokenVault,
}
}

112
node_modules/viem/zksync/actions/deployContract.ts generated vendored Normal file
View File

@@ -0,0 +1,112 @@
import type { Abi } from 'abitype'
import type { Account } from '../../accounts/types.js'
import type { DeployContractParameters as DeployContractParameters_ } from '../../actions/wallet/deployContract.js'
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import type { ErrorType } from '../../errors/utils.js'
import type { ContractConstructorArgs } from '../../types/contract.js'
import type { Hash, Hex } from '../../types/misc.js'
import {
contract2FactoryAddress,
contractDeployerAddress,
} from '../constants/address.js'
import type { ChainEIP712 } from '../types/chain.js'
import type { ContractDeploymentType } from '../types/contract.js'
import {
type EncodeDeployDataErrorType,
encodeDeployData,
} from '../utils/abi/encodeDeployData.js'
import {
type SendEip712TransactionErrorType,
type SendEip712TransactionParameters,
type SendEip712TransactionReturnType,
sendEip712Transaction,
} from './sendEip712Transaction.js'
export type DeployContractParameters<
abi extends Abi | readonly unknown[] = Abi,
chain extends ChainEIP712 | undefined = ChainEIP712 | undefined,
account extends Account | undefined = Account | undefined,
chainOverride extends ChainEIP712 | undefined = ChainEIP712 | undefined,
allArgs = ContractConstructorArgs<abi>,
> = DeployContractParameters_<abi, chain, account, chainOverride, allArgs> & {
deploymentType?: ContractDeploymentType | undefined
factoryDeps?: Hex[] | undefined
salt?: Hash | undefined
}
export type DeployContractReturnType = SendEip712TransactionReturnType
export type DeployContractErrorType =
| EncodeDeployDataErrorType
| SendEip712TransactionErrorType
| ErrorType
/**
* Deploys a contract to the network, given bytecode and constructor arguments using EIP712 transaction.
*
* - Docs: https://viem.sh/docs/contract/deployContract
*
* @param walletClient - Client to use
* @param parameters - {@link DeployContractParameters}
* @returns The [Transaction](https://viem.sh/docs/glossary/terms#transaction) hash. {@link DeployContractReturnType}
*
* @example
* import { createWalletClient, custom } from 'viem'
* import { privateKeyToAccount } from 'viem/accounts'
* import { zksync } from 'viem/chains'
* import { deployContract } from 'viem/zksync'
*
* const client = createWalletClient({
* account: privateKeyToAccount('0x…'),
* chain: zksync,
* transport: custom(provider),
* })
* const hash = await deployContract(client, {
* abi: [],
* account: '0x…,
* deploymentType: 'create',
* bytecode: '0x608060405260405161083e38038061083e833981016040819052610...',
* factoryDeps: ['0x608060405260405161083e38038061083e833981016040819052610...'],
* gasPerPubdata: 50000n
* })
*/
export function deployContract<
const abi extends Abi | readonly unknown[],
chain extends ChainEIP712 | undefined,
account extends Account | undefined,
chainOverride extends ChainEIP712 | undefined,
>(
walletClient: Client<Transport, chain, account>,
parameters: DeployContractParameters<abi, chain, account, chainOverride>,
): Promise<DeployContractReturnType> {
const { abi, args, bytecode, deploymentType, salt, ...request } =
parameters as DeployContractParameters
const data = encodeDeployData({
abi,
args,
bytecode,
deploymentType,
salt,
})
// Add the bytecode to the factoryDeps if it's not already there
request.factoryDeps = request.factoryDeps || []
if (!request.factoryDeps.includes(bytecode))
request.factoryDeps.push(bytecode)
return sendEip712Transaction(walletClient, {
...request,
data,
to:
deploymentType === 'create2' || deploymentType === 'create2Account'
? contract2FactoryAddress
: contractDeployerAddress,
} as unknown as SendEip712TransactionParameters<
chain,
account,
chainOverride
>)
}

962
node_modules/viem/zksync/actions/deposit.ts generated vendored Normal file
View File

@@ -0,0 +1,962 @@
import { type Address, parseAbi } from 'abitype'
import type { Account } from '../../accounts/types.js'
import {
type EstimateGasParameters,
estimateGas,
} from '../../actions/public/estimateGas.js'
import { readContract } from '../../actions/public/readContract.js'
import { waitForTransactionReceipt } from '../../actions/public/waitForTransactionReceipt.js'
import {
type SendTransactionErrorType,
type SendTransactionParameters,
type SendTransactionReturnType,
sendTransaction,
} from '../../actions/wallet/sendTransaction.js'
import {
type WriteContractParameters,
writeContract,
} from '../../actions/wallet/writeContract.js'
import type { Client } from '../../clients/createClient.js'
import { publicActions } from '../../clients/decorators/public.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import { erc20Abi } from '../../constants/abis.js'
import { zeroAddress } from '../../constants/address.js'
import { zeroHash } from '../../constants/bytes.js'
import { AccountNotFoundError } from '../../errors/account.js'
import { ClientChainNotConfiguredError } from '../../errors/chain.js'
import type { GetAccountParameter } from '../../types/account.js'
import type {
Chain,
DeriveChain,
GetChainParameter,
} from '../../types/chain.js'
import type { Hex } from '../../types/misc.js'
import type { UnionEvaluate, UnionOmit } from '../../types/utils.js'
import {
concatHex,
encodeAbiParameters,
encodeFunctionData,
type FormattedTransactionRequest,
isAddressEqual,
keccak256,
parseAccount,
} from '../../utils/index.js'
import { bridgehubAbi } from '../constants/abis.js'
import {
ethAddressInContracts,
l2NativeTokenVaultAddress,
legacyEthAddress,
} from '../constants/address.js'
import { requiredL1ToL2GasPerPubdataLimit } from '../constants/number.js'
import {
BaseFeeHigherThanValueError,
type BaseFeeHigherThanValueErrorType,
} from '../errors/bridge.js'
import type { ChainEIP712 } from '../types/chain.js'
import type { BridgeContractAddresses } from '../types/contract.js'
import { applyL1ToL2Alias } from '../utils/bridge/applyL1ToL2Alias.js'
import { estimateGasL1ToL2 } from './estimateGasL1ToL2.js'
import { getBridgehubContractAddress } from './getBridgehubContractAddress.js'
import { getDefaultBridgeAddresses } from './getDefaultBridgeAddresses.js'
import { getL1Allowance } from './getL1Allowance.js'
export type DepositParameters<
chain extends Chain | undefined = Chain | undefined,
account extends Account | undefined = Account | undefined,
chainOverride extends Chain | undefined = Chain | undefined,
chainL2 extends ChainEIP712 | undefined = ChainEIP712 | undefined,
accountL2 extends Account | undefined = Account | undefined,
_derivedChain extends Chain | undefined = DeriveChain<chain, chainOverride>,
> = UnionEvaluate<
UnionOmit<FormattedTransactionRequest<_derivedChain>, 'data' | 'to' | 'from'>
> &
Partial<GetChainParameter<chain, chainOverride>> &
Partial<GetAccountParameter<account>> & {
/** L2 client. */
client: Client<Transport, chainL2, accountL2>
/** The address of the token to deposit. */
token: Address
/** The amount of the token to deposit. */
amount: bigint
/** The address that will receive the deposited tokens on L2.
Defaults to the sender address.*/
to?: Address | undefined
/** (currently not used) The tip the operator will receive on top of
the base cost of the transaction. */
operatorTip?: bigint | undefined
/** Maximum amount of L2 gas that transaction can consume during execution on L2. */
l2GasLimit?: bigint | undefined
/** The L2 gas price for each published L1 calldata byte. */
gasPerPubdataByte?: bigint | undefined
/** The address on L2 that will receive the refund for the transaction.
If the transaction fails, it will also be the address to receive `amount`. */
refundRecipient?: Address | undefined
/** The address of the bridge contract to be used.
Defaults to the default ZKsync L1 shared bridge. */
bridgeAddress?: Address | undefined
/** Additional data that can be sent to a bridge. */
customBridgeData?: Hex | undefined
/** Whether token approval should be performed under the hood.
Set this flag to true (or provide transaction overrides) if the bridge does
not have sufficient allowance. The approval transaction is executed only if
the bridge lacks sufficient allowance; otherwise, it is skipped. */
approveToken?:
| boolean
| UnionEvaluate<
UnionOmit<
FormattedTransactionRequest<_derivedChain>,
'data' | 'to' | 'from'
>
>
| undefined
/** Whether base token approval should be performed under the hood.
Set this flag to true (or provide transaction overrides) if the bridge does
not have sufficient allowance. The approval transaction is executed only if
the bridge lacks sufficient allowance; otherwise, it is skipped. */
approveBaseToken?:
| boolean
| UnionEvaluate<
UnionOmit<
FormattedTransactionRequest<_derivedChain>,
'data' | 'to' | 'from'
>
>
| undefined
}
export type DepositReturnType = SendTransactionReturnType
export type DepositErrorType =
| SendTransactionErrorType
| BaseFeeHigherThanValueErrorType
/**
* Transfers the specified token from the associated account on the L1 network to the target account on the L2 network.
* The token can be either ETH or any ERC20 token. For ERC20 tokens, enough approved tokens must be associated with
* the specified L1 bridge (default one or the one defined in `bridgeAddress`).
* In this case, depending on is the chain ETH-based or not `approveToken` or `approveBaseToken`
* can be enabled to perform token approval. If there are already enough approved tokens for the L1 bridge,
* token approval will be skipped.
*
* @param client - Client to use
* @param parameters - {@link DepositParameters}
* @returns hash - The [Transaction](https://viem.sh/docs/glossary/terms#transaction) hash. {@link DepositReturnType}
*
* @example
* import { createPublicClient, http } from 'viem'
* import { privateKeyToAccount } from 'viem/accounts'
* import { zksync, mainnet } from 'viem/chains'
* import { deposit, legacyEthAddress, publicActionsL2 } from 'viem/zksync'
*
* const client = createPublicClient({
* chain: mainnet,
* transport: http(),
* })
*
* const clientL2 = createPublicClient({
* chain: zksync,
* transport: http(),
* }).extend(publicActionsL2())
*
* const account = privateKeyToAccount('0x…')
*
* const hash = await deposit(client, {
* client: clientL2,
* account,
* token: legacyEthAddress,
* to: account.address,
* amount: 1_000_000_000_000_000_000n,
* refundRecipient: account.address,
* })
*
* @example Account Hoisting
* import { createPublicClient, createWalletClient, http } from 'viem'
* import { privateKeyToAccount } from 'viem/accounts'
* import { zksync, mainnet } from 'viem/chains'
* import { legacyEthAddress, publicActionsL2 } from 'viem/zksync'
*
* const walletClient = createWalletClient({
* chain: mainnet,
* transport: http(),
* account: privateKeyToAccount('0x…'),
* })
*
* const clientL2 = createPublicClient({
* chain: zksync,
* transport: http(),
* }).extend(publicActionsL2())
*
* const hash = await deposit(walletClient, {
* client: clientL2,
* token: legacyEthAddress,
* to: walletClient.account.address,
* amount: 1_000_000_000_000_000_000n,
* refundRecipient: walletClient.account.address,
* })
*/
export async function deposit<
chain extends Chain | undefined,
account extends Account | undefined,
chainOverride extends Chain | undefined = Chain | undefined,
chainL2 extends ChainEIP712 | undefined = ChainEIP712 | undefined,
accountL2 extends Account | undefined = Account | undefined,
_derivedChain extends Chain | undefined = DeriveChain<chain, chainOverride>,
>(
client: Client<Transport, chain, account>,
parameters: DepositParameters<
chain,
account,
chainOverride,
chainL2,
accountL2
>,
): Promise<DepositReturnType> {
let {
account: account_ = client.account,
chain: chain_ = client.chain,
client: l2Client,
token,
amount,
approveToken,
approveBaseToken,
gas,
} = parameters
const account = account_ ? parseAccount(account_) : client.account
if (!account)
throw new AccountNotFoundError({
docsPath: '/docs/actions/wallet/sendTransaction',
})
if (!l2Client.chain) throw new ClientChainNotConfiguredError()
if (isAddressEqual(token, legacyEthAddress)) token = ethAddressInContracts
const bridgeAddresses = await getBridgeAddresses(client, l2Client)
const bridgehub = await getBridgehubContractAddress(l2Client)
const baseToken = await readContract(client, {
address: bridgehub,
abi: bridgehubAbi,
functionName: 'baseToken',
args: [BigInt(l2Client.chain.id)],
})
const { mintValue, tx } = await getL1DepositTx(
client,
account,
{ ...parameters, token },
bridgeAddresses,
bridgehub,
baseToken,
)
await approveTokens(
client,
chain_,
tx.bridgeAddress,
baseToken,
mintValue,
account,
token,
amount,
approveToken,
approveBaseToken,
)
if (!gas) {
const baseGasLimit = await estimateGas(client, {
account: account.address,
to: bridgehub,
value: tx.value,
data: tx.data,
} as EstimateGasParameters)
gas = scaleGasLimit(baseGasLimit)
}
return await sendTransaction(client, {
chain: chain_,
account,
gas,
...tx,
} as SendTransactionParameters)
}
async function getL1DepositTx<
chain extends Chain | undefined,
account extends Account | undefined,
chainOverride extends Chain | undefined = Chain | undefined,
chainL2 extends ChainEIP712 | undefined = ChainEIP712 | undefined,
accountL2 extends Account | undefined = Account | undefined,
_derivedChain extends Chain | undefined = DeriveChain<chain, chainOverride>,
>(
client: Client<Transport, chain, account>,
account: Account,
parameters: DepositParameters<
chain,
account,
chainOverride,
chainL2,
accountL2,
_derivedChain
>,
bridgeAddresses: BridgeContractAddresses & {
l1Nullifier: Address
l1NativeTokenVault: Address
},
bridgehub: Address,
baseToken: Address,
) {
let {
account: _account,
chain: _chain,
client: l2Client,
token,
amount,
to,
operatorTip = 0n,
l2GasLimit,
gasPerPubdataByte = requiredL1ToL2GasPerPubdataLimit,
refundRecipient = zeroAddress,
bridgeAddress,
customBridgeData,
value,
gasPrice,
maxFeePerGas,
maxPriorityFeePerGas,
approveToken: _approveToken,
approveBaseToken: _approveBaseToken,
...rest
} = parameters
if (!l2Client.chain) throw new ClientChainNotConfiguredError()
to ??= account.address
let gasPriceForEstimation = maxFeePerGas || gasPrice
if (!gasPriceForEstimation) {
const estimatedFee = await getFeePrice(client)
gasPriceForEstimation = estimatedFee.maxFeePerGas
maxFeePerGas = estimatedFee.maxFeePerGas
maxPriorityFeePerGas ??= estimatedFee.maxPriorityFeePerGas
}
const { l2GasLimit_, baseCost } = await getL2BridgeTxFeeParams(
client,
l2Client,
bridgehub,
gasPriceForEstimation,
account.address,
token,
amount,
to,
gasPerPubdataByte,
baseToken,
l2GasLimit,
bridgeAddress,
customBridgeData,
)
l2GasLimit = l2GasLimit_
let mintValue: bigint
let data: Hex
const isETHBasedChain = isAddressEqual(baseToken, ethAddressInContracts)
if (
(isETHBasedChain && isAddressEqual(token, ethAddressInContracts)) || // ETH on ETH-based chain
isAddressEqual(token, baseToken) // base token on custom chain
) {
// Deposit base token
mintValue = baseCost + operatorTip + amount
let providedValue = isETHBasedChain ? value : mintValue
if (!providedValue || providedValue === 0n) providedValue = mintValue
if (baseCost > providedValue)
throw new BaseFeeHigherThanValueError(baseCost, providedValue)
value = isETHBasedChain ? providedValue : 0n
bridgeAddress = bridgeAddresses.sharedL1 // required for approval of base token on custom chain
data = encodeFunctionData({
abi: bridgehubAbi,
functionName: 'requestL2TransactionDirect',
args: [
{
chainId: BigInt(l2Client.chain.id),
mintValue: providedValue,
l2Contract: to,
l2Value: amount,
l2Calldata: '0x',
l2GasLimit,
l2GasPerPubdataByteLimit: gasPerPubdataByte,
factoryDeps: [],
refundRecipient,
},
],
})
} else if (isAddressEqual(baseToken, ethAddressInContracts)) {
// Deposit token on ETH-based chain
mintValue = baseCost + BigInt(operatorTip)
value = mintValue
if (baseCost > mintValue)
throw new BaseFeeHigherThanValueError(baseCost, mintValue)
bridgeAddress ??= bridgeAddresses.sharedL1
data = encodeFunctionData({
abi: bridgehubAbi,
functionName: 'requestL2TransactionTwoBridges',
args: [
{
chainId: BigInt(l2Client.chain.id),
mintValue,
l2Value: 0n,
l2GasLimit,
l2GasPerPubdataByteLimit: gasPerPubdataByte,
refundRecipient,
secondBridgeAddress: bridgeAddress,
secondBridgeValue: 0n,
secondBridgeCalldata: await getSecondBridgeCalldata(
client,
bridgeAddresses.l1NativeTokenVault,
token,
amount,
to,
),
},
],
})
} else if (isAddressEqual(token, ethAddressInContracts)) {
// Deposit ETH on custom chain
mintValue = baseCost + operatorTip
value = amount
if (baseCost > mintValue)
throw new BaseFeeHigherThanValueError(baseCost, mintValue)
bridgeAddress = bridgeAddresses.sharedL1
data = encodeFunctionData({
abi: bridgehubAbi,
functionName: 'requestL2TransactionTwoBridges',
args: [
{
chainId: BigInt(l2Client.chain.id),
mintValue,
l2Value: 0n,
l2GasLimit,
l2GasPerPubdataByteLimit: gasPerPubdataByte,
refundRecipient,
secondBridgeAddress: bridgeAddress,
secondBridgeValue: amount,
secondBridgeCalldata: await getSecondBridgeCalldata(
client,
bridgeAddresses.l1NativeTokenVault,
ethAddressInContracts,
amount,
to,
),
},
],
})
} else {
// Deposit token on custom chain
mintValue = baseCost + operatorTip
value ??= 0n
if (baseCost > mintValue)
throw new BaseFeeHigherThanValueError(baseCost, mintValue)
bridgeAddress ??= bridgeAddresses.sharedL1
data = encodeFunctionData({
abi: bridgehubAbi,
functionName: 'requestL2TransactionTwoBridges',
args: [
{
chainId: BigInt(l2Client.chain.id),
mintValue,
l2Value: 0n,
l2GasLimit,
l2GasPerPubdataByteLimit: gasPerPubdataByte,
refundRecipient,
secondBridgeAddress: bridgeAddress,
secondBridgeValue: 0n,
secondBridgeCalldata: await getSecondBridgeCalldata(
client,
bridgeAddresses.l1NativeTokenVault,
token,
amount,
to,
),
},
],
})
}
return {
mintValue,
tx: {
bridgeAddress,
to: bridgehub,
data,
value,
gasPrice,
maxFeePerGas,
maxPriorityFeePerGas,
...rest,
},
}
}
async function approveTokens<
chain extends Chain | undefined,
chainOverride extends Chain | undefined = Chain | undefined,
_derivedChain extends Chain | undefined = DeriveChain<chain, chainOverride>,
>(
client: Client<Transport, chain>,
chain: Chain | null | undefined,
bridgeAddress: Address,
baseToken: Address,
mintValue: bigint,
account: Account,
token: Address,
amount: bigint,
approveToken?:
| boolean
| UnionEvaluate<
UnionOmit<
FormattedTransactionRequest<_derivedChain>,
'data' | 'to' | 'from'
>
>
| undefined,
approveBaseToken?:
| boolean
| UnionEvaluate<
UnionOmit<
FormattedTransactionRequest<_derivedChain>,
'data' | 'to' | 'from'
>
>
| undefined,
) {
if (isAddressEqual(baseToken, ethAddressInContracts)) {
// Deposit token on ETH-based chain
if (approveToken) {
const overrides = typeof approveToken === 'boolean' ? {} : approveToken
const allowance = await getL1Allowance(client, {
token,
bridgeAddress,
account,
})
if (allowance < amount) {
const hash = await writeContract(client, {
chain,
account,
address: token,
abi: erc20Abi,
functionName: 'approve',
args: [bridgeAddress, amount],
...overrides,
} satisfies WriteContractParameters as any)
await waitForTransactionReceipt(client, { hash })
}
}
return
}
if (isAddressEqual(token, ethAddressInContracts)) {
// Deposit ETH on custom chain
if (approveBaseToken) {
const overrides = typeof approveToken === 'boolean' ? {} : approveToken
const allowance = await getL1Allowance(client, {
token: baseToken,
bridgeAddress,
account,
})
if (allowance < mintValue) {
const hash = await writeContract(client, {
chain,
account,
address: baseToken,
abi: erc20Abi,
functionName: 'approve',
args: [bridgeAddress, mintValue],
...overrides,
} satisfies WriteContractParameters as any)
await waitForTransactionReceipt(client, { hash })
}
return
}
}
if (isAddressEqual(token, baseToken)) {
// Deposit base token on custom chain
if (approveToken || approveBaseToken) {
const overrides =
typeof approveToken === 'boolean'
? {}
: (approveToken ?? typeof approveBaseToken === 'boolean')
? {}
: approveBaseToken
const allowance = await getL1Allowance(client, {
token: baseToken,
bridgeAddress,
account,
})
if (allowance < mintValue) {
const hash = await writeContract(client, {
chain,
account,
address: baseToken,
abi: erc20Abi,
functionName: 'approve',
args: [bridgeAddress, mintValue],
...overrides,
} satisfies WriteContractParameters as any)
await waitForTransactionReceipt(client, { hash })
}
}
return
}
// Deposit token on custom chain
if (approveBaseToken) {
const overrides = typeof approveToken === 'boolean' ? {} : approveToken
const allowance = await getL1Allowance(client, {
token: baseToken,
bridgeAddress,
account,
})
if (allowance < mintValue) {
const hash = await writeContract(client, {
chain,
account,
address: baseToken,
abi: erc20Abi,
functionName: 'approve',
args: [bridgeAddress, mintValue],
...overrides,
} satisfies WriteContractParameters as any)
await waitForTransactionReceipt(client, { hash })
}
}
if (approveToken) {
const overrides = typeof approveToken === 'boolean' ? {} : approveToken
const allowance = await getL1Allowance(client, {
token,
bridgeAddress,
account,
})
if (allowance < amount) {
const hash = await writeContract(client, {
chain,
account,
address: token,
abi: erc20Abi,
functionName: 'approve',
args: [bridgeAddress, amount],
...overrides,
} satisfies WriteContractParameters as any)
await waitForTransactionReceipt(client, { hash })
}
}
}
async function getL2BridgeTxFeeParams<
chain extends Chain | undefined,
chainL2 extends ChainEIP712 | undefined,
>(
client: Client<Transport, chain>,
l2Client: Client<Transport, chainL2>,
bridgehub: Address,
gasPrice: bigint,
from: Address,
token: Address,
amount: bigint,
to: Address,
gasPerPubdataByte: bigint,
baseToken: Address,
l2GasLimit?: bigint | undefined,
bridgeAddress?: Address | undefined,
customBridgeData?: Hex | undefined,
) {
if (!l2Client.chain) throw new ClientChainNotConfiguredError()
let l2GasLimit_ = l2GasLimit
if (!l2GasLimit_)
l2GasLimit_ = bridgeAddress
? await getL2GasLimitFromCustomBridge(
client,
l2Client,
from,
token,
amount,
to,
gasPerPubdataByte,
bridgeAddress,
customBridgeData,
)
: await getL2GasLimitFromDefaultBridge(
client,
l2Client,
from,
token,
amount,
to,
gasPerPubdataByte,
baseToken,
)
const baseCost = await readContract(client, {
address: bridgehub,
abi: bridgehubAbi,
functionName: 'l2TransactionBaseCost',
args: [BigInt(l2Client.chain.id), gasPrice, l2GasLimit_, gasPerPubdataByte],
})
return { l2GasLimit_, baseCost }
}
async function getL2GasLimitFromDefaultBridge<
chain extends Chain | undefined,
chainL2 extends ChainEIP712 | undefined,
>(
client: Client<Transport, chain>,
l2Client: Client<Transport, chainL2>,
from: Address,
token: Address,
amount: bigint,
to: Address,
gasPerPubdataByte: bigint,
baseToken: Address,
) {
if (isAddressEqual(token, baseToken)) {
return await estimateGasL1ToL2(l2Client, {
chain: l2Client.chain,
account: from,
from,
to,
value: amount,
data: '0x',
gasPerPubdata: gasPerPubdataByte,
})
}
const value = 0n
const bridgeAddresses = await getDefaultBridgeAddresses(l2Client)
const l1BridgeAddress = bridgeAddresses.sharedL1
const l2BridgeAddress = bridgeAddresses.sharedL2
const bridgeData = await encodeDefaultBridgeData(client, token)
const calldata = encodeFunctionData({
abi: parseAbi([
'function finalizeDeposit(address _l1Sender, address _l2Receiver, address _l1Token, uint256 _amount, bytes _data)',
]),
functionName: 'finalizeDeposit',
args: [
from,
to,
isAddressEqual(token, legacyEthAddress) ? ethAddressInContracts : token,
amount,
bridgeData,
],
})
return await estimateGasL1ToL2(l2Client, {
chain: l2Client.chain,
account: applyL1ToL2Alias(l1BridgeAddress),
to: l2BridgeAddress,
data: calldata,
gasPerPubdata: gasPerPubdataByte,
value,
})
}
async function getL2GasLimitFromCustomBridge<
chain extends Chain | undefined,
chainL2 extends ChainEIP712 | undefined,
>(
client: Client<Transport, chain>,
l2Client: Client<Transport, chainL2>,
from: Address,
token: Address,
amount: bigint,
to: Address,
gasPerPubdataByte: bigint,
bridgeAddress: Address,
customBridgeData?: Hex,
) {
let customBridgeData_ = customBridgeData
if (!customBridgeData_ || customBridgeData_ === '0x')
customBridgeData_ = await encodeDefaultBridgeData(client, token)
const l2BridgeAddress = await readContract(client, {
address: token,
abi: parseAbi([
'function l2BridgeAddress(uint256 _chainId) view returns (address)',
]),
functionName: 'l2BridgeAddress',
args: [BigInt(l2Client.chain!.id)],
})
const calldata = encodeFunctionData({
abi: parseAbi([
'function finalizeDeposit(address _l1Sender, address _l2Receiver, address _l1Token, uint256 _amount, bytes _data)',
]),
functionName: 'finalizeDeposit',
args: [from, to, token, amount, customBridgeData_],
})
return await estimateGasL1ToL2(l2Client, {
chain: l2Client.chain,
account: from,
from: applyL1ToL2Alias(bridgeAddress),
to: l2BridgeAddress,
data: calldata,
gasPerPubdata: gasPerPubdataByte,
})
}
async function encodeDefaultBridgeData<chain extends Chain | undefined>(
client: Client<Transport, chain>,
token: Address,
) {
let token_ = token
if (isAddressEqual(token, legacyEthAddress)) token_ = ethAddressInContracts
let name = 'Ether'
let symbol = 'ETH'
let decimals = 18n
if (!isAddressEqual(token_, ethAddressInContracts)) {
name = await readContract(client, {
address: token_,
abi: erc20Abi,
functionName: 'name',
args: [],
})
symbol = await readContract(client, {
address: token_,
abi: erc20Abi,
functionName: 'symbol',
args: [],
})
decimals = BigInt(
await readContract(client, {
address: token_,
abi: erc20Abi,
functionName: 'decimals',
args: [],
}),
)
}
const nameBytes = encodeAbiParameters([{ type: 'string' }], [name])
const symbolBytes = encodeAbiParameters([{ type: 'string' }], [symbol])
const decimalsBytes = encodeAbiParameters([{ type: 'uint256' }], [decimals])
return encodeAbiParameters(
[{ type: 'bytes' }, { type: 'bytes' }, { type: 'bytes' }],
[nameBytes, symbolBytes, decimalsBytes],
)
}
async function getSecondBridgeCalldata<chain extends Chain | undefined>(
client: Client<Transport, chain>,
l1NativeTokenVault: Address,
token: Address,
amount: bigint,
to: Address,
): Promise<Hex> {
let assetId: Hex
let token_ = token
if (isAddressEqual(token, legacyEthAddress)) token_ = ethAddressInContracts
const assetIdFromNTV = await readContract(client, {
address: l1NativeTokenVault,
abi: parseAbi(['function assetId(address token) view returns (bytes32)']),
functionName: 'assetId',
args: [token_],
})
if (assetIdFromNTV && assetIdFromNTV !== zeroHash) assetId = assetIdFromNTV
else {
// Okay, the token have not been registered within the Native token vault.
// There are two cases when it is possible:
// - The token is native to L1 (it may or may not be bridged), but it has not been
// registered within NTV after the Gateway upgrade. We assume that this is not the case
// as the SDK is expected to work only after the full migration is done.
// - The token is native to the current chain and it has never been bridged.
if (!client.chain) throw new ClientChainNotConfiguredError()
assetId = keccak256(
encodeAbiParameters(
[{ type: 'uint256' }, { type: 'address' }, { type: 'address' }],
[BigInt(client.chain.id), l2NativeTokenVaultAddress, token_],
),
)
}
const ntvData = encodeAbiParameters(
[{ type: 'uint256' }, { type: 'address' }, { type: 'address' }],
[BigInt(amount), to, token_],
)
const data = encodeAbiParameters(
[{ type: 'bytes32' }, { type: 'bytes' }],
[assetId, ntvData],
)
return concatHex(['0x01', data])
}
async function getBridgeAddresses<
chain extends Chain | undefined,
chainL2 extends ChainEIP712 | undefined,
>(
client: Client<Transport, chain>,
l2Client: Client<Transport, chainL2>,
): Promise<
BridgeContractAddresses & {
l1Nullifier: Address
l1NativeTokenVault: Address
}
> {
const addresses = await getDefaultBridgeAddresses(l2Client)
let l1Nullifier = addresses.l1Nullifier
let l1NativeTokenVault = addresses.l1NativeTokenVault
if (!l1Nullifier)
l1Nullifier = await readContract(client, {
address: addresses.sharedL1,
abi: parseAbi(['function L1_NULLIFIER() view returns (address)']),
functionName: 'L1_NULLIFIER',
args: [],
})
if (!l1NativeTokenVault)
l1NativeTokenVault = await readContract(client, {
address: addresses.sharedL1,
abi: parseAbi(['function nativeTokenVault() view returns (address)']),
functionName: 'nativeTokenVault',
args: [],
})
return {
...addresses,
l1Nullifier,
l1NativeTokenVault,
}
}
function scaleGasLimit(gasLimit: bigint): bigint {
return (gasLimit * BigInt(12)) / BigInt(10)
}
async function getFeePrice<chain extends Chain | undefined>(
client: Client<Transport, chain>,
) {
const client_ = client.extend(publicActions)
const block = await client_.getBlock()
const baseFee =
typeof block.baseFeePerGas !== 'bigint'
? await client_.getGasPrice()
: block.baseFeePerGas
const maxPriorityFeePerGas = await client_.estimateMaxPriorityFeePerGas()
return {
maxFeePerGas: (baseFee * 3n) / 2n + maxPriorityFeePerGas,
maxPriorityFeePerGas: maxPriorityFeePerGas,
}
}

49
node_modules/viem/zksync/actions/estimateFee.ts generated vendored Normal file
View File

@@ -0,0 +1,49 @@
import { parseAccount } from '../../accounts/utils/parseAccount.js'
import type { SendTransactionParameters } from '../../actions/wallet/sendTransaction.js'
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import type { Account } from '../../types/account.js'
import { hexToBigInt } from '../../utils/encoding/fromHex.js'
import type { ChainEIP712 } from '../types/chain.js'
import type { PublicZksyncRpcSchema } from '../types/eip1193.js'
import type { ZksyncFee } from '../types/fee.js'
export type EstimateFeeParameters<
chain extends ChainEIP712 | undefined = ChainEIP712 | undefined,
account extends Account | undefined = Account | undefined,
chainOverride extends ChainEIP712 | undefined = ChainEIP712 | undefined,
> = SendTransactionParameters<chain, account, chainOverride>
export type EstimateFeeReturnType = ZksyncFee
/* @deprecated Use `eth_gasPrice` for `maxFeePerGas`, `eth_estimateGas` to get the `gasLimit`, set `maxPriorityFeePerGas` to `0`, and use `zks_gasPerPubdata` for `gasPerPubdataLimit` instead. */
export async function estimateFee<
chain extends ChainEIP712 | undefined,
account extends Account | undefined,
>(
client: Client<Transport, chain, account, PublicZksyncRpcSchema>,
parameters: EstimateFeeParameters<chain, account>,
): Promise<EstimateFeeReturnType> {
const { account: account_, ...request } = parameters
const account = account_ ? parseAccount(account_) : client.account
const formatters = client.chain?.formatters
const formatted = formatters?.transactionRequest?.format(
{
...request,
from: account?.address,
},
'estimateFee',
)
const result = await client.request({
method: 'zks_estimateFee',
params: [formatted],
})
return {
gasLimit: hexToBigInt(result.gas_limit),
gasPerPubdataLimit: hexToBigInt(result.gas_per_pubdata_limit),
maxPriorityFeePerGas: hexToBigInt(result.max_priority_fee_per_gas),
maxFeePerGas: hexToBigInt(result.max_fee_per_gas),
}
}

41
node_modules/viem/zksync/actions/estimateGasL1ToL2.ts generated vendored Normal file
View File

@@ -0,0 +1,41 @@
import { parseAccount } from '../../accounts/utils/parseAccount.js'
import type { SendTransactionParameters } from '../../actions/wallet/sendTransaction.js'
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import type { Account } from '../../types/account.js'
import type { ChainEIP712 } from '../types/chain.js'
import type { PublicZksyncRpcSchema } from '../types/eip1193.js'
export type EstimateGasL1ToL2Parameters<
chain extends ChainEIP712 | undefined = ChainEIP712 | undefined,
account extends Account | undefined = Account | undefined,
> = SendTransactionParameters<chain, account>
export type EstimateGasL1ToL2ReturnType = bigint
export async function estimateGasL1ToL2<
chain extends ChainEIP712 | undefined,
account extends Account | undefined,
>(
client: Client<Transport, chain, account, PublicZksyncRpcSchema>,
parameters: EstimateGasL1ToL2Parameters<chain, account>,
): Promise<EstimateGasL1ToL2ReturnType> {
const { account: account_, ...request } = parameters
const account = account_ ? parseAccount(account_) : client.account
const formatters = client.chain?.formatters
const formatted = formatters?.transactionRequest?.format(
{
...request,
from: account?.address,
},
'estimateGasL1ToL2',
)
const result = await client.request({
method: 'zks_estimateGasL1ToL2',
params: [formatted],
})
return result
}

250
node_modules/viem/zksync/actions/finalizeWithdrawal.ts generated vendored Normal file
View File

@@ -0,0 +1,250 @@
import { type Address, parseAbi } from 'abitype'
import type { Account } from '../../accounts/types.js'
import { readContract } from '../../actions/public/readContract.js'
import {
type SendTransactionErrorType,
type SendTransactionParameters,
type SendTransactionRequest,
type SendTransactionReturnType,
sendTransaction,
} from '../../actions/wallet/sendTransaction.js'
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import { AccountNotFoundError } from '../../errors/account.js'
import {
ChainNotFoundError,
type ChainNotFoundErrorType,
} from '../../errors/chain.js'
import type { Chain } from '../../types/chain.js'
import type { Hex } from '../../types/misc.js'
import {
decodeAbiParameters,
encodeFunctionData,
parseAccount,
slice,
} from '../../utils/index.js'
import {
WithdrawalLogNotFoundError,
type WithdrawalLogNotFoundErrorType,
} from '../errors/bridge.js'
import type { ChainEIP712 } from '../types/chain.js'
import type { BridgeContractAddresses } from '../types/contract.js'
import { getWithdrawalL2ToL1Log } from '../utils/bridge/getWithdrawalL2ToL1Log.js'
import { getWithdrawalLog } from '../utils/bridge/getWithdrawalLog.js'
import { getDefaultBridgeAddresses } from './getDefaultBridgeAddresses.js'
import { getLogProof } from './getLogProof.js'
export type FinalizeWithdrawalParameters<
chain extends Chain | undefined = Chain | undefined,
account extends Account | undefined = Account | undefined,
chainOverride extends Chain | undefined = Chain | undefined,
chainL2 extends ChainEIP712 | undefined = ChainEIP712 | undefined,
accountL2 extends Account | undefined = Account | undefined,
request extends SendTransactionRequest<
chain,
chainOverride
> = SendTransactionRequest<chain, chainOverride>,
> = Omit<
SendTransactionParameters<chain, account, chainOverride, request>,
'value' | 'data' | 'to'
> & {
/** L2 client */
client: Client<Transport, chainL2, accountL2>
/** Hash of the L2 transaction where the withdrawal was initiated. */
hash: Hex
/** 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 FinalizeWithdrawalReturnType = SendTransactionReturnType
export type FinalizeWithdrawalErrorType =
| SendTransactionErrorType
| WithdrawalLogNotFoundErrorType
| ChainNotFoundErrorType
/**
* Proves the inclusion of the `L2->L1` withdrawal message.
*
* @param client - Client to use
* @param parameters - {@link FinalizeWithdrawalParameters}
* @returns hash - The [Transaction](https://viem.sh/docs/glossary/terms#transaction) hash. {@link FinalizeWithdrawalReturnType}
*
* @example
* import { createPublicClient, http } from 'viem'
* import { privateKeyToAccount } from 'viem/accounts'
* import { mainnet, zksync } from 'viem/chains'
* import { finalizeWithdrawal, publicActionsL2 } from 'viem/zksync'
*
* const client = createPublicClient({
* chain: mainnet,
* transport: http(),
* })
*
* const clientL2 = createPublicClient({
* chain: zksync,
* transport: http(),
* }).extend(publicActionsL2())
*
* const hash = await finalizeWithdrawal(client, {
* account: privateKeyToAccount('0x…'),
* client: clientL2,
* hash: '0x...',
* })
*
* @example Account Hoisting
* import { createPublicClient, createWalletClient, http } from 'viem'
* import { privateKeyToAccount } from 'viem/accounts'
* import { mainnet, zksync } from 'viem/chains'
* import { finalizeWithdrawal, publicActionsL2 } from 'viem/zksync'
*
* const client = createWalletClient({
* account: privateKeyToAccount('0x…'),
* chain: mainnet,
* transport: http(),
* })
*
* const clientL2 = createPublicClient({
* chain: zksync,
* transport: http(),
* }).extend(publicActionsL2())
*
* const hash = await finalizeWithdrawal(client, {
* client: clientL2,
* hash: '0x…',
* })
*/
export async function finalizeWithdrawal<
chain extends Chain | undefined,
account extends Account | undefined,
accountL2 extends Account | undefined,
const request extends SendTransactionRequest<chain, chainOverride>,
chainOverride extends Chain | undefined,
chainL2 extends ChainEIP712 | undefined,
>(
client: Client<Transport, chain, account>,
parameters: FinalizeWithdrawalParameters<
chain,
account,
chainOverride,
chainL2,
accountL2,
request
>,
): Promise<FinalizeWithdrawalReturnType> {
const {
account: account_ = client.account,
client: l2Client,
hash,
index = 0,
...rest
} = parameters
const account = account_ ? parseAccount(account_) : client.account
if (!account)
throw new AccountNotFoundError({
docsPath: '/docs/actions/wallet/sendTransaction',
})
if (!l2Client.chain) throw new ChainNotFoundError()
const finalizeWithdrawalParams = await getFinalizeWithdrawalParams(l2Client, {
hash,
index,
})
const l1Nullifier = (await getBridgeAddresses(client, l2Client)).l1Nullifier
const data = encodeFunctionData({
abi: parseAbi([
'function finalizeDeposit((uint256 chainId, uint256 l2BatchNumber, uint256 l2MessageIndex, address l2Sender, uint16 l2TxNumberInBatch, bytes message, bytes32[] merkleProof) _finalizeWithdrawalParams)',
]),
functionName: 'finalizeDeposit',
args: [
{
chainId: BigInt(l2Client.chain.id),
l2BatchNumber: finalizeWithdrawalParams.l1BatchNumber!,
l2MessageIndex: BigInt(finalizeWithdrawalParams.l2MessageIndex),
l2Sender: finalizeWithdrawalParams.sender,
l2TxNumberInBatch: Number(finalizeWithdrawalParams.l2TxNumberInBlock),
message: finalizeWithdrawalParams.message,
merkleProof: finalizeWithdrawalParams.proof,
},
],
})
return await sendTransaction(client, {
account,
to: l1Nullifier,
data,
...rest,
} as SendTransactionParameters)
}
async function getFinalizeWithdrawalParams<
chain extends Chain | undefined,
account extends Account | undefined,
>(
client: Client<Transport, chain, account>,
parameters: { hash: Hex; index: number },
) {
const { hash } = parameters
const { log, l1BatchTxId } = await getWithdrawalLog(client, parameters)
const { l2ToL1LogIndex } = await getWithdrawalL2ToL1Log(client, parameters)
const sender = slice(log.topics[1]!, 12) as Address
const proof = await getLogProof(client, {
txHash: hash,
index: l2ToL1LogIndex!,
})
if (!proof) {
throw new WithdrawalLogNotFoundError({ hash })
}
const [message] = decodeAbiParameters([{ type: 'bytes' }], log.data)
return {
l1BatchNumber: log.l1BatchNumber,
l2MessageIndex: proof.id,
l2TxNumberInBlock: l1BatchTxId,
message,
sender,
proof: proof.proof,
}
}
async function getBridgeAddresses<
chain extends Chain | undefined,
chainL2 extends ChainEIP712 | undefined,
>(
client: Client<Transport, chain>,
l2Client: Client<Transport, chainL2>,
): Promise<
BridgeContractAddresses & {
l1Nullifier: Address
l1NativeTokenVault: Address
}
> {
const addresses = await getDefaultBridgeAddresses(l2Client)
let l1Nullifier = addresses.l1Nullifier
let l1NativeTokenVault = addresses.l1NativeTokenVault
if (!l1Nullifier)
l1Nullifier = await readContract(client, {
address: addresses.sharedL1,
abi: parseAbi(['function L1_NULLIFIER() view returns (address)']),
functionName: 'L1_NULLIFIER',
args: [],
})
if (!l1NativeTokenVault)
l1NativeTokenVault = await readContract(client, {
address: addresses.sharedL1,
abi: parseAbi(['function nativeTokenVault() view returns (address)']),
functionName: 'nativeTokenVault',
args: [],
})
return {
...addresses,
l1Nullifier,
l1NativeTokenVault,
}
}

34
node_modules/viem/zksync/actions/getAllBalances.ts generated vendored Normal file
View File

@@ -0,0 +1,34 @@
import type { Address } from 'abitype'
import { parseAccount } from '../../accounts/utils/parseAccount.js'
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import type { Account, GetAccountParameter } from '../../types/account.js'
import type { Chain } from '../../types/chain.js'
import { hexToBigInt } from '../../utils/encoding/fromHex.js'
import type { PublicZksyncRpcSchema } from '../types/eip1193.js'
export type GetAllBalancesParameters<
account extends Account | undefined = Account | undefined,
> = GetAccountParameter<account>
export type GetAllBalancesReturnType = { [key: Address]: bigint }
/* @deprecated This method has been removed from the node API. */
export async function getAllBalances<
chain extends Chain | undefined,
account extends Account | undefined,
>(
client: Client<Transport, chain, account, PublicZksyncRpcSchema>,
parameters: GetAllBalancesParameters<account>,
): Promise<GetAllBalancesReturnType> {
const { account: account_ } = parameters
const account = account_ ? parseAccount(account_) : client.account
const balances = await client.request({
method: 'zks_getAllAccountBalances',
params: [account!.address],
})
const convertedBalances: GetAllBalancesReturnType = {}
for (const token in balances)
(convertedBalances as any)[token] = hexToBigInt((balances as any)[token])
return convertedBalances
}

View File

@@ -0,0 +1,19 @@
import type { Address } from 'abitype'
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import type { Account } from '../../types/account.js'
import type { Chain } from '../../types/chain.js'
import type { PublicZksyncRpcSchema } from '../types/eip1193.js'
export type GetBaseTokenL1AddressReturnType = Address
/* @deprecated Use `getBridgeHubContractAddress` and call `baseToken(chainId)` instead. */
export async function getBaseTokenL1Address<
chain extends Chain | undefined,
account extends Account | undefined,
>(
client: Client<Transport, chain, account, PublicZksyncRpcSchema>,
): Promise<GetBaseTokenL1AddressReturnType> {
const result = await client.request({ method: 'zks_getBaseTokenL1Address' })
return result
}

27
node_modules/viem/zksync/actions/getBlockDetails.ts generated vendored Normal file
View File

@@ -0,0 +1,27 @@
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import type { Account } from '../../types/account.js'
import type { Chain } from '../../types/chain.js'
import type {
ZksyncBlockDetails,
ZksyncNumberParameter,
} from '../types/block.js'
import type { PublicZksyncRpcSchema } from '../types/eip1193.js'
export type GetBlockDetailsParameters = ZksyncNumberParameter
export type GetBlockDetailsReturnType = ZksyncBlockDetails
export async function getBlockDetails<
chain extends Chain | undefined,
account extends Account | undefined,
>(
client: Client<Transport, chain, account, PublicZksyncRpcSchema>,
parameters: GetBlockDetailsParameters,
): Promise<GetBlockDetailsReturnType> {
const result = await client.request({
method: 'zks_getBlockDetails',
params: [parameters.number],
})
return result
}

View File

@@ -0,0 +1,18 @@
import type { Address } from 'abitype'
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import type { Account } from '../../types/account.js'
import type { Chain } from '../../types/chain.js'
import type { PublicZksyncRpcSchema } from '../types/eip1193.js'
export type GetBridgehubContractAddressReturnType = Address
export async function getBridgehubContractAddress<
chain extends Chain | undefined,
account extends Account | undefined,
>(
client: Client<Transport, chain, account, PublicZksyncRpcSchema>,
): Promise<GetBridgehubContractAddressReturnType> {
const result = await client.request({ method: 'zks_getBridgehubContract' })
return result
}

View File

@@ -0,0 +1,25 @@
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import type { Account } from '../../types/account.js'
import type { Chain } from '../../types/chain.js'
import type { BridgeContractAddresses } from '../types/contract.js'
import type { PublicZksyncRpcSchema } from '../types/eip1193.js'
export type GetDefaultBridgeAddressesReturnType = BridgeContractAddresses
export async function getDefaultBridgeAddresses<
chain extends Chain | undefined,
account extends Account | undefined,
>(
client: Client<Transport, chain, account, PublicZksyncRpcSchema>,
): Promise<GetDefaultBridgeAddressesReturnType> {
const addresses = await client.request({ method: 'zks_getBridgeContracts' })
return {
erc20L1: addresses.l1Erc20DefaultBridge,
sharedL1: addresses.l1SharedDefaultBridge,
sharedL2: addresses.l2SharedDefaultBridge,
l1Nullifier: addresses.l1Nullifier,
l1NativeTokenVault: addresses.l1NativeTokenVault,
}
}

26
node_modules/viem/zksync/actions/getGasPerPubdata.ts generated vendored Normal file
View File

@@ -0,0 +1,26 @@
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import type { Account } from '../../types/account.js'
import { hexToBigInt } from '../../utils/encoding/fromHex.js'
import type { ChainEIP712 } from '../types/chain.js'
import type { PublicZksyncRpcSchema } from '../types/eip1193.js'
export type GetGasPerPubdataReturnType = bigint
export async function getGasPerPubdata<
chain extends ChainEIP712 | undefined,
account extends Account | undefined,
>(
client: Client<Transport, chain, account, PublicZksyncRpcSchema>,
): Promise<GetGasPerPubdataReturnType> {
const result = await client.request(
{
method: 'zks_gasPerPubdata',
},
{
dedupe: true,
},
)
return hexToBigInt(result)
}

43
node_modules/viem/zksync/actions/getL1Allowance.ts generated vendored Normal file
View File

@@ -0,0 +1,43 @@
import type { Address } from 'abitype'
import { parseAccount } from '../../accounts/utils/parseAccount.js'
import { readContract } from '../../actions/public/readContract.js'
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import { erc20Abi } from '../../constants/abis.js'
import type { AccountNotFoundError } from '../../errors/account.js'
import type { BaseError } from '../../errors/base.js'
import type { Account, GetAccountParameter } from '../../types/account.js'
import type { BlockTag } from '../../types/block.js'
import type { Chain } from '../../types/chain.js'
export type GetL1AllowanceParameters<
account extends Account | undefined = Account | undefined,
> = GetAccountParameter<account> & {
bridgeAddress: Address
blockTag?: BlockTag | undefined
token: Address
}
export type GetL1AllowanceReturnType = bigint
export type GetL1AllowanceErrorType = AccountNotFoundError | BaseError
export async function getL1Allowance<
chain extends Chain | undefined,
account extends Account | undefined,
>(
client: Client<Transport, chain, account>,
parameters: GetL1AllowanceParameters<account>,
): Promise<GetL1AllowanceReturnType> {
const { token, bridgeAddress, blockTag, account: account_ } = parameters
const account = account_ ? parseAccount(account_) : client.account
return await readContract(client, {
abi: erc20Abi,
address: token,
functionName: 'allowance',
args: [account!.address, bridgeAddress],
blockTag: blockTag,
})
}

68
node_modules/viem/zksync/actions/getL1Balance.ts generated vendored Normal file
View File

@@ -0,0 +1,68 @@
import type { Address } from 'abitype'
import { parseAccount } from '../../accounts/utils/parseAccount.js'
import {
type GetBalanceParameters,
getBalance,
} from '../../actions/public/getBalance.js'
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import type { AccountNotFoundError } from '../../errors/account.js'
import type { BaseError } from '../../errors/base.js'
import type { Account, GetAccountParameter } from '../../types/account.js'
import type { BlockTag } from '../../types/block.js'
import type { Chain } from '../../types/chain.js'
import { legacyEthAddress } from '../constants/address.js'
import { isEth } from '../utils/isEth.js'
import {
type GetL1TokenBalanceParameters,
getL1TokenBalance,
} from './getL1TokenBalance.js'
export type GetL1BalanceParameters<
account extends Account | undefined = Account | undefined,
> = GetAccountParameter<account> & { token?: Address | undefined } & (
| {
/** The balance of the account at a block number. */
blockNumber?: bigint | undefined
blockTag?: undefined
}
| {
blockNumber?: undefined
/** The balance of the account at a block tag. */
blockTag?: BlockTag | undefined
}
)
export type GetL1BalanceReturnType = bigint
export type GetL1BalanceErrorType = AccountNotFoundError | BaseError
export async function getL1Balance<
chain extends Chain | undefined,
account extends Account | undefined,
>(
client: Client<Transport, chain, account>,
...[parameters = {}]: account extends undefined
? [GetL1BalanceParameters<account>]
: [GetL1BalanceParameters<account>] | []
): Promise<GetL1BalanceReturnType> {
const {
account: account_ = client.account,
blockNumber,
blockTag,
token = legacyEthAddress,
} = parameters
const account = account_ ? parseAccount(account_) : undefined
if (isEth(token))
return await getBalance(client, {
address: account!.address,
blockNumber,
blockTag,
} as GetBalanceParameters)
return await getL1TokenBalance(client, {
...(parameters as GetL1TokenBalanceParameters<account>),
})
}

View File

@@ -0,0 +1,26 @@
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import type { Account } from '../../types/account.js'
import type { Chain } from '../../types/chain.js'
import { hexToNumber } from '../../utils/encoding/fromHex.js'
import type { PublicZksyncRpcSchema } from '../types/eip1193.js'
export type GetL1BatchBlockRangeParameters = {
l1BatchNumber: number
}
export type GetL1BatchBlockRangeReturnParameters = [number, number]
export async function getL1BatchBlockRange<
chain extends Chain | undefined,
account extends Account | undefined,
>(
client: Client<Transport, chain, account, PublicZksyncRpcSchema>,
parameters: GetL1BatchBlockRangeParameters,
): Promise<GetL1BatchBlockRangeReturnParameters> {
const [number_1, number_2] = await client.request({
method: 'zks_getL1BatchBlockRange',
params: [parameters.l1BatchNumber],
})
return [hexToNumber(number_1), hexToNumber(number_2)]
}

27
node_modules/viem/zksync/actions/getL1BatchDetails.ts generated vendored Normal file
View File

@@ -0,0 +1,27 @@
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import type { Account } from '../../types/account.js'
import type { Chain } from '../../types/chain.js'
import type {
ZksyncBatchDetails,
ZksyncNumberParameter,
} from '../types/block.js'
import type { PublicZksyncRpcSchema } from '../types/eip1193.js'
export type GetL1BatchDetailsParameters = ZksyncNumberParameter
export type GetL1BatchDetailsReturnType = ZksyncBatchDetails
export async function getL1BatchDetails<
chain extends Chain | undefined,
account extends Account | undefined,
>(
client: Client<Transport, chain, account, PublicZksyncRpcSchema>,
parameters: GetL1BatchDetailsParameters,
): Promise<GetL1BatchDetailsReturnType> {
const result = await client.request({
method: 'zks_getL1BatchDetails',
params: [parameters.number],
})
return result
}

18
node_modules/viem/zksync/actions/getL1BatchNumber.ts generated vendored Normal file
View File

@@ -0,0 +1,18 @@
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import type { Account } from '../../types/account.js'
import type { Chain } from '../../types/chain.js'
import type { Hex } from '../../types/misc.js'
import type { PublicZksyncRpcSchema } from '../types/eip1193.js'
export type GetL1BatchNumberReturnType = Hex
export async function getL1BatchNumber<
chain extends Chain | undefined,
account extends Account | undefined,
>(
client: Client<Transport, chain, account, PublicZksyncRpcSchema>,
): Promise<GetL1BatchNumberReturnType> {
const result = await client.request({ method: 'zks_L1BatchNumber' })
return result
}

19
node_modules/viem/zksync/actions/getL1ChainId.ts generated vendored Normal file
View File

@@ -0,0 +1,19 @@
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import type { Account } from '../../types/account.js'
import type { Chain } from '../../types/chain.js'
import type { Hex } from '../../types/misc.js'
import type { PublicZksyncRpcSchema } from '../types/eip1193.js'
export type GetL1ChainIdReturnType = Hex
/* @deprecated Use the `L1_CHAIN_ID()` method on the `L2AssetRouter` contract (deployed on `0x0000000000000000000000000000000000010003` address) */
export async function getL1ChainId<
chain extends Chain | undefined,
account extends Account | undefined,
>(
client: Client<Transport, chain, account, PublicZksyncRpcSchema>,
): Promise<GetL1ChainIdReturnType> {
const result = await client.request({ method: 'zks_L1ChainId' })
return result
}

59
node_modules/viem/zksync/actions/getL1TokenAddress.ts generated vendored Normal file
View File

@@ -0,0 +1,59 @@
import type { Address } from '../../accounts/index.js'
import { readContract } from '../../actions/public/readContract.js'
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import type { Account } from '../../types/account.js'
import type { Chain } from '../../types/chain.js'
import { isAddressEqual } from '../../utils/index.js'
import { l2SharedBridgeAbi } from '../constants/abis.js'
import { legacyEthAddress } from '../constants/address.js'
import { getDefaultBridgeAddresses } from './getDefaultBridgeAddresses.js'
export type GetL1TokenAddressParameters = {
/** The address of the token on L2. */
token: Address
}
export type GetL1TokenAddressReturnType = Address
/**
* Returns the L1 token address equivalent for a L2 token address as they are not equal.
* ETH address is set to zero address.
*
* @remarks Only works for tokens bridged on default ZKsync Era bridges.
*
* @param client - Client to use
* @param parameters - {@link GetL1TokenAddressParameters}
* @returns The L1 token address equivalent for a L2 token address.
*
*
* @example
* import { createPublicClient, http } from 'viem'
* import { zksync } from 'viem/chains'
*
* const client = createPublicClient({
* chain: zksync,
* transport: http(),
* })
*
* const address = await getL1TokenAddress(client, {token: '0x...'});
*/
export async function getL1TokenAddress<
chain extends Chain | undefined,
account extends Account | undefined,
>(
client: Client<Transport, chain, account>,
parameters: GetL1TokenAddressParameters,
): Promise<Address> {
const { token } = parameters
if (isAddressEqual(token, legacyEthAddress)) return legacyEthAddress
const bridgeAddress = (await getDefaultBridgeAddresses(client)).sharedL2
return await readContract(client, {
address: bridgeAddress,
abi: l2SharedBridgeAbi,
functionName: 'l1TokenAddress',
args: [token],
})
}

66
node_modules/viem/zksync/actions/getL1TokenBalance.ts generated vendored Normal file
View File

@@ -0,0 +1,66 @@
import type { Address } from '../../accounts/index.js'
import { parseAccount } from '../../accounts/utils/parseAccount.js'
import { readContract } from '../../actions/index.js'
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import { erc20Abi } from '../../constants/abis.js'
import type { AccountNotFoundErrorType } from '../../errors/account.js'
import type { BaseErrorType } from '../../errors/base.js'
import type { Account, GetAccountParameter } from '../../types/account.js'
import type { BlockTag } from '../../types/block.js'
import type { Chain } from '../../types/chain.js'
import {
TokenIsEthError,
type TokenIsEthErrorType,
} from '../errors/token-is-eth.js'
import { isEth } from '../utils/isEth.js'
export type GetL1TokenBalanceParameters<
account extends Account | undefined = Account | undefined,
> = GetAccountParameter<account> & { token: Address } & (
| {
/** The balance of the account at a block number. */
blockNumber?: bigint | undefined
blockTag?: undefined
}
| {
blockNumber?: undefined
/** The balance of the account at a block tag. */
blockTag?: BlockTag | undefined
}
)
export type GetL1TokenBalanceReturnType = bigint
export type GetL1TokenBalanceErrorType =
| AccountNotFoundErrorType
| TokenIsEthErrorType
| BaseErrorType
export async function getL1TokenBalance<
chain extends Chain | undefined,
account extends Account | undefined,
>(
client: Client<Transport, chain, account>,
parameters: GetL1TokenBalanceParameters<account>,
): Promise<GetL1TokenBalanceReturnType> {
const {
account: account_ = client.account,
blockTag,
blockNumber,
token,
} = parameters
if (isEth(token!)) throw new TokenIsEthError()
const account = account_ ? parseAccount(account_) : client.account
return await readContract(client, {
abi: erc20Abi,
address: token!,
functionName: 'balanceOf',
args: [account!.address],
blockNumber: blockNumber,
blockTag: blockTag,
})
}

70
node_modules/viem/zksync/actions/getL2TokenAddress.ts generated vendored Normal file
View File

@@ -0,0 +1,70 @@
import type { Address } from '../../accounts/index.js'
import { readContract } from '../../actions/public/readContract.js'
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import type { Account } from '../../types/account.js'
import type { Chain } from '../../types/chain.js'
import { isAddressEqual } from '../../utils/index.js'
import { l2SharedBridgeAbi } from '../constants/abis.js'
import {
ethAddressInContracts,
l2BaseTokenAddress,
legacyEthAddress,
} from '../constants/address.js'
import { getBaseTokenL1Address } from './getBaseTokenL1Address.js'
import { getDefaultBridgeAddresses } from './getDefaultBridgeAddresses.js'
export type GetL2TokenAddressParameters = {
/** The address of the token on L1. */
token: Address
/** The address of custom bridge, which will be used to get l2 token address. */
bridgeAddress?: Address | undefined
}
export type GetL2TokenAddressReturnType = Address
/**
* Returns the L2 token address equivalent for a L1 token address as they are not equal.
* ETH address is set to zero address.
*
* @remarks Only works for tokens bridged on default ZKsync Era bridges.
*
* @param client - Client to use
* @param parameters - {@link GetL2TokenAddressParameters}
* @returns The L2 token address equivalent for a L1 token address.
*
*
* @example
* import { createPublicClient, http } from 'viem'
* import { zksync } from 'viem/chains'
* import { publicActionsL2 } from 'viem/zksync'
*
* const client = createPublicClient({
* chain: zksync,
* transport: http(),
* }).extend(publicActionsL2())
*
* const address = await getL2TokenAddress(client, {token: '0x...'});
*/
export async function getL2TokenAddress<
chain extends Chain | undefined,
account extends Account | undefined,
>(
client: Client<Transport, chain, account>,
parameters: GetL2TokenAddressParameters,
): Promise<Address> {
let { token, bridgeAddress } = parameters
if (isAddressEqual(token, legacyEthAddress)) token = ethAddressInContracts
const baseToken = await getBaseTokenL1Address(client)
if (isAddressEqual(token, baseToken)) return l2BaseTokenAddress
bridgeAddress ??= (await getDefaultBridgeAddresses(client)).sharedL2
return await readContract(client, {
address: bridgeAddress,
abi: l2SharedBridgeAbi,
functionName: 'l2TokenAddress',
args: [token],
})
}

28
node_modules/viem/zksync/actions/getLogProof.ts generated vendored Normal file
View File

@@ -0,0 +1,28 @@
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import type { Account } from '../../types/account.js'
import type { Chain } from '../../types/chain.js'
import type { Hash } from '../../types/misc.js'
import type { PublicZksyncRpcSchema } from '../types/eip1193.js'
import type { MessageProof } from '../types/proof.js'
export type GetLogProofParameters = {
txHash: Hash
index?: number | undefined
}
export type GetLogProofReturnType = MessageProof | null
export async function getLogProof<
chain extends Chain | undefined,
account extends Account | undefined,
>(
client: Client<Transport, chain, account, PublicZksyncRpcSchema>,
parameters: GetLogProofParameters,
): Promise<MessageProof | null> {
const result = await client.request({
method: 'zks_getL2ToL1LogProof',
params: [parameters.txHash, parameters.index],
})
return result
}

View File

@@ -0,0 +1,19 @@
import type { Address } from 'abitype'
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import type { Account } from '../../types/account.js'
import type { Chain } from '../../types/chain.js'
import type { PublicZksyncRpcSchema } from '../types/eip1193.js'
export type GetMainContractAddressReturnType = Address
/* @deprecated Use `getBridgeHubContractAddress` and call `getZKChain(chainId)` instead. */
export async function getMainContractAddress<
chain extends Chain | undefined,
account extends Account | undefined,
>(
client: Client<Transport, chain, account, PublicZksyncRpcSchema>,
): Promise<GetMainContractAddressReturnType> {
const address = await client.request({ method: 'zks_getMainContract' })
return address
}

View File

@@ -0,0 +1,27 @@
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import type { Account } from '../../types/account.js'
import type { Chain } from '../../types/chain.js'
import type { ZksyncNumberParameter } from '../types/block.js'
import type { PublicZksyncRpcSchema } from '../types/eip1193.js'
import type { ZksyncRawBlockTransactions } from '../types/transaction.js'
import { camelCaseKeys } from '../utils/camelCaseKeys.js'
export type GetRawBlockTransactionsParameters = ZksyncNumberParameter
export type GetRawBlockTransactionsReturnType = ZksyncRawBlockTransactions
/* @deprecated Use `debug_getRawTransaction` and `debug_getRawTransactions` instead. */
export async function getRawBlockTransactions<
chain extends Chain | undefined,
account extends Account | undefined,
>(
client: Client<Transport, chain, account, PublicZksyncRpcSchema>,
parameters: GetRawBlockTransactionsParameters,
): Promise<GetRawBlockTransactionsReturnType> {
const result = await client.request({
method: 'zks_getRawBlockTransactions',
params: [parameters.number],
})
return camelCaseKeys(result) as GetRawBlockTransactionsReturnType
}

View File

@@ -0,0 +1,19 @@
import type { Address } from 'abitype'
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import type { Account } from '../../types/account.js'
import type { Chain } from '../../types/chain.js'
import type { PublicZksyncRpcSchema } from '../types/eip1193.js'
export type GetTestnetPaymasterAddressReturnType = Address | null
/* @deprecated Check the corresponding ZKsync chain technical documentation to find the testnet paymaster address */
export async function getTestnetPaymasterAddress<
chain extends Chain | undefined,
account extends Account | undefined,
>(
client: Client<Transport, chain, account, PublicZksyncRpcSchema>,
): Promise<GetTestnetPaymasterAddressReturnType> {
const result = await client.request({ method: 'zks_getTestnetPaymaster' })
return result
}

View File

@@ -0,0 +1,27 @@
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import type { Account } from '../../types/account.js'
import type { Chain } from '../../types/chain.js'
import type { Hash } from '../../types/misc.js'
import type { PublicZksyncRpcSchema } from '../types/eip1193.js'
import type { ZksyncTransactionDetails } from '../types/transaction.js'
export type GetTransactionDetailsParameters = {
txHash: Hash
}
export type GetTransactionDetailsReturnType = ZksyncTransactionDetails
export async function getTransactionDetails<
chain extends Chain | undefined,
account extends Account | undefined,
>(
client: Client<Transport, chain, account, PublicZksyncRpcSchema>,
parameters: GetTransactionDetailsParameters,
): Promise<GetTransactionDetailsReturnType> {
const result = await client.request({
method: 'zks_getTransactionDetails',
params: [parameters.txHash],
})
return result
}

View File

@@ -0,0 +1,104 @@
import type { Account } from '../../accounts/types.js'
import { readContract } from '../../actions/public/readContract.js'
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import {
ChainNotFoundError,
type ChainNotFoundErrorType,
} from '../../errors/chain.js'
import type { Chain } from '../../types/chain.js'
import type { Hash } from '../../types/misc.js'
import { l1SharedBridgeAbi } from '../constants/abis.js'
import {
WithdrawalLogNotFoundError,
type WithdrawalLogNotFoundErrorType,
} from '../errors/bridge.js'
import type { ChainEIP712 } from '../types/chain.js'
import { getWithdrawalL2ToL1Log } from '../utils/bridge/getWithdrawalL2ToL1Log.js'
import { getWithdrawalLog } from '../utils/bridge/getWithdrawalLog.js'
import { getDefaultBridgeAddresses } from './getDefaultBridgeAddresses.js'
import { getLogProof } from './getLogProof.js'
export type IsWithdrawalFinalizedParameters<
chain extends Chain | undefined = Chain | undefined,
account extends Account | undefined = Account | undefined,
> = {
/** L2 client */
client: Client<Transport, chain, account>
/** 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 IsWithdrawalFinalizedReturnType = boolean
export type IsWithdrawalFinalizedErrorType =
| WithdrawalLogNotFoundErrorType
| ChainNotFoundErrorType
/**
* Returns whether the withdrawal transaction is finalized on the L1 network.
*
* @param client - Client to use
* @param parameters - {@link IsWithdrawalFinalizedParameters}
* @returns bool - Whether the withdrawal transaction is finalized on the L1 network. {@link IsWithdrawalFinalizedReturnType}
*
* @example
* import { createPublicClient, http } from 'viem'
* import { mainnet, zksync } from 'viem/chains'
* import { isWithdrawalFinalized } from 'viem/zksync'
*
* const client = createPublicClient({
* chain: mainnet,
* transport: http(),
* })
*
* const clientL2 = createPublicClient({
* chain: zksync,
* transport: http(),
* })
*
* const hash = await isWithdrawalFinalized(client, {
* client: clientL2,
* hash: '0x...',
* })
*/
export async function isWithdrawalFinalized<
chain extends Chain | undefined,
account extends Account | undefined,
chainL2 extends ChainEIP712 | undefined,
accountL2 extends Account | undefined,
>(
client: Client<Transport, chain, account>,
parameters: IsWithdrawalFinalizedParameters<chainL2, accountL2>,
): Promise<IsWithdrawalFinalizedReturnType> {
const { client: l2Client, hash, index = 0 } = parameters
if (!l2Client.chain) throw new ChainNotFoundError()
const { log } = await getWithdrawalLog(l2Client, { hash, index })
const { l2ToL1LogIndex } = await getWithdrawalL2ToL1Log(l2Client, {
hash,
index,
})
// `getLogProof` is called not to get proof but
// to get the index of the corresponding L2->L1 log,
// which is returned as `proof.id`.
const proof = await getLogProof(l2Client, {
txHash: hash,
index: l2ToL1LogIndex!,
})
if (!proof) throw new WithdrawalLogNotFoundError({ hash })
const l1Bridge = (await getDefaultBridgeAddresses(l2Client)).sharedL1
return await readContract(client, {
address: l1Bridge,
abi: l1SharedBridgeAbi,
functionName: 'isWithdrawalFinalized',
args: [BigInt(l2Client.chain.id), log.l1BatchNumber!, BigInt(proof.id)],
})
}

282
node_modules/viem/zksync/actions/requestExecute.ts generated vendored Normal file
View File

@@ -0,0 +1,282 @@
import type { Address } from 'abitype'
import { generatePrivateKey } from '../../accounts/generatePrivateKey.js'
import type { Account } from '../../accounts/types.js'
import { privateKeyToAddress } from '../../accounts/utils/privateKeyToAddress.js'
import { readContract } from '../../actions/public/readContract.js'
import {
type SendTransactionErrorType,
type SendTransactionParameters,
type SendTransactionReturnType,
sendTransaction,
} from '../../actions/wallet/sendTransaction.js'
import type { Client } from '../../clients/createClient.js'
import { publicActions } from '../../clients/decorators/public.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import { AccountNotFoundError } from '../../errors/account.js'
import { ClientChainNotConfiguredError } from '../../errors/chain.js'
import type { GetAccountParameter } from '../../types/account.js'
import type {
Chain,
DeriveChain,
GetChainParameter,
} from '../../types/chain.js'
import type { Hex } from '../../types/misc.js'
import type { UnionEvaluate, UnionOmit } from '../../types/utils.js'
import {
encodeFunctionData,
type FormattedTransactionRequest,
isAddressEqual,
parseAccount,
} from '../../utils/index.js'
import { bridgehubAbi } from '../constants/abis.js'
import { ethAddressInContracts } from '../constants/address.js'
import { requiredL1ToL2GasPerPubdataLimit } from '../constants/number.js'
import {
BaseFeeHigherThanValueError,
type BaseFeeHigherThanValueErrorType,
} from '../errors/bridge.js'
import type { ChainEIP712 } from '../types/chain.js'
import { estimateGasL1ToL2 } from './estimateGasL1ToL2.js'
import { getBridgehubContractAddress } from './getBridgehubContractAddress.js'
export type RequestExecuteParameters<
chain extends Chain | undefined = Chain | undefined,
account extends Account | undefined = Account | undefined,
chainOverride extends Chain | undefined = Chain | undefined,
chainL2 extends ChainEIP712 | undefined = ChainEIP712 | undefined,
accountL2 extends Account | undefined = Account | undefined,
_derivedChain extends Chain | undefined = DeriveChain<chain, chainOverride>,
> = UnionEvaluate<
UnionOmit<FormattedTransactionRequest<_derivedChain>, 'data' | 'to' | 'from'>
> &
Partial<GetChainParameter<chain, chainOverride>> &
Partial<GetAccountParameter<account>> & {
/** L2 client. */
client: Client<Transport, chainL2, accountL2>
/** The L2 contract to be called. */
contractAddress: Address
/** The input of the L2 transaction. */
calldata: Hex
/** Maximum amount of L2 gas that transaction can consume during execution on L2. */
l2GasLimit?: bigint | undefined
/** The amount of base token that needs to be minted on non-ETH-based L2. */
mintValue?: bigint | undefined
/** The `msg.value` of L2 transaction. */
l2Value?: bigint | undefined
/** An array of L2 bytecodes that will be marked as known on L2. */
factoryDeps?: Hex[] | undefined
/** (currently not used) The tip the operator will receive on top of
the base cost of the transaction. */
operatorTip?: bigint | undefined
/** The L2 gas price for each published L1 calldata byte. */
gasPerPubdataByte?: bigint | undefined
/** The address on L2 that will receive the refund for the transaction.
If the transaction fails, it will also be the address to receive `l2Value`. */
refundRecipient?: Address | undefined
}
export type RequestExecuteReturnType = SendTransactionReturnType
export type RequestExecuteErrorType =
| SendTransactionErrorType
| BaseFeeHigherThanValueErrorType
/**
* Requests execution of a L2 transaction from L1.
*
* @param client - Client to use
* @param parameters - {@link RequestExecuteParameters}
* @returns hash - The [Transaction](https://viem.sh/docs/glossary/terms#transaction) hash. {@link RequestExecuteReturnType}
*
* @example
* import { createPublicClient, http } from 'viem'
* import { privateKeyToAccount } from 'viem/accounts'
* import { zksync, mainnet } from 'viem/chains'
* import { requestExecute, publicActionsL2 } from 'viem/zksync'
*
* const client = createPublicClient({
* chain: mainnet,
* transport: http(),
* })
*
* const clientL2 = createPublicClient({
* chain: zksync,
* transport: http(),
* }).extend(publicActionsL2())
*
* const hash = await requestExecute(client, {
* client: clientL2,
* account: privateKeyToAccount('0x…'),
* contractAddress: '0x43020e6e11cef7dce8e37baa09d9a996ac722057'
* calldata: '0x',
* l2Value: 1_000_000_000_000_000_000n,
* })
*
* @example Account Hoisting
* import { createPublicClient, createWalletClient, http } from 'viem'
* import { privateKeyToAccount } from 'viem/accounts'
* import { zksync, mainnet } from 'viem/chains'
* import { requestExecute, publicActionsL2 } from 'viem/zksync'
*
* const client = createWalletClient({
* account: privateKeyToAccount('0x…'),
* chain: mainnet,
* transport: http(),
* })
*
* const clientL2 = createPublicClient({
* chain: zksync,
* transport: http(),
* }).extend(publicActionsL2())
*
* const hash = await requestExecute(client, {
* client: clientL2,
* contractAddress: '0x43020e6e11cef7dce8e37baa09d9a996ac722057'
* calldata: '0x',
* l2Value: 1_000_000_000_000_000_000n,
* })
*/
export async function requestExecute<
chain extends Chain | undefined,
account extends Account | undefined,
chainOverride extends Chain | undefined = Chain | undefined,
chainL2 extends ChainEIP712 | undefined = ChainEIP712 | undefined,
accountL2 extends Account | undefined = Account | undefined,
>(
client: Client<Transport, chain, account>,
parameters: RequestExecuteParameters<
chain,
account,
chainOverride,
chainL2,
accountL2
>,
): Promise<RequestExecuteReturnType> {
let {
account: account_ = client.account,
chain: chain_ = client.chain,
client: l2Client,
contractAddress,
calldata,
l2Value = 0n,
mintValue = 0n,
operatorTip = 0n,
factoryDeps = [],
gasPerPubdataByte = requiredL1ToL2GasPerPubdataLimit,
refundRecipient,
l2GasLimit,
value,
gasPrice,
maxFeePerGas,
maxPriorityFeePerGas,
...rest
} = parameters
const account = account_ ? parseAccount(account_) : client.account
if (!account)
throw new AccountNotFoundError({
docsPath: '/docs/actions/wallet/sendTransaction',
})
if (!l2Client.chain) throw new ClientChainNotConfiguredError()
const bridgehub = await getBridgehubContractAddress(l2Client)
const baseToken = await readContract(client, {
address: bridgehub,
abi: bridgehubAbi,
functionName: 'baseToken',
args: [BigInt(l2Client.chain.id)],
})
const isETHBasedChain = isAddressEqual(baseToken, ethAddressInContracts)
refundRecipient ??= account.address
l2GasLimit ??= await estimateGasL1ToL2(l2Client, {
chain: l2Client.chain,
// If the `from` address is not provided, we use a random address, because
// due to storage slot aggregation, the gas estimation will depend on the address
// and so estimation for the zero address may be smaller than for the sender.
account:
l2Client.account ??
parseAccount(privateKeyToAddress(generatePrivateKey())),
data: calldata,
to: contractAddress,
value: l2Value,
gasPerPubdata: gasPerPubdataByte,
factoryDeps,
})
let gasPriceForEstimation = maxFeePerGas || gasPrice
if (!gasPriceForEstimation) {
const estimatedFee = await getFeePrice(client)
gasPriceForEstimation = estimatedFee.maxFeePerGas
maxFeePerGas = estimatedFee.maxFeePerGas
maxPriorityFeePerGas ??= estimatedFee.maxPriorityFeePerGas
}
const baseCost = await readContract(client, {
address: bridgehub,
abi: bridgehubAbi,
functionName: 'l2TransactionBaseCost',
args: [
BigInt(l2Client.chain.id),
gasPriceForEstimation,
l2GasLimit,
gasPerPubdataByte,
],
})
const l2Costs = baseCost + operatorTip + l2Value
let providedValue = isETHBasedChain ? value : mintValue
if (!providedValue || providedValue === 0n) {
providedValue = l2Costs
}
if (baseCost > providedValue)
throw new BaseFeeHigherThanValueError(baseCost, providedValue)
const data = encodeFunctionData({
abi: bridgehubAbi,
functionName: 'requestL2TransactionDirect',
args: [
{
chainId: BigInt(l2Client.chain.id),
mintValue: providedValue,
l2Contract: contractAddress,
l2Value: l2Value,
l2Calldata: calldata,
l2GasLimit: l2GasLimit,
l2GasPerPubdataByteLimit: gasPerPubdataByte,
factoryDeps: factoryDeps,
refundRecipient: refundRecipient,
},
],
})
return await sendTransaction(client, {
chain: chain_,
account: account,
to: bridgehub,
value: isETHBasedChain ? providedValue : value,
data,
gasPrice,
maxFeePerGas,
maxPriorityFeePerGas,
...rest,
} as SendTransactionParameters)
}
async function getFeePrice<chain extends Chain | undefined>(
client: Client<Transport, chain>,
) {
const client_ = client.extend(publicActions)
const block = await client_.getBlock()
const baseFee =
typeof block.baseFeePerGas !== 'bigint'
? await client_.getGasPrice()
: block.baseFeePerGas
const maxPriorityFeePerGas = await client_.estimateMaxPriorityFeePerGas()
return {
maxFeePerGas: (baseFee * 3n) / 2n + maxPriorityFeePerGas,
maxPriorityFeePerGas: maxPriorityFeePerGas,
}
}

View File

@@ -0,0 +1,143 @@
import type { Account } from '../../accounts/types.js'
import { parseAccount } from '../../accounts/utils/parseAccount.js'
import { getChainId } from '../../actions/public/getChainId.js'
import { prepareTransactionRequest } from '../../actions/wallet/prepareTransactionRequest.js'
import { sendRawTransaction } from '../../actions/wallet/sendRawTransaction.js'
import type {
SendTransactionErrorType,
SendTransactionParameters,
SendTransactionRequest,
SendTransactionReturnType,
} from '../../actions/wallet/sendTransaction.js'
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import { AccountNotFoundError } from '../../errors/account.js'
import type { BaseError } from '../../errors/base.js'
import type { Chain } from '../../types/chain.js'
import { assertCurrentChain } from '../../utils/chain/assertCurrentChain.js'
import {
type GetTransactionErrorParameters,
getTransactionError,
} from '../../utils/errors/getTransactionError.js'
import { getAction } from '../../utils/getAction.js'
import type { ChainEIP712 } from '../types/chain.js'
import { assertEip712Request } from '../utils/assertEip712Request.js'
import { signTransaction } from './signTransaction.js'
export type SendEip712TransactionParameters<
chain extends ChainEIP712 | undefined = ChainEIP712 | undefined,
account extends Account | undefined = Account | undefined,
chainOverride extends ChainEIP712 | undefined = ChainEIP712 | undefined,
request extends SendTransactionRequest<
chain,
chainOverride
> = SendTransactionRequest<chain, chainOverride>,
> = SendTransactionParameters<chain, account, chainOverride, request>
export type SendEip712TransactionReturnType = SendTransactionReturnType
export type SendEip712TransactionErrorType = SendTransactionErrorType
/**
* Creates, signs, and sends a new EIP712 transaction to the network.
*
* @param client - Client to use
* @param parameters - {@link SendEip712TransactionParameters}
* @returns The [Transaction](https://viem.sh/docs/glossary/terms#transaction) hash. {@link SendTransactionReturnType}
*
* @example
* import { createWalletClient, custom } from 'viem'
* import { zksync } from 'viem/chains'
* import { sendEip712Transaction } from 'viem/zksync'
*
* const client = createWalletClient({
* chain: zksync,
* transport: custom(window.ethereum),
* })
* const hash = await sendEip712Transaction(client, {
* account: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e',
* to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
* value: 1000000000000000000n,
* })
*
* @example
* // Account Hoisting
* import { createWalletClient, http } from 'viem'
* import { privateKeyToAccount } from 'viem/accounts'
* import { zksync } from 'viem/chains'
* import { sendEip712Transaction } from 'viem/zksync'
*
* const client = createWalletClient({
* account: privateKeyToAccount('0x…'),
* chain: zksync,
* transport: http(),
* })
*
* const hash = await sendEip712Transaction(client, {
* to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
* value: 1000000000000000000n,
* })
*/
export async function sendEip712Transaction<
chain extends ChainEIP712 | undefined,
account extends Account | undefined,
const request extends SendTransactionRequest<chain, chainOverride>,
chainOverride extends ChainEIP712 | undefined = undefined,
>(
client: Client<Transport, chain, account>,
parameters: SendEip712TransactionParameters<
chain,
account,
chainOverride,
request
>,
): Promise<SendEip712TransactionReturnType> {
const { account: account_ = client.account, chain = client.chain } =
parameters
const account = account_ ? parseAccount(account_) : client.account
if (!account)
throw new AccountNotFoundError({
docsPath: '/docs/actions/wallet/sendTransaction',
})
try {
assertEip712Request(parameters)
// Prepare the request for signing (assign appropriate fees, etc.)
const request = await prepareTransactionRequest(client, {
...parameters,
nonceManager: account.nonceManager,
parameters: ['gas', 'nonce', 'fees'],
} as any)
let chainId: number | undefined
if (chain !== null) {
chainId = await getAction(client, getChainId, 'getChainId')({})
assertCurrentChain({
currentChainId: chainId,
chain,
})
}
const serializedTransaction = await signTransaction(client, {
...request,
chainId,
} as any)
return await getAction(
client,
sendRawTransaction,
'sendRawTransaction',
)({
serializedTransaction,
})
} catch (err) {
throw getTransactionError(err as BaseError, {
...(parameters as GetTransactionErrorParameters),
account,
chain: chain as Chain,
})
}
}

94
node_modules/viem/zksync/actions/sendTransaction.ts generated vendored Normal file
View File

@@ -0,0 +1,94 @@
import type { Account } from '../../accounts/types.js'
import type {
SendTransactionErrorType as core_SendTransactionErrorType,
SendTransactionParameters as core_SendTransactionParameters,
SendTransactionReturnType as core_SendTransactionReturnType,
SendTransactionRequest,
} from '../../actions/wallet/sendTransaction.js'
import { sendTransaction as core_sendTransaction } from '../../actions/wallet/sendTransaction.js'
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import type { ChainEIP712 } from '../types/chain.js'
import { isEIP712Transaction } from '../utils/isEip712Transaction.js'
import {
type SendEip712TransactionParameters,
sendEip712Transaction,
} from './sendEip712Transaction.js'
export type SendTransactionParameters<
chain extends ChainEIP712 | undefined = ChainEIP712 | undefined,
account extends Account | undefined = Account | undefined,
chainOverride extends ChainEIP712 | undefined = ChainEIP712 | undefined,
request extends SendTransactionRequest<
chain,
chainOverride
> = SendTransactionRequest<chain, chainOverride>,
> = core_SendTransactionParameters<chain, account, chainOverride, request>
export type SendTransactionReturnType = core_SendTransactionReturnType
export type SendTransactionErrorType = core_SendTransactionErrorType
/**
* Creates, signs, and sends a new transaction to the network.
*
* - Docs: https://viem.sh/docs/zksync/actions/sendTransaction
* - JSON-RPC Methods:
* - JSON-RPC Accounts: [`eth_sendTransaction`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_sendtransaction)
* - Local Accounts: [`eth_sendRawTransaction`](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_sendrawtransaction)
*
* @param client - Client to use
* @param parameters - {@link SendTransactionParameters}
* @returns The [Transaction](https://viem.sh/docs/glossary/terms#transaction) hash. {@link SendTransactionReturnType}
*
* @example
* import { createWalletClient, custom } from 'viem'
* import { zksync } from 'viem/chains'
* import { sendTransaction } from 'viem/zksync'
*
* const client = createWalletClient({
* chain: zksync,
* transport: custom(window.ethereum),
* })
* const hash = await sendTransaction(client, {
* account: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e',
* to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
* value: 1000000000000000000n,
* })
*
* @example
* // Account Hoisting
* import { createWalletClient, http } from 'viem'
* import { privateKeyToAccount } from 'viem/accounts'
* import { zksync } from 'viem/chains'
* import { sendTransaction } from 'viem/zksync'
*
* const client = createWalletClient({
* account: privateKeyToAccount('0x…'),
* chain: zksync,
* transport: http(),
* })
* const hash = await sendTransaction(client, {
* to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
* value: 1000000000000000000n,
* })
*/
export async function sendTransaction<
chain extends ChainEIP712 | undefined,
account extends Account | undefined,
const request extends SendTransactionRequest<chain, chainOverride>,
chainOverride extends ChainEIP712 | undefined = undefined,
>(
client: Client<Transport, chain, account>,
parameters: SendTransactionParameters<chain, account, chainOverride, request>,
): Promise<SendTransactionReturnType> {
if (isEIP712Transaction(parameters))
return sendEip712Transaction(
client,
parameters as SendEip712TransactionParameters,
)
return core_sendTransaction(
client,
parameters as core_SendTransactionParameters,
)
}

View File

@@ -0,0 +1,153 @@
import type { Account } from '../../accounts/types.js'
import { parseAccount } from '../../accounts/utils/parseAccount.js'
import { getChainId } from '../../actions/public/getChainId.js'
import type {
SignTransactionErrorType,
SignTransactionReturnType,
} from '../../actions/wallet/signTransaction.js'
import { signTypedData } from '../../actions/wallet/signTypedData.js'
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import { AccountNotFoundError } from '../../errors/account.js'
import { BaseError } from '../../errors/base.js'
import type { GetAccountParameter } from '../../types/account.js'
import type {
ExtractChainFormatterParameters,
GetChainParameter,
} from '../../types/chain.js'
import type { UnionOmit } from '../../types/utils.js'
import { assertCurrentChain } from '../../utils/chain/assertCurrentChain.js'
import { getAction } from '../../utils/getAction.js'
import type { ChainEIP712 } from '../types/chain.js'
import type { TransactionRequestEIP712 } from '../types/transaction.js'
import {
type AssertEip712RequestParameters,
assertEip712Request,
} from '../utils/assertEip712Request.js'
type FormattedTransactionRequest<
chain extends ChainEIP712 | undefined = ChainEIP712 | undefined,
> = ExtractChainFormatterParameters<
chain,
'transactionRequest',
TransactionRequestEIP712
>
export type SignEip712TransactionParameters<
chain extends ChainEIP712 | undefined = ChainEIP712 | undefined,
account extends Account | undefined = Account | undefined,
chainOverride extends ChainEIP712 | undefined = ChainEIP712 | undefined,
> = UnionOmit<
FormattedTransactionRequest<
chainOverride extends ChainEIP712 ? chainOverride : chain
>,
'from'
> &
GetAccountParameter<account> &
GetChainParameter<chain, chainOverride>
export type SignEip712TransactionReturnType = SignTransactionReturnType
export type SignEip712TransactionErrorType = SignTransactionErrorType
/**
* Signs an EIP712 transaction.
*
*
* @param client - Client to use
* @param args - {@link SignTransactionParameters}
* @returns The signed serialized transaction. {@link SignTransactionReturnType}
*
* @example
* import { createWalletClient, custom } from 'viem'
* import { zksync } from 'viem/chains'
* import { signEip712Transaction } from 'viem/zksync'
*
* const client = createWalletClient({
* chain: zksync,
* transport: custom(window.ethereum),
* })
* const signature = await signEip712Transaction(client, {
* account: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e',
* to: '0x0000000000000000000000000000000000000000',
* value: 1n,
* })
*
* @example
* // Account Hoisting
* import { createWalletClient, http } from 'viem'
* import { privateKeyToAccount } from 'viem/accounts'
* import { zksync } from 'viem/chains'
* import { signEip712Transaction } from 'viem/zksync'
*
* const client = createWalletClient({
* account: privateKeyToAccount('0x…'),
* chain: zksync,
* transport: custom(window.ethereum),
* })
* const signature = await signEip712Transaction(client, {
* to: '0x0000000000000000000000000000000000000000',
* value: 1n,
* })
*/
export async function signEip712Transaction<
chain extends ChainEIP712 | undefined,
account extends Account | undefined,
chainOverride extends ChainEIP712 | undefined,
>(
client: Client<Transport, chain, account>,
args: SignEip712TransactionParameters<chain, account, chainOverride>,
): Promise<SignEip712TransactionReturnType> {
const {
account: account_ = client.account,
chain = client.chain,
...transaction
} = args
const account = account_ ? parseAccount(account_) : client.account
if (!account)
throw new AccountNotFoundError({
docsPath: '/docs/actions/wallet/signTransaction',
})
assertEip712Request({
account,
chain,
...(args as AssertEip712RequestParameters),
})
if (!chain?.custom?.getEip712Domain)
throw new BaseError('`getEip712Domain` not found on chain.')
if (!chain?.serializers?.transaction)
throw new BaseError('transaction serializer not found on chain.')
const chainId = await getAction(client, getChainId, 'getChainId')({})
if (chain !== null)
assertCurrentChain({
currentChainId: chainId,
chain: chain,
})
const eip712Domain = chain?.custom.getEip712Domain({
...transaction,
chainId,
from: account.address,
type: 'eip712',
})
const customSignature = await signTypedData(client, {
...eip712Domain,
account,
})
return chain?.serializers?.transaction(
{
chainId,
...transaction,
customSignature,
type: 'eip712' as any,
},
{ r: '0x0', s: '0x0', v: 0n },
) as SignEip712TransactionReturnType
}

95
node_modules/viem/zksync/actions/signTransaction.ts generated vendored Normal file
View File

@@ -0,0 +1,95 @@
import type { Account } from '../../accounts/types.js'
import type {
SignTransactionErrorType as SignTransactionErrorType_,
SignTransactionReturnType as SignTransactionReturnType_,
} from '../../actions/wallet/signTransaction.js'
import { signTransaction as signTransaction_ } from '../../actions/wallet/signTransaction.js'
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import type { GetAccountParameter } from '../../types/account.js'
import type {
ExtractChainFormatterParameters,
GetChainParameter,
} from '../../types/chain.js'
import type { UnionOmit } from '../../types/utils.js'
import type { ChainEIP712 } from '../types/chain.js'
import type { TransactionRequestEIP712 } from '../types/transaction.js'
import { isEIP712Transaction } from '../utils/isEip712Transaction.js'
import { signEip712Transaction } from './signEip712Transaction.js'
type FormattedTransactionRequest<
chain extends ChainEIP712 | undefined = ChainEIP712 | undefined,
> = ExtractChainFormatterParameters<
chain,
'transactionRequest',
TransactionRequestEIP712
>
export type SignTransactionParameters<
chain extends ChainEIP712 | undefined = ChainEIP712 | undefined,
account extends Account | undefined = Account | undefined,
chainOverride extends ChainEIP712 | undefined = ChainEIP712 | undefined,
> = UnionOmit<
FormattedTransactionRequest<
chainOverride extends ChainEIP712 ? chainOverride : chain
>,
'from'
> &
GetAccountParameter<account> &
GetChainParameter<chain, chainOverride>
export type SignTransactionReturnType = SignTransactionReturnType_
export type SignTransactionErrorType = SignTransactionErrorType_
/**
* Signs a transaction.
*
* - Docs: https://viem.sh/docs/zksync/actions/signTransaction
*
* @param args - {@link SignTransactionParameters}
* @returns The signed serialized transaction. {@link SignTransactionReturnType}
*
* @example
* import { createWalletClient, custom } from 'viem'
* import { zksync } from 'viem/chains'
* import { signTransaction } from 'viem/zksync'
*
* const client = createWalletClient({
* chain: zksync,
* transport: custom(window.ethereum),
* })
* const signature = await signTransaction(client, {
* account: '0xA0Cf798816D4b9b9866b5330EEa46a18382f251e',
* to: '0x0000000000000000000000000000000000000000',
* value: 1n,
* })
*
* @example
* // Account Hoisting
* import { createWalletClient, http } from 'viem'
* import { privateKeyToAccount } from 'viem/accounts'
* import { zksync } from 'viem/chains'
* import { signTransaction } from 'viem/zksync'
*
* const client = createWalletClient({
* account: privateKeyToAccount('0x…'),
* chain: zksync,
* transport: custom(window.ethereum),
* })
* const signature = await signTransaction(client, {
* to: '0x0000000000000000000000000000000000000000',
* value: 1n,
* })
*/
export async function signTransaction<
chain extends ChainEIP712 | undefined,
account extends Account | undefined,
chainOverride extends ChainEIP712 | undefined,
>(
client: Client<Transport, chain, account>,
args: SignTransactionParameters<chain, account, chainOverride>,
): Promise<SignTransactionReturnType> {
if (isEIP712Transaction(args)) return signEip712Transaction(client, args)
return await signTransaction_(client, args as any)
}

241
node_modules/viem/zksync/actions/withdraw.ts generated vendored Normal file
View File

@@ -0,0 +1,241 @@
import { type Address, parseAbi } from 'abitype'
import type { Account } from '../../accounts/types.js'
import { readContract } from '../../actions/public/readContract.js'
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import { AccountNotFoundError } from '../../errors/account.js'
import { ClientChainNotConfiguredError } from '../../errors/chain.js'
import type { GetAccountParameter } from '../../types/account.js'
import type { GetChainParameter } from '../../types/chain.js'
import type { UnionOmit } from '../../types/utils.js'
import type { EncodeFunctionDataReturnType } from '../../utils/abi/encodeFunctionData.js'
import {
encodeAbiParameters,
encodeFunctionData,
isAddressEqual,
keccak256,
parseAccount,
} from '../../utils/index.js'
import { ethTokenAbi, l2SharedBridgeAbi } from '../constants/abis.js'
import {
ethAddressInContracts,
l2AssetRouterAddress,
l2BaseTokenAddress,
l2NativeTokenVaultAddress,
legacyEthAddress,
} from '../constants/address.js'
import type { ChainEIP712 } from '../types/chain.js'
import type { ZksyncTransactionRequest } from '../types/transaction.js'
import { getDefaultBridgeAddresses } from './getDefaultBridgeAddresses.js'
import { getL1ChainId } from './getL1ChainId.js'
import { getL2TokenAddress } from './getL2TokenAddress.js'
import {
type SendTransactionErrorType,
type SendTransactionParameters,
type SendTransactionReturnType,
sendTransaction,
} from './sendTransaction.js'
export type WithdrawParameters<
chain extends ChainEIP712 | undefined = ChainEIP712 | undefined,
account extends Account | undefined = Account | undefined,
chainOverride extends ChainEIP712 | undefined = ChainEIP712 | undefined,
> = UnionOmit<
ZksyncTransactionRequest,
'from' | 'type' | 'value' | 'data' | 'to' | 'factoryDeps' | 'maxFeePerBlobGas'
> &
Partial<GetAccountParameter<account>> &
Partial<GetChainParameter<chain, chainOverride>> & {
/** The address of the recipient on L1. Defaults to the sender address. */
to?: Address | undefined
/** The address of the token. */
token: Address
/** The amount of the token to withdraw. */
amount: bigint
/** The address of the bridge contract to be used. */
bridgeAddress?: Address | undefined
}
export type WithdrawReturnType = SendTransactionReturnType
export type WithdrawErrorType = SendTransactionErrorType
/**
* Initiates the withdrawal process which withdraws ETH or any ERC20 token
* from the associated account on L2 network to the target account on L1 network.
*
* @param client - Client to use
* @param parameters - {@link WithdrawParameters}
* @returns hash - The [Transaction](https://viem.sh/docs/glossary/terms#transaction) hash. {@link WithdrawReturnType}
*
*
* @example
* import { createPublicClient, http } from 'viem'
* import { privateKeyToAccount } from 'viem/accounts'
* import { zksync } from 'viem/chains'
* import { withdraw, legacyEthAddress } from 'viem/zksync'
*
* const client = createPublicClient({
* chain: zksync,
* transport: http(),
* })
*
* const hash = await withdraw(client, {
* account: privateKeyToAccount('0x…'),
* amount: 1_000_000_000_000_000_000n,
* token: legacyEthAddress,
* })
*
* @example Account Hoisting
* import { createPublicClient, createWalletClient, http } from 'viem'
* import { privateKeyToAccount } from 'viem/accounts'
* import { zksync } from 'viem/chains'
* import { withdraw, legacyEthAddress } from 'viem/zksync'
*
* const client = createWalletClient({
* account: privateKeyToAccount('0x…'),
* chain: zksync,
* transport: http(),
* })
*
* const hash = await withdraw(client, {
* amount: 1_000_000_000_000_000_000n,
* token: legacyEthAddress,
* })
*
* @example Paymaster
* import { createPublicClient, http } from 'viem'
* import { privateKeyToAccount } from 'viem/accounts'
* import { zksync } from 'viem/chains'
* import {
* withdraw,
* legacyEthAddress,
* getApprovalBasedPaymasterInput
* } from 'viem/zksync'
*
* const client = createPublicClient({
* chain: zksync,
* transport: http(),
* })
*
* const hash = await withdraw(client, {
* account: privateKeyToAccount('0x…'),
* amount: 1_000_000_000_000_000_000n,
* token: legacyEthAddress,
* paymaster: '0x0EEc6f45108B4b806e27B81d9002e162BD910670',
* paymasterInput: getApprovalBasedPaymasterInput({
* minAllowance: 1n,
* token: '0x2dc3685cA34163952CF4A5395b0039c00DFa851D',
* innerInput: new Uint8Array(),
* }),
* })
*/
export async function withdraw<
chain extends ChainEIP712 | undefined,
account extends Account | undefined,
chainOverride extends ChainEIP712 | undefined = undefined,
>(
client: Client<Transport, chain, account>,
parameters: WithdrawParameters<chain, account, chainOverride>,
): Promise<WithdrawReturnType> {
let {
account: account_ = client.account,
chain: chain_ = client.chain,
token = l2BaseTokenAddress,
to,
amount,
bridgeAddress,
...rest
} = parameters
const account = account_ ? parseAccount(account_) : client.account
if (!account)
throw new AccountNotFoundError({
docsPath: '/docs/actions/wallet/sendTransaction',
})
if (!to) to = account.address
let data: EncodeFunctionDataReturnType
let contract: Address
let value = 0n
if (
isAddressEqual(token, legacyEthAddress) ||
isAddressEqual(token, ethAddressInContracts)
)
token = await getL2TokenAddress(client, { token: ethAddressInContracts })
if (isAddressEqual(token, l2BaseTokenAddress)) {
data = encodeFunctionData({
abi: ethTokenAbi,
functionName: 'withdraw',
args: [to],
})
value = amount
contract = l2BaseTokenAddress
} else {
const assetId = await readContract(client, {
address: l2NativeTokenVaultAddress,
abi: parseAbi(['function assetId(address token) view returns (bytes32)']),
functionName: 'assetId',
args: [token],
})
const originChainId = await readContract(client, {
address: l2NativeTokenVaultAddress,
abi: parseAbi([
'function originChainId(bytes32 assetId) view returns (uint256)',
]),
functionName: 'originChainId',
args: [assetId],
})
const l1ChainId = await getL1ChainId(client)
const isTokenL1Native =
originChainId === BigInt(l1ChainId) || token === ethAddressInContracts
if (!bridgeAddress) {
// If the legacy L2SharedBridge is deployed we use it for l1 native tokens.
bridgeAddress = isTokenL1Native
? (await getDefaultBridgeAddresses(client)).sharedL2
: l2AssetRouterAddress
}
// For non L1 native tokens we need to use the AssetRouter.
// For L1 native tokens we can use the legacy withdraw method.
if (!isTokenL1Native) {
contract = l2AssetRouterAddress
if (!chain_) throw new ClientChainNotConfiguredError()
const chainId = chain_.id
const assetId = keccak256(
encodeAbiParameters(
[{ type: 'uint256' }, { type: 'address' }, { type: 'address' }],
[BigInt(chainId), l2NativeTokenVaultAddress, token],
),
)
const assetData = encodeAbiParameters(
[{ type: 'uint256' }, { type: 'address' }, { type: 'address' }],
[BigInt(amount), to, token],
)
data = encodeFunctionData({
abi: parseAbi([
'function withdraw(bytes32 _assetId, bytes _transferData)',
]),
functionName: 'withdraw',
args: [assetId, assetData],
})
} else {
contract = bridgeAddress
data = encodeFunctionData({
abi: l2SharedBridgeAbi,
functionName: 'withdraw',
args: [to, token, amount],
})
}
}
return await sendTransaction(client, {
chain: chain_,
account,
to: contract,
data,
value,
...rest,
} as SendTransactionParameters)
}