Integration FAQ
Questions
Indexer and SDK
SDK
Github - https://github.com/cryptoalgebra/tonco-sdk/
Examples and references
Github - https://github.com/cryptoalgebra/tonco-demo
Mainnet
Explorer page: https://indexer.tonco.io
GraphQL endpoint: https://indexer.tonco.io
Farming Backend: https://api-farming.tonco.io
Router Contract - EQC_-t0nCnOFMdp7E7qPxAOCbCWGFz-e3pwxb6tTvFmshjt5
Testnet
Explorer page: https://testnet-indexer.tonco.io
GraphQL endpoint: https://testnet-indexer.tonco.io
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.
Alternatively, if you don’t want to depend on our infrastructure, you can rescan the blockchain in search of messages POOL_INIT sent by the router
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
If you want to manually scan and enumerate all the positions for a particular pool you can first use the method getPoolStateAndConfiguration and get "Number of active NFT positions" from it. Then iterate from 0 as the index of NFT and call get_nft_address_by_index()
Getting positions with NFT API's
Position NFT is a real NFT so you can use TonConsole Api and TonCenter API to get NFT address info and metadata. For position parameters, however, you would need to call the NFT get-method - GetPositionInfo()
Getting positions from TONCO indexer
Please address the GraphQL schema documents for more details - GraphQL Schema Getting collected fees - https://docs.tonco.io/technical-reference/indexer#position-data Here is a small snippet that uses our 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
Below is an example of how to retrieve data for a specific liquidity position using the Position entity from the SDK. 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 getCollectedFees method.
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
Sending swap can be done with our SDK - https://github.com/cryptoalgebra/tonco-sdk
An example of swap preparation can be found here - https://github.com/cryptoalgebra/tonco-sdk/blob/36eb0d7feadfcdcd60583ebe4098eb25fcc02591/src/classes/PoolMessageManager.ts#L649
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 POOLV3_SWAP
Swap estimate
This question depends on your requirements, limitations, and infrastructure of choice. Here are 4 options
The simplest and most precise way is to call the pool contract get method - https://docs.tonco.io/technical-reference/contracts/pool#getswapestimategas
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
You can use our Typescript implementation of user-side swap simulation using TONCO DEX SDK). It includes 2 ways to estimate a swap: on-chain and off-chain. Before actual blockchain execution please check that the estimates you made with TS match the contract call.
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;
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
A swap request is created as a payload for TRANSFER_NOTIFICATION. The current version of the swap request - Swap Cell Building 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.
Forming Messages for Mint
Messages can be constructed using our SDK (@toncodex/sdk@mainnet) The source code for message construction can be found here: (https://github.com/cryptoalgebra/tonco-sdk/blob/36eb0d7feadfcdcd60583ebe4098eb25fcc02591/src/classes/PoolMessageManager.ts#L141).
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.
You can find it the code here - https://github.com/cryptoalgebra/tonco-demo/blob/main/sdk_examples/mint/message/createMintMessage.ts
Last updated