Skip to main content

Overview

This guide teaches you how to build your own liquidity provider service from scratch. You’ll learn the complete technical flow for:
  1. Polling for quote requests from users
  2. Calculating and submitting competitive quotes
  3. Monitoring for quote acceptance
  4. Executing the on-chain order fulfillment
  5. Settling cross-chain via LayerZero
  6. Withdrawing your earned fees
By the end, you’ll understand how to implement a production-ready LP service that earns 3-15 basis points per swap.
This is a technical implementation guide. You should be comfortable with TypeScript, blockchain transactions, and smart contract interactions.

Prerequisites

  • Blockchain development experience: Understanding of transactions, gas, signatures
  • TypeScript/JavaScript knowledge
  • Web3 library: Viem, ethers.js, or web3.js
  • Funded wallet with gas tokens and stablecoins on multiple chains
  • API key from Lidian Developer Portal

Core Concepts

The LP Business Model

As an LP, you profit from the spread between input and output amounts:
User sends:  1000 USDC on Base Sepolia
LP quotes:   998.50 USDC on Polygon Amoy (15 bps fee = 1.50 USDC)
LP provides: 998.50 USDC from their liquidity
LP receives: 1000 USDC + 1.50 USDC fee (after settlement)
Net profit:  1.50 USDC (minus gas costs ~$0.10)

The Order Lifecycle

1. QUOTE REQUEST → LP receives user's swap intent
2. QUOTE CREATION → LP calculates output amount with fee
3. QUOTE ACCEPTANCE → User signs order with EIP-712
4. DEPOSIT → LP relays signed order to source chain contract
5. FILL → LP provides liquidity on destination chain
6. SETTLEMENT → LP initiates LayerZero message back to source
7. WITHDRAWAL → LP claims input tokens + earned fee

Step 1: Poll for Quote Requests

Fetch Quote Requests from API

interface QuoteRequest {
  id: string;
  inputChain: string;        // e.g., "base-sepolia"
  inputToken: string;        // e.g., "0x036CbD..."
  inputAmount: string;       // e.g., "1000000" (1 USDC with 6 decimals)
  outputChain: string;       // e.g., "polygon-amoy"
  outputToken: string;       // e.g., "0x41E94..."
  offerer: string;           // User's wallet address
  recipient: string;         // Recipient's wallet address
  startTime: number;
  endTime: number;
}

async function pollForQuoteRequests() {
  const response = await fetch('https://api.lidian.finance/api/v1/quote-requests', {
    headers: {
      'Content-Type': 'application/json',
      'x-api-key': process.env.LIDIAN_API_KEY
    }
  });
  
  const { data } = await response.json();
  return data; // Array of QuoteRequest[]
}

Continuous Polling Loop

const processedRequests = new Set<string>();

async function monitorQuoteRequests() {
  while (true) {
    try {
      const requests = await pollForQuoteRequests();
      
      for (const request of requests) {
        if (processedRequests.has(request.id)) continue;
        
        console.log(`New quote request: ${request.id}`);
        await handleQuoteRequest(request);
        processedRequests.add(request.id);
      }
    } catch (error) {
      console.error('Polling error:', error);
    }
    
    await sleep(2000); // Poll every 2 seconds
  }
}

Step 2: Calculate Quote with Fee

Fee Structure

Different tokens have different basis point fees:
const TOKEN_FEES = {
  'base-sepolia': {
    '0x036CbD53842c5426634e7929541eC2318f3dCF7e': 15, // USDC: 15 bps
    '0x66F5018cdb5d6Eb0a3d1AC57F8b77243eb0010fF': 5,  // USDT: 5 bps
  },
  'polygon-amoy': {
    '0x41E94Eb019C0762f9Bfcf9Fb1E58725BfB0e7582': 3,  // USDC: 3 bps
    '0x86f6D9931BE92Ad61572e80c0F5FAe45950D4cA1': 3,  // USDT: 3 bps
  }
};

