layerzero-value-transfer ยท v1.0.0 ยท 2026-07-22 ยท sha256 9fdbab82d7264a5a
layerzero-value-transfer v1.0.0A
Immutable. This exact content is served forever at /api/v1/blob/9fdbab82d7264a5a.
---
name: "layerzero-value-transfer"
version: 1.0.0
description: Cross-chain asset transfers via the LayerZero Value Transfer API. Quote, execute, and track bridging of 450+ tokens across 150+ chains (EVM, Solana, Aptos, TON) using OFT, Stargate, CCTP, and Aori routes. Quote-then-execute workflow with status polling.
author: starchild
tags: [layerzero, bridge, cross-chain, defi, stargate, cctp, oft]
metadata: {"starchild":{"emoji":"๐","requires":{"bins":["curl"]}}}
---
# LayerZero Value Transfer API
Unified REST API for moving assets across 150+ blockchains. One endpoint consolidates
multiple bridge/swap protocols โ you get a quote, sign the returned transactions, and
poll for completion. Gas is paid on the source chain only.
**Base URL:** `https://transfer.layerzero-api.com/v1`
**Auth (Starchild): the key is injected by sc-proxy โ you do NOT set
`LAYERZERO_API_KEY`.** `transfer.layerzero-api.com` is a proxied domain, so route
transfer calls through `core.http_client` and the platform adds the real key. The
`x-api-key` header value can be anything (or omitted); the proxy overrides it.
```python
from core.http_client import proxied_post, proxied_get
r = proxied_post(
"https://transfer.layerzero-api.com/v1/quotes",
json=body,
headers={"x-api-key": "proxy", "SC-CALLER-ID": f"chat:{thread_id}"},
timeout=40,
)
```
Discovery endpoints (`/chains`, `/tokens`, `/metadata`) need no auth and work with
plain `curl` too. A direct `curl` to a transfer endpoint bypasses the proxy and
returns `{"error": "Unauthorized"}` โ use `proxied_*` for anything that needs the key.
## Route types
| Route | Protocol |
|---|---|
| `OFT` | Standard omnichain token transfer |
| `STARGATE_V2_TAXI` | Instant Stargate transfer |
| `STARGATE_V2_BUS` | Batched (cheaper, slower) Stargate transfer |
| `CCTP` | Circle native USDC |
| `AORI` | Intent-based swap (uses EIP-712 signatures) |
The API picks the optimal route; you don't normally need to choose.
## Workflow
```
1. GET /chains, /tokens โ discover routes (optional)
2. POST /quotes โ get quote.id, feeUsd, userSteps
3. Execute userSteps โ sign & send each tx (or EIP-712 signature)
4. GET /status/{quoteId} โ poll every ~4s until terminal
```
### 1. Discovery
```bash
curl -s https://transfer.layerzero-api.com/v1/chains
# โ { "chains": [{ "name": "Base", "chainKey": "base", "chainType": "EVM",
# "chainId": 8453, "nativeCurrency": { "symbol": "ETH", "decimals": 18,
# "address": "0xEeee...EEeE" } }, ...] }
# Note: results are under the "chains" key (not a bare array). chainType is
# uppercase: EVM, SOLANA, APTOS, SUI, TON, TRON, STARKNET, IOTAMOVE.
# Tokens receivable from a given source token:
curl -s "https://transfer.layerzero-api.com/v1/tokens?transferrableFromChainKey=base&transferrableFromTokenAddress=0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE"
# โ { "tokens": [{ chainKey, address, decimals, symbol, name, price.usd }, ...],
# "pagination": { "nextToken"? } } (results under the "tokens" key)
```
- Native token address is `0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE`.
- List endpoints paginate: pass `pagination[nextToken]` and keep fetching until
the response has no `nextToken`.
- `GET /metadata` returns contract deployment addresses per chain.
### 2. Get a quote
```python
from core.http_client import proxied_post
r = proxied_post(
"https://transfer.layerzero-api.com/v1/quotes",
json={
"srcChainKey": "base",
"dstChainKey": "optimism",
"srcTokenAddress": "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE",
"dstTokenAddress": "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE",
"srcWalletAddress": "0xYOUR_WALLET",
"dstWalletAddress": "0xYOUR_WALLET",
"amount": "1000000000000000",
"options": {
"amountType": "EXACT_SRC_AMOUNT",
"feeTolerance": {"type": "PERCENT", "amount": 2},
},
},
headers={"x-api-key": "proxy", "SC-CALLER-ID": f"chat:{thread_id}"},
timeout=40,
)
quote = r.json()["quotes"][0] # id, feeUsd, dstAmount, userSteps
```
Response shape: `{"error": null, "quotes": [{ "id", "routeSteps", "fees",
"feeUsd", "feePercent", "srcAmount", "dstAmount", "dstAmountMin", "userSteps" }]}`.
`quotes` is an array (the API may return several routes); take `quotes[0]` unless
you want to compare `feeUsd`.
- `amount` is a string in the token's local decimals (wei for ETH).
- Response: `quote.id`, `quote.feeUsd`, `quote.userSteps` (ordered transactions to
execute). Show the user `feeUsd` and expected output before executing.
### 3. Execute userSteps
**EVM:** loop through `userSteps` in order; each contains ready-to-send transaction
calldata. Sign with the agent wallet, send, and wait for confirmation before the next
step. ERC-20 transfers typically yield two steps: `approve` then the bridge tx.
**Solana:** transaction blockhashes expire in ~60s, so first regenerate fresh data:
```python
r = proxied_post(
"https://transfer.layerzero-api.com/v1/build-user-steps",
json={"quoteId": "QUOTE_ID"},
headers={"x-api-key": "proxy", "SC-CALLER-ID": f"chat:{thread_id}"},
)
```
**Signature steps (intent routes like AORI):** sign the EIP-712 payload in
`userStep.signature.typedData`, then submit:
```python
r = proxied_post(
"https://transfer.layerzero-api.com/v1/submit-signature",
json={"quoteId": "QUOTE_ID", "signatures": ["0xSIGNATURE"]},
headers={"x-api-key": "proxy", "SC-CALLER-ID": f"chat:{thread_id}"},
)
```
### 4. Poll status
```python
from core.http_client import proxied_get
r = proxied_get(
"https://transfer.layerzero-api.com/v1/status/QUOTE_ID",
params={"txHash": "0xSRC_TX_HASH"},
headers={"x-api-key": "proxy", "SC-CALLER-ID": f"chat:{thread_id}"},
)
# โ { "status": "PROCESSING", "explorerUrl": "..." }
```
Poll every ~4 seconds. Terminal states: `SUCCEEDED`, `FAILED`, `UNKNOWN`.
Non-terminal: `PENDING`, `PROCESSING`. Share `explorerUrl` with the user.
## Safety rules
- โ ๏ธ **Never approve the LZMulticall (Wrapper) contract as a token spender.** The
API-generated calldata already uses the TransferDelegate contract for approvals โ
execute steps as returned, don't hand-craft approvals.
- Quotes expire โ get a fresh quote if execution is delayed; don't reuse old ones.
- Always confirm with the user before signing/sending real-value transactions:
state source/destination chains, token, amount, and `feeUsd`.
- Verify the destination address matches the user's intent before quoting.
- On `FAILED` or `UNKNOWN`, report the `explorerUrl` and do not retry blindly.