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

# Depository

> Fund a Layerswap swap by calling an on-chain contract instead of sending to a generated deposit address — ideal for smart-contract, server, and programmable wallets.

## Overview

The **Depository** is a Layerswap-operated smart contract that acts as an on-chain entry point for
funding a swap. Your wallet calls a single method on the Depository contract; it records the deposit,
tags it with the identifier of your swap, and forwards the funds to the solver that fills it.
Layerswap watches for the resulting `Deposited` event and progresses your swap automatically.

This is the recommended funding path when you are **integrating Layerswap as an aggregator**, or when
funding from a **smart-contract wallet, server wallet, or any programmable wallet** (e.g.
[Privy](/recipes/privy-wallets), Safe, account-abstraction wallets).

<Note>
  Layerswap encodes the call for you. When you create a swap with `use_depository: true`, the deposit
  action includes the contract address (`to_address`) and the fully encoded `call_data` — so the
  simplest path is to submit `call_data` as-is (plus a token approval for ERC20). The individual
  arguments, including the swap `id` and `receiver` that Layerswap assigns, are also returned in
  `encoded_args` if you'd rather build or verify the call yourself.
</Note>

The Depository is one of three ways to fund a swap — see
[Choosing a method](/api-reference/deposit-actions/choosing-a-method) for how it compares to a deposit
address or a direct transfer, and when to use each. The Depository and deposit-address methods are
**mutually exclusive** — setting both `use_depository: true` and `use_deposit_address: true` is rejected.

## Supported networks

* **EVM** chains where a Depository contract is deployed. Native and ERC20 deposits are both supported.
* **Tron** — **TRC20 tokens only**. Native TRX deposits via the Depository are not supported.

