Get started with XATA SDK

XATA
6 min readJan 12, 2022

The XATA SDK aims to give developers and projects an idea on how to get started with development on our Fair Liquidity Provisioning protocol. Integrate XATA with your project by using the XATA SDK JavaScript library to interact with the smart contract and/or trade on the liquidity pool.

Here’s how it works.

Prerequisites

Install the SDK by running the following command:

yarn add @xatadev/sdk

Make sure you have the following dependencies installed:

  • ethers.js
  • yarn

1. SDK Basics

XATA SDK is based on a fork of the Uniswap SDK that includes the XATA-API module, with several modifications to improve its flexibility so developers can interact easily with XATA and its technologies.

This section covers the steps needed to query for the parameters required for the various operations. We will cover only the Pair and Trade entities that can be used to fetch token prices of any given pair.

For more comprehensive documentation, refer here.

// 1. Import the modules and the ConveyorPair ABIimport { Currency, CurrencyAmount,  Pair, Token, ChainId, Trade, Route, Percent, TradeType } from ‘@xatadev/sdk’import { Contract } from ‘ethers’;import { abi as pairAbi } from ‘@xata/sdk/abis/ConveyorV2.json’// 2. Instantiate the Tokensconst TokenA = new Token(ChainId.MATIC, ‘0x2791bca1f2de4661ed88a30c99a7a9449aa84174’, 6) // USDC on Maticconst TokenB = new Token(ChainId.MATIC, ‘0x8f3cf7ad23cd3cadbd9735aff958023239c6a063’, 18) // DAI on MATIC// 3. Fetch the Pair addressconst pair_address = Pair.getAddress(TokenA, TokenB);// 4. Fetch the reserves, then the sort the tokensconst pairContract = new Contract(pair_address, pairAbi, web3)const [ reserve0, reserve1 ] = await pairContract.getReserves();const [ token0, token1 ] = tokenA.sortsBefore(tokenB) ? [tokenA, tokenB] : [tokenB, tokenA]// 5. Instantiate the Pairconst pair = new Pair(CurrencyAmount.fromRawAmount(token0, reserve0.toString()), CurrencyAmount.fromRawAmount(token1, reserve1.toString()));

Once you get to this point, you will be able to calculate the token price and the parameters needed to perform swap operations.

1.1 Calculate token price

When adding liquidity to an existing pair, the user supplies the amount for one of the tokens (independent), whereas the UI computes the amount for the other token (dependent). To get the amount of the dependent token, use the Pair.priceOf() method.

const amountARaw = ‘10’; // 10 USDCconst amountA = CurrencyAmount.fromRawAmount(tokenA, amountARaw);const amountB = pair.priceOf(tokenA).quote(amountA);

These amounts should be converted into BigNumber type, before passing into the API parameters.

1.2 Swap

First, establish the trading route

const route = new Route(pair, [tokenA, tokenB]);

Then, we can continue to get the minimum output or maximum input amount by using the Trade entity.

a. Exact input

const trade = new Trade(route, amountIn, TradeType.EXACT_INPUT)const slippage = new Percent(‘5’, ‘1000’); // 0.5%const amountOutMin = trade.minimumAmountOut(slippage)

b. Exact output

const trade = new Trade(route, amountIn, TradeType.EXACT_OUTPUT)const slippage = new Percent(‘5’, ‘1000’); // 0.5%const amountOutMin = trade.maxAmountInput(slippage)

1.3 Remove Liquidity —

Calculate withdrawable amount from liquidity

The amount of LP tokens that you hold determines the amount of tokens that can be withdrawn. Before getting this amount, we need to supply the total supply of the LP tokens and the amount of LP tokens to burn.

const totalSupplyRaw = await pairContract.totalSupply();const liquidityRaw = await pairContract.balanceOf(<your address>); // max liquidityconst totalSupply = CurrencyAmount.fromRawAmount(pairContract, totalSupplyRaw);const liquidity = CurrencyAmount.fromRawAmount(pairContract, liquidityRaw);const amountA = await pair.getLiquidityValue(tokenA, totalSupply, liquidity)const amountB = await pair.getLiquidityValue(tokenB, totalSupply, liquidity)

2. XATA-API

XATA is the very first liquidity provisioning protocol protected by Automata Network Conveyor, for a MEV-resistant trading experience. For that reason, all transactions sent to the contract must originate from a trusted relayer. The relayer provides an API endpoint to receive requests from the client. The API module is a convenient tool for developers to submit transaction requests to the relayer, using Uniswap-like function names and parameters.

In this article we will only walk you through the introduction of some basic parts of the API so it can give you an idea of how XATA API can be integrated into your app. To learn more, check out our documentation.

2.1 Setup

To use the API module, you must first initialize an instance, and provide a Web3 Provider and the address of the token that is used for payment.

// Import the API module from the SDKimport { Xata } from ‘@xatadev/sdk’// Instantiate the module. Then, provide a Web3 provider and the address of the fee token.const web3 = window.ethereum; // Metamaskconst usdc = ‘0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48’;const xataApi = new Xata(web3, usdc);

