Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: derivatives comments #458

Merged
merged 3 commits into from
Mar 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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