Makers
Introduction
For a detailed explanation about what being a Maker in the Hubble system means, please refer to the following blog posts:
Makers in Hubble vAMM (Part 2)
Ignition Period
When a new perp AMM is first launched, it goes through an ignition period which is basically a liquidity bootstrapping phase. During this time users are allowed to commit liquidity to the AMM but trading has not yet begun.
- Maker posts margin (or already has free margin)
- Commits the $ amount of liquidity they wish to add. Committed liquidity can be increased but not reduced during the ignition period.
- Once the AMM reaches a pre-determined liquidity goal, protocol team triggers a liftOff tx
- which uses the oracle price for the perp asset
- divides the committed $ in a 50/50 ratio
- adds the virtual assets to the amm so that trading can begin
- AMM is now said to be in an Active state.
// contract: ClearingHouse/*** @notice Commit liquidity during the ignition period.* Only the $ amount needs to be determined. Actual asset allocation happens at liftOff.* @param idx Index of the AMM* @param quoteAsset Amount of $ to commit*/function commitLiquidity(uint idx, uint quoteAsset) external;
Add Liquidity
Post ignition, liquidity can be added at any time. The asset/USD split will be determined at the current pool composition.
// contract: ClearingHouse/*** @notice Add liquidity to the amm. The free margin from margin account is utilized for the same* The liquidity can be provided on leverage.* @param idx Index of the AMM* @param baseAssetQuantity Amount of the asset to add to AMM. Equivalent amount of USD side is automatically added.* This means that user is actually adding 2 * baseAssetQuantity * markPrice.* @param minDToken Min amount of dTokens to receive. Used to cap slippage.*/function addLiquidity(uint idx, uint256 baseAssetQuantity, uint minDToken) external;
Impermanent position
This is probably the most important section for liquidity providers, so please read carefully!
We know that the idea of being a liquidity provider (LP) in any AMM is that these user’s take the counter-trade. So say in an ETH Uniswap pool, a trader buys 5 ETH, then all LPs collectively sell 5 ETH. In Hubble, the idea is the same - i.e. if a trader takes a 5 ETH long then the LPs (referred to as Makers) collectively share a 5 ETH short position. So if you own 1% of the pool, you’d have a 0.05 ETH short position. However, this position is referred to as an impermanent position (IP) because it changes with every trade.
- Avg. open price of the IP is a function of fee accrued in the Amm - e.g. Say the trader opened the 5 ETH long at an avg price of $2000, but because they paid a .05% fee, their actual open price will be $2000.1. This will mean that the maker goes 5 ETH short at $2000.1 which is a more favorable price than $2000 without fee. In this manner, a maker’s earned fee is reflected in a more and more favorable open price for the IP.
- If a maker removes their entire liquidity right at this moment, it becomes their permanent position i.e. as if they opened this position as a trader, with avg open price as explained above.
Maker’s impermanent position at the current time can be queried with this method:
// contract: HubbleViewer/*** @notice get maker impermanent position and unrealizedPnl for a particular amm* @param _maker maker address* @param idx amm index* @return position Maker's current impermanent position* @return openNotional Position open notional for the current impermanent position inclusive of fee earned* @return unrealizedPnl PnL if maker removes liquidity and closes their impermanent position in the same amm*/function getMakerPositionAndUnrealizedPnl(address _maker, uint idx) override public view returns (int256 position, uint openNotional, int256 unrealizedPnl);
So it’s possible to build a hedging strategy*, where:
- you query your IP every few blocks.
- Open an equivalent opposite position (5 ETH long) on another exchange so that the maker is overall delta neutral while earning fees in the Hubble amm.
Remove Liquidity
To remove liquidity, maker has to undergo an unbonding period.
- Maker expresses that they want to reduce their liquidity but stays in the system for min of 2 days and max of 3 days. This has been designed in a manner such that all withdrawals scheduled for a particular day are batched together at the end of the day. This is so that traders know what liquidity depth to expect 2 days in advance and adjust their positions accordingly. Allowing for sudden liquidity shocks in the AMM can lead to cascading liquidations and we mitigate that with an unbonding period. During the unbonding period, maker’s still act as counter-parties to the trades, so their IP at the time of starting to unbond and actual withdraw can be very different as well.
- After the unbonding period is over, makers needs to remove their liquidity within a withdrawal period of 1 day; failing which they will need to unbond again.
// contract: ClearingHouse/*** @notice Remove liquidity from the amm.* @param idx Index of the AMM* @param baseAssetQuantity Amount of the asset to remove to AMM. Equivalent amount of USD side is automatically removed.* This means that user is actually removing 2 * baseAssetQuantity * markPrice.* @param minQuoteValue Min amount of USD to remove.* @param minBaseValue Min amount of base to remove.* Both the above params enable capping slippage in either direction.*/function removeLiquidity(uint idx, uint256 amount, uint minQuoteValue, uint minBaseValue) external;
Funding Payments
Funding payments are an essential ingredient of any perps exchange. To that end, Maker’s pay or receive the funding payment on their impermanent position at the time of funding event. Maker’s pending funding payment can be queried as follows:
// contract: HubbleViewer/*** @notice Query pending funding amounts for many traders at once* @return takerFundings Pending taker funding indexed as [traderIdx][ammIdx]* @return makerFundings Pending maker funding indexed as [traderIdx][ammIdx]*/function getPendingFundings(address[] calldata traders) external view returns(int[][] memory takerFundings, int[][] memory makerFundings);**//** OR 1 AMM at once// contract: AMMfunction getPendingFundingPayment(address trader) override public view returns( int256 takerFundingPayment, int256 makerFundingPayment, int256 latestCumulativePremiumFraction, int256 latestPremiumPerDtoken );
Liquidations
Since a maker can choose to provide liquidity on leverage, they can also be liquidated. A maker liquidation is as simple as:
- Forcefully removing their liquidity from the AMM.
- Translating their impermanent position into permanent one i.e. it will appear as if the maker opened that position as a vanilla trader.
- A maker is charged a fixed penalty of $20; shared 50-50 b/w the insurance fund and the liquidator.
// contract: ClearingHousefunction liquidateMaker(address maker) override public;