Skip to main content

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 (recommended) or ethers.js
  • 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

1

Parse the transfer action

Extract call_data, to_address, amount, and network.chain_id from the transfer action.
2

Build the transaction

Construct a transaction object with the transfer action fields mapped to standard EVM transaction parameters.
3

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.
4

Send the transaction

Sign and broadcast the transaction, then return the hash.

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.
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;
}
When using a browser wallet (wagmi), ensure the user is connected to the correct chain (network.chain_id). If not, prompt them to switch networks before sending the transaction.

Next Step

After the transaction is submitted, notify Layerswap so it can match your deposit faster:
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 for details.