From 405f98ab2958940ef0b8d3e35b4b6a3b3fbdb2ab Mon Sep 17 00:00:00 2001 From: Aren Date: Thu, 5 Mar 2026 18:46:01 +0400 Subject: [PATCH 1/7] Add Handling Deposits section to documentation - Introduced a new group for Handling Deposits in the documentation - Added pages for various deposit actions including EVM, Bitcoin, Solana, and others --- api-reference/deposit-actions/bitcoin.mdx | 291 +++++++++++++++++++++ api-reference/deposit-actions/evm.mdx | 176 +++++++++++++ api-reference/deposit-actions/fuel.mdx | 204 +++++++++++++++ api-reference/deposit-actions/overview.mdx | 118 +++++++++ api-reference/deposit-actions/solana.mdx | 197 ++++++++++++++ api-reference/deposit-actions/starknet.mdx | 149 +++++++++++ api-reference/deposit-actions/ton.mdx | 261 ++++++++++++++++++ api-reference/deposit-actions/tron.mdx | 147 +++++++++++ docs.json | 13 + 9 files changed, 1556 insertions(+) create mode 100644 api-reference/deposit-actions/bitcoin.mdx create mode 100644 api-reference/deposit-actions/evm.mdx create mode 100644 api-reference/deposit-actions/fuel.mdx create mode 100644 api-reference/deposit-actions/overview.mdx create mode 100644 api-reference/deposit-actions/solana.mdx create mode 100644 api-reference/deposit-actions/starknet.mdx create mode 100644 api-reference/deposit-actions/ton.mdx create mode 100644 api-reference/deposit-actions/tron.mdx diff --git a/api-reference/deposit-actions/bitcoin.mdx b/api-reference/deposit-actions/bitcoin.mdx new file mode 100644 index 0000000..2375d42 --- /dev/null +++ b/api-reference/deposit-actions/bitcoin.mdx @@ -0,0 +1,291 @@ +--- +title: 'Bitcoin' +description: 'Execute deposit transactions on Bitcoin mainnet and testnet using PSBT construction.' +--- + +## Overview + +Bitcoin deposits use a UTXO-based model. The `call_data` from the deposit action is a **numeric memo** that must be embedded in the transaction as an `OP_RETURN` output. This memo is how Layerswap identifies and matches your deposit. + +**Prerequisites:** +- [bitcoinjs-lib](https://github.com/bitcoinjs/bitcoinjs-lib) for PSBT construction +- [@bitcoinerlab/secp256k1](https://github.com/nicolo-ribaudo/bitcoinerlab-secp256k1) for elliptic curve operations +- Access to a Bitcoin node or the [Mempool.space API](https://mempool.space/docs/api) for UTXO data and fee estimates + +## call_data Format + +For Bitcoin, `call_data` is a **numeric string** representing a memo identifier. Before embedding it into the transaction, convert it to a hex string: + +```javascript +const hexMemo = Number(callData).toString(16); +``` + +This hex memo is embedded as an `OP_RETURN` output in the transaction. + +## Transaction Construction + + + + Retrieve unspent transaction outputs for the sender's address. You can use the Mempool.space API or your own Bitcoin node. + + + For each UTXO, fetch the full raw transaction hex. This is needed to populate the `witnessUtxo` field in the PSBT inputs. + + + Select enough UTXOs to cover the deposit amount plus estimated fees. + + + Create a PSBT with: + - **Inputs**: Selected UTXOs with witness data + - **Output 1**: Payment to `to_address` for the deposit `amount` + - **Output 2**: `OP_RETURN` with the hex-encoded memo + - **Output 3** (if needed): Change back to the sender's address + + + Fetch the recommended fee rate from Mempool.space and calculate the transaction fee based on input/output count. Re-select UTXOs if the initial selection doesn't cover the fee. + + + Sign the PSBT with your private key and broadcast the raw transaction. + + + +## Full Example + +```typescript +import { + Psbt, + Transaction, + networks, + opcodes, + script, + initEccLib, + payments, +} from "bitcoinjs-lib"; +import * as ecc from "@bitcoinerlab/secp256k1"; +import ECPairFactory from "ecpair"; +import axios from "axios"; + +initEccLib(ecc); +const ECPair = ECPairFactory(ecc); + +interface Utxo { + txid: string; + vout: number; + value: number; + status: { confirmed: boolean }; +} + +const MEMPOOL_BASE = { + mainnet: "https://mempool.space", + testnet: "https://mempool.space/testnet", +}; + +async function fetchUtxos( + address: string, + version: "mainnet" | "testnet" +): Promise { + const base = MEMPOOL_BASE[version]; + const { data } = await axios.get( + `${base}/api/address/${address}/utxo` + ); + return data; +} + +async function fetchRawTx( + txid: string, + version: "mainnet" | "testnet" +): Promise { + const base = MEMPOOL_BASE[version]; + const { data } = await axios.get(`${base}/api/tx/${txid}/hex`); + return Transaction.fromHex(data); +} + +async function fetchFeeRate( + version: "mainnet" | "testnet" +): Promise { + const base = MEMPOOL_BASE[version]; + const { data } = await axios.get(`${base}/api/v1/fees/recommended`); + return data.economyFee; // sats/vByte +} + +function selectUtxos( + utxos: Utxo[], + target: bigint +): { selected: Utxo[]; total: bigint } { + const sorted = utxos.slice().sort((a, b) => a.value - b.value); + let sum = 0n; + const selected: Utxo[] = []; + for (const u of sorted) { + selected.push(u); + sum += BigInt(u.value); + if (sum >= target) break; + } + if (sum < target) { + throw new Error(`Insufficient funds: need ${target} sats, have ${sum}`); + } + return { selected, total: sum }; +} + +function estimateTxFee( + numInputs: number, + numOutputs: number, + satsPerVbyte: number +): bigint { + return BigInt((numInputs * 148 + numOutputs * 34 + 10) * satsPerVbyte); +} + +async function executeBitcoinDeposit( + depositAction: any, + senderAddress: string, + senderWIF: string, + isTestnet = false +) { + const { call_data, to_address, amount } = depositAction; + const version = isTestnet ? "testnet" : "mainnet"; + const network = isTestnet ? networks.testnet : networks.bitcoin; + const amountSats = Math.floor(amount * 1e8); + + // Convert numeric memo to hex for OP_RETURN + const hexMemo = Number(call_data).toString(16); + const memoBuffer = Buffer.from(hexMemo, "utf8"); + + if (memoBuffer.length > 80) { + throw new Error("Memo too long; max 80 bytes for OP_RETURN"); + } + + // Fetch UTXOs and fee rate + const utxos = await fetchUtxos(senderAddress, version); + const feeRate = await fetchFeeRate(version); + + // Iteratively build PSBT to account for fees + let fee = 0n; + let psbt: Psbt; + let totalSelected: bigint; + + do { + const target = BigInt(amountSats) + fee; + const { selected, total } = selectUtxos(utxos, target); + totalSelected = total; + + psbt = new Psbt({ network }); + + // Add inputs + for (const utxo of selected) { + const rawTx = await fetchRawTx(utxo.txid, version); + const out = rawTx.outs[utxo.vout]; + psbt.addInput({ + hash: utxo.txid, + index: utxo.vout, + witnessUtxo: { script: out.script, value: out.value }, + }); + } + + // Payment output + psbt.addOutput({ + address: to_address, + value: BigInt(amountSats), + }); + + // OP_RETURN memo output + psbt.addOutput({ + script: script.compile([opcodes.OP_RETURN, memoBuffer]), + value: 0n, + }); + + // Re-estimate fee + fee = estimateTxFee( + psbt.txInputs.length, + psbt.txOutputs.length + 1, // +1 for potential change output + feeRate + ); + } while (totalSelected < BigInt(amountSats) + fee); + + // Change output + const change = totalSelected - BigInt(amountSats) - fee; + if (change > 0n) { + psbt.addOutput({ address: senderAddress, value: change }); + } + + // Sign all inputs + const keyPair = ECPair.fromWIF(senderWIF, network); + const isTaproot = + senderAddress.startsWith("bc1p") || senderAddress.startsWith("tb1p"); + + for (let i = 0; i < psbt.inputCount; i++) { + if (isTaproot) { + psbt.signInput(i, keyPair, [Transaction.SIGHASH_DEFAULT]); + } else { + psbt.signInput(i, keyPair); + } + } + + psbt.finalizeAllInputs(); + const rawTxHex = psbt.extractTransaction().toHex(); + + // Broadcast via Mempool.space + const { data: txHash } = await axios.post( + `${MEMPOOL_BASE[version]}/api/tx`, + rawTxHex, + { headers: { "Content-Type": "text/plain" } } + ); + + return txHash; +} +``` + +## Signing for Different Address Types + +Bitcoin has several address formats, each with different signing requirements: + +| Address Prefix | Type | Sighash | +|---|---|---| +| `1...` | Legacy (P2PKH) | `SIGHASH_ALL` (1) | +| `3...` | Nested SegWit (P2SH-P2WPKH) | `SIGHASH_ALL` (1) | +| `bc1q...` / `tb1q...` | Native SegWit (P2WPKH) | `SIGHASH_ALL` (1) | +| `bc1p...` / `tb1p...` | Taproot (P2TR) | `SIGHASH_DEFAULT` (0) | + + + Taproot addresses require `SIGHASH_DEFAULT` (0) instead of `SIGHASH_ALL` (1). Using the wrong sighash type will produce an invalid signature. + + +## Hardware / Browser Wallet Signing + +If you're using a wallet provider (e.g., Xverse, Unisat, Leather) instead of a raw private key, the flow changes at the signing step. Instead of signing locally, you pass the unsigned PSBT hex to the wallet's `signPsbt` method: + +```typescript +const psbtHex = psbt.toHex(); +const isTaproot = + senderAddress.startsWith("bc1p") || senderAddress.startsWith("tb1p"); + +const signedPsbtHex = await walletProvider.request({ + method: "signPsbt", + params: { + psbt: psbtHex, + inputsToSign: [ + { + address: senderAddress, + signingIndexes: Array.from({ length: psbt.inputCount }, (_, i) => i), + sigHash: isTaproot ? 0 : 1, + }, + ], + finalize: false, + }, +}); + +const signedPsbt = Psbt.fromHex(signedPsbtHex); +signedPsbt.finalizeAllInputs(); +const rawTxHex = signedPsbt.extractTransaction().toHex(); +``` + +## Next Step + +After the transaction is submitted, notify Layerswap so it can match your deposit faster: + +```bash +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. \ No newline at end of file diff --git a/api-reference/deposit-actions/evm.mdx b/api-reference/deposit-actions/evm.mdx new file mode 100644 index 0000000..8591b72 --- /dev/null +++ b/api-reference/deposit-actions/evm.mdx @@ -0,0 +1,176 @@ +--- +title: 'EVM Chains' +description: '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: + +- **Native token transfers** (ETH, MATIC, etc.): `call_data` may be `0x` or contain contract interaction data if routed through a contract. +- **ERC-20 token transfers**: `call_data` contains the encoded `transfer(address,uint256)` function call or a more complex contract interaction. + +The `to_address` from the deposit action is the transaction recipient, and `amount` is in human-readable units. + +## Transaction Construction + + + + Extract `call_data`, `to_address`, `amount`, and `network.chain_id` from the deposit action. + + + Construct a transaction object with the deposit action fields mapped to standard EVM transaction parameters. + + + 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. + + + Sign and broadcast the transaction, then return the hash. + + + +## Full Example with viem + +```typescript +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; +} +``` + +## Full Example with ethers.js + +```typescript +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; +} +``` + +## Browser Wallet Example (wagmi) + +If your users connect wallets through a browser, you can use [wagmi](https://wagmi.sh/): + +```typescript +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; +} +``` + + + When using a browser wallet, 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: + +```bash +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. \ No newline at end of file diff --git a/api-reference/deposit-actions/fuel.mdx b/api-reference/deposit-actions/fuel.mdx new file mode 100644 index 0000000..69f928a --- /dev/null +++ b/api-reference/deposit-actions/fuel.mdx @@ -0,0 +1,204 @@ +--- +title: 'Fuel' +description: 'Execute deposit transactions on the Fuel network using pre-built script transactions from call_data.' +--- + +## Overview + +Fuel deposits use a script-based transaction model. The Layerswap API returns a **pre-built script transaction** in `call_data` that you need to deserialize, fund with the required coin quantities, and submit. + +**Prerequisites:** +- [fuels](https://docs.fuel.network/docs/fuels-ts/) (Fuel TypeScript SDK) for transaction construction and wallet interaction + +**Supported networks:** Fuel Mainnet, Fuel Testnet + +## call_data Format + +For Fuel, `call_data` is a **JSON string** containing two fields: + +```json +{ + "script": { /* ScriptTransactionRequest object */ }, + "quantities": [ + { "amount": "1000000", "assetId": "0x..." } + ] +} +``` + +- `script` — A serialized `ScriptTransactionRequest` object containing the transaction script, inputs, outputs, and other parameters. +- `quantities` — An array of coin quantities required to fund the transaction (covers the transfer amount and fees). + +## Transaction Construction + + + + Deserialize the JSON string and extract the `script` and `quantities` fields. + + + Use `ScriptTransactionRequest.from()` to create a proper transaction request object from the serialized data. + + + Call `estimateAndFund()` on the transaction with the wallet and required quantities. This estimates gas costs and adds the necessary coin inputs. + + + Simulate the transaction against the Fuel provider to verify it will succeed before sending. + + + Submit the transaction through the Fuel wallet and get the transaction ID. + + + +## Full Example (Server-side with Private Key) + +```typescript +import { + Provider, + Wallet, + ScriptTransactionRequest, + coinQuantityfy, +} from "fuels"; + +async function executeFuelDeposit( + depositAction: any, + privateKey: string +) { + const { call_data, network } = depositAction; + + // Connect to the Fuel provider + const provider = new Provider(network.node_url); + const wallet = Wallet.fromPrivateKey(privateKey, provider); + + // Parse the call_data + const parsedCallData = JSON.parse(call_data); + + // Reconstruct the script transaction + const scriptTransaction = ScriptTransactionRequest.from( + parsedCallData.script + ); + + // Parse coin quantities + const quantities = parsedCallData.quantities.map((q: any) => + coinQuantityfy(q) + ); + + // Estimate gas and fund the transaction with required coins + await scriptTransaction.estimateAndFund(wallet, { quantities }); + + // Simulate to verify (optional but recommended) + await provider.simulate(scriptTransaction); + + // Send the transaction + const response = await wallet.sendTransaction(scriptTransaction); + + return response.id; +} +``` + +## Full Example (Browser with Fuel Wallet) + +When using the Fuel Wallet browser extension, access the wallet through the Fuel connector: + +```typescript +import { + Provider, + ScriptTransactionRequest, + coinQuantityfy, +} from "fuels"; + +async function executeFuelDeposit( + depositAction: any, + fuel: any, // Fuel instance from @fuels/react + senderAddress: string +) { + const { call_data, network } = depositAction; + + const provider = new Provider(network.node_url); + const wallet = await fuel.getWallet(senderAddress, provider); + + if (!wallet) { + throw new Error("Fuel wallet not found"); + } + + const parsedCallData = JSON.parse(call_data); + const scriptTransaction = ScriptTransactionRequest.from( + parsedCallData.script + ); + const quantities = parsedCallData.quantities.map((q: any) => + coinQuantityfy(q) + ); + + await scriptTransaction.estimateAndFund(wallet, { quantities }); + + // Simulate first + await provider.simulate(scriptTransaction); + + // Send through the browser wallet + const response = await wallet.sendTransaction(scriptTransaction); + + return response.id; +} +``` + +## Using @fuels/react Hooks + +If you use the Fuel React SDK, you can integrate with the `useFuel` hook: + +```typescript +import { useFuel } from "@fuels/react"; +import { + Provider, + ScriptTransactionRequest, + coinQuantityfy, +} from "fuels"; + +function useFuelDeposit() { + const { fuel } = useFuel(); + + async function executeDeposit( + depositAction: any, + senderAddress: string + ): Promise { + if (!fuel) { + throw new Error("Fuel not initialized"); + } + + const { call_data, network } = depositAction; + + const provider = new Provider(network.node_url); + const wallet = await fuel.getWallet(senderAddress, provider); + + if (!wallet) { + throw new Error("Fuel wallet not found"); + } + + const parsedCallData = JSON.parse(call_data); + const scriptTransaction = ScriptTransactionRequest.from( + parsedCallData.script + ); + const quantities = parsedCallData.quantities.map((q: any) => + coinQuantityfy(q) + ); + + await scriptTransaction.estimateAndFund(wallet, { quantities }); + await provider.simulate(scriptTransaction); + + const response = await wallet.sendTransaction(scriptTransaction); + return response.id; + } + + return { executeDeposit }; +} +``` + +## Next Step + +After the transaction is submitted, notify Layerswap so it can match your deposit faster: + +```bash +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. \ No newline at end of file diff --git a/api-reference/deposit-actions/overview.mdx b/api-reference/deposit-actions/overview.mdx new file mode 100644 index 0000000..70f545d --- /dev/null +++ b/api-reference/deposit-actions/overview.mdx @@ -0,0 +1,118 @@ +--- +title: 'Handling Deposit Actions' +description: 'Learn how to execute deposit transactions on different blockchains after creating a swap via the Layerswap API.' +--- + +## Overview + +When you create a swap via `POST /api/v2/swaps`, the response includes a `deposit_actions` array. Each deposit action contains the destination address, amount, and a blockchain-specific `call_data` payload — everything you need to construct and submit a deposit transaction on the source chain. After broadcasting the transaction, you notify Layerswap with the transaction hash via the speedup endpoint so it can match the deposit and complete the swap. + +## Deposit Action Schema + +Each item in the `deposit_actions` array has the following structure: + + + Either `transfer` (wallet transaction) or `manual_transfer` (manual deposit to an address). Use the action with `type: "transfer"` for programmatic deposits. + + + + The deposit address to send funds to. + + + + The amount to transfer in human-readable units (e.g. `0.1` ETH, not wei). + + + + The amount in the token's smallest unit (e.g. wei for ETH, satoshi for BTC). + + + + Blockchain-specific payload used to construct the transaction. The format varies by chain — see the chain-specific guides below. + + + + The source network object, including `name`, `type`, `chain_id`, and `node_url`. + + + + The token being transferred, including `symbol`, `decimals`, and `contract` (null for native tokens). + + + + The token used to pay transaction fees on this network. + + + + Execution order if there are multiple deposit actions. + + +## Step-by-Step Flow + + + + Call `POST /api/v2/swaps` with `use_deposit_address: false` and include the `source_address` parameter. The response will contain `deposit_actions`. + + ```bash + curl -X POST https://api.layerswap.io/api/v2/swaps \ + -H "X-LS-APIKEY: your_api_key" \ + -H "Content-Type: application/json" \ + -d '{ + "source_network": "ETHEREUM_MAINNET", + "source_token": "ETH", + "destination_network": "ARBITRUM_MAINNET", + "destination_token": "ETH", + "destination_address": "0xRecipient...", + "source_address": "0xSender...", + "amount": "0.1", + "use_deposit_address": false + }' + ``` + + + From the response, find the deposit action with `type: "transfer"`: + + ```javascript + const response = await createSwap(/* ... */); + const depositAction = response.deposit_actions.find( + action => action.type === "transfer" + ); + + const { call_data, to_address, amount, network, token } = depositAction; + ``` + + + Use the `call_data`, `to_address`, and `amount` to construct and send a blockchain-specific transaction. See the chain guides below for implementation details. + + + After the transaction is submitted, call the speedup endpoint so Layerswap can match it faster: + + ```bash + 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": "0xYourTransactionHash..." }' + ``` + + + Poll `GET /api/v2/swaps/{swap_id}` or use [webhooks](/api-reference/webhook) to track the swap through its [lifecycle](/api-reference/swap-lifecycle). + + + +## call_data Format by Chain + +The `call_data` field is the key piece — its format depends on the source blockchain: + +| Blockchain | call_data Format | Guide | +|---|---|---| +| EVM (Ethereum, Arbitrum, Base, etc.) | Hex-encoded transaction data (`0x...`) | [EVM Guide](/api-reference/deposit-actions/evm) | +| Bitcoin | Numeric memo (encoded as OP_RETURN) | [Bitcoin Guide](/api-reference/deposit-actions/bitcoin) | +| Solana | Base64-encoded serialized transaction | [Solana Guide](/api-reference/deposit-actions/solana) | +| Starknet | JSON array of Starknet calls | [Starknet Guide](/api-reference/deposit-actions/starknet) | +| TON | JSON object with `comment` (and `amount` for Jettons) | [TON Guide](/api-reference/deposit-actions/ton) | +| Tron | String memo (hex-encoded into transaction data) | [Tron Guide](/api-reference/deposit-actions/tron) | +| Fuel | JSON object with `script` and `quantities` | [Fuel Guide](/api-reference/deposit-actions/fuel) | + + + zkSync Lite, Loopring, Paradex, and Immutable require multi-step authorization flows that are best handled through the [Layerswap Widget](/integration/UI/IntegrationOverview). They are not covered in this API-level guide. + diff --git a/api-reference/deposit-actions/solana.mdx b/api-reference/deposit-actions/solana.mdx new file mode 100644 index 0000000..f193aca --- /dev/null +++ b/api-reference/deposit-actions/solana.mdx @@ -0,0 +1,197 @@ +--- +title: 'Solana' +description: 'Execute deposit transactions on Solana by deserializing and signing the pre-built transaction from call_data.' +--- + +## Overview + +Solana deposits are straightforward because the Layerswap API returns a **fully constructed, serialized transaction** in `call_data`. You only need to decode it, set a fresh blockhash, sign it, and send it. + +**Prerequisites:** +- [@solana/web3.js](https://solana-labs.github.io/solana-web3.js/) for transaction handling and RPC communication + +## call_data Format + +For Solana, `call_data` is a **base64-encoded serialized `Transaction`**. It contains all the instructions, accounts, and program IDs already set up by the Layerswap backend — including SPL token transfers when applicable. + +```javascript +// Node.js / server-side +const buffer = Buffer.from(callData, "base64"); +const transaction = Transaction.from(buffer); + +// Browser +const buffer = Uint8Array.from(atob(callData), (c) => c.charCodeAt(0)); +const transaction = Transaction.from(buffer); +``` + +## Transaction Construction + + + + Convert the base64 `call_data` string into a `Transaction` object. + + + Fetch the latest blockhash from the Solana RPC and update the transaction. This ensures the transaction doesn't expire before it's confirmed. + + + Estimate the transaction fee and verify the sender has enough SOL for fees and enough of the source token for the transfer amount. + + + Sign the transaction with the sender's keypair or wallet adapter. + + + Submit the signed transaction to the network and wait for confirmation. + + + +## Full Example (Server-side with Keypair) + +```typescript +import { + Connection, + Transaction, + Keypair, + LAMPORTS_PER_SOL, + sendAndConfirmTransaction, +} from "@solana/web3.js"; +import bs58 from "bs58"; + +async function executeSolanaDeposit( + depositAction: any, + senderKeypair: Keypair +) { + const { call_data, network } = depositAction; + + const connection = new Connection(network.node_url, "confirmed"); + + // Decode base64 call_data into a Transaction + const buffer = Buffer.from(call_data, "base64"); + const transaction = Transaction.from(buffer); + + // Set a fresh blockhash + const { blockhash, lastValidBlockHeight } = + await connection.getLatestBlockhash(); + transaction.recentBlockhash = blockhash; + transaction.lastValidBlockHeight = lastValidBlockHeight; + + // Send and confirm + const signature = await sendAndConfirmTransaction( + connection, + transaction, + [senderKeypair], + { commitment: "confirmed" } + ); + + return signature; +} +``` + +## Full Example (Browser with Wallet Adapter) + +When your users connect via a Solana wallet (Phantom, Solflare, etc.), use the wallet adapter's `signTransaction` method: + +```typescript +import { Connection, Transaction, LAMPORTS_PER_SOL } from "@solana/web3.js"; + +async function executeSolanaDeposit( + depositAction: any, + nodeUrl: string, + signTransaction: (tx: Transaction) => Promise +) { + const { call_data } = depositAction; + + const connection = new Connection(nodeUrl, "confirmed"); + + // Decode base64 call_data + const buffer = Uint8Array.from(atob(call_data), (c) => c.charCodeAt(0)); + const transaction = Transaction.from(buffer); + + + // Set fresh blockhash + const blockHash = await connection.getLatestBlockhash(); + transaction.recentBlockhash = blockHash.blockhash; + transaction.lastValidBlockHeight = blockHash.lastValidBlockHeight; + + // Sign with wallet adapter + const signed = await signTransaction(transaction); + + // Send the signed transaction + const rawTransaction = signed.serialize(); + const txid = await connection.sendRawTransaction(rawTransaction, { + skipPreflight: true, + }); + + // Confirm + await connection.confirmTransaction( + { + signature: txid, + blockhash: blockHash.blockhash, + lastValidBlockHeight: blockHash.lastValidBlockHeight, + }, + "confirmed" + ); + + return txid; +} +``` + +## Sending with Retry Logic + +Solana transactions can sometimes fail to land due to network congestion. A robust implementation resends the transaction periodically until it's confirmed or the blockhash expires: + +```typescript +import { Connection, Transaction } from "@solana/web3.js"; + +async function sendWithRetry( + connection: Connection, + serializedTx: Buffer, + blockhash: string, + lastValidBlockHeight: number +): Promise { + const txid = await connection.sendRawTransaction(serializedTx, { + skipPreflight: true, + }); + + const controller = new AbortController(); + + // Resend every 2 seconds in the background + const resendLoop = async () => { + while (!controller.signal.aborted) { + await new Promise((r) => setTimeout(r, 2000)); + if (controller.signal.aborted) return; + try { + await connection.sendRawTransaction(serializedTx, { + skipPreflight: true, + }); + } catch { + // Ignore resend errors + } + } + }; + resendLoop(); + + try { + await connection.confirmTransaction( + { signature: txid, blockhash, lastValidBlockHeight }, + "confirmed" + ); + } finally { + controller.abort(); + } + + return txid; +} +``` + +## Next Step + +After the transaction is submitted, notify Layerswap so it can match your deposit faster: + +```bash +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. \ No newline at end of file diff --git a/api-reference/deposit-actions/starknet.mdx b/api-reference/deposit-actions/starknet.mdx new file mode 100644 index 0000000..2dcb9ac --- /dev/null +++ b/api-reference/deposit-actions/starknet.mdx @@ -0,0 +1,149 @@ +--- +title: 'Starknet' +description: 'Execute deposit transactions on Starknet using the multicall format from call_data.' +--- + +## Overview + +Starknet deposits are simple to execute because the Layerswap API returns a **pre-built array of Starknet calls** in `call_data`. You parse the JSON and pass it directly to the account's `execute` method, which handles multicall execution natively. + +**Prerequisites:** +- [starknet.js](https://www.starknetjs.com/) for account interaction and transaction execution + +**Supported networks:** Starknet Mainnet, Starknet Sepolia + +## call_data Format + +For Starknet, `call_data` is a **JSON-encoded array of call objects**. Each call in the array specifies a contract invocation: + +```json +[ + { + "contractAddress": "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", + "entrypoint": "transfer", + "calldata": ["0xRecipient", "0xAmountLow", "0xAmountHigh"] + } +] +``` + +For ERC-20 token transfers, the array typically contains a single `transfer` or `approve` + `transfer` call. For native ETH on Starknet, it's a direct transfer call on the ETH contract. + +## Transaction Construction + + + + Deserialize the JSON string into an array of Starknet call objects. + + + Pass the calls array to `account.execute()`. Starknet natively supports multicall, so all calls in the array are executed atomically in a single transaction. + + + The `execute` method returns an object with `transaction_hash`. + + + +## Full Example (Server-side with Private Key) + +```typescript +import { Account, RpcProvider, Call } from "starknet"; + +async function executeStarknetDeposit( + depositAction: any, + senderAddress: string, + privateKey: string +) { + const { call_data, network } = depositAction; + + const provider = new RpcProvider({ nodeUrl: network.node_url }); + const account = new Account(provider, senderAddress, privateKey); + + // Parse the call_data JSON into Starknet calls + const calls: Call[] = JSON.parse(call_data); + + // Execute the multicall transaction + const { transaction_hash } = await account.execute(calls); + + if (!transaction_hash) { + throw new Error("No transaction hash returned"); + } + + // Optionally wait for confirmation + await provider.waitForTransaction(transaction_hash); + + return transaction_hash; +} +``` + +## Full Example (Browser with starknet.js + Wallet) + +When using a browser wallet like ArgentX or Braavos, the wallet injects a `starknet` object. Use `get-starknet` to connect: + +```typescript +import { connect } from "get-starknet"; +import { Call } from "starknet"; + +async function executeStarknetDeposit(depositAction: any) { + const { call_data } = depositAction; + + // Connect to wallet + const starknet = await connect(); + if (!starknet?.isConnected || !starknet.account) { + throw new Error("Starknet wallet not connected"); + } + + // Parse the call_data JSON + const calls: Call[] = JSON.parse(call_data); + + // Execute through the connected wallet + const { transaction_hash } = await starknet.account.execute(calls); + + if (!transaction_hash) { + throw new Error("No transaction hash returned"); + } + + return transaction_hash; +} +``` + +## Full Example (Using starknet-react hooks) + +If you use [starknet-react](https://starknet-react.com/), you can access the account from the hook: + +```typescript +import { useAccount } from "@starknet-react/core"; +import { Call } from "starknet"; + +function useStarknetDeposit() { + const { account } = useAccount(); + + async function executeDeposit(depositAction: any): Promise { + if (!account) { + throw new Error("Starknet account not connected"); + } + + const calls: Call[] = JSON.parse(depositAction.call_data); + const { transaction_hash } = await account.execute(calls); + + if (!transaction_hash) { + throw new Error("No transaction hash returned"); + } + + return transaction_hash; + } + + return { executeDeposit }; +} +``` + +## Next Step + +After the transaction is submitted, notify Layerswap so it can match your deposit faster: + +```bash +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. \ No newline at end of file diff --git a/api-reference/deposit-actions/ton.mdx b/api-reference/deposit-actions/ton.mdx new file mode 100644 index 0000000..f6a0374 --- /dev/null +++ b/api-reference/deposit-actions/ton.mdx @@ -0,0 +1,261 @@ +--- +title: 'TON' +description: 'Execute deposit transactions on The Open Network for both native TON and Jetton (token) transfers.' +--- + +## Overview + +TON deposits require constructing a TON-specific message payload. The flow differs depending on whether you're transferring **native TON** or a **Jetton** (TRC-20-like token on TON). The `call_data` from the Layerswap API contains the information needed to build the correct payload. + +**Prerequisites:** +- [@ton/ton](https://github.com/ton-org/ton) for cell building and TON client +- [@tonconnect/ui-react](https://github.com/nicolo-ribaudo/tonconnect-ui-react) (for browser wallets) or a TON SDK for server-side signing + +## call_data Format + +For TON, `call_data` is a **JSON string** containing: + +```json +{ + "comment": "layerswap_memo_identifier", + "amount": "1000000000" +} +``` + +- `comment` — A text memo that Layerswap uses to identify the deposit. This is embedded in the transaction payload. +- `amount` — Present only for Jetton transfers; the Jetton amount in base units (nanojettons). For native TON transfers, use the deposit action's `amount` field instead. + +## Native TON Transfer + +For native TON transfers (when `token.contract` is null), the transaction is a simple message to the deposit address with a comment payload. + +### Transaction Construction + + + + Extract the `comment` field from the JSON. + + + Create a TON cell with a 32-bit zero prefix (indicates a text comment) followed by the comment string. + + + Send a message to `to_address` with the deposit `amount` (converted to nanotons) and the comment cell as payload. + + + +### Full Example + +```typescript +import { beginCell, toNano } from "@ton/ton"; + +function buildNativeTonTransaction( + depositAction: any +) { + const { call_data, to_address, amount } = depositAction; + const { comment } = JSON.parse(call_data); + + const body = beginCell() + .storeUint(0, 32) // 0 opcode = text comment + .storeStringTail(comment) + .endCell(); + + return { + validUntil: Math.floor(Date.now() / 1000) + 360, + messages: [ + { + address: to_address, + amount: toNano(amount).toString(), + payload: body.toBoc().toString("base64"), + }, + ], + }; +} +``` + +## Jetton Transfer + +For Jetton transfers (when `token.contract` is not null), you need to build a Jetton transfer message that targets the sender's Jetton wallet address (not the Jetton master contract). + +### Transaction Construction + + + + Extract both `comment` and `amount` from the JSON. + + + Use the Jetton master contract to look up the sender's Jetton wallet address via `get_wallet_address`. + + + Construct a cell with the Jetton transfer opcode (`0x0f8a7ea5`), the Jetton amount, the destination address, and a forward payload containing the comment. + + + Send the message to the sender's Jetton wallet address with enough TON attached to cover fees. + + + +### Full Example + +```typescript +import { + Address, + JettonMaster, + TonClient, + beginCell, + toNano, +} from "@ton/ton"; + +async function buildJettonTransaction( + depositAction: any, + senderAddress: string, + tonClient: TonClient +) { + const { call_data, to_address, token } = depositAction; + const { comment, amount: jettonAmount } = JSON.parse(call_data); + + const destinationAddress = Address.parse(to_address); + const userAddress = Address.parse(senderAddress); + + // Build the forward payload (comment) + const forwardPayload = beginCell() + .storeUint(0, 32) + .storeStringTail(comment) + .endCell(); + + // Build the Jetton transfer body + const body = beginCell() + .storeUint(0x0f8a7ea5, 32) // Jetton transfer opcode + .storeUint(0, 64) // query_id + .storeCoins(BigInt(jettonAmount)) // Jetton amount in base units + .storeAddress(destinationAddress) // destination + .storeAddress(destinationAddress) // response excess destination + .storeBit(0) // no custom payload + .storeCoins(toNano("0.00002")) // forward amount for notification + .storeBit(1) // forward payload as reference + .storeRef(forwardPayload) + .endCell(); + + // Resolve the sender's Jetton wallet address + const jettonMasterAddress = Address.parse(token.contract); + const jettonMaster = tonClient.open( + JettonMaster.create(jettonMasterAddress) + ); + const jettonWalletAddress = + await jettonMaster.getWalletAddress(userAddress); + + return { + validUntil: Math.floor(Date.now() / 1000) + 360, + messages: [ + { + address: jettonWalletAddress.toString(), + amount: toNano("0.045").toString(), // TON for fees; excess is returned + payload: body.toBoc().toString("base64"), + }, + ], + }; +} +``` + +## Sending via TON Connect + +If your users connect through a TON wallet (Tonkeeper, MyTonWallet, etc.), use TON Connect to send the built transaction: + +```typescript +import { TonConnectUI } from "@tonconnect/ui-react"; +import { TonClient } from "@ton/ton"; + +async function executeTonDeposit( + depositAction: any, + senderAddress: string, + tonConnectUI: TonConnectUI, + tonClient: TonClient +) { + const { token } = depositAction; + let transaction; + + if (token.contract) { + transaction = await buildJettonTransaction( + depositAction, + senderAddress, + tonClient + ); + } else { + transaction = buildNativeTonTransaction(depositAction); + } + + const result = await tonConnectUI.sendTransaction(transaction); + + // result.boc contains the sent message BOC + // You can use it to track the transaction on-chain + return result.boc; +} +``` + +## Server-side Sending + +For server-side execution without TON Connect, you can sign and send directly with a wallet key: + +```typescript +import { + WalletContractV4, + internal, + TonClient, + beginCell, + toNano, +} from "@ton/ton"; +import { mnemonicToPrivateKey } from "@ton/crypto"; + +async function executeTonDepositServerSide( + depositAction: any, + mnemonic: string[] +) { + const { call_data, to_address, amount, network } = depositAction; + const { comment } = JSON.parse(call_data); + + const tonClient = new TonClient({ + endpoint: network.node_url, + }); + + const keyPair = await mnemonicToPrivateKey(mnemonic); + const wallet = WalletContractV4.create({ + publicKey: keyPair.publicKey, + workchain: 0, + }); + + const contract = tonClient.open(wallet); + + const body = beginCell() + .storeUint(0, 32) + .storeStringTail(comment) + .endCell(); + + await contract.sendTransfer({ + seqno: await contract.getSeqno(), + secretKey: keyPair.secretKey, + messages: [ + internal({ + to: to_address, + value: toNano(amount), + body, + bounce: false, + }), + ], + }); +} +``` + + + The server-side example above shows a native TON transfer. For Jetton transfers, build the Jetton cell as shown in the Jetton section and target the sender's Jetton wallet address. + + +## Next Step + +After the transaction is submitted, notify Layerswap so it can match your deposit faster: + +```bash +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. \ No newline at end of file diff --git a/api-reference/deposit-actions/tron.mdx b/api-reference/deposit-actions/tron.mdx new file mode 100644 index 0000000..f59b46b --- /dev/null +++ b/api-reference/deposit-actions/tron.mdx @@ -0,0 +1,147 @@ +--- +title: 'Tron' +description: 'Execute deposit transactions on Tron for TRC-20 token transfers.' +--- + +## Overview + +Tron deposits require building a TRC-20 token transfer transaction using TronWeb, then appending the `call_data` as hex-encoded data before signing and broadcasting. + +**Prerequisites:** +- [tronweb](https://github.com/nicolo-ribaudo/tronweb) for transaction building and RPC communication + +**Supported networks:** Tron Mainnet, Tron Testnet (Shasta/Nile) + +## call_data Format + +For Tron, `call_data` is a **plain string** (a memo identifier). It is converted to hex and embedded in the transaction data field: + +```javascript +const hexData = Buffer.from(callData).toString("hex"); +``` + +This hex data is appended to the transaction using TronWeb's `addUpdateData` method, which Layerswap uses to identify and match the deposit. + +## Full Example (Server-side) + +```typescript +import { TronWeb } from "tronweb"; + +async function executeTronDeposit( + depositAction: any, + senderAddress: string, + privateKey: string +) { + const { call_data, to_address, amount, token, network } = depositAction; + + const tronWeb = new TronWeb({ + fullNode: network.node_url, + solidityNode: network.node_url, + privateKey, + }); + + const amountInBaseUnits = Math.floor( + amount * Math.pow(10, token.decimals) + ); + + // Build the TRC-20 transfer via smart contract + const { transaction: initialTransaction } = + await tronWeb.transactionBuilder.triggerSmartContract( + token.contract, + "transfer(address,uint256)", + { + feeLimit: 100_000_000, // 100 TRX fee limit + }, + [ + { type: "address", value: to_address }, + { type: "uint256", value: amountInBaseUnits }, + ], + senderAddress + ); + + // Append call_data as hex data + const hexData = Buffer.from(call_data).toString("hex"); + const transaction = await tronWeb.transactionBuilder.addUpdateData( + initialTransaction, + hexData, + "hex" + ); + + // Sign and broadcast + const signedTransaction = await tronWeb.trx.sign(transaction); + const result = await tronWeb.trx.sendRawTransaction(signedTransaction); + + if (result.result) { + return signedTransaction.txID; + } + + throw new Error("Transaction broadcast failed"); +} +``` + +## Browser Wallet Example + +When using a Tron wallet adapter (TronLink, etc.) in the browser: + +```typescript +import { TronWeb } from "tronweb"; + +async function executeTronDeposit( + depositAction: any, + senderAddress: string, + signTransaction: (tx: any) => Promise +) { + const { call_data, to_address, amount, token, network } = depositAction; + + const tronWeb = new TronWeb({ + fullNode: network.node_url, + solidityNode: network.node_url, + }); + + const amountInBaseUnits = Math.floor( + amount * Math.pow(10, token.decimals) + ); + + const { transaction: initialTransaction } = + await tronWeb.transactionBuilder.triggerSmartContract( + token.contract, + "transfer(address,uint256)", + { feeLimit: 100_000_000 }, + [ + { type: "address", value: to_address }, + { type: "uint256", value: amountInBaseUnits }, + ], + senderAddress + ); + + const hexData = Buffer.from(call_data).toString("hex"); + const transaction = await tronWeb.transactionBuilder.addUpdateData( + initialTransaction, + hexData, + "hex" + ); + + // Sign using the wallet adapter + const signedTransaction = await signTransaction(transaction); + const result = await tronWeb.trx.sendRawTransaction(signedTransaction); + + if (result.result) { + return signedTransaction.txID; + } + + throw new Error("Transaction broadcast failed"); +} +``` + +## Next Step + +After the transaction is submitted, notify Layerswap so it can match your deposit faster: + +```bash +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. diff --git a/docs.json b/docs.json index 34f0470..9de29ea 100644 --- a/docs.json +++ b/docs.json @@ -141,6 +141,19 @@ "security" ] }, + { + "group": "Handling Deposits", + "pages": [ + "api-reference/deposit-actions/overview", + "api-reference/deposit-actions/evm", + "api-reference/deposit-actions/bitcoin", + "api-reference/deposit-actions/solana", + "api-reference/deposit-actions/starknet", + "api-reference/deposit-actions/ton", + "api-reference/deposit-actions/tron", + "api-reference/deposit-actions/fuel" + ] + }, { "group": "Endpoints", "openapi": { From 6745c30f2e03ac626599b890d119012890191f19 Mon Sep 17 00:00:00 2001 From: Aren Date: Mon, 16 Mar 2026 15:49:32 +0400 Subject: [PATCH 2/7] Update documentation to reflect changes from 'deposit' to 'transfer' actions - Renamed sections and variables in the documentation to clarify the transition from deposit actions to transfer actions across various blockchain integrations. - Updated descriptions and examples to ensure consistency in terminology and improve user understanding. --- api-reference/deposit-actions/bitcoin.mdx | 2 +- api-reference/deposit-actions/evm.mdx | 8 ++++---- api-reference/deposit-actions/overview.mdx | 22 +++++++++------------- api-reference/deposit-actions/ton.mdx | 2 +- 4 files changed, 15 insertions(+), 19 deletions(-) diff --git a/api-reference/deposit-actions/bitcoin.mdx b/api-reference/deposit-actions/bitcoin.mdx index 2375d42..daf9b15 100644 --- a/api-reference/deposit-actions/bitcoin.mdx +++ b/api-reference/deposit-actions/bitcoin.mdx @@ -5,7 +5,7 @@ description: 'Execute deposit transactions on Bitcoin mainnet and testnet using ## Overview -Bitcoin deposits use a UTXO-based model. The `call_data` from the deposit action is a **numeric memo** that must be embedded in the transaction as an `OP_RETURN` output. This memo is how Layerswap identifies and matches your deposit. +Bitcoin deposits use a UTXO-based model. The `call_data` from the transfer action is a **numeric memo** that must be embedded in the transaction as an `OP_RETURN` output. This memo is how Layerswap identifies and matches your deposit. **Prerequisites:** - [bitcoinjs-lib](https://github.com/bitcoinjs/bitcoinjs-lib) for PSBT construction diff --git a/api-reference/deposit-actions/evm.mdx b/api-reference/deposit-actions/evm.mdx index 8591b72..6a54a95 100644 --- a/api-reference/deposit-actions/evm.mdx +++ b/api-reference/deposit-actions/evm.mdx @@ -18,16 +18,16 @@ For EVM chains, `call_data` is a **hex-encoded string** (`0x...`) representing t - **Native token transfers** (ETH, MATIC, etc.): `call_data` may be `0x` or contain contract interaction data if routed through a contract. - **ERC-20 token transfers**: `call_data` contains the encoded `transfer(address,uint256)` function call or a more complex contract interaction. -The `to_address` from the deposit action is the transaction recipient, and `amount` is in human-readable units. +The `to_address` from the transfer action is the transaction recipient, and `amount` is in human-readable units. ## Transaction Construction - - Extract `call_data`, `to_address`, `amount`, and `network.chain_id` from the deposit action. + + Extract `call_data`, `to_address`, `amount`, and `network.chain_id` from the transfer action. - Construct a transaction object with the deposit action fields mapped to standard EVM transaction parameters. + Construct a transaction object with the transfer action fields mapped to standard EVM transaction parameters. 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. diff --git a/api-reference/deposit-actions/overview.mdx b/api-reference/deposit-actions/overview.mdx index 70f545d..e3d0071 100644 --- a/api-reference/deposit-actions/overview.mdx +++ b/api-reference/deposit-actions/overview.mdx @@ -1,18 +1,18 @@ --- -title: 'Handling Deposit Actions' -description: 'Learn how to execute deposit transactions on different blockchains after creating a swap via the Layerswap API.' +title: 'Handling Transfer Actions' +description: 'Learn how to execute transfer transactions on different blockchains after creating a swap via the Layerswap API.' --- ## Overview -When you create a swap via `POST /api/v2/swaps`, the response includes a `deposit_actions` array. Each deposit action contains the destination address, amount, and a blockchain-specific `call_data` payload — everything you need to construct and submit a deposit transaction on the source chain. After broadcasting the transaction, you notify Layerswap with the transaction hash via the speedup endpoint so it can match the deposit and complete the swap. +When you create a swap via `POST /api/v2/swaps`, the response includes a `deposit_actions` array. Each transfer action contains the destination address, amount, and a blockchain-specific `call_data` payload — everything you need to construct and submit a transaction on the source chain. After broadcasting the transaction, you notify Layerswap with the transaction hash via the speedup endpoint so it can match the deposit and complete the swap. -## Deposit Action Schema +## Transfer Action Schema Each item in the `deposit_actions` array has the following structure: - Either `transfer` (wallet transaction) or `manual_transfer` (manual deposit to an address). Use the action with `type: "transfer"` for programmatic deposits. + Either `transfer` (wallet transaction) or `manual_transfer` (manual deposit to an address). Use the action with `type: "transfer"` for programmatic transfers. @@ -44,7 +44,7 @@ Each item in the `deposit_actions` array has the following structure: - Execution order if there are multiple deposit actions. + Execution order if there are multiple transfer actions. ## Step-by-Step Flow @@ -69,8 +69,8 @@ Each item in the `deposit_actions` array has the following structure: }' ``` - - From the response, find the deposit action with `type: "transfer"`: + + From the response, find the transfer action with `type: "transfer"`: ```javascript const response = await createSwap(/* ... */); @@ -111,8 +111,4 @@ The `call_data` field is the key piece — its format depends on the source bloc | Starknet | JSON array of Starknet calls | [Starknet Guide](/api-reference/deposit-actions/starknet) | | TON | JSON object with `comment` (and `amount` for Jettons) | [TON Guide](/api-reference/deposit-actions/ton) | | Tron | String memo (hex-encoded into transaction data) | [Tron Guide](/api-reference/deposit-actions/tron) | -| Fuel | JSON object with `script` and `quantities` | [Fuel Guide](/api-reference/deposit-actions/fuel) | - - - zkSync Lite, Loopring, Paradex, and Immutable require multi-step authorization flows that are best handled through the [Layerswap Widget](/integration/UI/IntegrationOverview). They are not covered in this API-level guide. - +| Fuel | JSON object with `script` and `quantities` | [Fuel Guide](/api-reference/deposit-actions/fuel) | \ No newline at end of file diff --git a/api-reference/deposit-actions/ton.mdx b/api-reference/deposit-actions/ton.mdx index f6a0374..0305986 100644 --- a/api-reference/deposit-actions/ton.mdx +++ b/api-reference/deposit-actions/ton.mdx @@ -23,7 +23,7 @@ For TON, `call_data` is a **JSON string** containing: ``` - `comment` — A text memo that Layerswap uses to identify the deposit. This is embedded in the transaction payload. -- `amount` — Present only for Jetton transfers; the Jetton amount in base units (nanojettons). For native TON transfers, use the deposit action's `amount` field instead. +- `amount` — Present only for Jetton transfers; the Jetton amount in base units (nanojettons). For native TON transfers, use the transfer action's `amount` field instead. ## Native TON Transfer From 0bf17f5cc27522e1a06a9d865625ac922344b570 Mon Sep 17 00:00:00 2001 From: Aren Date: Tue, 14 Apr 2026 19:39:29 +0400 Subject: [PATCH 3/7] Remove outdated transaction matching steps from API documentation to streamline the swap process description. --- integration/API.mdx | 6 ------ 1 file changed, 6 deletions(-) diff --git a/integration/API.mdx b/integration/API.mdx index 47514b3..da925d7 100644 --- a/integration/API.mdx +++ b/integration/API.mdx @@ -19,12 +19,6 @@ Layerswap handles millions of dollars in transactions every day across multiple Create Swap using the Layerswap API. - - Layerswap will monitor the source network for a transaction and will try to match it with the corresponding swap - - - Once the transaction is matched and added to the swap, Layerswap will initiate a counterparty transaction to the destination_address - Poll via Get Swap endpoint to see if the matching transaction Input was added to the swap From 217e761d99282347aa2246a85ec5406a38e58259 Mon Sep 17 00:00:00 2001 From: Aren Date: Tue, 14 Apr 2026 19:56:33 +0400 Subject: [PATCH 4/7] Mini fixes --- api-reference/deposit-actions/bitcoin.mdx | 2 +- api-reference/deposit-actions/overview.mdx | 16 ++++++++-------- api-reference/deposit-actions/ton.mdx | 2 +- api-reference/deposit-actions/tron.mdx | 2 +- docs.json | 2 +- integration/API.mdx | 3 +++ 6 files changed, 15 insertions(+), 12 deletions(-) diff --git a/api-reference/deposit-actions/bitcoin.mdx b/api-reference/deposit-actions/bitcoin.mdx index daf9b15..94c4369 100644 --- a/api-reference/deposit-actions/bitcoin.mdx +++ b/api-reference/deposit-actions/bitcoin.mdx @@ -9,7 +9,7 @@ Bitcoin deposits use a UTXO-based model. The `call_data` from the transfer actio **Prerequisites:** - [bitcoinjs-lib](https://github.com/bitcoinjs/bitcoinjs-lib) for PSBT construction -- [@bitcoinerlab/secp256k1](https://github.com/nicolo-ribaudo/bitcoinerlab-secp256k1) for elliptic curve operations +- [@bitcoinerlab/secp256k1](https://github.com/bitcoinerlab/secp256k1) for elliptic curve operations - Access to a Bitcoin node or the [Mempool.space API](https://mempool.space/docs/api) for UTXO data and fee estimates ## call_data Format diff --git a/api-reference/deposit-actions/overview.mdx b/api-reference/deposit-actions/overview.mdx index e3d0071..014cd77 100644 --- a/api-reference/deposit-actions/overview.mdx +++ b/api-reference/deposit-actions/overview.mdx @@ -11,7 +11,7 @@ When you create a swap via `POST /api/v2/swaps`, the response includes a `deposi Each item in the `deposit_actions` array has the following structure: - + Either `transfer` (wallet transaction) or `manual_transfer` (manual deposit to an address). Use the action with `type: "transfer"` for programmatic transfers. @@ -19,31 +19,31 @@ Each item in the `deposit_actions` array has the following structure: The deposit address to send funds to. - + The amount to transfer in human-readable units (e.g. `0.1` ETH, not wei). - + The amount in the token's smallest unit (e.g. wei for ETH, satoshi for BTC). - + Blockchain-specific payload used to construct the transaction. The format varies by chain — see the chain-specific guides below. - + The source network object, including `name`, `type`, `chain_id`, and `node_url`. - + The token being transferred, including `symbol`, `decimals`, and `contract` (null for native tokens). - + The token used to pay transaction fees on this network. - + Execution order if there are multiple transfer actions. diff --git a/api-reference/deposit-actions/ton.mdx b/api-reference/deposit-actions/ton.mdx index 0305986..d1918c4 100644 --- a/api-reference/deposit-actions/ton.mdx +++ b/api-reference/deposit-actions/ton.mdx @@ -9,7 +9,7 @@ TON deposits require constructing a TON-specific message payload. The flow diffe **Prerequisites:** - [@ton/ton](https://github.com/ton-org/ton) for cell building and TON client -- [@tonconnect/ui-react](https://github.com/nicolo-ribaudo/tonconnect-ui-react) (for browser wallets) or a TON SDK for server-side signing +- [@tonconnect/ui-react](https://github.com/ton-connect/sdk) (for browser wallets) or a TON SDK for server-side signing ## call_data Format diff --git a/api-reference/deposit-actions/tron.mdx b/api-reference/deposit-actions/tron.mdx index f59b46b..4ee81e6 100644 --- a/api-reference/deposit-actions/tron.mdx +++ b/api-reference/deposit-actions/tron.mdx @@ -8,7 +8,7 @@ description: 'Execute deposit transactions on Tron for TRC-20 token transfers.' Tron deposits require building a TRC-20 token transfer transaction using TronWeb, then appending the `call_data` as hex-encoded data before signing and broadcasting. **Prerequisites:** -- [tronweb](https://github.com/nicolo-ribaudo/tronweb) for transaction building and RPC communication +- [tronweb](https://github.com/tronprotocol/tronweb) for transaction building and RPC communication **Supported networks:** Tron Mainnet, Tron Testnet (Shasta/Nile) diff --git a/docs.json b/docs.json index 9de29ea..f6b5112 100644 --- a/docs.json +++ b/docs.json @@ -142,7 +142,7 @@ ] }, { - "group": "Handling Deposits", + "group": "Transfer Actions", "pages": [ "api-reference/deposit-actions/overview", "api-reference/deposit-actions/evm", diff --git a/integration/API.mdx b/integration/API.mdx index da925d7..ecf7b8e 100644 --- a/integration/API.mdx +++ b/integration/API.mdx @@ -19,6 +19,9 @@ Layerswap handles millions of dollars in transactions every day across multiple Create Swap using the Layerswap API. + + Use the `deposit_actions` from the swap response to submit a transaction on the source chain. See [Handling Deposits](/api-reference/deposit-actions/overview) for chain-specific guides. + Poll via Get Swap endpoint to see if the matching transaction Input was added to the swap From aa52883f9f9bb10cccccb7af89b1b48d29ace8ec Mon Sep 17 00:00:00 2001 From: Aren Date: Tue, 14 Apr 2026 20:00:03 +0400 Subject: [PATCH 5/7] fix links --- api-reference/deposit-actions/solana.mdx | 2 +- api-reference/deposit-actions/starknet.mdx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/api-reference/deposit-actions/solana.mdx b/api-reference/deposit-actions/solana.mdx index f193aca..457bf72 100644 --- a/api-reference/deposit-actions/solana.mdx +++ b/api-reference/deposit-actions/solana.mdx @@ -8,7 +8,7 @@ description: 'Execute deposit transactions on Solana by deserializing and signin Solana deposits are straightforward because the Layerswap API returns a **fully constructed, serialized transaction** in `call_data`. You only need to decode it, set a fresh blockhash, sign it, and send it. **Prerequisites:** -- [@solana/web3.js](https://solana-labs.github.io/solana-web3.js/) for transaction handling and RPC communication +- [@solana/web3.js](https://github.com/solana-foundation/solana-web3.js) for transaction handling and RPC communication ## call_data Format diff --git a/api-reference/deposit-actions/starknet.mdx b/api-reference/deposit-actions/starknet.mdx index 2dcb9ac..3f19f2e 100644 --- a/api-reference/deposit-actions/starknet.mdx +++ b/api-reference/deposit-actions/starknet.mdx @@ -8,7 +8,7 @@ description: 'Execute deposit transactions on Starknet using the multicall forma Starknet deposits are simple to execute because the Layerswap API returns a **pre-built array of Starknet calls** in `call_data`. You parse the JSON and pass it directly to the account's `execute` method, which handles multicall execution natively. **Prerequisites:** -- [starknet.js](https://www.starknetjs.com/) for account interaction and transaction execution +- [starknet.js](https://github.com/starknet-io/starknet.js) for account interaction and transaction execution **Supported networks:** Starknet Mainnet, Starknet Sepolia From 5b11746b221449b969b51d9f3776d35523cd1ddd Mon Sep 17 00:00:00 2001 From: Aren Date: Wed, 15 Apr 2026 18:03:50 +0400 Subject: [PATCH 6/7] Refactor deposit action documentation to enhance clarity and organization - Grouped blockchain deposit actions under a new "Blockchains" section for better structure. - Updated examples to clarify usage across different libraries, including viem, ethers.js, and others. - Improved consistency in terminology and formatting across various blockchain integrations. --- api-reference/deposit-actions/evm.mdx | 20 +++++++++----------- api-reference/deposit-actions/fuel.mdx | 20 ++++++++------------ api-reference/deposit-actions/solana.mdx | 14 +++++++------- api-reference/deposit-actions/starknet.mdx | 20 ++++++++------------ api-reference/deposit-actions/ton.mdx | 14 ++++++-------- api-reference/deposit-actions/tron.mdx | 14 +++++++------- docs.json | 19 ++++++++++++------- 7 files changed, 57 insertions(+), 64 deletions(-) diff --git a/api-reference/deposit-actions/evm.mdx b/api-reference/deposit-actions/evm.mdx index 6a54a95..0e408d6 100644 --- a/api-reference/deposit-actions/evm.mdx +++ b/api-reference/deposit-actions/evm.mdx @@ -37,9 +37,12 @@ The `to_address` from the transfer action is the transaction recipient, and `amo -## Full Example with viem +## Full Example -```typescript +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. + + +```typescript viem import { createWalletClient, createPublicClient, http, parseEther } from "viem"; import { privateKeyToAccount } from "viem/accounts"; import { mainnet, arbitrum, optimism, base, polygon } from "viem/chains"; @@ -100,9 +103,7 @@ async function executeEvmDeposit(depositAction, privateKey) { } ``` -## Full Example with ethers.js - -```typescript +```typescript ethers.js import { ethers } from "ethers"; async function executeEvmDeposit(depositAction, privateKey) { @@ -136,11 +137,7 @@ async function executeEvmDeposit(depositAction, privateKey) { } ``` -## Browser Wallet Example (wagmi) - -If your users connect wallets through a browser, you can use [wagmi](https://wagmi.sh/): - -```typescript +```typescript wagmi import { sendTransaction } from "@wagmi/core"; import { parseEther } from "viem"; @@ -157,9 +154,10 @@ async function executeEvmDeposit(depositAction, wagmiConfig) { return hash; } ``` + - When using a browser wallet, ensure the user is connected to the correct chain (`network.chain_id`). If not, prompt them to switch networks before sending the transaction. + 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. ## Next Step diff --git a/api-reference/deposit-actions/fuel.mdx b/api-reference/deposit-actions/fuel.mdx index 69f928a..4ce3a8e 100644 --- a/api-reference/deposit-actions/fuel.mdx +++ b/api-reference/deposit-actions/fuel.mdx @@ -48,9 +48,12 @@ For Fuel, `call_data` is a **JSON string** containing two fields: -## Full Example (Server-side with Private Key) +## Full Example -```typescript +Pick the flavor that matches your setup. The `Server-side` tab signs with a raw private key. The `Browser` tab uses the Fuel Wallet extension via the Fuel connector. The `@fuels/react` tab wraps it as a hook for React apps. + + +```typescript Server-side import { Provider, Wallet, @@ -94,11 +97,7 @@ async function executeFuelDeposit( } ``` -## Full Example (Browser with Fuel Wallet) - -When using the Fuel Wallet browser extension, access the wallet through the Fuel connector: - -```typescript +```typescript Browser import { Provider, ScriptTransactionRequest, @@ -139,11 +138,7 @@ async function executeFuelDeposit( } ``` -## Using @fuels/react Hooks - -If you use the Fuel React SDK, you can integrate with the `useFuel` hook: - -```typescript +```typescript @fuels/react import { useFuel } from "@fuels/react"; import { Provider, @@ -189,6 +184,7 @@ function useFuelDeposit() { return { executeDeposit }; } ``` + ## Next Step diff --git a/api-reference/deposit-actions/solana.mdx b/api-reference/deposit-actions/solana.mdx index 457bf72..5c8e750 100644 --- a/api-reference/deposit-actions/solana.mdx +++ b/api-reference/deposit-actions/solana.mdx @@ -44,9 +44,12 @@ const transaction = Transaction.from(buffer); -## Full Example (Server-side with Keypair) +## Full Example -```typescript +The `Server-side` tab signs locally with a `Keypair`. The `Browser` tab uses a connected wallet adapter (Phantom, Solflare, etc.) and its `signTransaction` method. + + +```typescript Server-side import { Connection, Transaction, @@ -86,11 +89,7 @@ async function executeSolanaDeposit( } ``` -## Full Example (Browser with Wallet Adapter) - -When your users connect via a Solana wallet (Phantom, Solflare, etc.), use the wallet adapter's `signTransaction` method: - -```typescript +```typescript Browser import { Connection, Transaction, LAMPORTS_PER_SOL } from "@solana/web3.js"; async function executeSolanaDeposit( @@ -134,6 +133,7 @@ async function executeSolanaDeposit( return txid; } ``` + ## Sending with Retry Logic diff --git a/api-reference/deposit-actions/starknet.mdx b/api-reference/deposit-actions/starknet.mdx index 3f19f2e..92cd509 100644 --- a/api-reference/deposit-actions/starknet.mdx +++ b/api-reference/deposit-actions/starknet.mdx @@ -42,9 +42,12 @@ For ERC-20 token transfers, the array typically contains a single `transfer` or -## Full Example (Server-side with Private Key) +## Full Example -```typescript +Pick the flavor that matches your setup. The `Server-side` tab signs with a raw private key via `starknet.js`. The `Browser` tab connects to an injected wallet like ArgentX or Braavos via `get-starknet`. The `starknet-react` tab wraps it as a hook for React apps. + + +```typescript Server-side import { Account, RpcProvider, Call } from "starknet"; async function executeStarknetDeposit( @@ -74,11 +77,7 @@ async function executeStarknetDeposit( } ``` -## Full Example (Browser with starknet.js + Wallet) - -When using a browser wallet like ArgentX or Braavos, the wallet injects a `starknet` object. Use `get-starknet` to connect: - -```typescript +```typescript Browser import { connect } from "get-starknet"; import { Call } from "starknet"; @@ -105,11 +104,7 @@ async function executeStarknetDeposit(depositAction: any) { } ``` -## Full Example (Using starknet-react hooks) - -If you use [starknet-react](https://starknet-react.com/), you can access the account from the hook: - -```typescript +```typescript starknet-react import { useAccount } from "@starknet-react/core"; import { Call } from "starknet"; @@ -134,6 +129,7 @@ function useStarknetDeposit() { return { executeDeposit }; } ``` + ## Next Step diff --git a/api-reference/deposit-actions/ton.mdx b/api-reference/deposit-actions/ton.mdx index d1918c4..fb45d0d 100644 --- a/api-reference/deposit-actions/ton.mdx +++ b/api-reference/deposit-actions/ton.mdx @@ -155,11 +155,12 @@ async function buildJettonTransaction( } ``` -## Sending via TON Connect +## Sending the Transaction -If your users connect through a TON wallet (Tonkeeper, MyTonWallet, etc.), use TON Connect to send the built transaction: +The `TON Connect` tab is for browser wallets like Tonkeeper or MyTonWallet — it picks between the native and Jetton builders above based on `token.contract`. The `Server-side` tab signs and sends directly with a wallet key for backend use. -```typescript + +```typescript TON Connect import { TonConnectUI } from "@tonconnect/ui-react"; import { TonClient } from "@ton/ton"; @@ -190,11 +191,7 @@ async function executeTonDeposit( } ``` -## Server-side Sending - -For server-side execution without TON Connect, you can sign and send directly with a wallet key: - -```typescript +```typescript Server-side import { WalletContractV4, internal, @@ -242,6 +239,7 @@ async function executeTonDepositServerSide( }); } ``` + The server-side example above shows a native TON transfer. For Jetton transfers, build the Jetton cell as shown in the Jetton section and target the sender's Jetton wallet address. diff --git a/api-reference/deposit-actions/tron.mdx b/api-reference/deposit-actions/tron.mdx index 4ee81e6..aa336c6 100644 --- a/api-reference/deposit-actions/tron.mdx +++ b/api-reference/deposit-actions/tron.mdx @@ -22,9 +22,12 @@ const hexData = Buffer.from(callData).toString("hex"); This hex data is appended to the transaction using TronWeb's `addUpdateData` method, which Layerswap uses to identify and match the deposit. -## Full Example (Server-side) +## Full Example -```typescript +The `Server-side` tab signs with a raw private key. The `Browser` tab uses a Tron wallet adapter (TronLink, etc.) and its `signTransaction` method. + + +```typescript Server-side import { TronWeb } from "tronweb"; async function executeTronDeposit( @@ -79,11 +82,7 @@ async function executeTronDeposit( } ``` -## Browser Wallet Example - -When using a Tron wallet adapter (TronLink, etc.) in the browser: - -```typescript +```typescript Browser import { TronWeb } from "tronweb"; async function executeTronDeposit( @@ -132,6 +131,7 @@ async function executeTronDeposit( throw new Error("Transaction broadcast failed"); } ``` + ## Next Step diff --git a/docs.json b/docs.json index f6b5112..3d32dc2 100644 --- a/docs.json +++ b/docs.json @@ -145,13 +145,18 @@ "group": "Transfer Actions", "pages": [ "api-reference/deposit-actions/overview", - "api-reference/deposit-actions/evm", - "api-reference/deposit-actions/bitcoin", - "api-reference/deposit-actions/solana", - "api-reference/deposit-actions/starknet", - "api-reference/deposit-actions/ton", - "api-reference/deposit-actions/tron", - "api-reference/deposit-actions/fuel" + { + "group": "Blockchains", + "pages": [ + "api-reference/deposit-actions/evm", + "api-reference/deposit-actions/bitcoin", + "api-reference/deposit-actions/solana", + "api-reference/deposit-actions/starknet", + "api-reference/deposit-actions/ton", + "api-reference/deposit-actions/tron", + "api-reference/deposit-actions/fuel" + ] + } ] }, { From 0bc89ca00176906ef1e20d87d27b4cef79139f6a Mon Sep 17 00:00:00 2001 From: Aren Date: Thu, 21 May 2026 15:22:46 +0400 Subject: [PATCH 7/7] Enhance deposit actions documentation for EVM, Starknet, and TON - Clarify `call_data` format for EVM chains, including memo details. - Add note on Starknet's transfer flow restrictions for specific networks. - Specify structure of `call_data` for Starknet and ensure atomic execution. - Update TON `call_data` to include asset information and clarify amount usage. --- api-reference/deposit-actions/evm.mdx | 8 ++++---- api-reference/deposit-actions/overview.mdx | 4 ++++ api-reference/deposit-actions/starknet.mdx | 12 ++++++++++-- api-reference/deposit-actions/ton.mdx | 8 +++++--- 4 files changed, 23 insertions(+), 9 deletions(-) diff --git a/api-reference/deposit-actions/evm.mdx b/api-reference/deposit-actions/evm.mdx index 0e408d6..467a096 100644 --- a/api-reference/deposit-actions/evm.mdx +++ b/api-reference/deposit-actions/evm.mdx @@ -13,12 +13,12 @@ This guide covers all EVM-compatible networks supported by Layerswap, including ## call_data Format -For EVM chains, `call_data` is a **hex-encoded string** (`0x...`) representing the transaction's `data` field: +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` may be `0x` or contain contract interaction data if routed through a contract. -- **ERC-20 token transfers**: `call_data` contains the encoded `transfer(address,uint256)` function call or a more complex contract interaction. +- **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`. -The `to_address` from the transfer action is the transaction recipient, and `amount` is in human-readable units. +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 diff --git a/api-reference/deposit-actions/overview.mdx b/api-reference/deposit-actions/overview.mdx index 014cd77..d5efb23 100644 --- a/api-reference/deposit-actions/overview.mdx +++ b/api-reference/deposit-actions/overview.mdx @@ -53,6 +53,10 @@ Each item in the `deposit_actions` array has the following structure: Call `POST /api/v2/swaps` with `use_deposit_address: false` and include the `source_address` parameter. The response will contain `deposit_actions`. + + Starknet, Paradex, and TON only support the transfer flow — `use_deposit_address: true` is rejected for these networks. All other source networks accept either mode. + + ```bash curl -X POST https://api.layerswap.io/api/v2/swaps \ -H "X-LS-APIKEY: your_api_key" \ diff --git a/api-reference/deposit-actions/starknet.mdx b/api-reference/deposit-actions/starknet.mdx index 92cd509..f0541c4 100644 --- a/api-reference/deposit-actions/starknet.mdx +++ b/api-reference/deposit-actions/starknet.mdx @@ -14,7 +14,10 @@ Starknet deposits are simple to execute because the Layerswap API returns a **pr ## call_data Format -For Starknet, `call_data` is a **JSON-encoded array of call objects**. Each call in the array specifies a contract invocation: +For Starknet, `call_data` is a **JSON-encoded array of call objects**. Layerswap always returns **two calls**: + +1. A `transfer` call on the token contract (ETH on Starknet is also an ERC-20). +2. A `watch` call on the Layerswap **Watchdog** contract, which the backend uses to match the deposit. ```json [ @@ -22,11 +25,16 @@ For Starknet, `call_data` is a **JSON-encoded array of call objects**. Each call "contractAddress": "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "entrypoint": "transfer", "calldata": ["0xRecipient", "0xAmountLow", "0xAmountHigh"] + }, + { + "contractAddress": "0xWatchdogContract...", + "entrypoint": "watch", + "calldata": ["0xSequenceNumber"] } ] ``` -For ERC-20 token transfers, the array typically contains a single `transfer` or `approve` + `transfer` call. For native ETH on Starknet, it's a direct transfer call on the ETH contract. +Both calls must execute atomically — pass the whole array to `account.execute()` as shown below; Starknet handles them as a single multicall transaction. ## Transaction Construction diff --git a/api-reference/deposit-actions/ton.mdx b/api-reference/deposit-actions/ton.mdx index fb45d0d..f02f191 100644 --- a/api-reference/deposit-actions/ton.mdx +++ b/api-reference/deposit-actions/ton.mdx @@ -17,13 +17,15 @@ For TON, `call_data` is a **JSON string** containing: ```json { - "comment": "layerswap_memo_identifier", - "amount": "1000000000" + "amount": "1000000000", + "asset": "TON", + "comment": "layerswap_memo_identifier" } ``` - `comment` — A text memo that Layerswap uses to identify the deposit. This is embedded in the transaction payload. -- `amount` — Present only for Jetton transfers; the Jetton amount in base units (nanojettons). For native TON transfers, use the transfer action's `amount` field instead. +- `amount` — The transfer amount in base units (nanotons for TON, base units of the Jetton otherwise). Always present; for native TON it matches the transfer action's `amount` field. +- `asset` — The source asset symbol (e.g. `TON`, `USDT`). Informational; the actual contract is on the transfer action's `token.contract`. ## Native TON Transfer