Integration Guide

Welcome to the Nabla integration guide.

If you are new to Nabla, we recommend you start with the Developer overview section first.

We will go through the steps to get an on-chain swap quote and show you how to execute an ERC20-to-ERC20 swap with Nabla. For this, we are going to call the following functions at the NablaPortal contract as our entry point:

  • quoteSwapExactTokensForTokens and

  • swapExactTokensForTokens


Let's begin

1. Retrieve price update data

Nabla is an oracle based DEX.

You can check what price update data is needed, either

  • Pyth price update data or

  • Nabla price update data

for a pool ensemble/hub in the deployed contracts section under "Router".

Pyth price update data

Get the price feed ids (one time task)

You can retrieve the Pyth price feed ids (bytes32) from the PythAdapter `getPriceFeedIdByAsset` for the assets you are interested in. In case of USDC and WETH on Arbitrum:

# WETH
cast call 0x4cC48Fde2296E49E7dA73159c0bf0f89Bd8AF4aa "getPriceFeedIdByAsset(address)(bytes32)" 0x82aF49447D8a07e3bd95BD0d56f35241523fBab1 --rpc-url $ARBITRUM_MAINNET_RPC_URL 
0xff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace

# USDC
cast call 0x4cC48Fde2296E49E7dA73159c0bf0f89Bd8AF4aa "getPriceFeedIdByAsset(address)(bytes32)" 0xaf88d065e77c8cC2239327C5EDb3A432268e5831 --rpc-url $ARBITRUM_MAINNET_RPC_URL 
0xeaa020c61cc479712813461ce153894a96a6c00b21ed0cfc2798d1f9a9e9c94a

Basically these are the price feeds from Pyth, also listed here: https://www.pyth.network/developers/price-feed-ids

Query Pyth's Hermes API

Example (curl):

curl -X 'GET' \
  'https://hermes.pyth.network/v2/updates/price/latest?ids%5B%5D=0xff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace&ids%5B%5D=0xeaa020c61cc479712813461ce153894a96a6c00b21ed0cfc2798d1f9a9e9c94a' \
  -H 'accept: application/json'

Response (snippet, parsed section):