After the module has been instantiated, you can switch between fee tokens at any time, by doing the following:

const usdt = ‘0xdac17f958d2ee523a2206206994597c13d831ec7’;await xataApi.setFeeToken(usdt);

2.2 Fee Token Calculation

A commonly-held misconception about gasless transactions is that they are free, but this is not the case. What happens instead is that the relayer pays for gas and charges an equivalent amount of the selected fee token. XATA SDK uses the CoinGecko API to determine the market value of the token.

Tokens that are not listed on the CoinGecko API are effectively deemed unacceptable, which would cause the SDK to throw an error. The SDK provides the function that you can use to calculate the amount of fee tokens:

  1. calculateFee() parameters:
  • Chain ID
  • Token address
  • Token decimals
  • Gas fee
  • Native token symbol. See here

2. calculateFeeThenConvert() parameters:

  • Chain ID
  • Token address
  • Token decimals
  • Gas fee

To implement it on your code, follow the steps below:

// 1. Import the functionsimport { calculateFee, calculateFeeThenConvert, ChainId  } from ‘@xatadev/sdk’;import { BigNumber } from ‘ethers’;// 2. Calculate the gas fee using ethers BigNumberconst gaslimit = BigNumber.from(‘100000’); // some gas limitconst gasPrice = BigNumber.from(‘10000’); // some gas priceconst gasFee = gaslimit.mul(gasPrice);// 3.1. Calculate the fee amount using calculateFee...const bscNative = ‘bnb’const bsc_usdt = ‘0x55d398326f99059ff775485246999027b3197955’ // 18 decimalsconst maxTokenFee = await calculateFee(ChainId.BSC, bsc_usdt, 18, gasFee, bscNative)// 3.2. ... or using calculateFeeThenConvertconst polygon_usdt = ‘0xc2132d05d31c914a87c6611c10748aeb04b58e8f’ // 6 decimalsconst maxTokenFee: await calculateFeeThenConvert(chainId.MATIC, polygon_usdt, 6, gasFee)

When to use calculateFee vs calculateFeeThenConvert?

To get token prices from networks that are natively supported by the CoinGecko API, use the calculateFee(). Otherwise, an intermediary currency (BNB) is needed to convert tokens priced in BNB to their respective native currency, with the calculateFeeThenConvert() method.

EVM networks that work with calculateFee():

  • Binance Smart Chain
  • Ethereum Mainnet

All other networks must use the calculateFeeThenConvert() method.

2.3 Add Liquidity—

Refer to guide here

If you are creating a new pool, you may supply any amount of tokens and essentially decide the token price within the liquidity pool. Otherwise, you should provide an independent amount, then compute the dependent amount.

Use the xataApi.addLiquidity() method, and provide the following parameters:

  • tokenA
  • tokenB
  • amountADesired
  • amountBDesired
  • amountAMin
  • amountBMin
  • user
  • deadline
  • gasLimit — Optional
  • gasPrice — Optional

2.4 Swap

Swap will allow you to exchange some amount of token for some amount of another token. There are two variants of swap you can use by integrating XATA SDK into your app: swapExactTokensForTokens and swapTokensForExactTokens.

Exact Tokens For Tokens —

Refer to guide here

This variant will let you swap an exact amount of input tokens for as many output tokens as possible, by calling the swapExactTokensForTokens() method and provide these parameters below:

  • amountIn
  • amountOutMin
  • path
  • user
  • gasLimit — Optional
  • gasPrice — Optional

Tokens For Exact Tokens —

Refer to guide here

While the first variant uses an exact amount of input for calculating the trade, swapTokensForExactTokens behaves quite differently. In this variant you will receive an exact amount of output tokens for as few input tokens as possible. To use it you need to invoke swapTokensForExactTokens() method by passing along these following parameters:

  • amountOut
  • amountInMax
  • path
  • user
  • gasLimit — Optional
  • gasPrice — Optional

2.5 Remove Liquidity —

Refer to guide here

Before withdrawing your tokens from the pool, this process requires the router contract to seek approval to burn the LP tokens in exchange for the withdrawable tokens pair.

The approval process does not require gas, and can be executed by simply invoking the xataApi.permitLP() method and provide these parameters below:

  • Pair address
  • Owner
  • Spender
  • Value
  • Nonce
  • Deadline

When you successfully sign the LP spending permit, the permitLP() method will return a signature object to you.

You can provide the signature into the removeLiquidity() method to execute the actual liquidity removal process. To summarize it, the removeLiquidity() method should have these following parameters:

  • tokenA
  • tokenB
  • liquidity
  • amountAMin
  • amountBMin
  • user
  • deadline
  • sig — Signature object
  • gasLimit — Optional
  • gasPrice — Optional

About XATA

XATA is a Fair Liquidity Provisioning Protocol that minimizes Maximal Extractable Value. It provides multi-chain support for anti-front-running across blockchains including Polygon and Binance Smart Chain, without any reliance on miner bribe or modification.

--

--