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

# Contracts

> How the Value Transfer API's contracts handle token approvals, bridge execution, and fees on each chain.

The Value Transfer API relies on three contracts per EVM chain: the **TransferDelegate** (handles token approvals), the **LZMulticall** (batches and executes bridge transactions), and the **Treasury** (collects fees).

<Note>
  **Setting token allowances**

  The Value Transfer API uses two separate contracts for approvals and execution. The **TransferDelegate** is the only contract that should be approved as a token spender. The **LZMulticall** (Wrapper) batches and executes bridge transactions but does not need or support token allowances.

  The API's approve `userStep` already encodes the correct TransferDelegate address in its calldata, so you don't need to look up or hardcode any contract address. Execute the step as returned.

  See [Contract Addresses](/v2/developers/value-transfer-api/contracts/addresses) for the Wrapper and Delegate addresses on each chain.
</Note>

## Contract architecture

Token transfers go through two contracts in sequence: the **Delegate** pulls tokens, then the **Wrapper** executes the bridge. A third contract, the **Treasury**, collects fees behind the scenes.

| Contract                    | Role                                 | Function                                        |
| --------------------------- | ------------------------------------ | ----------------------------------------------- |
| TransferDelegate (Delegate) | Approved spender for ERC20 transfers | `delegateTransferFrom(token, from, to, amount)` |
| LZMulticall (Wrapper)       | Batches and executes bridge calls    | `execute(calls, quoteId)`                       |
| Treasury                    | Fee collection                       | `getFees()`                                     |

## TransferDelegate (Delegate)

This is the contract users approve as the ERC20 spender. One function:

```
delegateTransferFrom(address token, address from, address to, uint256 amount)
```

When LZMulticall executes a bridge, it calls TransferDelegate to pull tokens from the user's wallet. That call only succeeds if the user has already approved TransferDelegate for that token.

The approve `userStep` returned by the API already encodes the TransferDelegate address in its calldata. No need to look it up or hardcode it.

## LZMulticall (Wrapper)

LZMulticall is a batch executor. It takes an array of calls and runs them in a single transaction, routing bridge operations through LayerZero.

Each LZMulticall deploys its own TransferDelegate in the constructor, so the two contracts are always paired 1:1. You can look up the paired Delegate address via the `TRANSFER_DELEGATE` getter on any LZMulticall deployment.

There are two execution modes:

* **Direct execution** — the caller is the signer. The API's bridge `userStep` uses this mode.
* **Signature-based execution** — a third party submits a pre-signed EIP-712 payload on behalf of the signer. Includes an expiration timestamp and per-signer nonce for replay protection.

When a call in the batch targets TransferDelegate, LZMulticall validates that the `from` address in the calldata matches the signer. One user can't move another user's tokens through the Delegate, even within the same batch.

The contract also has a `sweep()` function that recovers any ETH or tokens left over after execution.

LZMulticall is also the fee wrapper. Inside each `execute()` call, the batch deducts fees from the transfer amount and sends them to the Treasury before running the bridge. See [Fees](#fees) for details.

<Danger>
  **Never approve the LZMulticall (Wrapper) contract as a token spender**

  LZMulticall can forward arbitrary calls to any contract. If you approve it as a spender on any token, anyone can drain those tokens. Only approve the **TransferDelegate** as the spender.
</Danger>

## Treasury

Treasury collects fees for cross-chain transfers using basis points on native currency.

```
getFees(bool payInZro, uint256 relayerFee, uint256 oracleFee)
```

You don't interact with Treasury directly. The API calculates fees and includes the amounts in the bridge transaction's `value` field.

## Fees

LZMulticall is also the fee wrapper. Inside `execute()`, the batched calls deduct fees and send them to the Treasury before bridging the rest. The API builds this into the bridge `userStep` for you.

### Fee types

Up to three fees can apply per transfer:

| Fee              | Type       | Description                                                             |
| ---------------- | ---------- | ----------------------------------------------------------------------- |
| Base Fee         | Percentage | A percentage of the transfer amount.                                    |
| Partner Fee      | Percentage | A partner commission, configured per API key.                           |
| CCTP Receive Fee | Fixed      | A flat fee on CCTP (Circle) routes for destination-chain receive costs. |

Zero-amount fees are omitted. The total is subtracted from the source amount before bridging, so the destination amount is the post-fee value.

### How fees flow through the contracts

The fee mechanism depends on the token type:

**Native tokens (e.g., ETH):**

1. Call `LZMulticall.execute()` with `msg.value` set to the fee plus the bridge cost.
2. Inside the batch, one call sends the fee to the Treasury.
3. The remaining calls run the bridge.

**ERC20 tokens (e.g., USDC):**

1. Approve TransferDelegate for the full source amount (fees included).
2. Call `LZMulticall.execute()`.
3. Inside the batch, TransferDelegate pulls the full token amount from the user to the Wrapper.
4. A transfer sends the fee portion from the Wrapper to Treasury.
5. The remaining calls bridge the post-fee amount.

### Tracking

Each `execute()` call includes a `quoteId`. On confirmation, LZMulticall emits an `Executed(signer, quoteId, nonce)` event. The API uses this event to attribute the transfer to the API key that requested the quote, linking volume and fee data back to each integration.

## How the contracts work together

A typical ERC20 cross-chain transfer:

1. You request a quote. The API returns two `userSteps`: approve and bridge.
2. The **approve step** calls the ERC20 token's `approve()` with TransferDelegate as spender.
3. The **bridge step** calls LZMulticall's `execute()` on the source chain.
4. Inside that execution, LZMulticall calls `TransferDelegate.delegateTransferFrom()` to pull the full token amount (fees included) from your wallet to the Wrapper.
5. LZMulticall sends the fee portion to Treasury and bridges the remaining amount.

| Step    | `transaction.encoded.to`          | What it does                              |
| ------- | --------------------------------- | ----------------------------------------- |
| Approve | ERC20 token contract (e.g., USDC) | Calls `approve(TransferDelegate, amount)` |
| Bridge  | LZMulticall contract              | Routes the bridge through LayerZero       |

## Contract addresses

Each chain has its own Wrapper and Delegate deployments. See [Contract Addresses](/v2/developers/value-transfer-api/contracts/addresses) for the full list.

## Related

* [Executing userSteps safely](/v2/developers/value-transfer-api/api-reference/quotes#executing-usersteps-safely)
* [EVM Example](/v2/developers/value-transfer-api/examples/evm)
