Skip to main content

SOR API Guide

This guide will help you get started with the Odos API endpoints for generating a quote (/sor/quote/v2) and assembling a transaction (/sor/assemble).

This guide is meant to be the simplest implementation possible for getting and executing Odos quotes via the API. For advanced usage and detailed explanation of each parameter and feature, please explore other areas of the documentation such as our detailed interactive documentation.

Anatomy of a Swap

This diagram shows the flow of a swap transaction using the Odos API. The following steps will show how to do each part of this diagram.

diagram of swap overview

Setup

Firstly, you'll need to setup your project. This involves importing the required libraries for making HTTP requests.

Recommended HTTP libraries (examples below):

  • Python: requests (Requires installation from here)
  • Javascript: fetch (natively supported in most environments)

Step 1: Generate a Quote

The first step in using the Odos SOR API is generating a quote. This can be achieved by sending a POST request to the /sor/quote/v2 endpoint. It is recommended to start with the example request body and customize as necessary.

Required Quote Request Parameters:

  • chainId: the ID of the chain you are requesting the quote on
  • inputTokens: a list of token addresses and input amounts, currently anywhere from 1-6 input assets at once. Input amounts should be strings representing fixed precision integer amounts relative to each asset's decimals
  • outputTokens: a list of token addresses and output proportions, currently anywhere from 1-6 output assets at once. The proportions should always total up to 1
  • slippageLimitPercent: the slippage tolerance for the quote, meaning the maximum percentage of the quote the user is willing to lose to slippage, where 1 represents 1% (99% of the original quoted output)
  • userAddr: the checksummed address of the user who will eventually assemble and execute the quote (required to get a pathId in the response for assembly)

Recommended Optional Quote Request Parameters:

  • referralCode: a referral code for tracking your projects activity using the Odos API and enabling partner relationships based on usage, learn more here. Defaults to 0 for unregistered activity.
  • disableRFQs: Whether or not to disable RFQ liquidity sources, which have third-party API dependencies and quote expirations, both of which can cause an increase in failed quotes and TXN reverts. Defaults to true to maximize reliability, but can be set to false in order to access these additional liquidity sources.
  • compact: a flag for enabling compact call data for quote assembly, setting to true is recommended, learn more here. Defaults to true.

For path route visualization parameters, refer to the Path Viz Quick Start Guide.

import json

import requests

quote_url = "https://api.odos.xyz/sor/quote/v2"

quote_request_body = {
"chainId": 1, # Replace with desired chainId
"inputTokens": [
{
"tokenAddress": "0x...", # checksummed input token address
"amount": "100000", # input amount as a string in fixed integer precision
}
],
"outputTokens": [
{
"tokenAddress": "0x...", # checksummed output token address
"proportion": 1
}
],
"slippageLimitPercent": 0.3, # set your slippage limit percentage (1 = 1%)
"userAddr": "0x...", # checksummed user address
"referralCode": 0, # referral code (recommended)
"disableRFQs": True,
"compact": True,
}

response = requests.post(
quote_url,
headers={"Content-Type": "application/json"},
json=quote_request_body
)

if response.status_code == 200:
quote = response.json()
# handle quote response data
else:
print(f"Error in Quote: {response.json()}")
# handle quote failure cases

Replace the placeholder values in the request body with actual values for your desired quote. The userAddr should be the checksummed address of the user who may eventually assemble and execute the transaction.

You'll receive a response with the quote details. The pathId response field will be necessary for assembling your transactions in the next step. Paths are valid for 60 seconds after the quote is received, after which a new quote will have to be requested.

Step 2: Assemble the Transaction

In order to execute an Odos quote on chain, the transaction must be assembled. The Odos API will completely assemble the transaction for you, manual assembly is discouraged and not supported. Once you have the pathId from the quote, you can send a POST request to the /sor/assemble endpoint to get the on-chain transaction data.

assemble_url = "https://api.odos.xyz/sor/assemble"

assemble_request_body = {
"userAddr": "0x...", # the checksummed address used to generate the quote
"pathId": quote["pathId"], # Replace with the pathId from quote response in step 1
"simulate": False, # this can be set to true if the user isn't doing their own estimate gas call for the transaction
}

response = requests.post(
assemble_url,
headers={"Content-Type": "application/json"},
json=assemble_request_body
)

if response.status_code == 200:
assembled_transaction = response.json()
# handle Transaction Assembly response data
else:
print(f"Error in Transaction Assembly: {response.json()}")
# handle Transaction Assembly failure cases

Replace the placeholder values in the request body with actual values. The userAddr should be the checksummed address of the user who requested the quote and will be executing the transaction.

The response will contain all of the necessary parameters for transaction execution in the transaction field which can be used to sign and execute the swap on-chain.

Step 3: Execute the Transaction

Once you have the transaction details from the /sor/assemble response, you can use the transaction object to sign and send directly with an EOA wallet or conduct a low level call from a smart contract with the transaction.data field. Reminder that modifying transaction.data or assembling any Odos router function call from scratch is not officially supported and 100% at your own risk.

Recommended Web3 libraries (examples below):

from web3 import Web3

# 1. create web3 provider
w3 = Web3(Web3.HTTPProvider("node http endpoint for your network"))

# 2. Extract transaction object from assemble API response
transaction = assembled_transaction["transaction"]

# 3. Sign tx with a private key
pk = "Your EOA private key"

# web3py requires the value to be an integer
transaction["value"] = int(transaction["value"])

signed_tx = w3.eth.account.sign_transaction(transaction, pk)

# 4. Send the signed transaction
tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction)

If executing from another smart contract, the transaction.data field of the transaction given in the response can be used in a low level call from another contract:

(bool success, bytes memory result) = router.call{value: $ethInput}(data)

Where $ethInput is 0 unless the native coin of the network is an input, in which case the value should be set to the corresponding path input amount. Approvals for ERC20 inputs should be made to the router address prior to the call. The address of the router can be found in the to field of the response, as well as from the /info/router/{version}/{chain_id} endpoint.

Need Help?

  • For a deeper dive, the API Endpoints page is your go-to resource, providing an extensive look at all available endpoints, parameters, and more.
  • For technical assistance, visit our Support Page.
  • Join the Odos Discord Community to connect with other developers and our team.