> ## Documentation Index
> Fetch the complete documentation index at: https://docs.celo.org/llms.txt
> Use this file to discover all available pages before exploring further.

# Withdrawing CELO from L2 to L1

In this tutorial, you will learn how to programmatically withdraw CELO from Celo Sepolia to Sepolia using the [viem OP Stack](https://viem.sh/op-stack).

## Steps to Withdraw CELO

Withdrawals require the user to submit three transactions:

1. [Withdrawal initiating a transaction](https://viem.sh/op-stack/actions/initiateWithdrawal), which the user submits on L2.
2. [Withdrawal proving transaction](https://viem.sh/op-stack/actions/proveWithdrawal), which the user submits on L1 to prove that the withdrawal is legitimate.
3. [Withdrawal finalizing transaction](https://viem.sh/op-stack/actions/finalizeWithdrawal), which the user submits on L1 after the fault challenge period has passed, to actually run the transaction on L1.

## Code Example

The following example demonstrates how to configure a file with all the details you need for interacting with the Celo Sepolia.

<CodeGroup>
  ```js index.js theme={null}
  import {
    createPublicClient,
    createWalletClient,
    http,
    parseEther,
  } from "viem";
  import { privateKeyToAccount } from "viem/accounts";
  import { celoSepolia, sepolia } from "viem/chains";
  import {
    publicActionsL1,
    walletActionsL2,
    walletActionsL1,
    publicActionsL2,
  } from "viem/op-stack";

  const account = privateKeyToAccount(
    "[PRIVATE_KEY]",
  );

  const value = parseEther("0.0001"); // Amount to Withdraw

  export const publicClientL1 = createPublicClient({
    chain: sepolia,
    transport: http(),
  }).extend(publicActionsL1());

  export const publicClientL2 = createPublicClient({
    chain: celoSepolia,
    transport: http(),
  }).extend(publicActionsL2());

  export const walletClientL1 = createWalletClient({
    chain: sepolia,
    transport: http(),
    account,
  }).extend(walletActionsL1());

  export const walletClientL2 = createWalletClient({
    chain: celoSepolia,
    transport: http(),
    account,
  }).extend(walletActionsL2());

  export default async function main() {
    console.log("Building Initiate Withdrawal...");
    const args = await publicClientL1.buildInitiateWithdrawal({
      account,
      to: account.address, // Receive on the same address on L1.
      value,
    });

    console.log("Initiaiting Withdrawal...");
    const hash = await walletClientL2.initiateWithdrawal(args);

    const initiateWithdrawalReceipt = await publicClientL2.waitForTransactionReceipt({
      hash
    });
    console.log(`Withdrawal Initiated: ${initiateWithdrawalReceipt}`);

    /**
     * The below step can take upto 2 hours!
     *
     * Hence, you may want to use viem's `getTimeToProve`.
     *
     * https://viem.sh/op-stack/actions/getTimeToProve
     *
     * Store the wait time in a database
     * and let the user know to come back later.
     *
     * */
    console.log("Waiting to prove...");
    const { output, withdrawal } = await publicClientL1.waitToProve({
      receipt: initiateWithdrawalReceipt,
      targetChain: walletClientL2.chain,
    });

    console.log("Building Prove Withdrawal...");
    const proveArgs = await publicClientL2.buildProveWithdrawal({
      output,
      withdrawal,
    });

    console.log("Proving Withdrawal...");
    const proveHash = await walletClientL1.proveWithdrawal(proveArgs);

    const proveReceipt = await publicClientL1.waitForTransactionReceipt({
      hash: proveHash,
    });
    console.log(`Withdrawal Proved: ${proveReceipt}`);

    /**
     * The below step can take a few minutes, ideally 2 minutes.
     *
     * Hence, you may want to use viem's `getTimeToFinalize`.
     *
     * https://viem.sh/op-stack/actions/getTimeToFinalize
     *
     * Store the wait time in a database
     * and let the user know to come back later.
     *
     *
    */
    console.log("Waiting To Finalize...");
    await publicClientL1.waitToFinalize({
      targetChain: walletClientL2.chain,
      withdrawalHash: withdrawal.withdrawalHash,
    });

    console.log("Finalizing Withdrawal...");
    const finalizeWithdrawalHash = await walletClientL1.finalizeWithdrawal({
      targetChain: walletClientL2.chain,
      withdrawal,
    });

    const finalizeWithdrawalReceipt = await publicClientL1.waitForTransactionReceipt({
      hash: finalizeWithdrawalHash,
    });
    console.log(`Withdrawal Finalized: ${finalizeWithdrawalReceipt}`)
  }


  ```
</CodeGroup>