Calculate Output Amount

function calculateOutputAmount(
  inputAmount: bigint,
  inputDecimals: number,
  outputDecimals: number,
  feeBasisPoints: number
): bigint {
  // For stablecoins (1:1 ratio), calculate fee deduction
  // feeBasisPoints: 15 = 0.15% = 0.0015
  
  const FEE_DENOMINATOR = 10000n;
  const feeBps = BigInt(feeBasisPoints);
  
  // Calculate output = input * (1 - fee)
  // output = input * (10000 - feeBps) / 10000
  const outputAmount = (inputAmount * (FEE_DENOMINATOR - feeBps)) / FEE_DENOMINATOR;
  
  // Adjust for decimal differences if needed
  if (inputDecimals !== outputDecimals) {
    const decimalDiff = outputDecimals - inputDecimals;
    if (decimalDiff > 0) {
      return outputAmount * (10n ** BigInt(decimalDiff));
    } else {
      return outputAmount / (10n ** BigInt(-decimalDiff));
    }
  }
  
  return outputAmount;
}

// Example:
// Input: 1,000,000 (1 USDC with 6 decimals)
// Fee: 15 bps
// Output: 1,000,000 * (10000 - 15) / 10000 = 998,500 (0.9985 USDC)
// LP earns: 1,500 (0.0015 USDC = $1.50 on $1000 swap)

Check Liquidity Availability

import { createPublicClient, http, parseUnits } from 'viem';
import { polygonAmoy } from 'viem/chains';

async function checkLiquidity(
  chain: typeof polygonAmoy,
  tokenAddress: string,
  requiredAmount: bigint,
  lpWallet: string
): Promise<boolean> {
  const client = createPublicClient({
    chain,
    transport: http()
  });
  
  const balance = await client.readContract({
    address: tokenAddress,
    abi: [{
      name: 'balanceOf',
      type: 'function',
      stateMutability: 'view',
      inputs: [{ name: 'account', type: 'address' }],
      outputs: [{ type: 'uint256' }]
    }],
    functionName: 'balanceOf',
    args: [lpWallet]
  });
  
  return balance >= requiredAmount;
}

Step 3: Submit Quote to API

Create Quote Object

async function submitQuote(
  quoteRequestId: string,
  outputAmount: string
): Promise<string> {
  const response = await fetch('https://api.lidian.finance/api/v1/quotes', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'x-api-key': process.env.LIDIAN_API_KEY
    },
    body: JSON.stringify({
      quoteRequestId,
      outputAmount,
      liquidityProviderId: process.env.LP_WALLET_ADDRESS
    })
  });
  
  const { data } = await response.json();
  return data.id; // Returns quote ID (e.g., "quotes/abc123")
}

Handle Quote Request (Complete Flow)

async function handleQuoteRequest(request: QuoteRequest) {
  // 1. Get token fee
  const inputFee = TOKEN_FEES[request.inputChain]?.[request.inputToken] || 0;
  const outputFee = TOKEN_FEES[request.outputChain]?.[request.outputToken] || 0;
  const maxFee = Math.max(inputFee, outputFee);
  
  // 2. Calculate output amount
  const inputAmount = BigInt(request.inputAmount);
  const outputAmount = calculateOutputAmount(
    inputAmount,
    6, // USDC decimals
    6, // USDC decimals
    maxFee
  );
  
  // 3. Check if we have liquidity
  const hasLiquidity = await checkLiquidity(
    getChain(request.outputChain),
    request.outputToken,
    outputAmount,
    process.env.LP_WALLET_ADDRESS
  );
  
  if (!hasLiquidity) {
    console.log('Insufficient liquidity, skipping quote');
    return;
  }
  
  // 4. Submit quote
  const quoteId = await submitQuote(request.id, outputAmount.toString());
  console.log(`Quote submitted: ${quoteId} - Output: ${outputAmount.toString()}`);
  
  // 5. Start monitoring for acceptance
  monitorQuoteAcceptance(quoteId, request);
}

