- Minswap Stableswap uses Curve's Stableswap model: https://classic.curve.fi/files/stableswap-paper.pdf. This model aims to provide low slippage and low fees when trading stablecoins. The key metric in this model is Amplification Coefficient (TODO: Do we need to explain how's A work?). References Curve's contract: https://etherscan.io/address/0xbebc44782c7db0a1a60cb6fe97d0b483032ff1c7#code
- The Stableswap uses Batching architecture to solve concurrency on Cardano. Each user action will create an "Order" and "Batcher" will look through them and apply them into a "Stable Pool". A valid "Batcher" is a wallet which contains Minswap's License Token. Batching transaction is permissioned and only is triggered by "Batcher".
- Limitations:
- Current contract only supports non-ADA assets (i.e. a pool of ADA and ADA-pegged assets wouldn't be supported)
There're 3 contracts in the Stableswap system:
- Order Contract: represents "User Action", contains necessary funds and is waiting to be applied into a Pool
- Pool Contract: a.k.a Liquidity Pool, which holds all User's assets for trading.
- Liquidity Contract: a Minting Policy whose tokens represents the "share" of Liquidity Providers in Liquidity Pool
- User: An entity who wants to interact with StableSwap to deposit/withdraw liquidity or swap. The only requirement of users is that they must not be the same as batcher (because of how we filter UTxOs) and should not be any another Smart Contract (because an pending Order can only be cancelled by User's signature in case of over-slippage).
- Batcher: An entity who aggregate order UTxOs from users and match them with liquidity pool UTxO. A batcher must hold a batcher's license token. The license token must not be expired and the expired time must be between current time and Maximum Deadline (to prevent minting license with infinity deadline).
- Admin (aka Minswap team): An entity who has permission to update pools' amplification coefficient, withdraw admin fee and change the pool's stake address. An Admin must hold admin's license token.
- Pool NFT token: Assumed to be unique and can't be replicated. Pool NFT is minted by the team before creating a pool and will be put into the pool on creation. The team will choose the most secured way to mint the NFT (e.g. by using time-locked policy).
- LP token: Represents Liquidity Provider's share of pool. Each pool has different LP token.
- CurrencySymbol: Liquidity Contract
- TokenName: Same as pool NFT's TokenName.
- Batcher license token: Permit batcher to apply pool
- CurrencySymbol: Defined in Pool parameters. The policy is managed by team (e.g. multisig policy)
- TokenName: POSIX timestamp represents license deadline
- Admin license token:
- CurrencySymbol: Defined in Pool parameters. The policy is managed by team (e.g. multisig policy)
- TokenName: A constant string defined in pool parameters (e.g. "ADMIN")
Order Batching validator is a Withdrawal Script, is responsible for validating Pool Representation in the Transaction Inputs. This validator will help reduce Order Validator
cost in Batching Transaction.
- pool_hash: the hash of Liquidity Pool Script
- OrderBatchingRedeemer:
- pool_input_index: Index of Pool UTxO in Transaction Inputs.
- OrderBatchingRedeemer: The redeemer contains
pool_input_index
, it's used for finding Pool Input faster, it will be called on Batching Transaction.- validate that there's a Pool Input which have Address's Payment Credential matching with
pool_hash
- validate that there's a Pool Input which have Address's Payment Credential matching with
Order validator is responsible for holding "User Requests" funds and details about what users want to do with the liquidity pool. An order can only be applied to the liquidity pool by Batcher or cancelled by User's payment signature / Script Owner Representation (in case Owner is a Smart Contract)
- stake_credential: the Stake Credential of
Order Batching Validator
There are 5 order types:
- Exchange: is used for exchanging assets in the liquidity pool
- asset_in_index: The index of asset which users want to exchange
- asset_out_index: The index of asset which users want to exchange to
- minimum_asset_out: Minimum amount of Asset Out which users want to receive after exchanging
- Deposit: is used for depositing pool's assets and receiving LP Token
- minimum_lp: The minimum amount of LP Token which users want to receive after depositing
- Withdraw: is used for withdrawing pool's asset with the exact assets ratio of the liquidity pool at that time
- minimum_amounts: minimum amounts of received assets. The array has the same length and index as assets inside pools
- WithdrawImbalance: is used for withdrawing custom amount of assets.
- amounts_out: The exact amount of assets which users want to receive
- WithdrawOneCoin: is used for withdrawing a specific asset in the liquidity pool
- asset_out_index: The index of the asset which users want to withdraw
- minimum_asset_out: The minimum amount of Asset Out which users want to receive after withdrawal
An Order Datum keeps information about Order Type and some other informations:
- sender: The address of order's creator, only sender can cancel the order
- receiver: The address which receives the funds after order is processed
- receiver_datum_hash: (optional) the datum hash of the output after order is processed.
- step: The information about Order Type which we mentioned above
- batcher_fee: The fee users have to pay to Batcher to execute batching transaction
- output_ada: As known as Minimum ADA which users need to put to the Order, and these amounts will be returned with receiver Output
There're 2 order actions:
- ApplyOrder
- CancelOrder
- ApplyOrder: the redeemer will allow spending Order UTxO in Batching transaction
- validate that an Order can be spent if there's a single Pool UTxO that matches with pool_validator_hash parameter in the transaction inputs. The rest of validation is delegated to pool script
- CancelOrder: the redeemer will allow sender to spend Order UTxO to get back locked funds.
- validate that the transaction has sender's signature or sender script UTxO in the Transaction Inputs
Liquidity Minting Policy is responsible for making sure only Pool Validator can mint LP, other validations related how many LP will be minted will be forwarded to Pool Validator
- nft_asset: is known as Pool NFT asset which identifies Pool and make sure that Liquidity Pool is unique
None
- Validate that the transaction must have a Pool UTxO holding 1 NFT Asset in both the inputs and outputs
- Validate that transaction must only mint LP asset and LP Asset must have the same TokenName with NFT Asset
Pool validator is the most important part in the system. It's responsible for guaranteeing that Orders must be processed in the correct way and Liquidity Providers' funds cannot be stolen in any way.
- nft_asset: a.k.a Pool NFT asset which identifies Pool and make sure that the Liquidity Pool is unique
- lp_asset: is the "share" asset which is created by the Liquidity Minting Policy
- license_symbol: is the policy ID managed by the Minswap team, used for minting Batcher License and Admin License assets
- admin_asset: is used to identify Admin, can interact with WithdrawAdminFee and UpdateAmpOrStakeCredential redeemer
- maximum_deadline_range: is the maximum expiration time of Batcher license from now (to prevent minting infinity license)
- assets: the stable assets which the Pool supports trading
- multiples: is the multiple of stable assets, using for calculation between stable assets with different decimals
- fee: the numerator of the fee % users need to pay when interacting with the pool
- admin_fee: the numerator of the % of the fee that goes to Admin
- fee_denominator: is the denominator of fee and admin_fee, which help calculation more accurate
- balances: is the balances of Pool's assets, has the same index with assets in Pool's parameters
- total_liquidity: is the Total Liquidity (which is equals with total amount of minted LP Token)
- amp: is known as Amplification Coefficient, is the key metric in whole Stableswap system.
- order_hash: Validator Hash of Order Contract
There're 3 pool actions:
- ApplyPool: can only be triggered by Batcher, allow Batcher to take Order UTxOs and apply them to Liquidity Pool
- WithdrawAdminFee: can only be trigged by Admin, allow Admin to withdraw earned Admin Fee
- UpdateAmpOrStakeCredential: can only be trigged by Admin, allow Admin to update Amplification Coefficient configuration or update Pool's Stake Credential
- ApplyPool:
- Having only one Pool Input and Output in the transaction. The Pool Input and Output must have the same Address (both payment and stake credential part)
- Pool NFT must exist in Pool Input and Output value
- Pool Value must only contain necessary tokens inside:
- Minimum ADA
- Pool NFT Asset
- Stable Assets (which is defined in Pool Paramters)
- Batcher with valid license token must be a signer of transaction. A valid license token is the token having expired timestamp as TokenName and must be within current time and current time + maximum_deadline_range
- Irrelevant field (which is Amplification Coefficient) in Pool datum must be unchanged.
- Validate the Pool State (datum balances, value balances and total_liquidity) must be the same with the calculated amount after applying through all orders. The validator will loop through the list of batch inputs and outputs and validate each one, as well as calculate the final state of the pool. Important note that order inputs are sorted lexicographically due to Cardano ledger's design, so the Batcher will pre-calculate correct order inputs indexes, pass through the redeemer (input_indexes) and validator will sort the Order Inputs with the indexes to make sure that Orders will be processed with FIFO ordering
- Validate that transaction can only mint LP Token if having any order requires minting LP. Otherwise, transaction doesn't mint anything
- Balances in Pool In/Out datum must have the same length with Pool Assets
- WithdrawAdminFee:
- Having only one Pool Input and Output in the transaction. This redeemer doesn't allow any other scripts except Pool's script in the Inputs or Outputs
- Pool NFT must exist in Pool Input and Output value
- Pool Value must only contain necessary token inside:
- Minimum ADA
- Pool NFT Asset
- Stable Assets (which is defined in Pool Parameters)
- This transaction doesn't mint anything
- Pool Datum must be unchanged in this redeemer
- Only Admin token can trigger this redeemer
- Admin can only withdraw the exact accumulated admin fee amounts. These amounts are calculated by the difference of Pool Value and Datum Balances
- After Admin Fee amounts are withdrawn, Pool Value must be equals to Datum balances
- UpdateAmpOrStakeCredential:
- Having only one Pool Input and Output in the transaction. This redeemer doesn't allow any other scripts except Pool script in the Inputs or Outputs
- Pool NFT must exist in Pool Input and Output value
- Pool Value must only contain necessary tokens inside:
- Minimum ADA
- Pool NFT Asset
- Stable Assets (which is defined in Pool Parameters)
- This transaction doesn't mint anything
- Irrelevant fields (balances, total_liquidity) in Pool datum must be unchanged
- Only Admin license token can trigger this redeemer
- Pool Value must be unchanged in this redeemer
Create Pool transaction is quite simple. Because each Pool has to include a Pool NFT asset. Transaction only create a Pool UTxO which has Pool NFT inside and some initial datum. There's no validation for pool creation, and pools that users can interact on Minswap interface are created and whitelisted by Minswap team. Those pools (and their NFTs) are assumed to be created correctly.
Pool UTxO includes:
- Value:
- Minimum ADA
- Pool NFT
- Datum:
- balances: an array having N elements, each element has 0 value
- total_liquidity: 0
- amp: initial Amplication Coefficient (decided by Minswap team)
- order_hash: is the Validator Hash of
Order Contract
Create Order transaction will transfer User funds into an Order UTxO.
Besides common information such as sender, receiver, etc, each order type requires different information in step field (note that we only mention field name here, the fields' descriptions have been explained above):
- Exchange:
- Datum:
- asset_in_index
- asset_out_index
- minimum_asset_out
- Value:
- Output ADA + Batcher Fee
- Asset In + its amount
- Datum:
- Deposit:
- Datum:
- minimum_lp
- Value:
- Output ADA + Batcher Fee
- Assets which users want to deposit + their amounts
- Datum:
- Withdraw:
- Datum:
- minimum_amounts
- Value:
- Output ADA + Batcher Fee
- LP Token + its amount
- Datum:
- WithdrawImbalance:
- Datum:
- amounts_out
- Value:
- Output ADA + Batcher Fee
- LP Token + its amount
- Datum:
- WithdrawOneCoin:
- Datum:
- asset_out_index
- minimum_asset_out
- Value:
- Output ADA + Batcher Fee
- LP Token + its amount
- Datum:
Cancel Order transaction will spend Order UTxO and take users' fund back to their wallet. This transaction requires the sender's signature or sender script UTxO in the Transaction Inputs
Batching transaction is the most complex structure.
It requires a Pool UTxO, Batcher UTxOs (must include Batcher License Token), Order UTxOs which are applying to the Pool UTxO and Order Batching Withdrawal Script
Batcher will:
- Find all pending Orders (Order UTxOs) in the blockchain, sort them by FIFO ordering
- Find corresponding Pool UTxO that matches with these Orders
- Loop through Orders, apply them to the Pool UTxO, then calculate User funds after their requests are processed. The users' funds have to pay to receiver Address and include receiver_datum_hash (if present)
- Exchange:
- Value:
- Output ADA
- Asset Out + its amount (must be greater than minimum_asset_out)
- Value:
- Deposit:
- Value:
- Output ADA
- LP Token + its amount (must be greater than minimum_lp)
- Value:
- Withdraw:
- Value:
- Output ADA
- Pool Assets + their amounts (must be greater than minimum_amounts)
- Value:
- WithdrawImbalance:
- Value:
- Output ADA
- Pool Assets + their amounts (must be exact amounts_out)
- LP Token + change amount of LP Token (because slippage of this order affects LP Token which users put in Order, so LP Token may have changed after executing Batching transaction. This amount will be returned to receiver)
- Value:
- WithdrawOneCoin:
- Value:
- Output ADA
- Asset Out + its amount (must be greater than minimum_asset_out)
- Value:
- Exchange:
- Take Batcher Fee of all Orders, a part of them will be used for Transaction Fee, the remaining amount will be kept on Batcher wallet
Withdrawing Admin Fee transaction requires Admin's License Token.
The transaction will spend Admin's License Token, calculate earned Admin Fee amounts and pay them to Admin Wallet.
This transaction can either update Amplification Coefficient or update Pool's Stake Credential.
It will spend Pool UTxO and modify Amp configuration in Pool's Datum and take Datum & Value inside Pool UTxO to new UTxO (which has the same payment_credential and new stake_credential part)