github.com/KiraCore/sekai@v0.3.43/x/layer2/keeper/lp_swap_redeem_convert.go (about)

     1  package keeper
     2  
     3  import (
     4  	"github.com/KiraCore/sekai/x/layer2/types"
     5  	sdk "github.com/cosmos/cosmos-sdk/types"
     6  )
     7  
     8  func (k Keeper) LpTokenPrice(ctx sdk.Context, dapp types.Dapp) sdk.Dec {
     9  	lpToken := dapp.LpToken()
    10  	lpSupply := k.bk.GetSupply(ctx, lpToken).Amount
    11  	totalBond := dapp.TotalBond.Amount
    12  	if lpSupply.IsZero() {
    13  		return sdk.ZeroDec()
    14  	}
    15  	return sdk.NewDecFromInt(totalBond).Quo(sdk.NewDecFromInt(lpSupply))
    16  }
    17  
    18  func (k Keeper) OnCollectFee(ctx sdk.Context, fee sdk.Coins) error {
    19  	// TODO: The fixed fee will be applied after the swap from where
    20  	// - `50%` of the corresponding tokens must be **burned** (deminted)
    21  	// - `25%` given as a reward to liquidity providers
    22  	// - `25%` will be split between **ACTIVE** dApp executors, and verifiers (fisherman).
    23  	// Additionally, the premint and postmint tokens can be used to incentivize operators before
    24  	// dApp starts to generate revenue.
    25  	err := k.bk.BurnCoins(ctx, types.ModuleName, fee)
    26  	if err != nil {
    27  		return err
    28  	}
    29  	return nil
    30  }
    31  
    32  func (k Keeper) RedeemDappPoolTx(ctx sdk.Context, addr sdk.AccAddress, dapp types.Dapp, poolFee sdk.Dec, lpTokenAmount sdk.Coin) (sdk.Coin, error) {
    33  	// 	totalBond * lpSupply = (totalBond - swapBond) * (lpSupply + swapLpAmount)
    34  	lpToken := dapp.LpToken()
    35  	if lpToken != lpTokenAmount.Denom {
    36  		return sdk.Coin{}, types.ErrInvalidLpToken
    37  	}
    38  	lpSupply := k.bk.GetSupply(ctx, lpToken).Amount
    39  	totalBond := dapp.TotalBond.Amount
    40  	swapLpAmount := lpTokenAmount.Amount
    41  	totalBondAfterSwap := totalBond.Mul(lpSupply).Quo(lpSupply.Add(swapLpAmount))
    42  	swapBond := totalBond.Sub(totalBondAfterSwap)
    43  
    44  	dapp.TotalBond.Amount = totalBondAfterSwap
    45  	k.SetDapp(ctx, dapp)
    46  
    47  	fee := sdk.NewDecFromInt(swapBond).Mul(poolFee).RoundInt()
    48  	if fee.IsPositive() {
    49  		feeCoin := sdk.NewCoin(dapp.TotalBond.Denom, fee)
    50  		err := k.OnCollectFee(ctx, sdk.Coins{feeCoin})
    51  		if err != nil {
    52  			return sdk.Coin{}, err
    53  		}
    54  	}
    55  
    56  	// send lp tokens to the module account
    57  	err := k.bk.SendCoinsFromAccountToModule(ctx, addr, types.ModuleName, sdk.Coins{lpTokenAmount})
    58  	if err != nil {
    59  		return sdk.Coin{}, err
    60  	}
    61  
    62  	// send tokens to user
    63  	userReceiveCoin := sdk.NewCoin(dapp.TotalBond.Denom, swapBond.Sub(fee))
    64  	err = k.bk.SendCoinsFromModuleToAccount(ctx, types.ModuleName, addr, sdk.Coins{userReceiveCoin})
    65  	if err != nil {
    66  		return sdk.Coin{}, err
    67  	}
    68  
    69  	properties := k.gk.GetNetworkProperties(ctx)
    70  	threshold := sdk.NewInt(int64(properties.DappLiquidationThreshold)).Mul(sdk.NewInt(1000_000))
    71  	if dapp.LiquidationStart == 0 && dapp.TotalBond.Amount.LT(threshold) {
    72  		dapp.LiquidationStart = uint64(ctx.BlockTime().Unix())
    73  		k.SetDapp(ctx, dapp)
    74  	}
    75  
    76  	return userReceiveCoin, nil
    77  }
    78  
    79  func (k Keeper) SwapDappPoolTx(ctx sdk.Context, addr sdk.AccAddress, dapp types.Dapp, poolFee sdk.Dec, swapBond sdk.Coin) (sdk.Coin, error) {
    80  	// 	totalBond * lpSupply = (totalBond + swapBond) * (lpSupply - swapLpAmount)
    81  	lpToken := dapp.LpToken()
    82  	if swapBond.Denom != k.DefaultDenom(ctx) {
    83  		return sdk.Coin{}, types.ErrInvalidLpToken
    84  	}
    85  	lpSupply := k.bk.GetSupply(ctx, lpToken).Amount
    86  	totalBond := dapp.TotalBond.Amount
    87  	swapBondAmount := swapBond.Amount
    88  	totalLpAfterSwap := totalBond.Mul(lpSupply).Quo(totalBond.Add(swapBondAmount))
    89  	swapLpAmount := lpSupply.Sub(totalLpAfterSwap)
    90  
    91  	dapp.TotalBond.Amount = dapp.TotalBond.Amount.Add(swapBond.Amount)
    92  	k.SetDapp(ctx, dapp)
    93  
    94  	fee := sdk.NewDecFromInt(swapLpAmount).Mul(poolFee).RoundInt()
    95  	if fee.IsPositive() {
    96  		feeCoin := sdk.NewCoin(lpToken, fee)
    97  		err := k.OnCollectFee(ctx, sdk.Coins{feeCoin})
    98  		if err != nil {
    99  			return sdk.Coin{}, err
   100  		}
   101  	}
   102  
   103  	// send lp tokens to the module account
   104  	err := k.bk.SendCoinsFromAccountToModule(ctx, addr, types.ModuleName, sdk.Coins{swapBond})
   105  	if err != nil {
   106  		return sdk.Coin{}, err
   107  	}
   108  
   109  	// send tokens to user
   110  	userReceiveCoin := sdk.NewCoin(lpToken, swapLpAmount.Sub(fee))
   111  	err = k.bk.SendCoinsFromModuleToAccount(ctx, types.ModuleName, addr, sdk.Coins{userReceiveCoin})
   112  	if err != nil {
   113  		return sdk.Coin{}, err
   114  	}
   115  
   116  	properties := k.gk.GetNetworkProperties(ctx)
   117  	threshold := sdk.NewInt(int64(properties.DappLiquidationThreshold)).Mul(sdk.NewInt(1000_000))
   118  	if dapp.LiquidationStart != 0 && dapp.TotalBond.Amount.GTE(threshold) {
   119  		dapp.LiquidationStart = 0
   120  		k.SetDapp(ctx, dapp)
   121  	}
   122  
   123  	return userReceiveCoin, nil
   124  }
   125  
   126  func (k Keeper) ConvertDappPoolTx(
   127  	ctx sdk.Context,
   128  	addr sdk.AccAddress,
   129  	dapp1 types.Dapp,
   130  	dapp2 types.Dapp,
   131  	lpToken sdk.Coin,
   132  ) (sdk.Coin, error) {
   133  	swapBond, err := k.RedeemDappPoolTx(ctx, addr, dapp1, dapp1.PoolFee.Quo(sdk.NewDec(2)), lpToken)
   134  	if err != nil {
   135  		return sdk.Coin{}, err
   136  	}
   137  	return k.SwapDappPoolTx(ctx, addr, dapp2, dapp2.PoolFee.Quo(sdk.NewDec(2)), swapBond)
   138  }