Step 4: Monitor for Quote Acceptance

Poll for Order Creation

When a user accepts your quote, they sign the order and create it in the API:
async function monitorQuoteAcceptance(
  quoteId: string,
  originalRequest: QuoteRequest
) {
  const timeout = Date.now() + 300000; // 5 minute timeout
  
  while (Date.now() < timeout) {
    try {
      // Fetch the quote to see if it was accepted
      const response = await fetch(
        `https://api.lidian.finance/api/v1/quotes/${quoteId}`,
        {
          headers: { 'x-api-key': process.env.LIDIAN_API_KEY }
        }
      );
      
      const { data: quote } = await response.json();
      
      // Check if order was created
      if (quote.orderId) {
        console.log(`Quote accepted! Order ID: ${quote.orderId}`);
        await processOrder(quote.orderId, originalRequest, quote.outputAmount);
        return;
      }
      
      // Check if quote expired/cancelled
      if (quote.status === 'expired' || quote.status === 'cancelled') {
        console.log(`Quote ${quoteId} ${quote.status}`);
        return;
      }
      
    } catch (error) {
      console.error('Error monitoring quote:', error);
    }
    
    await sleep(2000); // Poll every 2 seconds
  }
  
  console.log(`Quote monitoring timeout: ${quoteId}`);
}

Fetch Order Details

interface Order {
  id: string;
  signature: string;          // EIP-712 signature from user
  quoteId: string;
  status: string;
  moneyMoverAccountId: string; // User's wallet
  liquidityProviderAccountId: string; // Your wallet
}

async function fetchOrder(orderId: string): Promise<Order> {
  const response = await fetch(
    `https://api.lidian.finance/api/v1/orders/${orderId}`,
    {
      headers: { 'x-api-key': process.env.LIDIAN_API_KEY }
    }
  );
  
  const { data } = await response.json();
  return data;
}

Step 5: Execute Deposit on Source Chain

Build Order Struct for Contract

import { encodeFunctionData, keccak256, encodePacked } from 'viem';

// Helper: Calculate chain ID hash
function getChainHash(chainKey: string): `0x${string}` {
  return keccak256(encodePacked(['string'], [chainKey]));
}

interface OrderStruct {
  inputAmount: bigint;
  outputAmount: bigint;
  inputToken: `0x${string}`;
  outputToken: `0x${string}`;
  startTime: number;
  endTime: number;
  srcChainId: `0x${string}`;
  dstChainId: `0x${string}`;
  offerer: `0x${string}`;
  recipient: `0x${string}`;
}

Call deposit() on Lidian Contract

import { createWalletClient, http } from 'viem';
import { privateKeyToAccount } from 'viem/accounts';
import { baseSepolia } from 'viem/chains';

const LIDIAN_CONTRACT = '0xc2c00E85ab6bcf865986DE84053a6169bCBfa70F'; // Base Sepolia

const LIDIAN_ABI = [{
  name: 'deposit',
  type: 'function',
  stateMutability: 'nonpayable',
  inputs: [
    {
      name: 'order',
      type: 'tuple',
      components: [
        { name: 'inputAmount', type: 'uint128' },
        { name: 'outputAmount', type: 'uint128' },
        { name: 'inputToken', type: 'address' },
        { name: 'outputToken', type: 'address' },
        { name: 'startTime', type: 'uint32' },
        { name: 'endTime', type: 'uint32' },
        { name: 'srcChainId', type: 'bytes32' },
        { name: 'dstChainId', type: 'bytes32' },
        { name: 'offerer', type: 'address' },
        { name: 'recipient', type: 'address' }
      ]
    },
    { name: 'signature', type: 'bytes' }
  ],
  outputs: []
}];

