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 }