TONCO Docs
TONCO Web AppSocials
TONCO Docs EN
TONCO Docs EN
  • Overview
    • What is TONCO
    • Bringing Concentrated Liquidity to TON
    • Team
    • Social Media
    • Audits
    • Roadmap
    • Brand Kit
  • Understanding Concentrated Liquidity
    • Glossary
    • Fees
    • NFT LP Tokens
    • Farming
    • Farming FAQ
  • Price Ranges
    • Meaning of Ranges
    • Range Presets
    • Advanced Range Presets
    • Price Moves in Ranges
    • Impermanent Loss
    • Choosing a Strategy
    • Liquidity Scenarios
  • Benefits of Concentrated Liquidity
    • Perks for Liquidity Providers
    • Perks for Traders
    • Perks for Projects
    • Liquid Staking Tokens (LST)
  • Concentrated Liquidity Playbook
    • Basic Strategies
    • Hedging with EVAA (Lending)
    • Hedging with Storm Trade (Perp DEX)
    • Hedging with Tradoor (Perpetual futures)
  • Liquidity Providing Tutorial
    • Adding Liquidity
    • Managing a Position
    • Liquidity Migration Guide
    • How APR is Сalculated
    • LPs FAQ
  • TONCO Points Program
    • Introduction
    • How to Earn Points
  • Technical Reference
    • 📇Indexer
    • GraphQL Schema
    • Integration FAQ
    • Core Logic
      • 🧺Pool overview
      • Swap calculation
      • 💰Liquidity and positions
      • 📏Ticks
      • 🏦Reserves
    • Contracts
      • 📜Scenarios
      • Pool
      • Router
      • Position NFT
      • Account
Powered by GitBook
On this page
  • Questions
  • Indexer and SDK
  • SDK
  • Examples and references
  • Mainnet
  • Testnet
  • Retrieve pool data
  • Getting pool APR
  • Example
  • Retrieving positions
  • Getting positions by index
  • Getting positions with NFT API's
  • Getting positions from TONCO indexer
  • Retrieving position data using SDK
  • Forming messages for the swap
  • Swap estimate
  • Marking transactions for referral tracking
  • Forming Messages for Mint
  1. Technical Reference

Integration FAQ

PreviousGraphQL SchemaNextCore Logic

Last updated 1 month ago

Questions

Indexer and SDK

SDK

Github -

Examples and references

Github -

Mainnet

  • Router Contract - EQC_-t0nCnOFMdp7E7qPxAOCbCWGFz-e3pwxb6tTvFmshjt5

Testnet

  • Router Contract - EQDnfag9lHlc0rS6YeI7WwRq-3ltcKSsYxLiXmveB7gNUzNO

Retrieve pool data

The best way to get all the pools and general information about them is to use our indexer.

// Some code
import { ApolloClient, InMemoryCache, gql} from "@apollo/client/core";
import { Command, OptionValues } from "commander";

export const POOLS_QUERY = gql`
query PoolsQuery { 
 pools {   
   name
   address
   jetton0 {
       address
       symbol
       decimals
   }
   jetton1 {
       address
       symbol
       decimals
   }
 }  
}
`;
async function queryPools(options: OptionValues) {


   const appoloClient = new ApolloClient({
       uri: "https://indexer.tonco.io/", 
       credentials: 'same-origin',
       cache: new InMemoryCache(),
   });
   const response = await appoloClient.query({ query: POOLS_QUERY });
   const appoloPoolList =  response.data.pools
   console.log(appoloPoolList);
}

Indexer is critical for our system, and we keep it highly available, however, we encourage caching the pool list.

Getting pool APR

For information about the APR of the pool in farming, you need to refer to the URL:

GET api-farming.tonco.io/apr?pool=<pool address>

The answer has “apr” as the base apr and an array of farmings. Farming is considered active if rewardsLeft is not equal to zero. Farming has a property - multiplier, it is a coefficient that denotes how many times farming increases the base apr.

In most cases, a pool has only one active farming, but it is possible that it will have several in the future.

Example

Request:

https://api-farming.tonco.io/apr?pool=EQD25vStEwc-h1QT1qlsYPQwqU5IiOhox5II0C_xsDNpMVo7

Response:

{
  "apr": 65.96151567163085,
  "farmings": [
    {
      "pool": "0:f6e6f4ad13073e875413d6a96c60f430a94e4888e868c79208d02ff1b0336931",
      "rewardsLeft": "0",
      "rewardToken": "0:b113a994b5024a16719f69139328eb759596c38a25f59028b146fecdc3621dfe",
      "rewardRate": "208334",
      "id": 5,
      "multiplier": 1.3277778973971204
    }
  ]
}

Retrieving positions

There are several ways to get all positions and positions per person.

Getting positions by index

Getting positions with NFT API's

Getting positions from TONCO indexer

import { ApolloClient, InMemoryCache, gql} from "@apollo/client/core";
import { Address, TonClient4 } from "@ton/ton";
import { getHttpV4Endpoint } from "@orbs-network/ton-access";
import { PoolV3Contract } from "../wrappers/PoolV3Contract";

export const POSITION_QUERY = gql`
query PositionQuery($where: PositionWhere) {
    positions(where: $where) {
      id
      owner
      pool
      nftAddress      
      tickLower
      tickUpper
      liquidity
      feeGrowthInside0LastX128
      feeGrowthInside1LastX128
    }
}
`;

async function queryPositions(options: OptionValues) {

    const appoloClient = new ApolloClient({
        uri: "https://indexer.tonco.io/", // Replace with your GraphQL endpoint
        credentials: 'same-origin',
        cache: new InMemoryCache(),
    });

    const poolAddress  = Address.parse("EQD25vStEwc-h1QT1qlsYPQwqU5IiOhox5II0C_xsDNpMVo7")
    const ownerAddress = Address.parse("EQC2nUFN69DWcdgiuvSKXI6P3vHF9Gu_zW3OnQf0s5DgYBmJ")
    console.log(poolAddress.toRawString())
    console.log(ownerAddress.toString({bounceable: true}))

    const response = await appoloClient.query({ query: POSITION_QUERY, variables: {
        "where": {
            "pool" : poolAddress.toRawString(),
            "owner": ownerAddress.toString({bounceable: true})
        }
        } });
    const appoloPositionsList =  response.data.positions
    const client =  new TonClient4({ endpoint : await getHttpV4Endpoint() })
    const poolOpened = client.open(new PoolV3Contract(poolAddress))

    for (let [i, positionInfo] of appoloPositionsList.entries()) {
        console.log(`# ${i} :`);
        console.log(positionInfo);
        
        const fees = await poolOpened.getCollectedFees(positionInfo.tickLower, positionInfo.tickUpper, positionInfo.liquidity, positionInfo.feeGrowthInside0LastX128, positionInfo.feeGrowthInside1LastX128)
        console.log(`  Fees Jetton0 : ${fees.amount0}`)
        console.log(`  Fees Jetton1 : ${fees.amount1}`)

        const reserves = await poolOpened.getMintEstimate(positionInfo.tickLower, positionInfo.tickUpper, positionInfo.liquidity)
        console.log(`  Reserves Jetton0 : ${reserves.amount0}`)
        console.log(`  Reserves Jetton1 : ${reserves.amount1}`)

    }
}

Retrieving position data using SDK

import { TonClient } from '@ton/ton';
import { Address } from '@ton/core';
import {
  Jetton,
  Pool,
  PoolV3Contract,
  Position,
  PositionNFTV3Contract,
  pTON_MINTER,
} from '@toncodex/sdk';

const client = new TonClient({
  endpoint: 'https://toncenter.com/api/v2/jsonRPC',
});

const poolAddress = 'EQD25vStEwc-h1QT1qlsYPQwqU5IiOhox5II0C_xsDNpMVo7'; // TON - USDT

const poolContract = client.open(
  new PoolV3Contract(Address.parse(poolAddress)),
);
const poolData = await poolContract.getPoolStateAndConfiguration();

const jetton0 = new Jetton(
  pTON_MINTER,
  9,
  'TON',
  'TON',
  'https://cache.tonapi.io/imgproxy/0boBDKrVQY502vqLLXqwwZTS87PyqSQq0hke-x11lqs/rs:fill:200:200:1/g:no/aHR0cHM6Ly90b25jby5pby9zdGF0aWMvdG9rZW4vVE9OX1RPS0VOLndlYnA.webp',
);
const jetton1 = new Jetton(
  'EQCxE6mUtQJKFnGfaROTKOt1lZbDiiX1kCixRv7Nw2Id_sDs',
  6,
  'USD₮',
  'Tether USD',
  'https://tether.to/images/logoCircle.png',
);