async function executeDeposit(
  order: OrderStruct,
  signature: `0x${string}`
) {
  const account = privateKeyToAccount(process.env.LP_PRIVATE_KEY as `0x${string}`);
  const client = createWalletClient({
    account,
    chain: baseSepolia,
    transport: http()
  });
  
  console.log('Executing deposit on source chain...');
  
  const hash = await client.writeContract({
    address: LIDIAN_CONTRACT,
    abi: LIDIAN_ABI,
    functionName: 'deposit',
    args: [order, signature]
  });
  
  console.log(`Deposit tx: ${hash}`);
  
  // Wait for confirmation
  const receipt = await client.waitForTransactionReceipt({ hash });
  console.log(`Deposit confirmed at block ${receipt.blockNumber}`);
  
  return receipt;
}
Important: The deposit transaction uses the user’s signature to pull tokens from their wallet. The LP does not need to hold the input tokens.

Step 6: Execute Fill on Destination Chain

Approve Token Spending (if needed)

const ERC20_ABI = [{
  name: 'approve',
  type: 'function',
  stateMutability: 'nonpayable',
  inputs: [
    { name: 'spender', type: 'address' },
    { name: 'amount', type: 'uint256' }
  ],
  outputs: [{ type: 'bool' }]
}];

async function approveTokenIfNeeded(
  tokenAddress: `0x${string}`,
  spenderAddress: `0x${string}`,
  amount: bigint
) {
  const account = privateKeyToAccount(process.env.LP_PRIVATE_KEY as `0x${string}`);
  const client = createWalletClient({
    account,
    chain: polygonAmoy,
    transport: http()
  });
  
  // Check current allowance
  const publicClient = createPublicClient({
    chain: polygonAmoy,
    transport: http()
  });
  
  const allowance = await publicClient.readContract({
    address: tokenAddress,
    abi: [{
      name: 'allowance',
      type: 'function',
      stateMutability: 'view',
      inputs: [
        { name: 'owner', type: 'address' },
        { name: 'spender', type: 'address' }
      ],
      outputs: [{ type: 'uint256' }]
    }],
    functionName: 'allowance',
    args: [account.address, spenderAddress]
  });
  
  if (allowance >= amount) {
    console.log('Sufficient allowance already exists');
    return;
  }
  
  // Approve tokens
  console.log('Approving tokens...');
  const hash = await client.writeContract({
    address: tokenAddress,
    abi: ERC20_ABI,
    functionName: 'approve',
    args: [spenderAddress, amount]
  });
  
  await client.waitForTransactionReceipt({ hash });
  console.log('Approval confirmed');
}

Call fill() on Destination Chain

const LIDIAN_CONTRACT_AMOY = '0x7bE37DE6d81C6B231c8579901C6717f1A08c41ed'; // Polygon Amoy

async function executeFill(order: OrderStruct) {
  const account = privateKeyToAccount(process.env.LP_PRIVATE_KEY as `0x${string}`);
  const client = createWalletClient({
    account,
    chain: polygonAmoy,
    transport: http()
  });
  
  // 1. Approve Lidian contract to spend output tokens
  await approveTokenIfNeeded(
    order.outputToken,
    LIDIAN_CONTRACT_AMOY,
    order.outputAmount
  );
  
  // 2. Call fill()
  console.log('Executing fill on destination chain...');
  
  const hash = await client.writeContract({
    address: LIDIAN_CONTRACT_AMOY,
    abi: [{
      name: 'fill',
      type: 'function',
      stateMutability: 'payable',
      inputs: [{
        name: 'order',
        type: 'tuple',
        components: [
          { name: 'inputAmount', type: 'uint128' },
          { name: 'outputAmount', type: 'uint128' },
          { name: 'inputToken', type: 'address' },
          { name: 'outputToken', type: 'address' },
          { name: 'startTime', type: 'uint32' },
          { name: 'endTime', type: 'uint32' },
          { name: 'srcChainId', type: 'bytes32' },
          { name: 'dstChainId', type: 'bytes32' },
          { name: 'offerer', type: 'address' },
          { name: 'recipient', type: 'address' }
        ]
      }],
      outputs: []
    }],
    functionName: 'fill',
    args: [order]
  });
  
  console.log(`Fill tx: ${hash}`);
  
  const receipt = await client.waitForTransactionReceipt({ hash });
  console.log(`Fill confirmed at block ${receipt.blockNumber}`);
  
  return receipt;
}
After fill, the LP’s output tokens are locked in the destination chain contract. You must complete settlement to unlock your funds on the source chain.

