Skip to content

Commit

Permalink
Merge commit '6347f1dad2d234b352fb3ba0cd2b6d8ee0fb5e32' into jh/scaff…
Browse files Browse the repository at this point in the history
…old-liquidfarm

* commit '6347f1dad2d234b352fb3ba0cd2b6d8ee0fb5e32':
  fix: rename reward-auction to rewards-auction query command
  chore: fix RewardsAuctions query command, apply updated spec to store LiquidFarm object
  fix: rename lfCoin to UnfarmingCoin and add validation check for the liquid coin denom
  • Loading branch information
jeonghoyeo7 committed Aug 5, 2022
2 parents 3cee581 + 6347f1d commit e013f4f
Show file tree
Hide file tree
Showing 18 changed files with 257 additions and 144 deletions.
10 changes: 4 additions & 6 deletions proto/squad/liquidfarming/v1beta1/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,9 @@ message MsgUnfarm {

string farmer = 2;

cosmos.base.v1beta1.Coin lf_coin = 3 [
cosmos.base.v1beta1.Coin unfarming_coin = 3 [
(gogoproto.nullable) = false,
(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coin",
(gogoproto.customname) = "LFCoin"
(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coin"
];
}

Expand All @@ -71,10 +70,9 @@ message MsgUnfarmAndWithdraw {

string farmer = 2;

cosmos.base.v1beta1.Coin lf_coin = 3 [
cosmos.base.v1beta1.Coin unfarming_coin = 3 [
(gogoproto.nullable) = false,
(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coin",
(gogoproto.customname) = "LFCoin"
(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coin"
];
}

Expand Down
39 changes: 39 additions & 0 deletions x/liquidfarming/abci.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package liquidfarming

import (
"fmt"
"time"

"github.com/cosmos/cosmos-sdk/telemetry"
sdk "github.com/cosmos/cosmos-sdk/types"

"github.com/cosmosquad-labs/squad/v2/x/liquidfarming/keeper"
"github.com/cosmosquad-labs/squad/v2/x/liquidfarming/types"
)

func BeginBlocker(ctx sdk.Context, k keeper.Keeper) {
defer telemetry.ModuleMeasureSince(types.ModuleName, time.Now(), telemetry.MetricKeyBeginBlocker)

liquidFarmSet := map[uint64]types.LiquidFarm{}
for _, liquidFarm := range k.GetAllLiquidFarms(ctx) {
liquidFarmSet[liquidFarm.PoolId] = liquidFarm
}

paramsLiquidFarmSet := map[uint64]types.LiquidFarm{}
for _, liquidFarm := range k.GetParams(ctx).LiquidFarms {
liquidFarmSet[liquidFarm.PoolId] = liquidFarm
}

for poolId := range paramsLiquidFarmSet {
delete(liquidFarmSet, poolId)
}

if len(liquidFarmSet) != 0 {
// Means that LiquidFarm is removed in params
fmt.Println("Removed")
}
if len(paramsLiquidFarmSet) != 0 {
// Means that LiquidFarm is newly added in params
fmt.Println("Added")
}
}
10 changes: 5 additions & 5 deletions x/liquidfarming/client/cli/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -223,14 +223,14 @@ $ %s query %s queued-farmings --farmer %s1zaavvzxez0elundtn32qnk9lkm8kmcszzsv80v

func NewQueryRewardsAuctionsCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "rewards-auctions",
Args: cobra.NoArgs,
Use: "rewards-auctions [pool-id]",
Args: cobra.ExactArgs(1),
Short: "Query all rewards auctions for the liquidfarm",
Long: strings.TrimSpace(
fmt.Sprintf(`Query all rewards auctions for the liquidfarm on a network.
Example:
$ %s query %s rewards-auctions
$ %s query %s rewards-auctions 1
`,
version.AppName, types.ModuleName,
),
Expand Down Expand Up @@ -272,14 +272,14 @@ $ %s query %s rewards-auctions

func NewQueryRewardsAuctionCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "reward-auction [pool-id] [auction-id]",
Use: "rewards-auction [pool-id] [auction-id]",
Args: cobra.ExactArgs(2),
Short: "Query the specific reward auction",
Long: strings.TrimSpace(
fmt.Sprintf(`Query the specific reward auction on a network.
Example:
$ %s query %s reward-auction 1 1
$ %s query %s rewards-auction 1 1
`,
version.AppName, types.ModuleName,
),
Expand Down
3 changes: 3 additions & 0 deletions x/liquidfarming/keeper/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ func (k Keeper) InitGenesis(ctx sdk.Context, genState types.GenesisState) {

k.SetParams(ctx, genState.Params)

for _, liquidFarm := range genState.Params.LiquidFarms {
k.SetLiquidFarm(ctx, liquidFarm)
}
for _, record := range genState.QueuedFarmingRecords {
farmerAddr, err := sdk.AccAddressFromBech32(record.Farmer)
if err != nil {
Expand Down
6 changes: 2 additions & 4 deletions x/liquidfarming/keeper/grpc_query.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,9 @@ func (k Querier) LiquidFarms(c context.Context, req *types.QueryLiquidFarmsReque
}

ctx := sdk.UnwrapSDKContext(c)
params := k.GetParams(ctx)

liquidFarmsRes := []types.LiquidFarmResponse{}
for _, liquidFarm := range params.LiquidFarms {
for _, liquidFarm := range k.GetAllLiquidFarms(ctx) {
reserveAcc := types.LiquidFarmReserveAddress(liquidFarm.PoolId)
poolCoinDenom := liquiditytypes.PoolCoinDenom(liquidFarm.PoolId)
queuedAmt := k.farmingKeeper.GetAllQueuedCoinsByFarmer(ctx, reserveAcc).AmountOf(poolCoinDenom)
Expand Down Expand Up @@ -72,10 +71,9 @@ func (k Querier) LiquidFarm(c context.Context, req *types.QueryLiquidFarmRequest
}

ctx := sdk.UnwrapSDKContext(c)
params := k.GetParams(ctx)

liquidFarmRes := types.LiquidFarmResponse{}
for _, liquidFarm := range params.LiquidFarms {
for _, liquidFarm := range k.GetAllLiquidFarms(ctx) {
if liquidFarm.PoolId == req.PoolId {
reserveAcc := types.LiquidFarmReserveAddress(liquidFarm.PoolId)
poolCoinDenom := liquiditytypes.PoolCoinDenom(liquidFarm.PoolId)
Expand Down
2 changes: 1 addition & 1 deletion x/liquidfarming/keeper/hooks.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ func (h Hooks) AfterStaked(ctx sdk.Context, stakingAcc sdk.AccAddress, stakingCo
// It creates the first rewards auction if liquid farm doesn't have any auction before.
// If there is an ongoing rewards auction, finish the auction and create the next one.
func (h Hooks) AfterAllocateRewards(ctx sdk.Context) {
for _, liquidFarm := range h.k.GetParams(ctx).LiquidFarms {
for _, liquidFarm := range h.k.GetAllLiquidFarms(ctx) {
poolId := liquidFarm.PoolId
auctionId := h.k.GetLastRewardsAuctionId(ctx, poolId)

Expand Down
11 changes: 0 additions & 11 deletions x/liquidfarming/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,14 +66,3 @@ func (k Keeper) GetParams(ctx sdk.Context) (params types.Params) {
func (k Keeper) SetParams(ctx sdk.Context, params types.Params) {
k.paramSpace.SetParamSet(ctx, &params)
}

// GetLiquidFarm returns LiquidFarm object by the given pool id.
func (k Keeper) GetLiquidFarm(ctx sdk.Context, poolId uint64) (liquidFarm types.LiquidFarm, found bool) {
params := k.GetParams(ctx)
for _, lf := range params.LiquidFarms {
if lf.PoolId == poolId {
return lf, true
}
}
return types.LiquidFarm{}, false
}
4 changes: 1 addition & 3 deletions x/liquidfarming/keeper/keeper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,9 +147,7 @@ func (s *KeeperTestSuite) deposit(depositor sdk.AccAddress, poolId uint64, depos

func (s *KeeperTestSuite) createLiquidFarm(liquidFarm types.LiquidFarm) types.LiquidFarm {
s.T().Helper()
params := s.keeper.GetParams(s.ctx)
params.LiquidFarms = append(params.LiquidFarms, liquidFarm)
s.keeper.SetParams(s.ctx, params)
s.keeper.SetLiquidFarm(s.ctx, liquidFarm)
return liquidFarm
}

Expand Down
67 changes: 34 additions & 33 deletions x/liquidfarming/keeper/liquidfarm.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,46 +12,47 @@ import (
liquiditytypes "github.com/cosmosquad-labs/squad/v2/x/liquidity/types"
)

// Farm handles types.MsgFarm to liquid farm.
func (k Keeper) Farm(ctx sdk.Context, msg *types.MsgFarm) error {
params := k.GetParams(ctx)

poolId := uint64(0)
minFarmAmt := sdk.ZeroInt()
for _, liquidFarm := range params.LiquidFarms {
if liquidFarm.PoolId == msg.PoolId {
poolId = liquidFarm.PoolId
minFarmAmt = liquidFarm.MinimumFarmAmount
break
}
}
if poolId == 0 {
// ValidateMsgFarm validates types.MsgFarm.
func (k Keeper) ValidateMsgFarm(ctx sdk.Context, msg *types.MsgFarm) error {
liquidFarm, found := k.GetLiquidFarm(ctx, msg.PoolId)
if !found {
return sdkerrors.Wrapf(sdkerrors.ErrNotFound, "liquid farm by pool %d not found", msg.PoolId)
}
minFarmAmt := liquidFarm.MinimumFarmAmount

if msg.FarmingCoin.Amount.LT(minFarmAmt) {
return sdkerrors.Wrapf(types.ErrSmallerThanMinimumAmount, "%s is smaller than %s", msg.FarmingCoin.Amount, minFarmAmt)
}

pool, found := k.liquidityKeeper.GetPool(ctx, poolId)
pool, found := k.liquidityKeeper.GetPool(ctx, liquidFarm.PoolId)
if !found {
return sdkerrors.Wrapf(sdkerrors.ErrNotFound, "pool %d not found", poolId)
return sdkerrors.Wrapf(sdkerrors.ErrNotFound, "pool %d not found", liquidFarm.PoolId)
}

if pool.PoolCoinDenom != msg.FarmingCoin.Denom {
return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "expected denom %s, but got %s", pool.PoolCoinDenom, msg.FarmingCoin.Denom)
}

farmerAddr := msg.GetFarmer()
farmingCoin := msg.FarmingCoin
reserveAddr := types.LiquidFarmReserveAddress(poolId)

poolCoinBalance := k.bankKeeper.SpendableCoins(ctx, farmerAddr).AmountOf(pool.PoolCoinDenom)
if poolCoinBalance.LT(farmingCoin.Amount) {
poolCoinBalance := k.bankKeeper.SpendableCoins(ctx, msg.GetFarmer()).AmountOf(pool.PoolCoinDenom)
if poolCoinBalance.LT(msg.FarmingCoin.Amount) {
return sdkerrors.Wrapf(sdkerrors.ErrInsufficientFunds, "%s is smaller than %s", poolCoinBalance, minFarmAmt)
}

// Reserve farming coins
return nil
}

// Farm handles types.MsgFarm to liquid farm.
func (k Keeper) Farm(ctx sdk.Context, msg *types.MsgFarm) error {
if err := k.ValidateMsgFarm(ctx, msg); err != nil {
return err
}

params := k.GetParams(ctx)
farmerAddr := msg.GetFarmer()
farmingCoin := msg.FarmingCoin
reserveAddr := types.LiquidFarmReserveAddress(msg.PoolId)

// Reserve the farming coin
if err := k.bankKeeper.SendCoins(ctx, farmerAddr, reserveAddr, sdk.NewCoins(farmingCoin)); err != nil {
return sdkerrors.Wrap(err, "reserve farming coin")
}
Expand All @@ -66,15 +67,15 @@ func (k Keeper) Farm(ctx sdk.Context, msg *types.MsgFarm) error {
ctx.GasMeter().ConsumeGas(sdk.Gas(numQueuedFarmings)*params.DelayedFarmGasFee, "DelayedFarmGasFee")
}

// Stake with the reserve account in the farming module
// Stake in the farming module with the reserve account
if err := k.farmingKeeper.Stake(ctx, reserveAddr, sdk.NewCoins(farmingCoin)); err != nil {
return err
}

currentEpochDays := k.farmingKeeper.GetCurrentEpochDays(ctx)
endTime := ctx.BlockTime().Add(time.Duration(currentEpochDays) * farmingtypes.Day) // current time + epoch days

k.SetQueuedFarming(ctx, endTime, pool.PoolCoinDenom, farmerAddr, types.QueuedFarming{
k.SetQueuedFarming(ctx, endTime, liquiditytypes.PoolCoinDenom(msg.PoolId), farmerAddr, types.QueuedFarming{
PoolId: msg.PoolId,
Amount: msg.FarmingCoin.Amount,
})
Expand All @@ -100,14 +101,14 @@ type UnfarmInfo struct {
// Unfarm handles types.MsgUnfarm to unfarm LFCoin.
// The logic doesn't check whether or not liquid farm exists because it can be removed for some reason and
// farmers still need to be able to unfarm their pool coin.
func (k Keeper) Unfarm(ctx sdk.Context, poolId uint64, farmer sdk.AccAddress, lfCoin sdk.Coin) (UnfarmInfo, error) {
func (k Keeper) Unfarm(ctx sdk.Context, poolId uint64, farmer sdk.AccAddress, unfarmingCoin sdk.Coin) (UnfarmInfo, error) {
reserveAddr := types.LiquidFarmReserveAddress(poolId)
lfCoinDenom := types.LiquidFarmCoinDenom(poolId)

lfCoinBalance := k.bankKeeper.SpendableCoins(ctx, farmer).AmountOf(lfCoinDenom)
if lfCoinBalance.LT(lfCoin.Amount) {
if lfCoinBalance.LT(unfarmingCoin.Amount) {
return UnfarmInfo{},
sdkerrors.Wrapf(types.ErrInsufficientUnfarmingAmount, "%s is smaller than %s", lfCoinBalance, lfCoin.Amount)
sdkerrors.Wrapf(types.ErrInsufficientUnfarmingAmount, "%s is smaller than %s", lfCoinBalance, unfarmingCoin.Amount)
}

pool, found := k.liquidityKeeper.GetPool(ctx, poolId)
Expand All @@ -121,14 +122,14 @@ func (k Keeper) Unfarm(ctx sdk.Context, poolId uint64, farmer sdk.AccAddress, lf
unfarmFee := sdk.ZeroInt() // TODO: TBD

// UnfarmedAmount = TotalStakedLPAmount / TotalSupplyLFAmount * UnfarmingLFAmount * (1 - UnfarmFee)
unfarmedAmt := lpCoinTotalStaked.Quo(lfCoinTotalSupply).Mul(lfCoin.Amount).Mul(sdk.OneInt().Sub(unfarmFee))
unfarmedAmt := lpCoinTotalStaked.Quo(lfCoinTotalSupply).Mul(unfarmingCoin.Amount).Mul(sdk.OneInt().Sub(unfarmFee))
unfarmedCoin := sdk.NewCoin(pool.PoolCoinDenom, unfarmedAmt)

// Send the unfarming LFCoin to module account and burn them
if err := k.bankKeeper.SendCoinsFromAccountToModule(ctx, farmer, types.ModuleName, sdk.NewCoins(lfCoin)); err != nil {
if err := k.bankKeeper.SendCoinsFromAccountToModule(ctx, farmer, types.ModuleName, sdk.NewCoins(unfarmingCoin)); err != nil {
return UnfarmInfo{}, err
}
if err := k.bankKeeper.BurnCoins(ctx, types.ModuleName, sdk.NewCoins(lfCoin)); err != nil {
if err := k.bankKeeper.BurnCoins(ctx, types.ModuleName, sdk.NewCoins(unfarmingCoin)); err != nil {
return UnfarmInfo{}, err
}

Expand All @@ -145,7 +146,7 @@ func (k Keeper) Unfarm(ctx sdk.Context, poolId uint64, farmer sdk.AccAddress, lf
types.EventTypeUnfarm,
sdk.NewAttribute(types.AttributeKeyPoolId, strconv.FormatUint(poolId, 10)),
sdk.NewAttribute(types.AttributeKeyFarmer, farmer.String()),
sdk.NewAttribute(types.AttributeKeyUnfarmingCoin, lfCoin.String()),
sdk.NewAttribute(types.AttributeKeyUnfarmingCoin, unfarmingCoin.String()),
sdk.NewAttribute(types.AttributeKeyUnfarmedCoin, unfarmedCoin.String()),
),
})
Expand All @@ -160,7 +161,7 @@ func (k Keeper) Unfarm(ctx sdk.Context, poolId uint64, farmer sdk.AccAddress, lf

// UnfarmAndWithdraw handles types.MsgUnfarmAndWithdraw to unfarm LFCoin and withdraw pool coin from the pool.
func (k Keeper) UnfarmAndWithdraw(ctx sdk.Context, msg *types.MsgUnfarmAndWithdraw) error {
unfarmInfo, err := k.Unfarm(ctx, msg.PoolId, msg.GetFarmer(), msg.LFCoin)
unfarmInfo, err := k.Unfarm(ctx, msg.PoolId, msg.GetFarmer(), msg.UnfarmingCoin)
if err != nil {
return sdkerrors.Wrapf(err, "unable to unfarm")
}
Expand Down
2 changes: 1 addition & 1 deletion x/liquidfarming/keeper/msg_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ func (m msgServer) CancelQueuedFarming(goCtx context.Context, msg *types.MsgCanc
func (m msgServer) Unfarm(goCtx context.Context, msg *types.MsgUnfarm) (*types.MsgUnfarmResponse, error) {
ctx := sdk.UnwrapSDKContext(goCtx)

if _, err := m.Keeper.Unfarm(ctx, msg.PoolId, msg.GetFarmer(), msg.LFCoin); err != nil {
if _, err := m.Keeper.Unfarm(ctx, msg.PoolId, msg.GetFarmer(), msg.UnfarmingCoin); err != nil {
return nil, err
}

Expand Down
55 changes: 53 additions & 2 deletions x/liquidfarming/keeper/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,42 @@ import (
"github.com/cosmosquad-labs/squad/v2/x/liquidfarming/types"
)

// GetQueuedFarming returns a queued farming object for the given end time, farming coin denom and farmer.
// GetLiquidFarm returns liquid farm object by the given pool id.
func (k Keeper) GetLiquidFarm(ctx sdk.Context, poolId uint64) (liquidFarm types.LiquidFarm, found bool) {
store := ctx.KVStore(k.storeKey)
bz := store.Get(types.GetLiquidFarmKey(poolId))
if bz == nil {
return
}
k.cdc.MustUnmarshal(bz, &liquidFarm)
found = true
return
}

// GetAllLiquidFarms returns all liquid farm objects stored in the store.
func (k Keeper) GetAllLiquidFarms(ctx sdk.Context) []types.LiquidFarm {
liquidFarms := []types.LiquidFarm{}
k.IterateLiquidFarms(ctx, func(liquidFarm types.LiquidFarm) (stop bool) {
liquidFarms = append(liquidFarms, liquidFarm)
return false
})
return liquidFarms
}

// SetLiquidFarm stores liquid farm object with the given pool idl.
func (k Keeper) SetLiquidFarm(ctx sdk.Context, liquidFarm types.LiquidFarm) {
store := ctx.KVStore(k.storeKey)
bz := k.cdc.MustMarshal(&liquidFarm)
store.Set(types.GetLiquidFarmKey(liquidFarm.PoolId), bz)
}

// DeleteLiquidFarm deletes the liquid farm object from the store.
func (k Keeper) DeleteLiquidFarm(ctx sdk.Context, liquidFarm types.LiquidFarm) {
store := ctx.KVStore(k.storeKey)
store.Delete(types.GetLiquidFarmKey(liquidFarm.PoolId))
}

// GetQueuedFarming returns a queued farming object by the given end time, farming coin denom and farmer.
func (k Keeper) GetQueuedFarming(ctx sdk.Context, endTime time.Time, farmingCoinDenom string, farmerAcc sdk.AccAddress) (queuedFarming types.QueuedFarming, found bool) {
store := ctx.KVStore(k.storeKey)
bz := store.Get(types.GetQueuedFarmingKey(endTime, farmingCoinDenom, farmerAcc))
Expand All @@ -32,7 +67,7 @@ func (k Keeper) GetQueuedFarmingsByFarmer(ctx sdk.Context, farmerAcc sdk.AccAddr
return queuedFarmings
}

// SetQueuedFarming stores a queued farming with the given end time, farming coin denom, and farmer address.
// SetQueuedFarming stores a queued farming by the given end time, farming coin denom, and farmer address.
func (k Keeper) SetQueuedFarming(ctx sdk.Context, endTime time.Time, farmingCoinDenom string, farmerAcc sdk.AccAddress, queuedFarming types.QueuedFarming) {
store := ctx.KVStore(k.storeKey)
bz := k.cdc.MustMarshal(&queuedFarming)
Expand Down Expand Up @@ -151,6 +186,22 @@ func (k Keeper) SetWinningBid(ctx sdk.Context, bid types.Bid, auctionId uint64)
store.Set(types.GetWinningBidKey(bid.PoolId, auctionId), bz)
}

// IterateLiquidFarms iterates through all liquid farm objects
// stored in the store and invokes callback function for each item.
// Stops the iteration when the callback function for each time.
func (k Keeper) IterateLiquidFarms(ctx sdk.Context, cb func(liquidFarm types.LiquidFarm) (stop bool)) {
store := ctx.KVStore(k.storeKey)
iter := sdk.KVStorePrefixIterator(store, types.LiquidFarmKeyPrefix)
defer iter.Close()
for ; iter.Valid(); iter.Next() {
var liquidFarm types.LiquidFarm
k.cdc.MustUnmarshal(iter.Value(), &liquidFarm)
if cb(liquidFarm) {
break
}
}
}

// IterateQueuedFarmings iterates through all queued farming objects
// stored in the store and invokes callback function for each item.
// Stops the iteration when the callback function returns true.
Expand Down
Loading

0 comments on commit e013f4f

Please sign in to comment.