How our routing works
- You provide the input token, the output token and the amount you want to swap.
- We build the optimal route for you. This route can be direct
(input token -> output token)or indirect(input token -> token1 -> token2 -> ... -> output token). By splitting the amount of the input token between several liquidity pools on several decentralized exchanges (DeDust, STONfi, etc), we can reduce the price impact and get a better price for you. - We build the transactions that will swap the tokens.
- You send the transactions to the blockchain.
- If slippage is tolerated or deadline exceeds (in rare cases of blockchain lags), the transaction is being (possibly partially) reverted. Otherwise, you receive the output token in your wallet.
Basic usage
Swapping assets using our SDK and TonConnect SDK:Advanced usage
There are extra settings that you’re able to modify in case you want more control over how routes are built. The following parameters can be configured:max_length- maximum path length in tokens, default is 3. If specified, it must be an integer from [2; 5] range. Value of 2 indicates that route can contain only direct-swaps paths(input token -> output token). Value of 3, however, states that route may also contain paths with one intermediate token(input token -> token1 -> output token).
max_splits- maximum number of splits, default is 4. If specified, it must be an integer from [1; 20] range. Each split is a distinct path, therefore a distinct blockchain-message that will need to be sent. Currently, wallet contract implementations up to version 4 support not more than 4 messages in a single transaction. Starting from version 5, the number of message in a single transaction has been raise to 255(but ours upper limit is 20).
-
pool_selectoris an optional property that allows you to control which liquidity pools can be used whilst building the route.blockchains- allows you to limit liquidity pools to given blockchains only. Currently swap.coffee does not support cross-chain swaps, but who knows what will happen tomorrow 🙂 If you’re certain that you won’t like performing cross-chain swaps in the future, set this property to [“ton”] value. By default, all supported blockchains are used.dexes- allows you to limit liquidity pools to given dexes only. By default, all supported DEXes are used.max_volatility- allows you to filter out those liquidity pools, whose price volatility over the last 15 minutes exceeded the given value. The higher the value, the more volatile liquidity pools may be used.
Difference between direct and indirect routes
Direct routes without intermediate tokens are usually more safe, but less profitable. Indirect routes with intermediate tokens are usually more profitable, but less safe, because the price of intermediate tokens can change during the transaction and chance that your may receive intermediate tokens instead of the desired output token is higher. It’s called “slippage” - the difference between the expected price and the actual price. For example, when you setslippage to 0.1, it means that transaction within blockchain must be aborted if any of the swaps lead to obtaining less than 1 - 0.1 = 0.9 = 90% of amount predicted by swap.coffee backend in returned route. Due to async nature of TON blockchain, such slippage abortion can also lead to a situation where the sender is left with neither the input nor the output tokens, but an intermediate one.
There are also tokens that can’t be swapped directly, because they don’t share a liquidity pool. Therefore, if you setup parameters so that only direct swaps allowed (i.e. if max_length is equal to 2), an empty route will be built for you.
ExactOut swaps
If you want to receive an exact amount of output tokens, you can specify theoutput_amount parameter. Those swaps, in comparison to direct swaps (when you specify input_amount instead), may be significantly less profitable. They also do not support splitting, which means that resulting route (if exists) will always contain a single path.
Multi-asset swaps
Sometimes you might want to exchange multiple input assets for a single output asset in one operation. A common use case is swapping various tokens from your balance into a primary asset like TON or USDT. swap.coffee supports this scenario through Multi-asset swap feature. To use this feature via sdk, you’ll needbuildMultiAssetRoute function of the RoutingApi. This function is similar to its single-asset counterpart (buildRoute), but designed for multiple inputs.
Here are the key differences from buildRoute:
- Input parameters:
- Instead of
input_token: ApiTokenAddressandinput_amount: number,buildMultiAssetRouteaccepts a singleinput_assetsparameter. input_assetsis an array ofApiMultiAssetInputAssetobject, where each one has the following structure:
{ asset: ApiTokenAddress, amount: number }
This allows you to specify each input token and its corresponding amount.buildMultiAssetRoutedoes not supportoutput_amountfield.
- Instead of
- Return value structure:
buildMultiAssetRoutereturns anApiMultiAssetRouteobject.- The
ApiRouteobject (returned bybuildRoute) describes a single swap operation and contains fields likeinput_token,output_token,input_amount,output_amount, andpaths. - The
ApiMultiAssetRouteobject (returned bybuildMultiAssetRoute) aggregates information for the multi-asset swap:- It contains a
routes: ApiRoute[]field. Each element here is anApiRouteobject, representing one part of the multi-asset swap. - It contains an
output_token: ApiTokenfield, representing a single output token of the multi-asset swap. - It provides aggregated totals like
total_output_amount,total_savings,total_estimated_cashback_usd, etc., summing up corresponding values from all individual routes.
- It contains a
buildMultiAssetRoute to swap both TON and USDT for CES:
MEV Protection
You can enable MEV protection, which protects user’s swaps from the so-called sandwich attacks: a MEV bot buys the token before your trade and sells it immediately afterward, causing you to purchase at a higher price. By enabling MEV protection, you can ensure that swaps are not only secure but also maximally profitable. Note that we charge an additional fee for each split in the swap. However, this fee should be absolutely justified when swapping large amounts of liquidity. Be aware that enabling MEV protection will exclude the following DEXes from the routing due to their technical limitations:- STON.fi (v1 only)
Checking transaction results
Along with the transaction built, you receive theroute_id field. It can be used to check the result of the route’s transactions on the blockchain.
Basic usage
SDK contains inbuilt method for waiting execution results of route’s transactions. Promise will be resolved when all transactions are in terminal status (one ofsucceeded, failed or timed_out).
Advanced usage
By passingroute_id into getTransactionsResult() you can obtain current state of the route’s transactions execution status. Response is as follows:
buildTransactionsV2
method with.
Each element of the steps corresponds to a single swap within transaction. For example, if transaction is
A -> B -> C, then first entry in steps describes A -> B swap, and the second one describes B -> C.
TX_STATUSis a status of a single transaction (related to a single path):pendingindicates that none of transaction’s swaps have occurred in the blockchain yet.partially_complete- some (but not all) of transaction’s swaps have occurred in the blockchain.succeeded- all of transaction’s swaps have successfully executed in blockchain.failed- one of transaction’s swaps has been aborted due to slippage tolerance.timed_out- our service could not wait enough for at least one of transaction’s swaps to be present in the blockchain. This happens if more than 5 minutes have passed since the transaction was generated by our service until the user sent it, or if more than 3 minutes have passed since the previous swap for this transaction appeared in the blockchain.
SWAP_STATUSis a status of a single swap within a transaction:pendingindicates that this swap didn’t happen yet.cancelled- swap has been cancelled due to one of the previous swaps within same transaction failure or timeout.succeeded- swap successfully executed.failed- swap has been aborted due to slippage tolerance.timed_out- our service could not wait enough for this swap to be present in the blockchain.
- Transaction’s
inputandoutputfields are presented only if at least one swap has already moved to statussucceededorfailed. - Swap’s
inputandoutputfields are presented only if swap’s status issucceededorfailed. On failure (abortion due to slippage tolerance)outputis equal toinput.
route_id (and transactions) is generated via
buildTransactionsV2.
If all transactions are in terminal status (one of succeeded, failed or timed_out), further receipt of this
route’s status will be possible only for 1 minute, after which it will be invalidated from our service’s cache.
Custom fees (for partners only)
Starting January 2025 various DEXes stopped sharing their fees with aggregators like swap.coffee. We understand the desire of our partners to continue earning on user transactions, and therefore we provide functionality for charging additional fees. To do so, it is enough to pass thecustom_fee property to the transaction construction method:
custom_fee specification looks as follows:
Fixed fee
This method is for those cases when you want to charge the same level of commission on all trades through your service, regardless of the trade volume. Please keep in mind thatfixed_fee is specified in nano-TONs and must not be less than
10_000_000, which equals 0.01 TON.
Volume-percentage based fee
If you want to charge more commission the larger the trade the user makes, this method is for you.percentage_fee is specified in a parts on 1/1_000_000: 1 stands for 0.0001% and 1_000_000 stands for 100%.
Whilst using this method, you must also specify min_percentage_fee_fixed property, which, as much as fixed_fee,
must not be less than 10_000_000, which equals 0.01 TON. It is also up to you whether you want to limit fee value
from the above by setting max_percentage_fee_fixed property.
Overall, the final formula for volume-percentage based fee is as follows:
Thinking of max splits
Because of custom fees being withdrawn as a separate transactions, it is very important to keep in mind that wallet contracts have a limitation of how much transactions they may send at once: no more than 4 for walletV4 and no more than 255 for walletV5. That’s why, when adding custom fees, you must guarantee that the route for which you are building transactions contains no more thanmax_wallet_txs - 1 splits: it is configurable during buildRoute invocation (as shown above).
Default value of max_splits for buildRoute is 4. So, if you haven’t specified that property before, it’s time to
start doing so. If you have tools to determine user’s wallet version, you may set it to 3 for walletV4 and to 20
for walletV5. Otherwise, you can just leave it at 3, because in most circumstances this is more than enough for a
good route to be built.