const pool = new Pool(
  jetton0,
  jetton1,
  poolData.lp_fee_current,
  poolData.price_sqrt.toString(),
  poolData.liquidity.toString(),
  poolData.tick,
  poolData.tick_spacing,
);

const positionNFTAddress = 'EQAy5YMXX7e3916Io3Mi9DG3Xf7UAz2bKMMioYCOeYlDm7Ry'; // #3143 LP Position: [ -62160 -> -56100 ]

const positionContract = client.open(
  new PositionNFTV3Contract(Address.parse(positionNFTAddress)),
);

const positionInfo = await positionContract.getPositionInfo();

const liquidity = positionInfo.liquidity.toString();
const tickLower = positionInfo.tickLow;
const tickUpper = positionInfo.tickHigh;
const feeGrowthInside0LastX128 = positionInfo.feeGrowthInside0LastX128;
const feeGrowthInside1LastX128 = positionInfo.feeGrowthInside1LastX128;

const position = new Position({
  pool, // pool instance
  tickLower,
  tickUpper,
  liquidity,
});

// position amounts
const { amount0, amount1 } = position;

// fee amounts
const { amount0: feeAmount0, amount1: feeAmount1 } =
  await poolContract.getCollectedFees(
    tickLower,
    tickUpper,
    BigInt(liquidity),
    feeGrowthInside0LastX128,
    feeGrowthInside1LastX128,
  );

Forming messages for the swap

Swap estimate

This question depends on your requirements, limitations, and infrastructure of choice. Here are 4 options

  1. If you have ever implemented integration with other Algebra EVM projects written in your language of choice - then the output simulation can be bit-precise

a) Estimate Swap 1 TON -> USDT Example (on-chain)

import { Address, toNano, TonClient4 } from "@ton/ton";
import { getHttpV4Endpoint } from "@orbs-network/ton-access";
import { getSwapEstimate, PoolV3Contract, pTON_MINTER } from "@toncodex/sdk";

const POOL_ADDRESS = "EQD25vStEwc-h1QT1qlsYPQwqU5IiOhox5II0C_xsDNpMVo7"; // TON - USDT

const endpoint = await getHttpV4Endpoint();
const client = new TonClient4({ endpoint });

const poolV3Contract = client.open(new PoolV3Contract(Address.parse(POOL_ADDRESS)));

const inputJettonAddress = Address.parse(pTON_MINTER); // TON
const amountIn = toNano(1); // 1 TON

/* pool.jetton0_minter and pool.jetton1_minter from poolState are always sorted, so jetton0 is always first */
const { jetton0_minter } = await poolV3Contract.getPoolStateAndConfiguration(); // TON
const zeroToOne = inputJettonAddress.equals(jetton0_minter); // true

/* estimate 1 TON to USDT swap on-chain */
const result = await getSwapEstimate(amountIn, POOL_ADDRESS, zeroToOne, client);
return result;

b) Estimate Swap 1 TON -> USDT Example (off-chain)

import { Address, toNano, TonClient4 } from "@ton/ton";
import { getHttpV4Endpoint } from "@orbs-network/ton-access";
import { PoolV3Contract, pTON_MINTER, SwapSimulator, TickConstructorArgs } from "@toncodex/sdk";

const POOL_ADDRESS = "EQD25vStEwc-h1QT1qlsYPQwqU5IiOhox5II0C_xsDNpMVo7"; // TON - USDT

const endpoint = await getHttpV4Endpoint();
const client = new TonClient4({ endpoint });

const poolV3Contract = client.open(new PoolV3Contract(Address.parse(POOL_ADDRESS)));

const inputJettonAddress = Address.parse(pTON_MINTER); // TON
const amountIn = toNano(1); // 1 TON

const { jetton0_minter, price_sqrt, tick, tick_spacing, lp_fee_current, liquidity } =
        await poolV3Contract.getPoolStateAndConfiguration();

/* pool.jetton0_minter and pool.jetton1_minter from poolState are always sorted, so jetton0 is always first */
const zeroToOne = inputJettonAddress.equals(jetton0_minter); // true

const poolTicks = await poolV3Contract.getTickInfosAll();
const tickList: TickConstructorArgs[] = poolTicks.map((tick) => ({
    index: tick.tickNum,
    liquidityGross: tick.liquidityGross.toString(),
    liquidityNet: tick.liquidityNet.toString(),
}));

const swapSimulator = new SwapSimulator(price_sqrt, tick, tick_spacing, liquidity, lp_fee_current, tickList);

