diff --git a/content/tutorials/how-to-withdraw-eth/10.index.md b/content/tutorials/how-to-withdraw-eth/10.index.md index c5096301..fab2bbc7 100644 --- a/content/tutorials/how-to-withdraw-eth/10.index.md +++ b/content/tutorials/how-to-withdraw-eth/10.index.md @@ -140,6 +140,92 @@ L2 Balance is 5712612651486983637 Withdraw transaction sent 0x4905176d42b4c3b4ab10f611e688b2d849e761493f4583119b7c7731b4254cf4 ``` +## Finalize withdrawal script + +Finalize withdrawal is the process that is run later on the L1 (once the L2 batches are proven), and which is actually responsible for transferring +the tokens into your account. + +This part is permissionless - so anyone can trigger it. In sepolia, this is done by the cronjob, that is run by the community, but on all the other chains +(mainnet, local networks), you have to trigger it yourself. + + +### withdraw-finalize.ts script + +```typescript +import { Wallet, Provider } from "zksync-ethers"; +import * as ethers from "ethers"; + +// load env file +import dotenv from "dotenv"; +dotenv.config(); + +// HTTP RPC endpoints +const L1_RPC_ENDPOINT = process.env.L1_RPC_ENDPOINT || ""; // or an RPC endpoint from Infura/Chainstack/QuickNode/etc. +const L2_RPC_ENDPOINT = process.env.L2_RPC_ENDPOINT || "https://sepolia.era.zksync.dev"; // or the ZKsync Era mainnet + +// Wallet +const WALLET_PRIV_KEY = process.env.WALLET_PRIV_KEY || ""; + + +if (!WALLET_PRIV_KEY) { + throw new Error("Wallet private key is not configured in env file"); +} + +if (!L1_RPC_ENDPOINT) { + throw new Error("Missing L1 RPC endpoint. Check chainlist.org or an RPC node provider"); +} + +async function main() { + // Please set your TX id, that you received from the withdraw.ts before. + const WITHDRAW_TX = "" + + console.log(`Finalizing withdrawal for ${WITHDRAW_TX}`); + + // Initialize the wallet. + const l1provider = new ethers.Provider(L1_RPC_ENDPOINT); + const l2provider = new Provider(L2_RPC_ENDPOINT); + const wallet = new Wallet(WALLET_PRIV_KEY, l2provider, l1provider); + + const isFinalized = await wallet.isWithdrawalFinalized(WITHDRAW_TX); + console.log("IS finalized ", isFinalized); + + if (isFinalized == true) { + console.log("Your withdrawal is already finalized. Your tokens should be on L1"); + console.log(`L1 Balance is ${await wallet.getBalanceL1()}`); + console.log(`L2 Balance is ${await wallet.getBalance()}`); + + } else { + console.log(`L1 Balance before is ${await wallet.getBalanceL1()}`); + console.log("Finalizing withdrawal now"); + + const result = await wallet.finalizeWithdrawal(WITHDRAW_TX); + console.log("Waiting for tx :", result.hash); + const receipt = await result.wait(); + + console.log("Receipt status: ", receipt?.status) + console.log(`L1 Balance after is ${await wallet.getBalanceL1()}`); + } + +} + +main() + .then() + .catch((error) => { + console.error(error); + process.exitCode = 1; + }); +``` + +### Run the Script + +Remember to set your withdrawal transaction from the previous step into the code at line 26 and execute the script using the following command: + +```sh +npx ts-node withdraw-finalize.ts +``` + + + ## Conclusion By following this guide, you have successfully withdrawn ETH from L2 to L1 using the ZKsync Javascript SDK.