Skip to content

Commit

Permalink
Merge pull request #458 from UnUniFi/derivatives-comments
Browse files Browse the repository at this point in the history
chore: derivatives comments
  • Loading branch information
mkXultra authored Mar 24, 2023
2 parents 055054c + f652ef3 commit 151c93f
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 1 deletion.
3 changes: 3 additions & 0 deletions x/derivatives/abci.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,13 @@ func saveBlockTime(ctx sdk.Context, k keeper.Keeper) {
}

// BeginBlocker
// In mainnet, BeginBlocker will have no function.
func BeginBlocker(ctx sdk.Context, k keeper.Keeper) {
CheckPosition(ctx, k)
}

// todo: fixme this function is temporary treatment.
// In mainnet, this function will be executed by off chain bots.
func CheckPosition(ctx sdk.Context, k keeper.Keeper) {
positions := k.GetAllPositions(ctx)
params := k.GetParams(ctx)
Expand Down Expand Up @@ -57,6 +59,7 @@ func CheckPosition(ctx sdk.Context, k keeper.Keeper) {
}

// EndBlocker
// In EndBlocker, the snapshot of pool market cap and block time are saved.
func EndBlocker(ctx sdk.Context, k keeper.Keeper) {
setPoolMarketCapSnapshot(ctx, k)
saveBlockTime(ctx, k)
Expand Down
23 changes: 22 additions & 1 deletion x/derivatives/keeper/lpt.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,20 +46,29 @@ func (k Keeper) GetLPTokenPrice(ctx sdk.Context) sdk.Dec {
return k.GetPoolMarketCap(ctx).CalculateLPTokenPrice(k.GetLPTokenSupply(ctx))
}

// amount: amount of asset that will go to pool
// return1: amount of LP token that value is equal to the asset that will go to pool
// return2: mint fee amount of LP token (fee included in return1)
func (k Keeper) DetermineMintingLPTokenAmount(ctx sdk.Context, amount sdk.Coin) (sdk.Coin, sdk.Coin, error) {
currentSupply := k.bankKeeper.GetSupply(ctx, types.LiquidityProviderTokenDenom)

// assetPrice is the price of the asset in metrics ticker (USD in default)
assetPrice, err := k.GetAssetPrice(ctx, amount.Denom)
if err != nil {
return sdk.Coin{}, sdk.Coin{}, err
}
// actualAmount means the amount of the asset that is in the pool
actualAmount := k.GetAssetBalance(ctx, amount.Denom)

// for asset "i",
// targetAmount[i] = targetWeight[i] * poolMarketCap / price[i]
// targetWeight is determined in params of pool
targetAmount, err := k.GetAssetTargetAmount(ctx, amount.Denom)
if err != nil {
return sdk.Coin{}, sdk.Coin{}, err
}

// assetMc is the market cap of the asset that will go to the pool, in metrics ticker (USD in default)
assetMc := assetPrice.Price.Mul(sdk.NewDecFromInt(amount.Amount))
if currentSupply.Amount.IsZero() {
// TODO: we can eliminate unnecessary calculation -> assetPrice.Price
Expand All @@ -73,16 +82,20 @@ func (k Keeper) DetermineMintingLPTokenAmount(ctx sdk.Context, amount sdk.Coin)

mintAmount := assetMc.Quo(lptPrice)

// increaseRate = (actualAmount - targetAmount) / targetAmount
increaseRate := sdk.NewDecFromInt(actualAmount.Amount).Sub(sdk.NewDecFromInt(targetAmount.Amount)).Quo(sdk.NewDecFromInt(targetAmount.Amount))
if increaseRate.IsNegative() {
increaseRate = sdk.NewDec(0)
}

// mintFeeRate = baseMintFeeRate * (1 + increaseRate)
mintFeeRate := k.GetLPTokenBaseMintFee(ctx).Mul(increaseRate.Add(sdk.NewDecWithPrec(1, 0)))

// mintFee = mintFeeRate * mintAmount
return sdk.NewCoin(types.LiquidityProviderTokenDenom, mintAmount.TruncateInt()), sdk.NewCoin(types.LiquidityProviderTokenDenom, mintAmount.Mul(mintFeeRate).TruncateInt()), nil
}

// Assume the ticker of LP token is DLP and redeemDenom is XXX, then this emits the rate of DLP/XXX
func (k Keeper) LptDenomRate(ctx sdk.Context, redeemDenom string) (sdk.Dec, error) {
lptPrice := k.GetLPTokenPrice(ctx)
redeemAssetPrice, err := k.GetAssetPrice(ctx, redeemDenom)
Expand All @@ -92,6 +105,9 @@ func (k Keeper) LptDenomRate(ctx sdk.Context, redeemDenom string) (sdk.Dec, erro
return lptPrice.Quo(redeemAssetPrice.Price), nil
}

// amount: amount of TP token that will be burnt
// return1: amount of redeemDenom that value is equal to the LP token that will be burnt
// return2: redeem fee amount of redeemDenom
func (k Keeper) GetRedeemDenomAmount(ctx sdk.Context, lptAmount sdk.Int, redeemDenom string) (sdk.Coin, sdk.Coin, error) {
lptPrice := k.GetLPTokenPrice(ctx)
redeemAssetPrice, err := k.GetAssetPrice(ctx, redeemDenom)
Expand All @@ -100,17 +116,19 @@ func (k Keeper) GetRedeemDenomAmount(ctx sdk.Context, lptAmount sdk.Int, redeemD
return sdk.Coin{}, sdk.Coin{}, err
}

// totalSupply is the total supply of LP token
totalSupply := k.bankKeeper.GetSupply(ctx, types.LiquidityProviderTokenDenom)
if totalSupply.Amount.IsZero() {
return sdk.Coin{}, sdk.Coin{}, types.ErrNoLiquidityProviderToken
}

// redeemAssetBalance is the amount of redeemDenom in the pool. The variable name is little weird
redeemAssetBalance := k.GetAssetBalance(ctx, redeemDenom)

if redeemAssetPrice.Price.IsNil() || redeemAssetPrice.Price.IsZero() {
return sdk.Coin{}, sdk.Coin{}, types.ErrInvalidRedeemAmount
}
// redeem amount = lptPrice * lptAmount / redeemAssetPrice
// redeemAmount = lptPrice * lptAmount / redeemAssetPrice
totalRedeemAmount := lptPrice.Mul(sdk.NewDecFromInt(lptAmount)).Quo(redeemAssetPrice.Price)

if totalRedeemAmount.GT(sdk.NewDecFromInt(redeemAssetBalance.Amount)) {
Expand All @@ -122,11 +140,13 @@ func (k Keeper) GetRedeemDenomAmount(ctx sdk.Context, lptAmount sdk.Int, redeemD
return sdk.Coin{}, sdk.Coin{}, err
}

// increaseRate = (targetAmount - redeemAssetBalance) / targetAmount
increaseRate := sdk.NewDecFromInt(targetAmount.Amount).Sub(sdk.NewDecFromInt(redeemAssetBalance.Amount)).Quo(sdk.NewDecFromInt(targetAmount.Amount))
if increaseRate.IsNegative() {
increaseRate = sdk.NewDec(0)
}

// redeemFeeRate = baseRedeemFeeRate * (1 + increaseRate)
redeemFeeRate := k.GetLPTokenBaseRedeemFee(ctx).Mul(increaseRate.Add(sdk.NewDecWithPrec(1, 0)))

redeem := sdk.NewCoin(redeemDenom, totalRedeemAmount.TruncateInt())
Expand All @@ -138,6 +158,7 @@ func (k Keeper) GetRedeemDenomAmount(ctx sdk.Context, lptAmount sdk.Int, redeemD
return redeem, fee, nil
}

// Decrease is misleading. Subtract is correct.
func (k Keeper) DecreaseRedeemDenomAmount(ctx sdk.Context, amount sdk.Coin) error {
redeemAssetBalance := k.GetAssetBalance(ctx, amount.Denom)
decreasedAmount, err := redeemAssetBalance.SafeSub(amount)
Expand Down
6 changes: 6 additions & 0 deletions x/derivatives/keeper/pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ func (k Keeper) IsAssetValid(ctx sdk.Context, iasset types.PoolParams_Asset) boo
return false
}

// TODO: The name GetAssetBalance is weird. We need to change the name like "GetAssetAmountInPool"
// TODO: Furthermore, is this really needed? Can we just use the bankKeeper function of getBalance for pool module account?
func (k Keeper) GetAssetBalance(ctx sdk.Context, denom string) sdk.Coin {
store := ctx.KVStore(k.storeKey)
bz := store.Get(types.AssetDepositKeyPrefix(denom))
Expand Down Expand Up @@ -111,6 +113,7 @@ func (k Keeper) GetUserDeposits(ctx sdk.Context, depositor sdk.AccAddress) []sdk
return deposits
}

// Is this really needed? Just managing pool module account balance is enough, and managing deposited asset of each user is not needed.
func (k Keeper) GetUserDenomDepositAmount(ctx sdk.Context, depositer sdk.AccAddress, denom string) sdk.Int {
store := ctx.KVStore(k.storeKey)
bz := store.Get(types.AddressAssetPoolDepositKeyPrefix(depositer, denom))
Expand All @@ -123,6 +126,7 @@ func (k Keeper) GetUserDenomDepositAmount(ctx sdk.Context, depositer sdk.AccAddr
return coin.Amount
}

// Is this really needed? Just managing pool module account balance is enough, and managing deposited asset of each user is not needed.
func (k Keeper) SetUserDenomDepositAmount(ctx sdk.Context, addr sdk.AccAddress, denom string, amount sdk.Int) {
store := ctx.KVStore(k.storeKey)
coin := sdk.Coin{
Expand All @@ -134,6 +138,7 @@ func (k Keeper) SetUserDenomDepositAmount(ctx sdk.Context, addr sdk.AccAddress,
}

func (k Keeper) DepositPoolAsset(ctx sdk.Context, depositor sdk.AccAddress, asset sdk.Coin) {
// Is this really needed? Just managing pool module account balance is enough, and managing deposited asset of each user is not needed.
userDenomDepositAmount := k.GetUserDenomDepositAmount(ctx, depositor, asset.Denom)
userDenomDepositAmount = userDenomDepositAmount.Add(asset.Amount)
k.SetUserDenomDepositAmount(ctx, depositor, asset.Denom, userDenomDepositAmount)
Expand Down Expand Up @@ -202,6 +207,7 @@ func (k Keeper) GetPoolMarketCap(ctx sdk.Context) types.PoolMarketCap {
}
}

// TODO: put comments to explain this function
func (k Keeper) IsPriceReady(ctx sdk.Context) bool {
assets := k.GetPoolAssets(ctx)

Expand Down

0 comments on commit 151c93f

Please sign in to comment.