Route and Calldata

Slippage is an important concept in trading that can have a significant impact on your trading outcomes. It refers to the difference between the expected price of a trade and the actual price at which the trade is executed. Slippage can occur in various market conditions and for several reasons, and it’s crucial for traders to be aware of its potential effects.Fibrous uses slippage settings to prevent you from losing money; there is no need to increase your slippage when you spot an arbitrage opportunity.Fibrous is still in alpha version. Please make sure you have adjusted your slippage properly.

Usage on EVM Networks (Base, Scroll)

Here’s how to execute a swap on EVM-compatible networks like Base and Scroll:
import { Router as FibrousRouter } from "fibrous-router-sdk";
import {  ethers, parseUnits } from "ethers";
import { account } from "./account";
import { humanReadableEvmSwapCallDataLog } from "../utils/humanReadableEvmLog";
import dotenv from "dotenv";
import { monitorTransaction } from "./utils";

dotenv.config();
// RPC URL for the EVM network, you can change this to the RPC URL of your choice
const RPC_URL = process.env.HYPER_EVM_RPC_URL;
// Destination address for the swap (optional)
const destination = process.env.EVM_PUBLIC_KEY;
// Private key of the account that will be used to sign the transaction
const privateKey = process.env.EVM_PRIVATE_KEY;

 const fibrous = new FibrousRouter();
    if (!privateKey || !RPC_URL || !destination) {
        throw new Error("Missing environment variables");
    }
    // Create a new contract instance
    const account0 = account(privateKey, RPC_URL);
    const chainId = fibrous.supportedChains.find(chain => chain.chain_name == "hyperevm")?.chain_id;
    if (!chainId) {
        throw new Error("Chain not supported");
    }

    const contractWallet = await fibrous.getContractWAccount(account0 as any, chainId);
    const provider = new ethers.JsonRpcProvider(RPC_URL);
    // Build route options
    const tokens = await fibrous.supportedTokens(chainId);
    // const inputToken = await fibrous.getToken(
    //         "0xb8ce59fc3717ada4c02eadf9682a9e934f625ebb",
    //     chainId,
    // );
    const inputToken = tokens.get("hype");
    if (!inputToken) {
        throw new Error("Input token not found");
    }
    const tokenInAddress = inputToken.address;
    const outputToken = tokens.get("khype");
    // if you want to search for a token that is not verified, you can use the getToken method
    // const outputToken = await fibrous.getToken(
    //     "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913", // USDC address
    //     "base",
    // );
    if (!outputToken) {
        throw new Error("Output token not found");
    }
    const tokenOutAddress = outputToken.address;
    const tokenInDecimals = Number(inputToken.decimals);
    const inputAmount = BigInt(parseUnits("10", tokenInDecimals)); // 5 Hype
    const isNativeToken =
        tokenInAddress == "0x0000000000000000000000000000000000000000";
    // Call the buildTransaction method in order to build the transaction
    // slippage: The maximum acceptable slippage of the buyAmount amount.
    const slippage = 1;
    const {route, calldata} = await fibrous.buildRouteAndCalldata(
        inputAmount,
        tokenInAddress,
        tokenOutAddress,
        slippage,
        destination || account0.address,
        chainId,
    );

    const approveResponse = await fibrous.buildApproveEVM(
        inputAmount,
        tokenInAddress,
        account0 as any,
        chainId,
    );
    humanReadableEvmSwapCallDataLog(
        calldata,
        inputToken,
        outputToken,
        await fibrous.supportedProtocols(chainId),
    );
    if (approveResponse === true) {
        try {
            // Type guard: EVM chains return EvmTransactionData
            if ("route" in calldata && "swap_parameters" in calldata) {
                const feeData = await provider.getFeeData();
                if (!feeData.gasPrice) {
                    console.log("gasPrice not found");
                    return;
                }
                let tx;
                if (isNativeToken) {

                    tx = await contractWallet.swap(
                        calldata.route,
                        calldata.swap_parameters,
                        {
                            value: inputAmount,
                            gasPrice: feeData.gasPrice * 4n,
                        },
                      
                    );
                } else {
                 
                    tx = await contractWallet.swap(
                        calldata.route,
                        calldata.swap_parameters,
                        {
                            gasPrice: feeData.gasPrice * 2n,
                        },
                    );
                }
                await monitorTransaction(tx);
             
            } else {
                console.error("Invalid swap call data for EVM transaction");
            }
        } catch (e) {
            console.error("Error swapping tokens: ", e);
        }
    } else {
        console.error("Error approving tokens");
    }