...
  "parsed": [
    {
      "id": "ff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace",
      "price": {
        "price": "305192675883",
        "conf": "153073812",
        "expo": -8,
        "publish_time": 1737975905
      },
...
{
      "id": "eaa020c61cc479712813461ce153894a96a6c00b21ed0cfc2798d1f9a9e9c94a",
      "price": {
        "price": "100003959",
        "conf": "117800",
        "expo": -8,
        "publish_time": 1737975905
      },

In this example the prices come with 8-decimal accuracy.

Full response:

{
  "binary": {
    "encoding": "hex",
    "data": [
      "504e41550100000003b801000000040d005ac409b82275b0f4581f0b6811974cc248d573f0b3a2150fc51f29f34e3ce6590c5afbb6751d96c2b888181fd97e6666aa2f59c661129b744c68920b3440beab000283426c73cbe491cd752d30a69c45d9fde6fe23040743d9dcb228ebd96efd785e12a61d39fc0ede203846e4bc11000fea59cf15f68c8956a8e0b2ab1bd5cc9cf200035791c4ae302ea0981d6c59a24ad83c5c52f2de48327c8fd79a6844a17bcba8a061af7ec15cbb93fbabce85d57f85102efddb0f9eb2dfed3776861f113d320ffb00047edb291f562eae0298ecd3863759f225f6da140fc1abe75e8fb2193ffedfdaa44895da1874dc4d385e6ec248af4aedba7c44842cda59df01b8dc2cef61abd13c0006c077eab40dc27a24622075c3477e837c098678a498b435e2c0a51eaba38b833543ebc93e0580815df106f4c33b8af0be9ae2e57a1429d0168bdc13ad16cb859b0108b496b670f8287721c4ef47d59ea3d117310abf6954d952883e160ea3154372720b398175a5d58c78d24d13f22c3ee465bf2e74fad91762b9f13d489d8458a6e6010ac07ce5fd5d56c89128ac9b064e8ae776da3f79a30446755f4e01d4b4db709e7c7a859c15ef4e302720e2c1f80a35ad469069c1bed440a679cc827d4d7d60ab90000bf8d0ab54e8dabbb1b0e8e6ec94ffd9b26915f1eaea6248774d8d6da8e995ff3455bc287362498a534541516fd8e931a6f91b30aa9305326c8005297fd9ed76fb010ca3127f7d4232b16aaaf9b528445b6219f1c1fe1a045677ea3dd095428e2a5e356d7fa8e28d6ad9696ae2adaf5ced471d20f06411f9711ebbe6f5d9d7737e4848000dd57293c785f4e43f0078df31b9be587f1d1e72336a08387b38737337994ff54a170bacc2f512550fb37a99d2f603a6acd140536999da093239f58d92f0b01609010e49c95d1badf53ceef358c7ae2852e2db2fc6999111bdff9dfbf855baf05abe863af6c5f2205bcc457ffc59c9cd36aabf96493a886f08c1691bb0fdc6036b351b000fbc02a92c1d94ac517e5844882b37b24f5097ad3ae246e3db9197a518d028e600622634b66bdec568a1fcff7291abcd0eeda7d747a0461da2a79a545935eff1660011006e9c665f83b9f4c32ddfa015ad9b56adae4214155e0dcae1dc69d9b53266742491b2ec95acdcb223af499d911df177956d89c27157211c006815c8ac5b93e90067976c2a00000000001ae101faedac5851e32b9b23b5f9411a8c2bac4aae3ed4dd7b811dd1a72ea4aa71000000000684a2f8014155575600000000000b9189b30000271046ce0774a317ccaebc81d3c486f14d96faafbcc302005500ff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace0000004760ec68200000000007fcfb98fffffff80000000067976c2a0000000067976c2900000047324fd2500000000009b2196a0bdc38644b353ef712c262043f6acf1aeca2ded131c37aab82271a1086e80957fcb03ff4707a920d2d5d62e4aad732b67f4ceb2192f61fe78e6e6ab46a15b45eac3728e4ad5f855960af2d10e512ef2e5cb57cb45eb93cb9b1b1cdfbc7bef79ca60599fbe8a67117d5bea1279f2ae39d350842484aeef2874c565559d6c4ab7693d98123b8600bd7acab21483545fa41c4d1e341fd2771f11395a2f8b67b78b7fd298439aa89bfedc10ecdc17d59ba2e6ae1a659d36ed3bdd02e40f9245ae51f15edf6e39ed91de880ed19773f8b7662cb6147e203afc1c5389e8ee83a005500eaa020c61cc479712813461ce153894a96a6c00b21ed0cfc2798d1f9a9e9c94a0000000005f5eb3f000000000001c939fffffff80000000067976c2a0000000067976c290000000005f5efd6000000000001b8190b9318da3665983c37b51bfe867db74406319810b9d0baa775344898275de3a5f93feaf82e9be5af47653daba796886dcd54f74c6b26dce797b455275d795ce318d7daa1cb788662a736d6f918bfe7021eb7e01606b69139ad4544ea31be423c2aef7a2f19ce4108c397c5e454d4194a4da0c005af34b9277dc07cd01a1ea4d832cd9d2159d5b1e17c8dd0f4ea45fa41c4d1e341fd2771f11395a2f8b67b78b7fd298439aa89bfedc10ecdc17d59ba2e6ae1a659d36ed3bdd02e40f9245ae51f15edf6e39ed91de880ed19773f8b7662cb6147e203afc1c5389e8ee83a"
    ]
  },
  "parsed": [
    {
      "id": "ff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace",
      "price": {
        "price": "306568783904",
        "conf": "134019992",
        "expo": -8,
        "publish_time": 1737976874
      },
      "ema_price": {
        "price": "305786770000",
        "conf": "162666858",
        "expo": -8,
        "publish_time": 1737976874
      },
      "metadata": {
        "slot": 194087347,
        "proof_available_time": 1737976875,
        "prev_publish_time": 1737976873
      }
    },
    {
      "id": "eaa020c61cc479712813461ce153894a96a6c00b21ed0cfc2798d1f9a9e9c94a",
      "price": {
        "price": "100002623",
        "conf": "117049",
        "expo": -8,
        "publish_time": 1737976874
      },
      "ema_price": {
        "price": "100003798",
        "conf": "112665",
        "expo": -8,
        "publish_time": 1737976874
      },
      "metadata": {
        "slot": 194087347,
        "proof_available_time": 1737976875,
        "prev_publish_time": 1737976873
      }
    }
  ]
}

For Pyth price update data, there is also a SSE streaming endpoint available https://hermes.pyth.network/docs/#/rest/price_stream_sse_handler

Nabla price update data

Get the price feed ids (one time task)

The price feed ids used for Nabla price update data are identical to Pyth. This is to ensure alignment with pool ensembles/hubs that still using Pyth price feeds and to ensure ease of integration.

The price feed ids from Pyth are listed here: https://www.pyth.network/developers/price-feed-ids

Query Nabla Quote API

Response (snippet, parsed section):

...
    {
      "id": "3fa4252848f9f0a1480be62745a4629d9eb1322aebab8a791e344b3b9c1adcf5",
      "metadata": {

      },
      "price": {
        "price": 29225000,
        "publish_time": 1744383661422
      }
    },
...

In this example the prices come with 8-decimal accuracy.

Full response:

{
  "binary": {
    "data": [
      string
    ],
    "encoding": "hex"
  },
  "parsed": [
    {
      "id": "3fa4252848f9f0a1480be62745a4629d9eb1322aebab8a791e344b3b9c1adcf5",
      "metadata": {

      },
      "price": {
        "price": 29480000,
        "publish_time": 1744379324061
      }
    }
  ]
}

For Nabla price update data, there is also a SSE streaming endpoint available.

2. Get an on-chain quote

We have just received the price information about the assets we are interested in. Now we can feed the prices directly into the NablaPortal quoting function:

NablaPortal.quoteSwapExactTokensForTokens(
    uint256 _amountIn, 
    address[] _tokenPath, 
    address[] _routerPath, 
    [priceTokenA, priceTokenB]
) external view returns (uint256 amountOut_)

Example quote with foundry's cast for 1k USDC (6 decimal precision) to WETH through Nabla's Main Crypto Hub on Arbitrum:

cast call 0xcB94Eee869a2041F3B44da423F78134aFb6b676B \
	"quoteSwapExactTokensForTokens(uint256 amountIn, address[] tokenPath, address[] routerPath, uint256[] tokenPrices)(uint256)" \
	1000000000 \
	"[0xaf88d065e77c8cC2239327C5EDb3A432268e5831,0x272dF896f4D0c97F65e787f861bb6e882776a155]" \
	"[0x7bcFc8b8ff61456ad7C5E2be8517D01df006d18d]" \
	"[100003959,305192675883]" \
	--rpc-url $(ARBITRUM_MAINNET_RPC_URL)

3. Perform a swap

We have received price updata data and are happy with the quote, we can now perform a swap through NablaPortal. For this to work we need to feed the price update data into the swap function as `_priceUpdateData`.

NablaPortal.swapExactTokensForTokens(
        uint256 _amountIn,
        uint256 _amountOutMin,
        address[] calldata _tokenPath,
        address[] calldata _routerPath,
        address _to,
        uint256 _deadline,
        bytes[] calldata _priceUpdateData
    )

If all requirements are met (e.g. minimum amount to accept & price update data not too old) the swap will execute successfully. πŸŽ‰


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