Integration Guide (onchain quoting)

Two modes of integration are possible. Onchain quoting - described in this guide, and offchain state syncing and simulation. While the former is trivial to implement, the latter is better suited for Nabla's High Frequency Pricing engine and will result with greater volumes and revenues over time.

If you are new to Nabla, we recommend you start with the Developer overview section first and explore our Nabla Swap API for reference.

We will go through the steps to discover pools and get an on-chain swap quote and show you how to execute a swap via NablaPortal contract.


1. Pool Discovery

ABI

  1. Fetch available routers Portal.getRouters() → returns all supported routers.

    function getRouters() external view returns (address[] memory routers)
  2. Get pools and assets of router Portal.getRouterPools(router) → returns assets and pools supported by that router.

       function getRouterPools(address router) external view returns (address[] memory assets, address[] memory pools)

Note that currently (and in the forseeable future) we are deploying a single router only.

Ethers.js example

import { ethers } from "ethers";

const portalAddress = process.env.PORTAL_ADDRESS;

const provider = new ethers.JsonRpcProvider(process.env.RPC_URL);

const portalAbi = [
  "function getRouters() external view returns (address[])",
  "function getRouterPools(address router) external view returns (address[])"
];

const portal = new ethers.Contract(
  portalAddress,
  portalAbi,
  provider
);

async function discoverPools() {
  const routers = await portal.getRouters();
  console.log("Routers:", routers);

  const pools = await portal.getRouterPools(routers[0]);
  const [poolAddresses, assetAddresses] = pools;
  console.log("Pools and assets for router 0:");
  poolsAddresses.forEach((pool, i) => {
    console.log("Pool:", pool, "Asset:", assetAddresses[i])
  })

  return {router: routers[0], assets: assetAddresses};
}

discoverPools();

2. Quoting

ABI

function quoteSwapExactTokensForTokens(
    uint256 _amountIn,
    address[] calldata _tokenPath,
    address[] calldata _routerPath
) external view returns (uint256 amountOut_)

_amountIn: input token amount

_tokenPath: ordered list of token addresses (swap path).

_routerPath: ordered list of routers

Ethers.js example

const portalAddress = process.env.PORTAL_ADDRESS;

const portalQuoteAbi = [
  "function quoteSwapExactTokensForTokens(uint256 amountIn, address[] tokenPath, address[] routerPath) external view returns (uint256)"
];

const portal = new ethers.Contract(
  portalAddress,
  quoterAbi,
  provider
);

async function getQuote(assetA, assetB, router) {
  const quote = await portal.quoteSwapExactTokensForTokens(
    ethers.parseUnits("1.0", 18), 
    [assets[0], assets[1]],
    [router]
  );
  console.log("Quoted output:", quote.toString());
}

3. Swapping

ABI

function swapExactTokensForTokens(
    uint256 _amountIn,
    uint256 _amountOutMin,
    address[] calldata _tokenPath,
    address[] calldata _routerPath,
    address _to,
    uint256 _deadline
) external returns (uint256 amountOut_)

Ethers.js example

const wallet = new ethers.Wallet(PRIVATE_KEY, provider);
const portalAddress = proces.env.PORTAL_ADDRESS;

const portalAbiSwap = [
  "function swapExactTokensForTokens(uint256,uint256,address[],address[],address,uint256,bytes[]) external returns (uint256)"
];

const portalWithSigner = new ethers.Contract(
  portalAddress,
  portalAbiSwap,
  wallet
);

async function doSwap(assetA, assetB, router, quotedOut) {
  const tx = await portalWithSigner.swapExactTokensForTokens(
    ethers.parseUnits("1.0", 18),     // amount in
    quotedOut * 9975n / 10000n,       // slippage tolerance (eg 0.25%)
    [assets[0], assets[1]],           // token path
    [router],                         // router path
    wallet.address,                   // recipient
    Math.floor(Date.now() / 1000) + 1, // deadline  
);
  console.log("Swap tx:", tx.hash);
}

4. Full flow example

import { ethers } from "ethers";

const RPC_URL = process.env.RPC_URL;
const PRIVATE_KEY = process.env.PRIVATE_KEY;

const provider = new ethers.JsonRpcProvider(RPC_URL);
const wallet = new ethers.Wallet(PRIVATE_KEY, provider);

// ---- ABIs ----
const portalAbi = [
  "function getRouters() external view returns (address[])",
  "function getRouterPools(address router) external view returns (address[])",
  "function quoteSwapExactTokensForTokens(uint256,uint256,address[],address[],address,uint256,bytes[]) external returns (uint256)"
  "function swapExactTokensForTokens(uint256,uint256,address[],address[],address,uint256,bytes[]) external returns (uint256)"
];

// ---- Contract addresses ----
const portalAddress = process.env.PORTAL_ADDRESS;


async function discoverPools() {
  const [router] = await portal.getRouters();

  const [poolAddresses, assets] = await portal.getRouterPools(routers[0]);

  return {router, assets};
}

async function main() {
  const portal = new ethers.Contract(PORTAL, portalAbi, wallet);

  // 1. Discover pools
  const {router, assets} = await discoverPools();

 
  // 2. Quote swap
  const amount = ethers.parseUnits("1", 18);

  const quotedOut = await portal.quoteSwapExactTokensForTokens(
    amount,
    [asset[0], asset[1]],
    [router]
  );
  console.log("Quoted output:", quotedOut.toString());

  // 3. Execute swap
  const minAmountOut = quotedOut * 9990n / 10000n; // 0.1 % slippage tolerance
  const tx = await portal.swapExactTokensForTokens(
    amount,
    minAmountOut,
    [asset[0], asset[1]],
    [router],
    wallet.address,
    Math.floor(Date.now() / 1000) + 1
  );
  console.log("Swap tx hash:", tx.hash);
}

main().catch(console.error);

Done ☺️

Thanks for integrating with Nabla 🙌 If you have questions, please do not hesitate to get in contact and ask in our Discord or Telegram.

Last updated