Step 7: Settle via LayerZero

Quote LayerZero Fee

const LZ_ADAPTER_AMOY = '0x9ecf258aA68a483ac89057cBB9deAD71D6a7a3E0';

const ADAPTER_ABI = [{
  name: 'quote',
  type: 'function',
  stateMutability: 'view',
  inputs: [
    { name: 'dstChainId', type: 'bytes32' },
    { name: 'msgType', type: 'uint8' },
    { name: '_options', type: 'bytes' },
    { name: 'payInLzToken', type: 'bool' },
    { name: 'srcChainId', type: 'bytes32' },
    { name: 'sender', type: 'address' }
  ],
  outputs: [{ name: 'nativeFee', type: 'uint256' }]
}];

async function quoteLzFee(
  srcChainHash: `0x${string}`,
  dstChainHash: `0x${string}`,
  lpAddress: `0x${string}`
): Promise<bigint> {
  const client = createPublicClient({
    chain: polygonAmoy,
    transport: http()
  });
  
  // LayerZero options: 300k gas for lzReceive
  const options = '0x00030100110100000000000000000000000000030d40'; // 300k gas
  
  const fee = await client.readContract({
    address: LZ_ADAPTER_AMOY,
    abi: ADAPTER_ABI,
    functionName: 'quote',
    args: [
      dstChainHash,  // destination (source chain)
      0,             // msgType = settlement
      options,
      false,         // don't pay in LZ token
      srcChainHash,  // source chain
      lpAddress      // filler address
    ]
  });
  
  return fee as bigint;
}

Execute Settlement

async function executeSettlement(
  srcChainHash: `0x${string}`,
  dstChainHash: `0x${string}`
) {
  const account = privateKeyToAccount(process.env.LP_PRIVATE_KEY as `0x${string}`);
  const client = createWalletClient({
    account,
    chain: polygonAmoy,
    transport: http()
  });
  
  // 1. Quote the LayerZero fee
  const lzFee = await quoteLzFee(srcChainHash, dstChainHash, account.address);
  console.log(`LayerZero fee: ${lzFee.toString()} wei`);
  
  // 2. Call settle() with LZ fee as msg.value
  console.log('Executing settlement...');
  
  const options = '0x00030100110100000000000000000000000000030d40';
  
  const hash = await client.writeContract({
    address: LZ_ADAPTER_AMOY,
    abi: [{
      name: 'settle',
      type: 'function',
      stateMutability: 'payable',
      inputs: [
        { name: 'filler', type: 'address' },
        { name: 'dstChainId', type: 'bytes32' },
        { name: '_options', type: 'bytes' }
      ],
      outputs: []
    }],
    functionName: 'settle',
    args: [account.address, dstChainHash, options],
    value: lzFee
  });
  
  console.log(`Settlement tx: ${hash}`);
  
  const receipt = await client.waitForTransactionReceipt({ hash });
  console.log(`Settlement confirmed at block ${receipt.blockNumber}`);
  
  return receipt;
}
Settlement triggers a LayerZero cross-chain message. It takes ~30-60 seconds for the message to be delivered and verified on the source chain.

Step 8: Withdraw Funds + Fee

Wait for Settlement Delivery