If you request `use_depository: true` on a network that does not have a Depository deployed, swap
creation fails with an "unsupported depository" error. The set of enabled networks grows over time —
always rely on the `to_address` returned by the API rather than hard-coding addresses (see
[Contract addresses](#contract-addresses)).

## How it works

1. **Create the swap** with `use_depository: true`.
2. **Fetch the deposit actions** (returned inline on swap creation, or via
   [`GET /swaps/{swapId}/deposit_actions`](/api-reference/swaps/get-deposit-actions)). The action's
   `to_address` is the Depository contract and `call_data` is the encoded deposit call.
3. **For ERC20 only:** approve the Depository contract (`to_address`) to spend the token amount.
4. **Submit the transaction** to `to_address` with the returned `call_data` (and `value` for native
   deposits — see below).
5. Layerswap detects the on-chain `Deposited` event, correlates it to your swap via the embedded
   `id`, and completes delivery on the destination chain.

## The contract

The Depository exposes two deposit methods:

```solidity theme={null}
// Native asset (ETH, etc.) — send the deposit amount as msg.value
function depositNative(bytes32 id, address receiver) external payable;

// ERC20 / TRC20 — requires prior approval of `amount` to this contract
function depositERC20(bytes32 id, address token, address receiver, uint256 amount) external;
```

On a successful deposit the contract emits:

```solidity theme={null}
event Deposited(
    bytes32 indexed id,        // identifies your swap; pre-encoded by Layerswap
    address indexed token,     // the deposited token (address(0) for native deposits)
    address indexed receiver,  // the solver that fills your swap
    uint256 amount
);
```

## Using the Depository via the API

### 1. Create the swap

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.layerswap.io/api/v2/swaps \
    -H "X-LS-APIKEY: $LAYERSWAP_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "source_network": "ETHEREUM_MAINNET",
      "source_token": "USDC",
      "destination_network": "ARBITRUM_MAINNET",
      "destination_token": "USDC",
      "destination_address": "0xYourRecipient",
      "amount": 100,
      "use_depository": true
    }'
  ```
</CodeGroup>

See the [Create Swap](/api-reference/swaps/create-swap) endpoint for the full request schema.

### 2. Read the deposit action

The response includes a `deposit_actions` array. For a Depository swap the relevant fields are:

| Field                             | Meaning                                                                                                                  |
| --------------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
| `to_address`                      | The Depository contract address on the source chain — your transaction target **and** the ERC20 approval target          |
| `call_data`                       | The fully encoded `depositNative` / `depositERC20` call — submit as-is                                                   |
| `amount` / `amount_in_base_units` | For **native** deposits: the value to send (`msg.value`), in decimal and base units. For **ERC20** deposits both are `0` |
| `token`                           | The token being deposited (`symbol`, `contract`, `decimals`)                                                             |
| `fee_token`                       | The gas asset on the network                                                                                             |
| `encoded_args`                    | The individual decoded arguments, in order, for inspection                                                               |
| `gas_limit`                       | Suggested gas limit                                                                                                      |
| `order`                           | Execution order when an action has multiple steps                                                                        |

<Tabs>
  <Tab title="ERC20 deposit">
    ```json theme={null}
    {
      "order": 0,
      "type": "transfer",
      "to_address": "0x<DepositoryContract>",
      "call_data": "0x<encoded depositERC20(id, token, receiver, amount)>",
      "amount": 0,
      "amount_in_base_units": "0",
      "token": { "symbol": "USDC", "contract": "0x<tokenContract>", "decimals": 6 },
      "fee_token": { "symbol": "ETH", "contract": null, "decimals": 18 },
      "encoded_args": [
        "0x0000…<id>",
        "0x<tokenContract>",
        "0x<receiver>",
        "0x<amountHex>"
      ],
      "gas_limit": "120000"
    }
    ```

    For ERC20 the top-level `amount` is `0` (no native value is sent). The token and amount live inside
    `call_data` / `encoded_args`, so you **must approve first** — see below.
  </Tab>

  <Tab title="Native deposit">
    ```json theme={null}
    {
      "order": 0,
      "type": "transfer",
      "to_address": "0x<DepositoryContract>",
      "call_data": "0x<encoded depositNative(id, receiver)>",
      "amount": 0.05,
      "amount_in_base_units": "50000000000000000",
      "token": { "symbol": "ETH", "contract": null, "decimals": 18 },
      "fee_token": { "symbol": "ETH", "contract": null, "decimals": 18 },
      "encoded_args": [
        "0x0000…<id>",
        "0x<receiver>"
      ],
      "gas_limit": "45000"
    }
    ```

    For native deposits, send `amount_in_base_units` as the transaction `value`.
  </Tab>
</Tabs>

### 3. Approve (ERC20 only)

Before calling `depositERC20`, approve the Depository contract (`to_address`) to spend the deposit
amount. Native deposits skip this step.

### 4. Submit the deposit transaction

<Tabs>
  <Tab title="EVM (viem)">
    ```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
    });
    ```
  </Tab>

  <Tab title="Tron (TronWeb)">
    ```ts TronWeb theme={null}
    import { TronWeb } from "tronweb";

    // `swap` is the POST /api/v2/swaps response; PRIVATE_KEY signs the deposit
    const action = swap.deposit_actions[0];
    const [id, , receiverHex, amountHex] = action.encoded_args; // [id, token, receiver, amount]
    const amount = BigInt(amountHex).toString();

    const tronWeb = new TronWeb({
      fullNode: action.network.node_url,
      solidityNode: action.network.node_url,
      privateKey: PRIVATE_KEY,
    });
    const sender = tronWeb.defaultAddress.base58;

    // encoded_args carry EVM-style hex addresses — convert the receiver to a Tron address
    const receiver = tronWeb.address.fromHex("41" + receiverHex.replace(/^0x/, ""));

    // 1) Approve the Depository (to_address) to spend the TRC-20 amount
    const approveTx = (
      await tronWeb.transactionBuilder.triggerSmartContract(
        action.token.contract, // TRC-20 token (base58)
        "approve(address,uint256)",
        { feeLimit: 100_000_000 },
        [
          { type: "address", value: action.to_address },
          { type: "uint256", value: amount },
        ],
        sender,
      )
    ).transaction;
    await tronWeb.trx.sendRawTransaction(await tronWeb.trx.sign(approveTx));

    // 2) Call depositERC20(bytes32 id, address token, address receiver, uint256 amount)
    //    on the Depository (wait for the approval to confirm first)
    const depositTx = (
      await tronWeb.transactionBuilder.triggerSmartContract(
        action.to_address, // Depository contract (base58)
        "depositERC20(bytes32,address,address,uint256)",
        { feeLimit: 100_000_000 },
        [
          { type: "bytes32", value: id },
          { type: "address", value: action.token.contract },
          { type: "address", value: receiver },
          { type: "uint256", value: amount },
        ],
        sender,
      )
    ).transaction;
    await tronWeb.trx.sendRawTransaction(await tronWeb.trx.sign(depositTx));
    ```
  </Tab>
</Tabs>

<Warning>
  The swap `id` and the `receiver` are assigned by Layerswap — use the exact values from the deposit
  action. Submitting `call_data` as-is is the safest option; if you instead rebuild the call from
  `encoded_args`, don't alter those two values, or Layerswap won't be able to match the on-chain
  deposit to your swap.
</Warning>

## Deposit detection

The `id` argument encoded in `call_data` ties your on-chain deposit to your swap. Layerswap monitors
the `Deposited` event and matches its `id` back to your swap, then fills the destination side. From
this point the swap follows the normal [swap lifecycle](/api-reference/swap-lifecycle).

## Contract addresses

The **authoritative** Depository address for a given swap is always the `to_address` returned in the
deposit action — read it per swap rather than caching a global value, since deployments are added
over time and a few chains use a different address.

Most EVM chains share a single deterministically-deployed Depository address. A small number of
chains (e.g. those where deterministic deployment wasn't possible) use a chain-specific address. In
all cases, trust the API response.

## Common errors

| Situation                                                       | What happens                                                                   |
| --------------------------------------------------------------- | ------------------------------------------------------------------------------ |
| `use_depository: true` on a network with no Depository deployed | Swap creation fails (unsupported depository)                                   |
| `use_depository: true` **and** `use_deposit_address: true`      | Rejected — the two methods are mutually exclusive                              |
| ERC20 deposit without sufficient approval to `to_address`       | On-chain revert; approve the Depository first                                  |
| Deposit to a `receiver` that isn't the one Layerswap assigned   | On-chain revert (`NotWhitelisted`); use the `receiver` from the deposit action |

## Related

* [Privy wallets recipe](/recipes/privy-wallets) — end-to-end Depository flow with a Privy server wallet
* [Get deposit actions](/api-reference/swaps/get-deposit-actions) — full response schema
* [Deposit Widget](/integration/UI/Widget/DepositWidget) — drop-in UI that handles this for you
* [Security](/security) — Depository audit report
