@sentre/senswap
v1.0.9
Published
SenSwap is a Balancer-like AMM on Solana. The AMM implementation is heavily relying on [Balancer's Whitepaper](https://balancer.fi/whitepaper.pdf).
Downloads
15
Maintainers
Readme
SenSwap
SenSwap is a Balancer-like AMM on Solana. The AMM implementation is heavily relying on Balancer's Whitepaper.
Beside that, we also add some extra features to help leverage others on-top application in the future. You can find details in the Implementation.
Preresiquite
Install anchor-lang
Please follow this link https://www.anchor-lang.com/docs/installation to setup anchor-lang on your machine.
pnpm
Due to some conlicts between yarn
and anchor-lang
, we decided to migrate yarn
to pnpm
within this project. Follow https://pnpm.io/installation to setup pnpm and run the below commands to install the project's dependencies
pnpm install
Build
To build the program,
pnpm build
Test
To run the testcase,
pnpm test
Folder Structure
| Folder name | Description |
| ------------------------------- | --------------------------------------------------------------------------------------------------------- |
| src/balancer-amm
| The smart contract implementation |
| src/balancer-amm/instructions
| The smart contract's processors. Each instruction from users will be navigated to the relevant processor. |
| src/balancer-amm/schema
| Defines program account schema. |
| lib
| The SenSwap Javascript SDK to help developers to interact with the smart contract. |
| migrations
| Contains smart contract deployment scripts. |
| tests
| Contains testcases for both the smart contract and the SDK. |
| .github
| Defines Github workflows |
Implementation
This section will require the reader to understand both the current documentation and the source code also.
Fig.1. This is flowchart-like diagram depicting available features of SenSwap corresponding to its state. Note that the circle is just a diagram connector and has no semantic meaning.
How to initialize a pool?
To initialize a pool, the pool owner needs to call initialize_pool
first. The function will ask for basic info like mints
, treasuries
, weights
, etc., to create a pool account and store these info.
Note that initialize_pool
won't create any accounts (execept the pool account) and keep the status of PoolState::Uninitialized
until the pool when owner calls initialize_join
.
To create the treasuries (aka token accounts) corresponding to the mints, and also deposit the initial amount of tokens into the pool, the pool owner must call initialize_join
for all mints one by one. After all, the pool will transmit the status from PoolState::Uninitialized
to PoolState::Initializing
and there are a number LP initialized for the pool owner aka the first liquidity provider.
In case of incorrect configs, the pool owner can cancel the pool by close_pool
. This function is only possible when the pool is PoolState::Uninitialized
.
There current pool limit is 8 mints.
How to finalize a pool?
Once the pool is initialized, only the pool owner is able to update weights, add/remove liquidity. This limit is to avoid rug pull and build a foundation for liquidity boostrapping (aka. launchpad).
To open the pool to the publish, the pool owner must finalized the pool state from PoolState::Initializing
to PoolState::Initialized
. At that time, the publish can join and add/remove liquidity to the pool.
How to add liquidity?
By adding liquidity, the user will become an liquidity provider. However, add_liquidity
differs from initialize_pool
that it requires all token deposited at once. In exchange, the liquidity provider will receive a corresponding number of LP tokens.
How to remove liquidity?
The liquidity providers can return LP tokens via remove_liquidity
~~or remove_sided_liqudity
~~ to get back their deposited tokens.
~~The different between remove_liquidity
and remove_sided_liqudity
is that remove_liquidity
will return all mints respectively to the current proportion while remove_sided_liqudity
will allow liquidity providers to select their single favorite mint to withdraw.~~
Senswap now only supports remove_liquidity
for full liquidity withdrawals.
Swap
Users can run a swap by calling swap
. There exists fees for each transaction. You can find more in Fee & Tax.
Route
route
is a high-level abstract function of swap
. Users can call multiple swap
-s in a monolithic transaction of route
. The basic idea is that route
will verify params for each swap
then self-invoke the program by calling swap
. This function is really helpful for AMM aggregators.
Fee & Tax
On each swap
, there are fees that the trader must to pay:
Liquidity Provision Fee (aka
fee
):- IT'S COLLECTED OVER BIDDING TOKENS.
- This fee is to incentivize people to provide liquidity into the pool and avoid permanent loss.
Platform Fee (aka
tax
):- IT'S COLLECTED OVER BIDDING TOKENS.
- This tax is to help SenSwap maintain the system and develop more features to the platform.
- However, the
tax
is not only for the SenSwap foundation, but also being structured for the referral system. When referrer addresses are injected in a transaction, thetax
will splitted equally for the platform fee and referral fees. For example, there are 2 referrer addresses in aswap
transaction and 90 tokens for thetax
, then the platform fee will be 30 tokens, and 30 tokens for each referrer. - There is MAXIMUM 2 referral addresses.
- We skip the tax in term of inbalance liquidity provision.
As you may notice, SenSwap allows liquidity providers add/remove liquidity asymmetrically while the system will make an auto swap to balance the structure. Because of the auto swap, the fee & tax is available in add_liquidity
, and remove_liquidity
. However, the referal system is disabled in those transaction types.
Pause & Resume (aka Frezee & thaw)
Only avaiable when
PoolState::Initializing
.
These actions are rarely used and only avaialble when the pool is in state of PoolState::Initializing
. When the pool owner is creating a pool or launching their tokens but meet some fatal flaws, the can call freezePool
to secure the pool and their tokens.
Computing Precision
In regard to the Balancer's multiple-weighted-tokens AMM, the computation is heavily relies on fractional exponentiation. To keep the implementation effective and reliable, we employ directly the float system f64
in Rust to for only float exponentiation. For bounded precision, we immediately check the swap price must fall into the gap of previous and next spot price: prev_spot_price < swap_price < next_spot_price
.
Audited
Copyright
SenSwap © 2023 Sentizen Foundation.