async function waitForSettlement(orderId: string): Promise<boolean> {
  const timeout = Date.now() + 120000; // 2 minute timeout
  
  while (Date.now() < timeout) {
    try {
      // Check if settlement message was delivered
      // You can track this via LayerZero scan or contract events
      const settled = await checkIfSettled(orderId);
      
      if (settled) {
        console.log('Settlement message delivered');
        return true;
      }
    } catch (error) {
      console.error('Error checking settlement:', error);
    }
    
    await sleep(5000); // Check every 5 seconds
  }
  
  console.log('Settlement timeout');
  return false;
}

Execute Withdrawal

async function executeWithdrawal(
  inputToken: `0x${string}`,
  amount: bigint
) {
  const account = privateKeyToAccount(process.env.LP_PRIVATE_KEY as `0x${string}`);
  const client = createWalletClient({
    account,
    chain: baseSepolia,
    transport: http()
  });
  
  console.log('Executing withdrawal...');
  console.log(`Amount: ${amount.toString()}`);
  
  const hash = await client.writeContract({
    address: LIDIAN_CONTRACT,
    abi: [{
      name: 'withdraw',
      type: 'function',
      stateMutability: 'nonpayable',
      inputs: [
        { name: 'token', type: 'address' },
        { name: 'amount', type: 'uint256' }
      ],
      outputs: []
    }],
    functionName: 'withdraw',
    args: [inputToken, amount]
  });
  
  console.log(`Withdrawal tx: ${hash}`);
  
  const receipt = await client.waitForTransactionReceipt({ hash });
  console.log(`Withdrawal confirmed at block ${receipt.blockNumber}`);
  console.log('✅ Order complete! Fees earned.');
  
  return receipt;
}

Complete Implementation Example

async function processOrder(
  orderId: string,
  quoteRequest: QuoteRequest,
  outputAmount: string
) {
  try {
    // 1. Fetch order with signature
    const order = await fetchOrder(orderId);
    
    // 2. Build order struct
    const orderStruct: OrderStruct = {
      inputAmount: BigInt(quoteRequest.inputAmount),
      outputAmount: BigInt(outputAmount),
      inputToken: quoteRequest.inputToken as `0x${string}`,
      outputToken: quoteRequest.outputToken as `0x${string}`,
      startTime: quoteRequest.startTime,
      endTime: quoteRequest.endTime,
      srcChainId: getChainHash(quoteRequest.inputChain),
      dstChainId: getChainHash(quoteRequest.outputChain),
      offerer: quoteRequest.offerer as `0x${string}`,
      recipient: quoteRequest.recipient as `0x${string}`
    };
    
    // 3. Deposit on source chain
    await executeDeposit(orderStruct, order.signature as `0x${string}`);
    
    // 4. Fill on destination chain
    await executeFill(orderStruct);
    
    // 5. Settle back to source chain
    await executeSettlement(
      orderStruct.srcChainId,
      orderStruct.dstChainId
    );
    
    // 6. Wait for settlement delivery
    const settled = await waitForSettlement(orderId);
    if (!settled) {
      throw new Error('Settlement timeout');
    }
    
    // 7. Withdraw funds + fee
    const withdrawAmount = orderStruct.inputAmount; // This includes your fee
    await executeWithdrawal(orderStruct.inputToken, withdrawAmount);
    
    console.log(`✅ Order ${orderId} completed successfully!`);
    
  } catch (error) {
    console.error(`❌ Order processing failed:`, error);
    throw error;
  }
}

Profit Calculation

After completing an order, calculate your earnings:
function calculateProfit(
  inputAmount: bigint,
  outputAmount: bigint,
  gasUsed: {
    deposit: bigint;
    fill: bigint;
    settle: bigint;
    withdraw: bigint;
  },
  gasPrice: bigint
): bigint {
  // Fee earned (difference between input and output)
  const feeEarned = inputAmount - outputAmount;
  
  // Total gas cost
  const totalGas = gasUsed.deposit + gasUsed.fill + gasUsed.settle + gasUsed.withdraw;
  const gasCost = totalGas * gasPrice;
  
  // Net profit (in wei)
  const netProfit = feeEarned - gasCost;
  
  return netProfit;
}

