STON.fi is a decentralized automated market maker (AMM) built on TON blockchain providing virtually zero fees, low slippage, an extremely easy interface, and direct integration with TON wallets.
Caution
The examples on this page use STON.fi’s API v2, which is currently under development. Thus, all addresses are given in testnet .
Proceed with caution and vigilance — do not attempt to send funds from the mainnet to the testnet and vice versa.
Before going further, familiarize yourself with the following:
Swaps
Read more about swaps in the STON.fi documentation .
Swaps use StonfiSwap
Message and SwapAdditionalData
Struct :
/// https://docs.ston.fi/docs/developer-section/api-reference-v2/router#swap-0x6664de2a
message ( 0x6664de2a ) StonfiSwap {
// Address of the other Router token wallet
otherTokenWallet : Address ;
// Where to send refunds upon a failed swap
// Where to send excesses upon a successful swap
excessesAddress : Address ;
// UNIX timestamp of execution deadline for the swap
// Reference to another Cell with additional data,
// using the Tact's greedy auto-layout mechanism
additionalData : SwapAdditionalData ;
/// https://docs.ston.fi/docs/developer-section/api-reference-v2/router#additional_data-body
struct SwapAdditionalData {
// Minimum required amount of tokens to receive
// Defaults to 1, which causes the swap to fail
// only if no tokens are received
minOut : Int as coins = 1 ;
// Where to send tokens upon a successful swap
receiverAddress : Address ;
// Forward fees for the `customPayload` if it's not `null`
fwdGas : Int as coins = 0 ;
// Custom payload that will be sent upon a successful swap
// Defaults to `null`, which means no payload
customPayload : Cell ? = null ;
// Forward fees for `refundPayload` if it's not `null`
refundFwdGas : Int as coins = 0 ;
// Custom payload that will be sent upon a failed swap
// Defaults to `null`, which means no payload
refundPayload : Cell ? = null ;
// Referral fee, between 0 (no fee) and 100 (1%)
// Defaults to 10, which means 0.1% fee
refFee : Int as uint16 = 10 ;
// Address of the referral
referralAddress : Address ? = null ;
▶️ Open in Web IDE
The STON.fi SDK defines some constants to deal with fees . Note that these are hardcoded values, but the best practice is to calculate fees dynamically using current config params instead.
/// Hardcoded fee value to pay for sending a message to the Jetton wallet
const FeeSwapJettonToJetton : Int = ton ( "0.3" );
/// Hardcoded fee value to pay forward fees from the Jetton wallet
const FeeSwapJettonToJettonFwd : Int = ton ( "0.24" );
/// Hardcoded fee value to pay for sending a message to the Jetton wallet
const FeeSwapJettonToToncoin : Int = ton ( "0.3" );
/// Hardcoded fee value to pay for sending a message to the Jetton wallet
const FeeSwapJettonToToncoinFwd : Int = ton ( "0.24" );
/// Hardcoded fee value to pay for sending a message and subsequent forwarding
const FeeSwapToncoinToJetton : Int = ton ( "0.01" ) + ton ( "0.3" );
▶️ Open in Web IDE
Jetton to Jetton
Caution
The following example uses STON.fi’s API v2, which is currently under development. Thus, all addresses are given in testnet .
In addition, some variables such as offerAmount
are hardcoded for demonstration purposes. Don’t forget to change them in real life scenarios.
const RouterAddress : Address =
address ( "kQALh-JBBIKK7gr0o4AVf9JZnEsFndqO0qTCyT-D-yBsWk0v" );
// Router Jetton Wallet address
const RouterJettonWallet : Address =
address ( "kQAtX3x2s-wMtYTz8CfmAyloHAB73vONzJM5S2idqXl-_5xK" );
/// NOTE : To calculate and provide Jetton wallet address for the target user,
/// make sure to check links after this code snippet
fun jettonToJetton ( myJettonWalletAddress : Address ) {
// Amount of Jettons to swap
let offerAmount : Int = 100_000 ;
let forwardPayload = StonfiSwap {
otherTokenWallet : RouterJettonWallet ,
refundAddress : myAddress (),
excessesAddress : myAddress (),
// Deadline is set to 10,000 seconds from now
deadline : now () + 10_000 ,
additionalData : SwapAdditionalData { receiverAddress : myAddress () },
// Start a swap with the message to the Jetton wallet
to : myJettonWalletAddress ,
value : FeeSwapJettonToJetton ,
destination : RouterAddress ,
responseDestination : myAddress (),
forwardTonAmount : FeeSwapJettonToJettonFwd ,
forwardPayload : forwardPayload . toCell (),
// Helper Messages, Structs and constants described earlier on this page
message ( 0x6664de2a ) StonfiSwap {
otherTokenWallet : Address ;
excessesAddress : Address ;
additionalData : SwapAdditionalData ;
struct SwapAdditionalData {
minOut : Int as coins = 1 ;
receiverAddress : Address ;
fwdGas : Int as coins = 0 ;
customPayload : Cell ? = null ;
refundFwdGas : Int as coins = 0 ;
refundPayload : Cell ? = null ;
refFee : Int as uint16 = 10 ;
referralAddress : Address ? = null ;
const FeeSwapJettonToJetton : Int = ton ( "0.3" );
const FeeSwapJettonToJettonFwd : Int = ton ( "0.24" );
// Messages from the Jetton standard
message ( 0xf8a7ea5 ) JettonTransfer {
responseDestination : Address ? ;
customPayload : Cell ? = null ;
forwardTonAmount : Int as coins ;
forwardPayload : Cell ? ; // slightly adjusted
▶️ Open in Web IDE
Jetton to Toncoin
Jetton to Toncoin swap is very similar to Jetton to Jetton swap with the only difference that the RouterJettonWallet
address is replaced with RouterProxyTonWallet
.
Caution
The following example uses STON.fi’s API v2, which is currently under development. Thus, all addresses are given in testnet .
In addition, some variables such as offerAmount
are hardcoded for demonstration purposes. Don’t forget to change them in real life scenarios.
const RouterAddress : Address =
address ( "kQALh-JBBIKK7gr0o4AVf9JZnEsFndqO0qTCyT-D-yBsWk0v" );
const RouterProxyTonWallet : Address =
address ( "kQBbJjnahBMGbMUJwhAXLn8BiigcGXMJhSC0l7DBhdYABhG7" );
/// NOTE : To calculate and provide Jetton wallet address for the target user,
/// make sure to check links after this code snippet
fun jettonToToncoin ( myJettonWalletAddress : Address ) {
// Amount of Jettons to swap
let offerAmount : Int = 100_000 ;
let forwardPayload = StonfiSwap {
otherTokenWallet : RouterProxyTonWallet ,
refundAddress : myAddress (),
excessesAddress : myAddress (),
// Deadline is set to 10,000 seconds from now
deadline : now () + 10_000 ,
additionalData : SwapAdditionalData { receiverAddress : myAddress () },
// Start a swap with the message to the Jetton wallet
to : myJettonWalletAddress ,
value : FeeSwapJettonToToncoin ,
destination : RouterAddress ,
responseDestination : myAddress (),
forwardTonAmount : FeeSwapJettonToToncoinFwd ,
forwardPayload : forwardPayload . toCell (),
// Helper Messages, Structs and constants described earlier on this page
message ( 0x6664de2a ) StonfiSwap {
otherTokenWallet : Address ;
excessesAddress : Address ;
additionalData : SwapAdditionalData ;
struct SwapAdditionalData {
minOut : Int as coins = 1 ;
receiverAddress : Address ;
fwdGas : Int as coins = 0 ;
customPayload : Cell ? = null ;
refundFwdGas : Int as coins = 0 ;
refundPayload : Cell ? = null ;
refFee : Int as uint16 = 10 ;
referralAddress : Address ? = null ;
const FeeSwapJettonToToncoin : Int = ton ( "0.3" );
const FeeSwapJettonToToncoinFwd : Int = ton ( "0.24" );
// Messages from the Jetton standard
message ( 0xf8a7ea5 ) JettonTransfer {
responseDestination : Address ? ;
customPayload : Cell ? = null ;
forwardTonAmount : Int as coins ;
forwardPayload : Cell ? ; // slightly adjusted
▶️ Open in Web IDE
Toncoin to Jetton
To swap Toncoin to Jetton, STON.fi requires the use of a so-called proxy Toncoin wallet (or pTON for short). To interact with it properly, we need to introduce a ProxyToncoinTransfer
Message :
/// https://github.com/ston-fi/sdk/blob/786ece758794bd5c575db8b38f5e5de19f43f0d1/packages/sdk/src/contracts/pTON/v2_1/PtonV2_1.ts
message ( 0x01f3835d ) ProxyToncoinTransfer {
// Unique identifier used to trace transactions across multiple contracts
// Defaults to 0, which means we don't mark messages to trace their chains
queryId : Int as uint64 = 0 ;
// Toncoin amount for the swap
// Where to send refunds upon a failed swap
// Optional custom payload to attach to the swap
▶️ Open in Web IDE
Notice that ProxyToncoinTransfer
is quite similar to JettonTransfer
, except that it doesn’t require any addresses other than the refund address, nor does it require any forward amounts to be specified.
Caution
The following example uses STON.fi’s API v2, which is currently under development. Thus, all addresses are given in testnet .
In addition, some variables such as offerAmount
are hardcoded for demonstration purposes. Don’t forget to change them in real life scenarios.
// Router's pTON wallet address
const RouterProxyTonWallet : Address
= address ( "kQBbJjnahBMGbMUJwhAXLn8BiigcGXMJhSC0l7DBhdYABhG7" );
// Router's Jetton wallet address
const RouterJettonWallet : Address =
address ( "kQAtX3x2s-wMtYTz8CfmAyloHAB73vONzJM5S2idqXl-_5xK" );
// Amount of Toncoin to swap
let offerAmount : Int = 1_000 ;
let forwardPayload = StonfiSwap {
otherTokenWallet : RouterJettonWallet ,
refundAddress : myAddress (),
excessesAddress : myAddress (),
// Deadline is set to 10,000 seconds from now
deadline : now () + 10_000 ,
additionalData : SwapAdditionalData { receiverAddress : myAddress () },
// Start a swap with the message to the proxy Toncoin wallet
to : RouterProxyTonWallet ,
value : FeeSwapToncoinToJetton + offerAmount ,
body : ProxyToncoinTransfer {
refundAddress : myAddress (),
forwardPayload : forwardPayload . toCell (),
// Helper Messages, Structs and constants described earlier on this page
message ( 0x01f3835d ) ProxyToncoinTransfer {
queryId : Int as uint64 = 0 ;
message ( 0x6664de2a ) StonfiSwap {
otherTokenWallet : Address ;
excessesAddress : Address ;
additionalData : SwapAdditionalData ;
struct SwapAdditionalData {
minOut : Int as coins = 1 ;
receiverAddress : Address ;
fwdGas : Int as coins = 0 ;
customPayload : Cell ? = null ;
refundFwdGas : Int as coins = 0 ;
refundPayload : Cell ? = null ;
refFee : Int as uint16 = 10 ;
referralAddress : Address ? = null ;
const FeeSwapToncoinToJetton : Int = ton ( "0.3" );
▶️ Open in Web IDE
Liquidity provision
Read more about liquidity provision in the STON.fi documentation .
STON.fi allows you to deposit liquidity by specifying only one type of token - the pool will automatically perform the swap and mint liquidity provider (LP) tokens. To do this you need to set bothPositive
field of ProvideLiquidity
Message to false
.
Liquidity deposits use ProvideLiquidity
Message and ProvideLiqudityAdditionalData
Struct :
/// https://docs.ston.fi/docs/developer-section/api-reference-v2/router#provide_lp-0x37c096df
message ( 0x37c096df ) ProvideLiquidity {
// Address of the other Router token wallet
otherTokenWallet : Address ;
// Where to send refunds if provisioning fails
// Where to send excesses if provisioning succeeds
excessesAddress : Address ;
// UNIX timestamp of execution deadline for the provisioning
// Reference to another Cell with additional data,
// using the Tact's greedy auto-layout mechanism
additionalData : ProvideLiquidityAdditionalData ;
/// https://docs.ston.fi/docs/developer-section/api-reference-v2/router#additional_data-body-1
struct ProvideLiquidityAdditionalData {
// Minimum required amount of LP tokens to receive
// Defaults to 1, which causes the provisioning to fail
// only if no tokens are received
minLpOut : Int as coins = 1 ;
// Where to send LP tokens if provisioning succeeds
receiverAddress : Address ;
// Should both tokens in a pair have a positive quantity?
// If not, then the pool would perform an additional swap for the lacking token
// Defaults to `true`, which means that deposit would only go through
// when both token amounts are non-zero
bothPositive : Bool = true ;
// Forward fees for the `customPayload` if it's not `null`
fwdGas : Int as coins = 0 ;
// Custom payload that will be sent if provisioning succeeds
// Defaults to `null`, which means no payload
customPayload : Cell ? = null ;
▶️ Open in Web IDE
The STON.fi SDK defines some constants to deal with fees . Note that these are hardcoded values, but the best practice is to calculate fees dynamically using current config params instead.
/// Hardcoded fee value to pay for sending a liquidity provisioning message
/// when depositing a certain amount of Jettons
const FeeSingleSideProvideLpJetton : Int = ton ( "1" );
/// Hardcoded fee value to pay forward fees of subsequent messages for liquidity provisioning
const FeeSingleSideProvideLpJettonFwd : Int = ton ( "0.8" );
/// Hardcoded fee value to pay for sending a liquidity provisioning message
/// when depositing a certain amount of Toncoins
const FeeSingleSideProvideLpToncoin : Int = ton ( "0.01" ) + ton ( "0.8" );
▶️ Open in Web IDE
Jetton deposit
Caution
The following example uses STON.fi’s API v2, which is currently under development. Thus, all addresses are given in testnet .
In addition, some variables such as offerAmount
are hardcoded for demonstration purposes. Don’t forget to change them in real life scenarios.
const RouterAddress : Address =
address ( "kQALh-JBBIKK7gr0o4AVf9JZnEsFndqO0qTCyT-D-yBsWk0v" );
// Router's pTON wallet address
const RouterProxyTonWallet : Address =
address ( "kQBbJjnahBMGbMUJwhAXLn8BiigcGXMJhSC0l7DBhdYABhG7" );
// Router's Jetton wallet address
const RouterJettonWallet : Address =
address ( "kQAtX3x2s-wMtYTz8CfmAyloHAB73vONzJM5S2idqXl-_5xK" );
/// NOTE : To calculate and provide Jetton wallet address for the target user,
/// make sure to check links after this code snippet
fun jettonDeposit ( myJettonWalletAddress : Address ) {
// Amount of Jettons for liquidity provisioning
let offerAmount = 100_000 ;
let forwardPayload = ProvideLiquidity {
otherTokenWallet : RouterProxyTonWallet ,
refundAddress : myAddress (),
excessesAddress : myAddress (),
// Deadline is set to 1,000 seconds from now
additionalData : ProvideLiquidityAdditionalData {
receiverAddress : myAddress (),
bothPositive : false , // i.e. single side
to : myJettonWalletAddress ,
value : FeeSingleSideProvideLpJetton ,
destination : RouterAddress ,
responseDestination : myAddress (),
forwardTonAmount : FeeSingleSideProvideLpJettonFwd ,
forwardPayload : forwardPayload . toCell (),
// Helper Messages, Structs and constants described earlier on this page
message ( 0x37c096df ) ProvideLiquidity {
otherTokenWallet : Address ;
excessesAddress : Address ;
additionalData : ProvideLiquidityAdditionalData ;
struct ProvideLiquidityAdditionalData {
minLpOut : Int as coins = 1 ;
receiverAddress : Address ;
bothPositive : Bool = true ;
fwdGas : Int as coins = 0 ;
customPayload : Cell ? = null ;
const FeeSingleSideProvideLpJetton : Int = ton ( "1" );
const FeeSingleSideProvideLpJettonFwd : Int = ton ( "0.8" );
// Messages from the Jetton standard
message ( 0xf8a7ea5 ) JettonTransfer {
responseDestination : Address ? ;
customPayload : Cell ? = null ;
forwardTonAmount : Int as coins ;
forwardPayload : Cell ? ; // slightly adjusted
▶️ Open in Web IDE
Toncoin deposit
Caution
The following example uses STON.fi’s API v2, which is currently under development. Thus, all addresses are given in testnet .
In addition, some variables such as offerAmount
are hardcoded for demonstration purposes. Don’t forget to change them in real life scenarios.
// Router's pTON wallet address
const RouterProxyTonWallet : Address =
address ( "kQBbJjnahBMGbMUJwhAXLn8BiigcGXMJhSC0l7DBhdYABhG7" );
// Router's Jetton wallet address
const RouterJettonWallet : Address =
address ( "kQAtX3x2s-wMtYTz8CfmAyloHAB73vONzJM5S2idqXl-_5xK" );
// Amount of Jettons for liquidity provisioning
let offerAmount = 100_000 ;
let forwardPayload = ProvideLiquidity {
otherTokenWallet : RouterJettonWallet ,
refundAddress : myAddress (),
excessesAddress : myAddress (),
additionalData : ProvideLiquidityAdditionalData {
receiverAddress : myAddress (),
bothPositive : false , // i.e. single side
to : RouterProxyTonWallet ,
value : FeeSingleSideProvideLpToncoin + offerAmount ,
body : ProxyToncoinTransfer {
refundAddress : myAddress (),
forwardPayload : forwardPayload . toCell (),
// Helper Messages, Structs and constants described earlier on this page
message ( 0x01f3835d ) ProxyToncoinTransfer {
queryId : Int as uint64 = 0 ;
message ( 0x37c096df ) ProvideLiquidity {
otherTokenWallet : Address ;
excessesAddress : Address ;
additionalData : ProvideLiquidityAdditionalData ;
struct ProvideLiquidityAdditionalData {
minLpOut : Int as coins = 1 ;
receiverAddress : Address ;
bothPositive : Bool = true ;
fwdGas : Int as coins = 0 ;
customPayload : Cell ? = null ;
const FeeSingleSideProvideLpToncoin : Int = ton ( "0.01" ) + ton ( "0.8" );
▶️ Open in Web IDE
Withdraw liquidity
To withdraw liquidity, burning LP tokens is required. You can refer to examples of Jetton burning in the respective section of Jettons Cookbook page . However, more Toncoins should be added than for the normal burn, since adding too few may result in LP tokens being burned, but no (or only partial) liquidity being sent from the pool. Therefore, consider attaching at least 0.5 0.5 0.5 Toncoin — excess amount will be returned.