Skip to main content
How to integrate TED Protocol into your application.

Overview

TED Protocol can be integrated through direct contract calls (medium complexity, full control), an SDK (coming soon, easy integration), or an embeddable widget (coming soon, lowest complexity). This guide covers direct contract integration.

Prerequisites

You’ll need a Web3 library (ethers.js, web3.js, or viem), TED Protocol contract addresses from the Contract Addresses page, and the contract ABIs.

Setup

Initialize your connection to TED Protocol:
import { ethers } from 'ethers';

// Contract addresses (example - verify on contract-addresses page)
const DIAMOND_ADDRESS = "0x...";  // Network-specific

// Combined ABI (includes all facets)
const TED_ABI = [
    // IFXSwap
    "function swap(address tokenIn, address tokenOut, uint256 amountIn, uint256 minAmountOut, uint256 deadline) returns (uint256)",
    "function getQuote(address tokenIn, address tokenOut, uint256 amountIn) view returns (tuple(uint256 amountOut, uint256 priceImpact, address[] route, uint256 gasEstimate))",

    // ICrossChainSwap
    "function crossChainSwap(tuple(address tokenIn, address tokenOut, uint256 amountIn, uint256 minAmountOut, uint32 srcChainId, uint32 dstChainId, address recipient, uint256 deadline, bytes bridgeOptions)) payable returns (bytes32)",
    "function estimateFees(tuple(address tokenIn, address tokenOut, uint256 amountIn, uint256 minAmountOut, uint32 srcChainId, uint32 dstChainId, address recipient, uint256 deadline, bytes bridgeOptions)) view returns (uint256, uint256)",

    // Events
    "event Swap(address indexed sender, address indexed tokenIn, address indexed tokenOut, uint256 amountIn, uint256 amountOut, address dex)",
    "event CrossChainSwapInitiated(bytes32 indexed messageId, address indexed sender, uint32 srcChainId, uint32 dstChainId, address tokenIn, address tokenOut, uint256 amountIn)"
];

// Initialize
const provider = new ethers.BrowserProvider(window.ethereum);
const signer = await provider.getSigner();
const tedProtocol = new ethers.Contract(DIAMOND_ADDRESS, TED_ABI, signer);

Same-Chain Swap

Execute a swap on a single chain by first approving tokens, getting a quote, calculating minimum output with slippage, and executing the swap:
async function executeSwap(tokenIn, tokenOut, amountIn, slippageBps = 50) {
    // 1. Approve tokens (if not already approved)
    const tokenContract = new ethers.Contract(tokenIn, ERC20_ABI, signer);
    const allowance = await tokenContract.allowance(userAddress, DIAMOND_ADDRESS);

    if (allowance < amountIn) {
        const approveTx = await tokenContract.approve(DIAMOND_ADDRESS, amountIn);
        await approveTx.wait();
    }

    // 2. Get quote
    const quote = await tedProtocol.getQuote(tokenIn, tokenOut, amountIn);

    // 3. Calculate minimum output with slippage
    const minAmountOut = quote.amountOut * (10000n - BigInt(slippageBps)) / 10000n;

    // 4. Execute swap
    const deadline = Math.floor(Date.now() / 1000) + 600; // 10 minutes

    const tx = await tedProtocol.swap(
        tokenIn,
        tokenOut,
        amountIn,
        minAmountOut,
        deadline
    );

    const receipt = await tx.wait();

    // 5. Parse events for confirmation
    const swapEvent = receipt.logs.find(log => {
        try {
            return tedProtocol.interface.parseLog(log)?.name === 'Swap';
        } catch { return false; }
    });

    if (swapEvent) {
        const parsed = tedProtocol.interface.parseLog(swapEvent);
        return {
            amountIn: parsed.args.amountIn,
            amountOut: parsed.args.amountOut,
            txHash: receipt.hash
        };
    }
}

Cross-Chain Swap