// Example:
// Input: 1,000 USDC (1,000,000,000 with 6 decimals)
// Output: 998.5 USDC (998,500,000 with 6 decimals)
// Fee earned: 1.5 USDC (1,500,000)
// Gas cost: ~$0.10 (100,000 wei assuming USDC = ETH for simplicity)
// Net profit: 1.4 USDC ($1.40)

Production Considerations

Error Handling

async function processOrderWithRetry(
  orderId: string,
  maxRetries: number = 3
) {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      await processOrder(orderId, quoteRequest, outputAmount);
      return; // Success
    } catch (error) {
      console.error(`Attempt ${attempt} failed:`, error);
      
      if (attempt === maxRetries) {
        // Final failure - alert admin
        await sendAlert(`Order ${orderId} failed after ${maxRetries} attempts`);
        throw error;
      }
      
      // Wait before retry (exponential backoff)
      await sleep(Math.pow(2, attempt) * 1000);
    }
  }
}

Balance Monitoring

async function checkBalances(): Promise<void> {
  const chains = ['base-sepolia', 'polygon-amoy'];
  
  for (const chain of chains) {
    const balance = await getTokenBalance(
      chain,
      USDC_ADDRESS,
      LP_WALLET
    );
    
    if (balance < MIN_BALANCE_THRESHOLD) {
      await sendAlert(`Low balance on ${chain}: ${balance}`);
    }
  }
}

// Run every 5 minutes
setInterval(checkBalances, 5 * 60 * 1000);

Nonce Management

class NonceManager {
  private nonces = new Map<string, number>();
  
  async getNonce(address: string, chainId: number): Promise<number> {
    const key = `${address}-${chainId}`;
    
    if (!this.nonces.has(key)) {
      const nonce = await fetchOnChainNonce(address, chainId);
      this.nonces.set(key, nonce);
    }
    
    return this.nonces.get(key)!;
  }
  
  incrementNonce(address: string, chainId: number): void {
    const key = `${address}-${chainId}`;
    const current = this.nonces.get(key) || 0;
    this.nonces.set(key, current + 1);
  }
}

Testing Your Implementation

Testnet Setup

  1. Get testnet tokens from faucets:
  2. Fund your LP wallet with:
    • Gas tokens (ETH, MATIC)
    • Stablecoins (USDC, USDT)
  3. Test with small amounts first:
    • Start with $1-10 swaps
    • Verify all transactions succeed
    • Check balance updates

Debug Logging

function logOrderProgress(step: string, data: any) {
  console.log(`[${new Date().toISOString()}] ${step}`, {
    orderId: data.orderId,
    chain: data.chain,
    txHash: data.txHash,
    gasUsed: data.gasUsed,
    ...data
  });
}

Contract Addresses

Testnet Contracts

NetworkLidian ContractLayerZero Adapter
Base Sepolia0xc2c00E85ab6bcf865986DE84053a6169bCBfa70F0xe6dF658A8f53D47fec5294F351Adf11111C6fa01
Polygon Amoy0x7bE37DE6d81C6B231c8579901C6717f1A08c41ed0x9ecf258aA68a483ac89057cBB9deAD71D6a7a3E0
Avalanche Fuji0x875200c20719eB6914405c5C989226F97418e9280xDfaF9D6f669625eb63C98F3A34d03eC06ea2A073

Next Steps

Now that you understand the implementation:
  1. Build your service using this guide as a reference
  2. Test thoroughly on testnets before mainnet
  3. Monitor performance and optimize for your use case
  4. Scale gradually as you gain confidence
For production API keys and support, contact the Lidian team.

Additional Resources