Usage on Starknet

For Starknet, the process is slightly different due to its unique architecture:
import { Router as FibrousRouter } from "fibrous-router-sdk";
import { Call } from "starknet";
import { parseUnits } from "ethers";
import "dotenv/config";
import { account } from "./account";
import { humanReadableStarknetSwapCallDataLog } from "../utils/humanReadableStarknetLog";

const PUBLIC_KEY = process.env.STARKNET_PUBLIC_KEY;
const PRIVATE_KEY = process.env.STARKNET_PRIVATE_KEY;
const RPC_URL = process.env.STARKNET_RPC_URL;
const DESTINATION = process.env.STARKNET_PUBLIC_KEY; // The address to receive the tokens after the swap is completed (required)

 // Create a new router instance
const fibrous = new FibrousRouter();
const chainId = fibrous.supportedChains.find(chain => chain.chain_name == "starknet")?.chain_id;
if (!chainId) {
    throw new Error("Chain not supported");
}
if (!DESTINATION || !PRIVATE_KEY || !RPC_URL || !PUBLIC_KEY) {
    throw new Error("Missing environment variables");
}

// Get the supported tokens for the Starknet chain
const tokens = await fibrous.supportedTokens(chainId);
/**
  * recommended that use the token address directly
  * because there may be more than one token with the same symbol.
  */
const inputToken = await fibrous.getToken(
    "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", // ETH address
    chainId,
);
if (!inputToken) {
    throw new Error("Input token not found");
}
const outputToken = tokens.get("strk"); // this search in only the tokens that are verified
    // if you want to search for a token that is not verified, you can use the getToken method
    // const outputToken = await fibrous.getToken(
    //     "0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", // STRK address
    //     "starknet",
    // );
    if (!outputToken) {
        throw new Error("Output token not found");
    }
const tokenInAddress = inputToken.address;
const tokenOutAddress = outputToken.address;
const tokenInDecimals = Number(inputToken?.decimals);
if (!tokenInAddress || !tokenOutAddress || !tokenInDecimals) {
    throw new Error("Token not found");
}
const inputAmount = BigInt(parseUnits("0.0001", tokenInDecimals)); // 0.0001 ETH

// Call the buildTransaction method in order to build the transaction
// slippage: The maximum acceptable slippage of the buyAmount amount.
const slippage = 1; // 1%
const {route, calldata} = await fibrous.buildRouteAndCalldata(
    inputAmount,
    tokenInAddress,
    tokenOutAddress,
    slippage,
    DESTINATION,
    chainId,
    {
        reverse: false,
        direct: false,
        excludeProtocols: [],
    },
);

// https://www.starknetjs.com/docs/guides/connect_account
// If this account is based on a Cairo v2 contract (for example OpenZeppelin account 0.7.0 or later), do not forget to add the parameter "1" after the privateKey parameter
const account0 = account(PRIVATE_KEY, PUBLIC_KEY, "1", RPC_URL);
const approveCall: Call = await fibrous.buildApproveStarknet(
    inputAmount,
    tokenInAddress,
);
humanReadableStarknetSwapCallDataLog(
    calldata,
    inputToken,
    outputToken,
    await fibrous.supportedProtocols(chainId),
);

// Type guard: Starknet chains return Call
if ("contractAddress" in calldata && "entrypoint" in calldata) {
    const resp = await account0.execute([approveCall, calldata]);
    console.log(`https://voyager.online/tx/${resp.transaction_hash}`);
} else {
    console.error("Invalid swap call data for Starknet transaction");
}

Important Notes

  1. Always handle errors appropriately in production code
  2. Set a reasonable slippage value based on your trading strategy
  3. Make sure to have sufficient balance and approved tokens before executing swaps
  4. Monitor transaction status and implement proper error handling
  5. Consider implementing retry mechanisms for failed transactions
  6. Keep private keys secure and never expose them in your code