/* estimate 1 TON to USDT swap off-chain */
const result = await swapSimulator.swapExactIn(zeroToOne, amountIn);
return result;
  1. You can use our Kotlin implementation of user-side swap simulation.

# Usage example
# Expecting you have JVM and kotlinc 

git clone [email protected]:cryptoalgebra/tonco-demo.git 
cd tonco-demo
cd swap_kotlin
./run.sh

Marking transactions for referral tracking

With TONCO v1 It is possible to mark transactions to be able to index them for needs of referral tracking

  • You have 64 bits of query_id at your disposal. We don't alter it and copy it in the outgoing messages

Forming Messages for Mint

Example: Minting a Position in the TON/USDT Pool Below is an example of mint preparation for the TON/USDT pool within the price range [3.1, 6.5], based on an input amount of 1 TON.

⚠️ Important ⚠️: The validation step inside the example is crucial. Skipping it may result in a loss of funds.

Explorer page:

GraphQL endpoint:

Farming Backend:

Explorer page:

GraphQL endpoint:

Alternatively, if you don’t want to depend on our infrastructure, you can rescan the blockchain in search of messages sent by the router

APRfinal=APR⋅∑ifarming_multiplieriAPR_{final} = APR \cdot \sum_i farming\_multiplier _iAPRfinal​=APR⋅i∑​farming_multiplieri​

If you want to manually scan and enumerate all the positions for a particular pool you can first use the method and get "Number of active NFT positions" from it. Then iterate from 0 as the index of NFT and call

Position NFT is a real NFT so you can use and to get NFT address info and metadata. For position parameters, however, you would need to call the NFT get-method -

Please address the GraphQL schema documents for more details - Getting collected fees - Here is a small snippet that uses our indexer\

Below is an example of how to retrieve data for a specific liquidity position using the Position entity from the . The Position instance calculates the current token amounts based on liquidity and price range, while accumulated fees can be fetched directly from the smart contract via the method.

Sending swap can be done with our SDK -

An example of swap preparation can be found here -

A swap request is created as a payload in the jetton transfer and is sent to the router. The general logic of the input parameters can be derived from the SDK example above and the doc of the pool swap message

The simplest and most precise way is to call the pool contract get method -

You can use our Typescript implementation of user-side swap simulation using ). It includes 2 ways to estimate a swap: and . Before actual blockchain execution please check that the estimates you made with TS match the contract call.

A swap request is created as a payload for . The current version of the swap request - uses at most 850bits and 1ref. In the current version, all remaining cell part is ignored. However, to be future-proof proof we recommend to occupy second maybe_ref (1 ref and 1 bit). This cell starts with 4 byte of your service id and any content you need as remaining data.

Messages can be constructed using our SDK () The source code for message construction can be found here: ().

You can find it the code here -

https://indexer.tonco.io
https://indexer.tonco.io
https://api-farming.tonco.io
https://testnet-indexer.tonco.io
https://testnet-indexer.tonco.io
TonConsole Api
TonCenter API
GetPositionInfo()
GraphQL Schema
https://docs.tonco.io/technical-reference/indexer#position-data
SDK
getCollectedFees
https://github.com/cryptoalgebra/tonco-sdk
https://github.com/cryptoalgebra/tonco-sdk/blob/36eb0d7feadfcdcd60583ebe4098eb25fcc02591/src/classes/PoolMessageManager.ts#L649
https://docs.tonco.io/technical-reference/contracts/pool#getswapestimategas
TONCO DEX SDK
on-chain
off-chain
@toncodex/sdk@mainnet
https://github.com/cryptoalgebra/tonco-sdk/blob/36eb0d7feadfcdcd60583ebe4098eb25fcc02591/src/classes/PoolMessageManager.ts#L141
https://github.com/cryptoalgebra/tonco-demo/blob/main/sdk_examples/mint/message/createMintMessage.ts
https://github.com/cryptoalgebra/tonco-sdk/
https://github.com/cryptoalgebra/tonco-demo
What is your infrastructure? Do you have SDK?
How do you retrieve all the pools you have?
Now I have a pool, how do I get an APR value?
How do you retrieve all the positions?
How do I perform a swap from my code?
How do I predict the result of the swap?
How do I mark the swap transactions to be able to trace referrals?
How do I mint position from my code?
Swap Cell Building
TRANSFER_NOTIFICATION
POOL_INIT
getPoolStateAndConfiguration
get_nft_address_by_index()
POOLV3_SWAP