UNPKG

viem

Version:

TypeScript Interface for Ethereum

438 lines • 19.9 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.deposit = deposit; const abitype_1 = require("abitype"); const estimateGas_js_1 = require("../../actions/public/estimateGas.js"); const readContract_js_1 = require("../../actions/public/readContract.js"); const waitForTransactionReceipt_js_1 = require("../../actions/public/waitForTransactionReceipt.js"); const sendTransaction_js_1 = require("../../actions/wallet/sendTransaction.js"); const writeContract_js_1 = require("../../actions/wallet/writeContract.js"); const public_js_1 = require("../../clients/decorators/public.js"); const abis_js_1 = require("../../constants/abis.js"); const address_js_1 = require("../../constants/address.js"); const account_js_1 = require("../../errors/account.js"); const chain_js_1 = require("../../errors/chain.js"); const index_js_1 = require("../../utils/index.js"); const abis_js_2 = require("../constants/abis.js"); const address_js_2 = require("../constants/address.js"); const number_js_1 = require("../constants/number.js"); const bridge_js_1 = require("../errors/bridge.js"); const applyL1ToL2Alias_js_1 = require("../utils/bridge/applyL1ToL2Alias.js"); const estimateGasL1ToL2_js_1 = require("./estimateGasL1ToL2.js"); const getBridgehubContractAddress_js_1 = require("./getBridgehubContractAddress.js"); const getDefaultBridgeAddresses_js_1 = require("./getDefaultBridgeAddresses.js"); const getL1Allowance_js_1 = require("./getL1Allowance.js"); async function deposit(client, parameters) { let { account: account_ = client.account, chain: chain_ = client.chain, client: l2Client, token, amount, approveToken, approveBaseToken, gas, } = parameters; const account = account_ ? (0, index_js_1.parseAccount)(account_) : client.account; if (!account) throw new account_js_1.AccountNotFoundError({ docsPath: '/docs/actions/wallet/sendTransaction', }); if (!l2Client.chain) throw new chain_js_1.ClientChainNotConfiguredError(); if ((0, index_js_1.isAddressEqual)(token, address_js_2.legacyEthAddress)) token = address_js_2.ethAddressInContracts; const bridgeAddresses = await (0, getDefaultBridgeAddresses_js_1.getDefaultBridgeAddresses)(l2Client); const bridgehub = await (0, getBridgehubContractAddress_js_1.getBridgehubContractAddress)(l2Client); const baseToken = await (0, readContract_js_1.readContract)(client, { address: bridgehub, abi: abis_js_2.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 (0, estimateGas_js_1.estimateGas)(client, { account: account.address, to: bridgehub, value: tx.value, data: tx.data, }); gas = scaleGasLimit(baseGasLimit); } return await (0, sendTransaction_js_1.sendTransaction)(client, { chain: chain_, account, gas, ...tx, }); } async function getL1DepositTx(client, account, parameters, bridgeAddresses, bridgehub, baseToken) { let { account: _account, chain: _chain, client: l2Client, token, amount, to, operatorTip = 0n, l2GasLimit, gasPerPubdataByte = number_js_1.requiredL1ToL2GasPerPubdataLimit, refundRecipient = address_js_1.zeroAddress, bridgeAddress, customBridgeData, value, gasPrice, maxFeePerGas, maxPriorityFeePerGas, approveToken: _approveToken, approveBaseToken: _approveBaseToken, ...rest } = parameters; if (!l2Client.chain) throw new chain_js_1.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; let data; const isETHBasedChain = (0, index_js_1.isAddressEqual)(baseToken, address_js_2.ethAddressInContracts); if ((isETHBasedChain && (0, index_js_1.isAddressEqual)(token, address_js_2.ethAddressInContracts)) || (0, index_js_1.isAddressEqual)(token, baseToken)) { mintValue = baseCost + operatorTip + amount; let providedValue = isETHBasedChain ? value : mintValue; if (!providedValue || providedValue === 0n) providedValue = mintValue; if (baseCost > providedValue) throw new bridge_js_1.BaseFeeHigherThanValueError(baseCost, providedValue); value = isETHBasedChain ? providedValue : 0n; bridgeAddress = bridgeAddresses.sharedL1; data = (0, index_js_1.encodeFunctionData)({ abi: abis_js_2.bridgehubAbi, functionName: 'requestL2TransactionDirect', args: [ { chainId: BigInt(l2Client.chain.id), mintValue: providedValue, l2Contract: to, l2Value: amount, l2Calldata: '0x', l2GasLimit, l2GasPerPubdataByteLimit: gasPerPubdataByte, factoryDeps: [], refundRecipient, }, ], }); } else if ((0, index_js_1.isAddressEqual)(baseToken, address_js_2.ethAddressInContracts)) { mintValue = baseCost + BigInt(operatorTip); value = mintValue; if (baseCost > mintValue) throw new bridge_js_1.BaseFeeHigherThanValueError(baseCost, mintValue); bridgeAddress ??= bridgeAddresses.sharedL1; data = (0, index_js_1.encodeFunctionData)({ abi: abis_js_2.bridgehubAbi, functionName: 'requestL2TransactionTwoBridges', args: [ { chainId: BigInt(l2Client.chain.id), mintValue, l2Value: 0n, l2GasLimit, l2GasPerPubdataByteLimit: gasPerPubdataByte, refundRecipient, secondBridgeAddress: bridgeAddress, secondBridgeValue: 0n, secondBridgeCalldata: (0, index_js_1.encodeAbiParameters)((0, abitype_1.parseAbiParameters)('address x, uint256 y, address z'), [token, amount, to]), }, ], }); } else if ((0, index_js_1.isAddressEqual)(token, address_js_2.ethAddressInContracts)) { mintValue = baseCost + operatorTip; value = amount; if (baseCost > mintValue) throw new bridge_js_1.BaseFeeHigherThanValueError(baseCost, mintValue); bridgeAddress = bridgeAddresses.sharedL1; data = (0, index_js_1.encodeFunctionData)({ abi: abis_js_2.bridgehubAbi, functionName: 'requestL2TransactionTwoBridges', args: [ { chainId: BigInt(l2Client.chain.id), mintValue, l2Value: 0n, l2GasLimit, l2GasPerPubdataByteLimit: gasPerPubdataByte, refundRecipient, secondBridgeAddress: bridgeAddress, secondBridgeValue: amount, secondBridgeCalldata: (0, index_js_1.encodeAbiParameters)((0, abitype_1.parseAbiParameters)('address x, uint256 y, address z'), [address_js_2.ethAddressInContracts, 0n, to]), }, ], }); } else { mintValue = baseCost + operatorTip; value ??= 0n; if (baseCost > mintValue) throw new bridge_js_1.BaseFeeHigherThanValueError(baseCost, mintValue); bridgeAddress ??= bridgeAddresses.sharedL1; data = (0, index_js_1.encodeFunctionData)({ abi: abis_js_2.bridgehubAbi, functionName: 'requestL2TransactionTwoBridges', args: [ { chainId: BigInt(l2Client.chain.id), mintValue, l2Value: 0n, l2GasLimit, l2GasPerPubdataByteLimit: gasPerPubdataByte, refundRecipient, secondBridgeAddress: bridgeAddress, secondBridgeValue: 0n, secondBridgeCalldata: (0, index_js_1.encodeAbiParameters)((0, abitype_1.parseAbiParameters)('address x, uint256 y, address z'), [token, amount, to]), }, ], }); } return { mintValue, tx: { bridgeAddress, to: bridgehub, data, value, gasPrice, maxFeePerGas, maxPriorityFeePerGas, ...rest, }, }; } async function approveTokens(client, chain, bridgeAddress, baseToken, mintValue, account, token, amount, approveToken, approveBaseToken) { if ((0, index_js_1.isAddressEqual)(baseToken, address_js_2.ethAddressInContracts)) { if (approveToken) { const overrides = typeof approveToken === 'boolean' ? {} : approveToken; const allowance = await (0, getL1Allowance_js_1.getL1Allowance)(client, { token, bridgeAddress, account, }); if (allowance < amount) { const hash = await (0, writeContract_js_1.writeContract)(client, { chain, account, address: token, abi: abis_js_1.erc20Abi, functionName: 'approve', args: [bridgeAddress, amount], ...overrides, }); await (0, waitForTransactionReceipt_js_1.waitForTransactionReceipt)(client, { hash }); } } return; } if ((0, index_js_1.isAddressEqual)(token, address_js_2.ethAddressInContracts)) { if (approveBaseToken) { const overrides = typeof approveToken === 'boolean' ? {} : approveToken; const allowance = await (0, getL1Allowance_js_1.getL1Allowance)(client, { token: baseToken, bridgeAddress, account, }); if (allowance < mintValue) { const hash = await (0, writeContract_js_1.writeContract)(client, { chain, account, address: baseToken, abi: abis_js_1.erc20Abi, functionName: 'approve', args: [bridgeAddress, mintValue], ...overrides, }); await (0, waitForTransactionReceipt_js_1.waitForTransactionReceipt)(client, { hash }); } return; } } if ((0, index_js_1.isAddressEqual)(token, baseToken)) { if (approveToken || approveBaseToken) { const overrides = typeof approveToken === 'boolean' ? {} : (approveToken ?? typeof approveBaseToken === 'boolean') ? {} : approveBaseToken; const allowance = await (0, getL1Allowance_js_1.getL1Allowance)(client, { token: baseToken, bridgeAddress, account, }); if (allowance < mintValue) { const hash = await (0, writeContract_js_1.writeContract)(client, { chain, account, address: baseToken, abi: abis_js_1.erc20Abi, functionName: 'approve', args: [bridgeAddress, mintValue], ...overrides, }); await (0, waitForTransactionReceipt_js_1.waitForTransactionReceipt)(client, { hash }); } } return; } if (approveBaseToken) { const overrides = typeof approveToken === 'boolean' ? {} : approveToken; const allowance = await (0, getL1Allowance_js_1.getL1Allowance)(client, { token: baseToken, bridgeAddress, account, }); if (allowance < mintValue) { const hash = await (0, writeContract_js_1.writeContract)(client, { chain, account, address: baseToken, abi: abis_js_1.erc20Abi, functionName: 'approve', args: [bridgeAddress, mintValue], ...overrides, }); await (0, waitForTransactionReceipt_js_1.waitForTransactionReceipt)(client, { hash }); } } if (approveToken) { const overrides = typeof approveToken === 'boolean' ? {} : approveToken; const allowance = await (0, getL1Allowance_js_1.getL1Allowance)(client, { token, bridgeAddress, account, }); if (allowance < amount) { const hash = await (0, writeContract_js_1.writeContract)(client, { chain, account, address: token, abi: abis_js_1.erc20Abi, functionName: 'approve', args: [bridgeAddress, amount], ...overrides, }); await (0, waitForTransactionReceipt_js_1.waitForTransactionReceipt)(client, { hash }); } } } async function getL2BridgeTxFeeParams(client, l2Client, bridgehub, gasPrice, from, token, amount, to, gasPerPubdataByte, baseToken, l2GasLimit, bridgeAddress, customBridgeData) { if (!l2Client.chain) throw new chain_js_1.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 (0, readContract_js_1.readContract)(client, { address: bridgehub, abi: abis_js_2.bridgehubAbi, functionName: 'l2TransactionBaseCost', args: [BigInt(l2Client.chain.id), gasPrice, l2GasLimit_, gasPerPubdataByte], }); return { l2GasLimit_, baseCost }; } async function getL2GasLimitFromDefaultBridge(client, l2Client, from, token, amount, to, gasPerPubdataByte, baseToken) { if ((0, index_js_1.isAddressEqual)(token, baseToken)) { return await (0, estimateGasL1ToL2_js_1.estimateGasL1ToL2)(l2Client, { chain: l2Client.chain, account: from, from, to, value: amount, data: '0x', gasPerPubdata: gasPerPubdataByte, }); } const value = 0n; const bridgeAddresses = await (0, getDefaultBridgeAddresses_js_1.getDefaultBridgeAddresses)(l2Client); const l1BridgeAddress = bridgeAddresses.sharedL1; const l2BridgeAddress = bridgeAddresses.sharedL2; const bridgeData = await encodeDefaultBridgeData(client, token); const calldata = (0, index_js_1.encodeFunctionData)({ abi: (0, abitype_1.parseAbi)([ 'function finalizeDeposit(address _l1Sender, address _l2Receiver, address _l1Token, uint256 _amount, bytes _data)', ]), functionName: 'finalizeDeposit', args: [ from, to, (0, index_js_1.isAddressEqual)(token, address_js_2.legacyEthAddress) ? address_js_2.ethAddressInContracts : token, amount, bridgeData, ], }); return await (0, estimateGasL1ToL2_js_1.estimateGasL1ToL2)(l2Client, { chain: l2Client.chain, account: (0, applyL1ToL2Alias_js_1.applyL1ToL2Alias)(l1BridgeAddress), to: l2BridgeAddress, data: calldata, gasPerPubdata: gasPerPubdataByte, value, }); } async function getL2GasLimitFromCustomBridge(client, l2Client, from, token, amount, to, gasPerPubdataByte, bridgeAddress, customBridgeData) { let customBridgeData_ = customBridgeData; if (!customBridgeData_ || customBridgeData_ === '0x') customBridgeData_ = await encodeDefaultBridgeData(client, token); const l2BridgeAddress = await (0, readContract_js_1.readContract)(client, { address: token, abi: (0, abitype_1.parseAbi)([ 'function l2BridgeAddress(uint256 _chainId) view returns (address)', ]), functionName: 'l2BridgeAddress', args: [BigInt(l2Client.chain.id)], }); const calldata = (0, index_js_1.encodeFunctionData)({ abi: (0, abitype_1.parseAbi)([ 'function finalizeDeposit(address _l1Sender, address _l2Receiver, address _l1Token, uint256 _amount, bytes _data)', ]), functionName: 'finalizeDeposit', args: [from, to, token, amount, customBridgeData_], }); return await (0, estimateGasL1ToL2_js_1.estimateGasL1ToL2)(l2Client, { chain: l2Client.chain, account: from, from: (0, applyL1ToL2Alias_js_1.applyL1ToL2Alias)(bridgeAddress), to: l2BridgeAddress, data: calldata, gasPerPubdata: gasPerPubdataByte, }); } async function encodeDefaultBridgeData(client, token) { let token_ = token; if ((0, index_js_1.isAddressEqual)(token, address_js_2.legacyEthAddress)) token_ = address_js_2.ethAddressInContracts; let name = 'Ether'; let symbol = 'ETH'; let decimals = 18n; if (!(0, index_js_1.isAddressEqual)(token_, address_js_2.ethAddressInContracts)) { name = await (0, readContract_js_1.readContract)(client, { address: token_, abi: abis_js_1.erc20Abi, functionName: 'name', args: [], }); symbol = await (0, readContract_js_1.readContract)(client, { address: token_, abi: abis_js_1.erc20Abi, functionName: 'symbol', args: [], }); decimals = BigInt(await (0, readContract_js_1.readContract)(client, { address: token_, abi: abis_js_1.erc20Abi, functionName: 'decimals', args: [], })); } const nameBytes = (0, index_js_1.encodeAbiParameters)([{ type: 'string' }], [name]); const symbolBytes = (0, index_js_1.encodeAbiParameters)([{ type: 'string' }], [symbol]); const decimalsBytes = (0, index_js_1.encodeAbiParameters)([{ type: 'uint256' }], [decimals]); return (0, index_js_1.encodeAbiParameters)([{ type: 'bytes' }, { type: 'bytes' }, { type: 'bytes' }], [nameBytes, symbolBytes, decimalsBytes]); } function scaleGasLimit(gasLimit) { return (gasLimit * BigInt(12)) / BigInt(10); } async function getFeePrice(client) { const client_ = client.extend(public_js_1.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, }; } //# sourceMappingURL=deposit.js.map