Get A Quote

KyberSwap Elastic Security Incident

On 22 Nov 2023, the Elastic protocol experienced a security incident. More details can be found via our official channels.

All other KyberSwap products (Aggregator, Limit Order, & Classic) continue to be fully operational.

Introduction

Before executing a trade, you will first need to get a quote for the tokens that are being swapped. The quote is generated by the KyberSwap Quoter contract and consists of the input amount consumed, the output amount received, as well as the estimated gas required for the trade.

The logic for getting a quote can be found in the quote.ts file linked below:

Flow

Trade Parameters

For our trade example, we will be swapping 1 USDC -> KNC via the KNC-USDC 1% Fee Tier pool.

Getting A Quote

Step 1: Get the address of the pool to swap against

We first need to identify the pool through which our swap will be routed. Each pool can be uniquely identified by the token pair as well as the configured pool fee tier.

Using KyberSwap Analytics, we know that there is an existing KNC-USDC 1% Fee Tier pool at the following address:

targetPool: 0x4b440a7de0ab7041934d0c171849a76cc33234fa

To programatically get the above address without prior knowledge of the pool, we can use the computePoolAddress() function which returns the address of the pool created by the Factory contract based on the token pair and configured fee tier.

const poolAddress = computePoolAddress({
    factoryAddress: elasticContracts.FACTORY,
    tokenA: token0,
    tokenB: token1,
    fee: FeeAmount.EXOTIC,
    initCodeHashManualOverride: '0x00e263aaa3a2c06a89b53217a9e7aad7e15613490a72e0f95f303c4de2dc7045'
});
ParamsRemarks

factoryAddress

The Elastic Factory address. Specified in constant.ts. Please refer to Elastic Contract Addresses for the full list of Factory addresses across various chains.

tokenA

Input token for the swap. Specified in constant.ts.

tokenB

Output token for the swap. Specified in constant.ts.

fee

Fee configuration as per FeeAmount enum.

initCodeHashManualOverride

In order to create contracts with a known address, KyberSwap Elastic pools utilizes an initCodeHash value. This initCodeHash must be passed in whenever computing the address of such pools. More info here. Elastic Pools initCodeHash: 0x00e263aaa3a2c06a89b53217a9e7aad7e15613490a72e0f95f303c4de2dc7045

Based on the inputs above, you should be able to see the target pool address printed in your console. You can choose different tokens/fees and validate the result against KyberSwap Analytics.

Step 2: Extract pool information to construct Pool instance

With the pool address, we can then create an Ethers Contract instance which would give us access to the pool information. To create the Contract instance, we will also need access to the pool contract ABI. For your convenience, a sample ABI has been included under /abis/pools.json. This pool ABI will apply to all Elastic pools.

const poolContract = new ethers.Contract(
    poolAddress,
    PoolABI,
    getProvider()
);

Once the Contract instance is created, we can then pull the following information using the relevant Contract methods:

  • swapFeeUnits(): The fee configuration of the pool.

  • getLiquidityState(): The base and reinvest liquidity of the pool.

  • getPoolStates(): The sqrt price and current tick of the pool.

We now have all the information required to create a Pool instance.

All the functions above are covered by getPool() which returns the newly created Pool instance for the target pool.

Step 3: Encode quoter call parameters

We can now start to form the quote call parameters to be sent to the Quoter contract. The SwapQuoter abstract class exposes a quoteCallParameters() method which handles the encoding of the relevant on-chain quote methods.

For the purposes of this example, we will route the swap via the target pool by first creating the corresponding Route instance:

const route = new Route([pool], token0, token1);

We can then go ahead and encode the call parameters:

const quoteCallParameters = SwapQuoter.quoteCallParameters(
    route,
    CurrencyAmount.fromRawAmount(token0, token0RawAmountIn),
    TradeType.EXACT_INPUT
);

Note that we use the CurrencyAmount class to handle the raw token amount according to the token's decimal specification. Additionally, we specify the TradeType as EXACT_INPUT which takes in an exact tokenIn amount to calculate the output.

Step 4: Call the quoter contract

With the encoded quoter call parameters, we can then use our configured Ethers provider to call the Quoter contract. Note that we are only sending the calldata from the quoteCallParameters to the Quoter contract.

const returnedQuoteRaw = await getProvider().call({
    to: elasticContracts.QUOTER,
    data: quoteCallParameters.calldata
});

The quote will be returned as a hexstring which requires further processing to be converted into a human-readable format.

Step 5: Translate the call results

To decode the returnedQuoteRaw, we will need to leverage the Quoter contract ABI which has been conveniently included with the Elastic SDK. In this case, we know that the quote was requested based on the quoteExactInputSingle method.

const returnedQuote = SwapQuoter.INTERFACE.decodeFunctionResult('quoteExactInputSingle', returnedQuoteRaw);

After reformatting the above object, we are able to view the details of our quote printed in the console:

Last updated