Nabla Docs
  • Nabla Finance
    • The problem Nabla solves
    • Benefits of using Nabla
  • Protocol Overview
    • Swap Algorithm
    • Liquidity Pools
      • Swap Pools
      • Backstop Pool
    • Oracle Details
      • Architecture
      • Pyth
      • Chainlink
      • EV:GO
  • Roadmap
  • Protocol-owned Liquidity (POL)
    • Trading Fees and LP Incentives
    • Nabla as an autonomous protocol
  • Security
    • Audits
    • Bug Bounty Program
  • Mainnet Alpha
    • Risks and Benefits of being a Mainnet Alpha LP
  • Monad Testnet
    • Add Monad Testnet to Metamask
    • Get Monad Test Tokens
    • Monad Testnet Tasks
  • Testnet Beta
    • Connect Wallet to Base Sepolia
    • Testnet Beta Tasks
    • Obtaining Base Sepolia Ether for Gas
    • Test Assets
    • Connect Wallet to Base Sepolia Testnet
    • Performing a Swap
    • Managing Swap Pool Liquidity
    • Redeem Swap Pool Shares via Backstop Pool
    • Managing Backstop Pool Liquidity
    • Withdraw Backstop Pool Liquidity via Excess Swap Pool
  • Testnet Alpha
    • Testnet Alpha Results
    • Whitelisting for testnet
      • Whitelist Campaigns List
      • $PYTH Stakers Whitelist
    • Connect Wallet to Sepolia Testnet
    • Requesting Testnet Gas
    • How to contribute to testing
    • Performing a Swap
    • Managing Swap Pool Liquidity
    • How to swap into a swap pool that is depleted
    • Managing Backstop Pool Liquidity
    • Redeem Swap Pool Shares via Backstop Pool
    • Withdraw Backstop Pool Liquidity via Excess Swap Pool
  • Liquidity Provision
  • $NABLA
    • $sNABLA Token Utility
    • Staking Mechanism
    • Fee Distribution
    • Tokenomics
    • Token Utility Summary
    • Governance
      • Initial Governance Implementation
      • Governance structure
      • Discussion and Proposal process
      • Voting process
      • Transparency and record-keeping
      • Code of conduct
      • Amendments to the Governance Framework
      • Template for a vote
  • $AMBER Onchain Points Program
    • Mainnet Alpha Rewards
      • Arbitrum-Mainnet Alpha Rewards
      • Base-Mainnet Alpha Rewards
    • $AMBER FAQ
  • πŸ’»Developers
    • Integration Guide
    • NablaPortal
    • NablaRouter
    • SwapPool
    • GenericPool
    • NablaBackstopPool
    • PythAdapter
    • ISlippageCurve
    • Contract addresses
      • Arbitrum One
      • Base
      • Monad Testnet
    • Contract errors
  • Community
    • Linktree
    • Twitter
    • Discord
    • Telegram
  • Whitepaper
  • Legal
    • Privacy Policy
    • Terms of Service
Powered by GitBook
On this page
  • Let's begin
  • 1. Retrieve price update data
  • 2. Get an on-chain quote
  • 3. Perform a swap
  • Done
  1. Developers

Integration Guide

PreviousDevelopersNextNablaPortal

Last updated 29 days ago

Welcome to the Nabla integration guide.

If you are new to Nabla, we recommend you start with the 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 contract as our entry point:

  • quoteSwapExactTokensForTokens and

  • swapExactTokensForTokens


Let's begin

1. Retrieve price update data

Nabla is an oracle based DEX.

You need to submit signed price update data to Nabla contracts, for hubs either using Pyth or Nabla Oracle price feeds.

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 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 `` 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:

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.

The price data field is needed for getting a most up-to-date quote

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
      }
    }
  ]
}

The data field is the needed price update data for moving forward with a swap.

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

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.

Query Nabla Quote API

Please contact us if you're interested in integrating 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.

The price data field is needed for getting a most up-to-date quote

Full response:

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

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

The data field is the needed price update data for moving forward with a swap.

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

2. Get an on-chain quote

NablaPortal.quoteSwapExactTokensForTokens(
    uint256 _amountIn, 
    address[] _tokenPath, 
    address[] _routerPath, 
    [priceTokenA, priceTokenB]
) external view returns (uint256 amountOut_)
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

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

The price updata data is considered as valid if on-chain update is "not too old". Also, if another bot or user updates the price on-chain that is newer than the one you have submitted, this newer price is taken.


The price feed ids from Pyth are listed here:

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

Example quote with foundry's cast for 1k USDC (6 decimal precision) to WETH through :

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

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.

πŸ’»
πŸŽ‰
☺️
πŸ™Œ
Developer overview
NablaPortal
deployed contracts section
PythAdapter
getPriceFeedIdByAsset
https://www.pyth.network/developers/price-feed-ids
https://hermes.pyth.network/docs/#/rest/price_stream_sse_handler
https://www.pyth.network/developers/price-feed-ids
NablaPortal
Nabla's Main Crypto Hub on Arbitrum
NablaPortal
_priceUpdateData