> ## Documentation Index
> Fetch the complete documentation index at: https://layerswaplabsv0-babgev-deposit-actions-guide.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# EVM Chains

> Execute deposit transactions on Ethereum, Arbitrum, Optimism, Base, Polygon, and other EVM-compatible networks.

## Overview

This guide covers all EVM-compatible networks supported by Layerswap, including Ethereum, Arbitrum, Optimism, Base, Polygon, Linea, zkSync Era, Scroll, and others.

**Prerequisites:**

* [viem](https://viem.sh/) (recommended) or [ethers.js](https://docs.ethers.org/)
* A wallet client or signer with funds on the source network

## call\_data Format

For EVM chains, `call_data` is a **hex-encoded string** (`0x...`) representing the transaction's `data` field. It always carries a Layerswap memo (a fixed prefix followed by a sequence number) that the backend uses to match the deposit:

* **Native token transfers** (ETH, MATIC, etc.): `call_data` is the memo hex. `to_address` is the deposit address and `amount` / `amount_in_base_units` carry the value to send.
* **ERC-20 token transfers**: `call_data` is the encoded `transfer(address,uint256)` function call with the memo hex appended. `to_address` is the **token contract**, and `amount` / `amount_in_base_units` are `0` — the actual transfer value is encoded inside `call_data`.

In both cases, build the transaction with `to: to_address`, `value: amount`, and `data: call_data` and the wallet will route it correctly.

## Transaction Construction

<Steps>
  <Step title="Parse the deposit action">
    Extract `call_data`, `to_address`, `amount`, and `network.chain_id` from the deposit action.
  </Step>

  <Step title="Build the transaction">
    Construct a transaction object with the deposit action fields mapped to standard EVM transaction parameters.
  </Step>

  <Step title="Estimate gas (optional)">
    Call `eth_estimateGas` for a more accurate gas limit. If estimation fails, the transaction can still be sent without an explicit gas limit — the wallet or node will estimate it.
  </Step>

  <Step title="Send the transaction">
    Sign and broadcast the transaction, then return the hash.
  </Step>
</Steps>

## Full Example

Pick the library that fits your stack. The `viem` and `ethers.js` tabs cover server-side or Node.js usage. The `wagmi` tab is for browser-side use with a connected wallet.

<CodeGroup>
  ```typescript viem theme={null}
  import { createWalletClient, createPublicClient, http, parseEther } from "viem";
  import { privateKeyToAccount } from "viem/accounts";
  import { mainnet, arbitrum, optimism, base, polygon } from "viem/chains";

  const CHAIN_MAP = {
    1: mainnet,
    42161: arbitrum,
    10: optimism,
    8453: base,
    137: polygon,
    // Add other EVM chains as needed
  };

  async function executeEvmDeposit(depositAction, privateKey) {
    const { call_data, to_address, amount, network } = depositAction;
    const chainId = Number(network.chain_id);
    const chain = CHAIN_MAP[chainId];

    if (!chain) {
      throw new Error(`Unsupported chain ID: ${chainId}`);
    }

    const account = privateKeyToAccount(privateKey);

    const walletClient = createWalletClient({
      account,
      chain,
      transport: http(network.node_url),
    });

    const publicClient = createPublicClient({
      chain,
      transport: http(network.node_url),
    });

    // Estimate gas
    let gas;
    try {
      gas = await publicClient.estimateGas({
        account: account.address,
        to: to_address,
        value: parseEther(amount.toString()),
        data: call_data,
      });
    } catch (error) {
      console.warn("Gas estimation failed, proceeding without explicit gas limit");
    }

    // Send transaction
    const hash = await walletClient.sendTransaction({
      to: to_address,
      value: parseEther(amount.toString()),
      data: call_data,
      gas,
    });

    return hash;
  }
  ```

  ```typescript ethers.js theme={null}
  import { ethers } from "ethers";

  async function executeEvmDeposit(depositAction, privateKey) {
    const { call_data, to_address, amount, network } = depositAction;

    const provider = new ethers.JsonRpcProvider(network.node_url);
    const wallet = new ethers.Wallet(privateKey, provider);

    // Estimate gas
    let gasLimit;
    try {
      gasLimit = await provider.estimateGas({
        from: wallet.address,
        to: to_address,
        value: ethers.parseEther(amount.toString()),
        data: call_data,
      });
    } catch (error) {
      console.warn("Gas estimation failed, proceeding without explicit gas limit");
    }

    // Send transaction
    const tx = await wallet.sendTransaction({
      to: to_address,
      value: ethers.parseEther(amount.toString()),
      data: call_data,
      gasLimit,
    });

    return tx.hash;
  }
  ```

  ```typescript wagmi theme={null}
  import { sendTransaction } from "@wagmi/core";
  import { parseEther } from "viem";

  async function executeEvmDeposit(depositAction, wagmiConfig) {
    const { call_data, to_address, amount, network } = depositAction;

    const hash = await sendTransaction(wagmiConfig, {
      chainId: Number(network.chain_id),
      to: to_address,
      value: parseEther(amount.toString()),
      data: call_data,
    });

    return hash;
  }
  ```
</CodeGroup>

<Note>
  When using a browser wallet ([wagmi](https://wagmi.sh/)), ensure the user is connected to the correct chain (`network.chain_id`). If not, prompt them to switch networks before sending the transaction.
</Note>

## Funding via the Depository

The example above covers the **direct transfer** and **deposit address** methods. If you created the swap
with `use_depository: true`, the deposit action targets the on-chain
[Depository](/api-reference/depository) contract instead — submit its `call_data`, and for ERC-20 approve
the contract first:

```ts viem theme={null}
import { createWalletClient, custom, parseAbi } from "viem";

// `swap` is the POST /api/v2/swaps response
const action = swap.deposit_actions[0];
const wallet = createWalletClient({ transport: custom(window.ethereum) });

// ERC-20 only: approve the Depository (to_address) to pull the tokens.
// The amount is the 4th depositERC20 argument, returned in encoded_args.
if (action.token.contract) {
  await wallet.writeContract({
    address: action.token.contract,
    abi: parseAbi(["function approve(address spender, uint256 amount) returns (bool)"]),
    functionName: "approve",
    args: [action.to_address, BigInt(action.encoded_args[3])],
  });
}

// Submit the prepared depositNative / depositERC20 call exactly as returned
await wallet.sendTransaction({
  to: action.to_address, // the Depository contract
  data: action.call_data,
  value: BigInt(action.amount_in_base_units), // 0 for ERC-20, the deposit amount for native
});
```

See [Choosing a method](/api-reference/deposit-actions/choosing-a-method) for when to use each.

## Next Step

After the transaction is submitted, notify Layerswap so it can match your deposit faster:

```bash theme={null}
curl -X POST https://api.layerswap.io/api/v2/swaps/{swap_id}/deposit_speedup \
  -H "X-LS-APIKEY: your_api_key" \
  -H "Content-Type: application/json" \
  -d '{ "transaction_id": "YOUR_TX_HASH" }'
```

See the [full deposit flow](/api-reference/deposit-actions/overview) for details, or the [Depository](/api-reference/depository) guide to fund via the on-chain contract (`use_depository`).
