This protocol is a foundational, decentralized system for perpetual trading on BTC. It integrates core functionalities such as leveraged trading, collateral management, liquidity provisioning, and liquidation mechanisms. Designed for simplicity and robustness, it provides a secure environment for traders and liquidity providers (LPs) while incorporating advanced features like real-time leverage calculations, borrowing fees, and dynamic reserve management.
Protocol:
Vault:
PrepToken:
- Overview
- Key Features
- Role of Parties
- Smart Contracts
- Key Functions
- Usage Instructions
- Important Links
The Minimal Perpetual Trading Protocol facilitates leveraged trading on BTC through a decentralized system. Traders can open long or short positions, while liquidity providers back the system with funds. The protocol ensures stability via collateralized reserves, borrowing fees, and liquidation mechanisms. By streamlining essential trading features, this protocol serves as a proof-of-concept for perpetual trading systems.
- Leveraged Trading: Offers up to 15x leverage for traders, with real-time leverage tracking to ensure system stability.
- Dynamic Reserve Management: Maintains 15% reserves for open positions, adjusting based on profit and loss scenarios, as well as the difference between long and short positions.
- Borrowing Fees: Traders pay a borrowing fee on reserves held by the protocol, calculated at 15% annually.
- Collateral Flexibility: Traders can withdraw collateral even with open positions, provided leverage remains within limits.
- Liquidation Mechanism: Automatically liquidates positions exceeding 30x leverage, rewarding liquidators with 0.5% of the liquidated position.
- ERC-4626 Vault: Implements tokenized liquidity shares for LPs, dynamically adjusting based on protocol profits and losses.
Traders open leveraged positions on BTC by depositing collateral. They can manage positions using functions for increasing, decreasing, or closing trades.
LPs deposit funds into the protocol’s vault to provide liquidity. In return, they earn fees and receive proportional shares of vault profits.
The Admin configures initial protocol settings, such as vault address.
Independent actors who monitor leverage levels. Liquidators can close over-leveraged positions for a 0.5% reward of the liquidated position size.
An ERC-20 token pegged to $1, used as collateral for traders and liquidity providers.
Holds liquidity from LPs, distributing shares proportionally. Reserves are dynamically adjusted based on trader activity.
The core contract managing trader positions, collateral, leverage, and liquidation processes.
-
openPositionWithSize(uint256 _size, bool _isLong)
- Opens a position by specifying the size.
- Validates that the vault holds 15% of the position size for reserves.
-
openPositionWithToken(uint256 _sizeOfToken, bool _isLong)
- Opens a position by specifying the token amount.
- Automatically calculates the position size based on the BTC price.
-
increasePosition(uint256 _size)
- Adds to an open position. Allowed even in loss, provided leverage remains ≤ 15x.
-
decreasePosition(uint256 _size)
- Reduces the size of an open position, adjusting collateral and profit/loss proportionally.
-
closePosition()
- Fully closes a position, settling any profit or loss.
-
depositCollateral(uint256 amount)
- Deposits collateral into the protocol.
-
withdrawCollateral(uint256 amount)
- Withdraws collateral, even with open positions, if leverage remains ≤ 15x.
-
checkPositionLeverageAndLiquidability(uint id)
- Checks if a position exceeds 30x leverage and is liquidatable.
-
liquidatePosition(uint id)
- Liquidates a position exceeding 30x leverage, reducing its size by one-third and awarding 0.5% of the position size to the liquidator.
-
deposit(uint256 amount)
- Deposits liquidity into the vault, receiving proportional shares.
-
withdraw(uint256 amount)
- Withdraws liquidity, adhering to reserve constraints.
-
redeem(uint256 shares)
- Redeems shares for underlying assets.
Position management covers the processes for LPs withdrawing funds, users opening positions, and ensuring the protocol's liquidity reserves are maintained. Below are the key aspects and functions involved:
- Purpose: The
liquidityReservesToHold()
function calculates the amount of reserves required to support both existing and new positions. - Calculation: The reserves are now determined by 15% of the difference between long and short positions, considering any profits and losses from previous trades. This ensures the protocol has enough liquidity to support ongoing trades.
- Usage:
- LPs with Drawn Funds: Before LPs can withdraw money, the protocol checks if this withdrawal will not affect the current position existed, based on this calculated reserve. If the current reserves are sufficient after the withdrawal to cover the positions’s then good otherwise, the action will be halted.
- New Positions: Before users can open new positions, the protocol checks that there are enough reserves available to maintain both the new position and existing ones. This ensures that the liquidity vault is sufficiently funded to handle new trades without compromising existing positions.
Calculated as:
leverage = position / (collateral + PnL)
- Profit is added.
- loss is subtracted.
- Annual fee: 15% of reserves held for the position.
- Formula:
borrowingFee = reserveAmount * timePassed * (15% / 1 year)
- 0.5% of the liquidated position size.
- Acquire Prep Tokens: Use the
mint()
function in thePrepToken
contract. - Approve Protocol: Allow the
Protocol
contract to spend tokens withapprove()
. - Deposit Collateral: Use
depositCollateral()
to fund your account. - Open Positions: Use either
openPositionWithSize()
oropenPositionWithToken()
based on preference. - Manage Positions:
- Increase: Use
increasePosition()
. - Decrease: Use
decreasePosition()
. - Close: Use
closePosition()
.
- Increase: Use
- Withdraw Collateral: Call
withdrawCollateral()
after closing positions or ensuring leverage ≤ 15x.
- Acquire Prep Tokens: Use the
mint()
function. - Approve Vault: Allow the vault to spend tokens with
approve()
. - Deposit Liquidity: Use
deposit()
to receive proportional shares. - Withdraw or Redeem:
- Withdraw: Specify the asset amount.
- Redeem: Specify the share amount.
-
Monitor Positions:
Use thegetNumOfOpenPositionsIds()
function to retrieve the list of open positions. For example, if it returns 5, the open position IDs are(1, 2, 3, 4, 5)
. If it returns 0, there are no open positions at the moment. -
Identify Unused IDs:
UsegetIdsNotInUse()
to get the IDs that are not assigned to any active positions. For example, if it returns[3, 4]
, it means these IDs are available, and the open positions are[1, 2, 5]
. -
Check Leverage and Liquidation Status:
For each open position ID, usecheckPositionLeverageAndLiquidability(uint id)
to check if it is eligible for liquidation. This function returns a tuple:
(uint256 leverageRate, bool isLiquidable)
leverageRate
: The current leverage of the position.isLiquidable
: Whether the position is liquidable based on its leverage rate.
A position is liquidatable ifleverageRate > 30x
andisLiquidable
istrue
.
-
Liquidate Position:
If the position is liquidatable, useliquidatePosition(uint id)
to liquidate that position. Liquidating a position rewards the liquidator with 0.5% of the position's size, which will be added to the liquidator’s balance. This reward can be withdrawn using thewithdrawCollateral()
function or used for further trading.
Note: A trader cannot liquidate their own position.
This protocol provides a streamlined and secure environment for perpetual trading, balancing simplicity with robust risk management. Whether you're a trader, LP, or liquidator, the system ensures transparency, fairness, and efficiency.