Execute swaps across different blockchains:
async function executeCrossChainSwap(params) {
    const {
        tokenIn,
        tokenOut,
        amountIn,
        srcChainId,
        dstChainId,
        recipient,
        slippageBps = 100
    } = params;

    // 1. Approve tokens
    const tokenContract = new ethers.Contract(tokenIn, ERC20_ABI, signer);
    const approveTx = await tokenContract.approve(DIAMOND_ADDRESS, amountIn);
    await approveTx.wait();

    // 2. Estimate fees
    const crossChainParams = {
        tokenIn,
        tokenOut,
        amountIn,
        minAmountOut: 0n,  // Will calculate after quote
        srcChainId,
        dstChainId,
        recipient,
        deadline: Math.floor(Date.now() / 1000) + 3600,
        bridgeOptions: "0x"
    };

    const [nativeFee, bridgeFee] = await tedProtocol.estimateFees(crossChainParams);

    // 3. Get expected output and set minimum
    const quote = await tedProtocol.getQuote(tokenIn, tokenOut, amountIn);
    crossChainParams.minAmountOut = quote.amountOut * (10000n - BigInt(slippageBps)) / 10000n;

    // 4. Execute cross-chain swap
    const tx = await tedProtocol.crossChainSwap(crossChainParams, {
        value: nativeFee
    });

    const receipt = await tx.wait();

    // 5. Get message ID for tracking
    const event = receipt.logs.find(log => {
        try {
            return tedProtocol.interface.parseLog(log)?.name === 'CrossChainSwapInitiated';
        } catch { return false; }
    });

    if (event) {
        const parsed = tedProtocol.interface.parseLog(event);
        return {
            messageId: parsed.args.messageId,
            txHash: receipt.hash
        };
    }
}

Tracking Cross-Chain Transfers

Monitor transfer status using the LayerZero Scan API:
async function trackTransfer(messageId) {
    const response = await fetch(
        `https://api.layerzeroscan.com/tx/${messageId}`
    );
    const data = await response.json();

    return {
        status: data.status,  // 'INFLIGHT', 'DELIVERED', 'FAILED'
        srcTxHash: data.srcTxHash,
        dstTxHash: data.dstTxHash
    };
}

Token Approvals

Standard approval grants the protocol permission to spend your tokens:
async function approveToken(tokenAddress, amount) {
    const token = new ethers.Contract(tokenAddress, ERC20_ABI, signer);
    const tx = await token.approve(DIAMOND_ADDRESS, amount);
    await tx.wait();
}
Permit (gasless approval) is supported by TEDP and some stablecoins via ERC-2612. This allows you to sign an approval off-chain and include it in your swap transaction, saving gas on the separate approval transaction. See the API Reference for permit implementation details.

Error Handling

Always simulate transactions before executing and handle custom errors:
async function safeSwap(tokenIn, tokenOut, amountIn) {
    try {
        // Simulate first
        await tedProtocol.swap.staticCall(
            tokenIn,
            tokenOut,
            amountIn,
            0n,  // Will fail if there's an issue
            Math.floor(Date.now() / 1000) + 600
        );

        // Execute if simulation passes
        return await executeSwap(tokenIn, tokenOut, amountIn);

    } catch (error) {
        // Parse custom errors
        if (error.data) {
            const iface = new ethers.Interface([
                "error InsufficientOutput(uint256 expected, uint256 actual)",
                "error DeadlineExpired(uint256 deadline, uint256 timestamp)",
                "error UnsupportedToken(address token)",
                "error ProtocolPaused()"
            ]);

            try {
                const decoded = iface.parseError(error.data);
                console.error(`Error: ${decoded.name}`, decoded.args);
            } catch {
                console.error("Unknown error:", error);
            }
        }
        throw error;
    }
}

Best Practices

Always get fresh quotes. Quotes are valid for a short time—execute immediately after quoting. Set appropriate slippage. For stablecoin pairs, use 0.1-0.5%. For cross-chain swaps, use 0.5-1%. For large amounts, use lower slippage to avoid unnecessary losses. Handle network switching. Ensure users are on the correct network before executing transactions:
async function ensureCorrectNetwork(requiredChainId) {
    const currentChainId = await provider.getNetwork().then(n => n.chainId);

    if (currentChainId !== requiredChainId) {
        await window.ethereum.request({
            method: 'wallet_switchEthereumChain',
            params: [{ chainId: ethers.toQuantity(requiredChainId) }]
        });
    }
}
Implement retry logic. Network issues can cause temporary failures—retrying with exponential backoff improves reliability.

Support

For integration support, join the #developers channel on Discord, email [email protected], or open issues and discussions on GitHub.