Architecture
This document explains the logic behind STON.fi Jetton-to-Jetton DEX
Actors
Router
The router is the contract that acts as an entrypoint for all DEX calls. It is responsible for routing all Jetton calls with transfer_notification
op to the correct pool contract.
It acts as a sovereign over the DEX, and can be used to lock/unlock trading on all pools, to change fees on a certain pool or to upgrade its own contract. The router is the only contract that can be upgraded. Each Jetton that goes through the DEX is owned by the router. The router does not store anything about pairs.
Pool
The pool is the contract that stores the AMM data for a certain pair and is responsible for handling "swaps" or providing liquidity for a certain pool. For each pair (e.g. TOKEN/USDT), there is only a single pool contract. The pool is also a Jetton Minter
, and handles minting/burning of Liquidity Provider Jettons. All the swap/lp calculations are done in the pool contract.
Account
The account contract holds information about the liquidity provided by the user before minting new liquidity. It interacts only with a single pool contract. For each user, there is single account contract for each pool. The router "routes" the temporary liquidity to the correct account contract. Then the account contract calls the pool contract again to mint new liquidity (once it satisfies some requirements).
Wallet (for LP jettons)
The wallet contract is a standard Jetton wallet and is used to hold the LP Jetton minted by Pools.
Calls descriptions
Swap
Lets assume that Alice wants to buy TOKEN using USDT. She should initialize a simple transfer to her own USDT Wallet with a custom payload. Once the Router receives the confirmation of the transfer, it will call the Pool contract to perform the real swap. Then the Pool contract will return the TOKEN Jetton calling pay_to
op to the Router.
Providing liquidity (both amounts)
Now Alice wants to provide liquidity to the TOKEN/USDT pair. This process must be done via two different calls. Obviously, since wallets support up to 4 transactions at same time, it is possible to call both calls at the same time (at least, from the user's perspective).
At the beginning, she should start a transfer to her own USDT Wallet with a custom payload. Once the Router receives the confirmation of the transfer, it will call the Pool contract, and then the Pool contract will route the request to her own Account contract. Once the request arrives to the Account contract, the first phase ends here. This time the Account contract doesn't generate any transactions.
In Dex v1 it is possible to provide liquidity using a different ratio than the current one in the pool, thus the unbalanced part will be lost to the user and distributed across all liquidity providers. In Dex v2 always a max amount of liquidity is minted to the user, meaning the unbalanced amount of a tokens is automatically swapped using the current token ratio in the pool.
Now, Alice makes another transfer of the other Jetton (in our case, TOKEN) in the same way as before. This time, the Account contract will generate a new message to the Pool contract to mint new liquidity.
Providing liquidity (single side provision)
Dex v2 supports liquidity provision using only one token by automatically performing a swap before minting liquidity
Creating a pool
V1
To create a new Pool, just provide the minimum amount of liquidity to pair (1001 Jettons). This initial liquidity will be sent to null address
. Any LP calls after this will mint LP Jettons to a user.
V2
To create a new Pool, just provide the minimum amount of liquidity to pair (1001 Jettons). A basic amount of 1001 lp tokens will be reserved on pool on initial liquidity deposit with the rest going to the user.
Last updated