This a Appchain for a DEX that is based on the Uniswap V2 design and is built using substrate. It uses FRAME to construct the runtime and includes a custom DEX pallet that I created. The DEX also allows for users to attempt flash loans with the liquidity in the pools. The DEX includes functionality to incentivize users to create liquidity
pools and also provides a price oracle based on the existing liquidity pools. The swap and loan fee has a default value of 3 percent, but the pallet provides an the extrinsic set_fee
to allow the fee to be changed. The Origins that have permission to set the fee is configured in the runtime.
When a user calls swap_exact_in_for_out
DOT for KSM when a liquidity pool already exists, they first pay a fee in the input token Dot in this case. The trading fees from each swap are added to the pool for the relevant pair of tokens. This means that, as a liquidity provider, when you withdraw your liquidity, you receive a portion of the transaction fees based on your share of the pool.
Now after paying the fee, how much will the user receive? This is the determined by the constant product formula:
X * Y = K
This means that the product K of the reserves of the two tokens in the pool must remain constant. This is calculated by balancing the following equation X * Y = newX * newY
.
The current exchange rate between an input toke and an output token is determined by the following formula:
ratio = output / input
Divides the amount of tokens in the output pool by the amount of tokens in the input pool and returns a percentage as the result
This is the math that is used to ensure a fair distribution of liquidity provider (LP) tokens based on the amount of liquidity provided.
When a user creates a creates a new pool. The amount of LP tokens they receive is calculated by the following formula:
lp = sqrt(a*b)
Where a
is the amount of tokenA and b
is the amount of tokenB.
When a user adds liquidity to an existing pool, the amount of LP tokens they receive is calculated by the following formula:
lp = sqrt((A+a)*(B+b)) - sqrt(A*B)
Where A
is the amount of tokenA in the pool, B
is the amount of tokenB in the pool, a
is the amount of tokenA the user is adding, and b
is the amount of tokenB the user is adding.
When a user removes liquidity from an existing pool, the amount of tokens a and b they receive is calculated by the following formula.
amountA = (amountLP / totalLP) * totalA
amountB = (amountLP / totalLP) * totalB
Here are the extrinsics functions that are available to be called by users to interact with a runtime that implements the DEX pallet. To call an extrinsic, you need to create a transaction from an account with sufficient balance and broadcast it to the network. This action will trigger the associated extrinsic function. You may construct these transactions directly through JavaScript or with the Polkadot.js API
Description: Adds liquidity to a pool on behalf of the user. If necessary, this will create the pool. LP tokens are minted to the caller.
Call index: 0
fn add_liquidity(
origin: OriginFor<T>,
asset_a: AssetIdOf<T>,
asset_b: AssetIdOf<T>,
amount_a: AssetBalanceOf<T>,
amount_b: AssetBalanceOf<T>,
) -> DispatchResult
Description: Removes liquidity from a pool on behalf of the user. The token_amount represents the amount of LP tokens to be burned in exchange for underlying assets.
Call index: 1
fn remove_liquidity(
origin: OriginFor<T>,
asset_a: AssetIdOf<T>,
asset_b: AssetIdOf<T>,
token_amount: AssetBalanceOf<T>,
) -> DispatchResult
Description: Swaps an exact amount of asset_in for a minimum amount of asset_out on behalf of who. The swap fee is deducted from the out amount.
Call index: 2
fn swap_exact_in_for_out(
origin: OriginFor<T>,
asset_in: AssetIdOf<T>,
asset_out: AssetIdOf<T>,
exact_in: AssetBalanceOf<T>,
min_out: AssetBalanceOf<T>,
) -> DispatchResult
Description: Swaps a max amount of asset_in for an exact amount of asset_out on behalf of who. The swap fee is added to the in amount.
Call index: 3
swap_in_for_exact_out(
origin: OriginFor<T>,
asset_in: AssetIdOf<T>,
asset_out: AssetIdOf<T>,
max_in: AssetBalanceOf<T>,
exact_out: AssetBalanceOf<T>,
) -> DispatchResult
Description: Emits an event with a percentage representing the current exchange rate between asset_in and asset_out.
Call index: 4
fn price_oracle(
_origin: OriginFor<T>,
asset_in: AssetIdOf<T>,
asset_out: AssetIdOf<T>,
) -> DispatchResult
Description: Sets the fee for the DEX pallet. Each input represents 100 basis points. An input of 4 would yield a fee of 400 basis points or 4 percent. The fee can Only be set by the origin that is configured in the runtime.
Call index: 5
fn set_fee(
origin: OriginFor<T>,
new_fee: u16,
) -> DispatchResult
Description: Allows a user to attempt a flash loan. The user can dispatch any system call to return the loan with the fee. The user must return the amount of tokens that they borrowed plus a fee or an error will be thrown and the extrinstic will revert.
Call index: 6
fn flash_loan(
origin: OriginFor<T>,
asset_id: AssetIdOf<T>,
amount: AssetBalanceOf<T>,
call: Box<<T as frame_system::Config>::RuntimeCall>
) -> DispatchResult