Skip to content

Commit

Permalink
Merge pull request #340 from cosmosquad-labs/limit-num-pools
Browse files Browse the repository at this point in the history
fix: limit the number of active pools in a pair
  • Loading branch information
dongsam authored Jul 18, 2022
2 parents 0251d7d + a406c70 commit 7ae07d3
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 11 deletions.
17 changes: 6 additions & 11 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,23 +38,14 @@ Ref: https://keepachangelog.com/en/1.0.0/

## [Unreleased]

## v2.1.0

### Client Breaking Changes

* (x/liquidity) [\#338](https://github.com/cosmosquad-labs/squad/pull/338) Refactor `OrderBooks` query:
* `tick_precisions` field has been removed from `QueryOrderBooksRequest`
* `tick_precision` field has been removed from `OrderBookResponse` and `price_unit` has been added instead
* The order between `sells` and `buys` has been changed

### CLI Breaking Changes

* (x/liquidity) [\#338](https://github.com/cosmosquad-labs/squad/pull/338) Refactor `order-books` query cmd:
* `[tick-precisions]` argument has been removed: `order-books [pair-ids]`
* Response structure has been changed

## v2.0.0

### Client Breaking Changes

* (x/liquidity) [\#335](https://github.com/cosmosquad-labs/squad/pull/335) Modify `PoolResponse`:
* `balances` field has been modified to contain `base_coin` and `quote_coin` fields
* `pool_coin_supply` field has been added
Expand All @@ -70,6 +61,9 @@ Ref: https://keepachangelog.com/en/1.0.0/

### CLI Breaking Changes

* (x/liquidity) [\#338](https://github.com/cosmosquad-labs/squad/pull/338) Refactor `order-books` query cmd:
* `[tick-precisions]` argument has been removed: `order-books [pair-ids]`
* Response structure has been changed
* (x/farming) [\#334](https://github.com/cosmosquad-labs/squad/pull/334) Add `historical-rewards` query cmd:
* `historical-rewards [staking-coin-denom]`
* (x/liquidity) [\#318](https://github.com/cosmosquad-labs/squad/pull/318) Add `create-ranged-pool` tx cmd and `order-books` query cmd:
Expand All @@ -82,6 +76,7 @@ Ref: https://keepachangelog.com/en/1.0.0/

### State Machine Breaking

* (x/liquidity) [\#340](https://github.com/cosmosquad-labs/squad/pull/340) Add `MaxNumActivePoolsPerPair` global constant
* (x/liquidity) [\#318](https://github.com/cosmosquad-labs/squad/pull/318) Change `Pool` struct for ranged pools and refactor matching logic
* Add `type`, `creator`, `min_price` and `max_price` fields to `Pool` struct
* Refactor matching logic both for fairness of matching and efficiency of pool order placement
Expand Down
18 changes: 18 additions & 0 deletions x/liquidity/keeper/pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,16 +89,23 @@ func (k Keeper) ValidateMsgCreatePool(ctx sdk.Context, msg *types.MsgCreatePool)
// Check if there is a basic pool in the pair.
// Creating multiple basic pools within the same pair is disallowed.
duplicate := false
numActivePools := 0
_ = k.IteratePoolsByPair(ctx, pair.Id, func(pool types.Pool) (stop bool, err error) {
if pool.Type == types.PoolTypeBasic && !pool.Disabled {
duplicate = true
return true, nil
}
if !pool.Disabled {
numActivePools++
}
return false, nil
})
if duplicate {
return types.ErrPoolAlreadyExists
}
if numActivePools >= types.MaxNumActivePoolsPerPair {
return types.ErrTooManyPools
}

return nil
}
Expand Down Expand Up @@ -191,6 +198,17 @@ func (k Keeper) ValidateMsgCreateRangedPool(ctx sdk.Context, msg *types.MsgCreat
}
}

numActivePools := 0
_ = k.IteratePoolsByPair(ctx, pair.Id, func(pool types.Pool) (stop bool, err error) {
if !pool.Disabled {
numActivePools++
}
return false, nil
})
if numActivePools >= types.MaxNumActivePoolsPerPair {
return types.ErrTooManyPools
}

return nil
}

Expand Down
52 changes: 52 additions & 0 deletions x/liquidity/keeper/pool_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -591,3 +591,55 @@ func (s *KeeperTestSuite) TestRangedPoolDepositWithdraw_single_side2() {
s.Require().True(intEq(sdk.ZeroInt(), s.getBalance(s.addr(3), "denom2").Amount))
s.Require().True(intEq(sdk.NewInt(1000000), s.getBalance(s.addr(3), "denom1").Amount))
}

func (s *KeeperTestSuite) TestMaxNumActivePoolsPerPair() {
s.Run("basic pool and ranged pools", func() {
s.SetupTest()
pair := s.createPair(s.addr(0), "denom1", "denom2", true)

pool1 := s.createPool(s.addr(0), pair.Id, utils.ParseCoins("1000000denom1,1000000denom2"), true)
for i := 0; i < types.MaxNumActivePoolsPerPair-1; i++ {
s.createRangedPool(
s.addr(0), pair.Id, utils.ParseCoins("1000000denom1,1000000denom2"),
utils.ParseDec("0.5"), utils.ParseDec("2.0"), utils.ParseDec("1.0"), true)
}

s.fundAddr(s.addr(0), utils.ParseCoins("1000000denom1,1000000denom2"))
_, err := s.keeper.CreateRangedPool(s.ctx, types.NewMsgCreateRangedPool(
s.addr(0), pair.Id, utils.ParseCoins("1000000denom1,1000000denom2"),
utils.ParseDec("0.5"), utils.ParseDec("2.0"), utils.ParseDec("1.5")))
s.Require().ErrorIs(err, types.ErrTooManyPools)

s.withdraw(s.addr(0), pool1.Id, sdk.NewCoin(pool1.PoolCoinDenom, s.keeper.GetPoolCoinSupply(s.ctx, pool1)))
s.nextBlock()

s.createRangedPool(
s.addr(0), pair.Id, utils.ParseCoins("1000000denom1,1000000denom2"),
utils.ParseDec("0.5"), utils.ParseDec("2.0"), utils.ParseDec("1.0"), true)
})

s.Run("ranged pools only", func() {
s.SetupTest()
pair := s.createPair(s.addr(0), "denom1", "denom2", true)

for i := 0; i < types.MaxNumActivePoolsPerPair; i++ {
s.createRangedPool(
s.addr(0), pair.Id, utils.ParseCoins("1000000denom1,1000000denom2"),
utils.ParseDec("0.5"), utils.ParseDec("2.0"), utils.ParseDec("1.0"), true)
}
pool1, _ := s.keeper.GetPool(s.ctx, 1)

s.fundAddr(s.addr(0), utils.ParseCoins("1000000denom1,1000000denom2"))
_, err := s.keeper.CreateRangedPool(s.ctx, types.NewMsgCreateRangedPool(
s.addr(0), pair.Id, utils.ParseCoins("1000000denom1,1000000denom2"),
utils.ParseDec("0.5"), utils.ParseDec("2.0"), utils.ParseDec("1.5")))
s.Require().ErrorIs(err, types.ErrTooManyPools)

s.withdraw(s.addr(0), pool1.Id, sdk.NewCoin(pool1.PoolCoinDenom, s.keeper.GetPoolCoinSupply(s.ctx, pool1)))
s.nextBlock()

s.createRangedPool(
s.addr(0), pair.Id, utils.ParseCoins("1000000denom1,1000000denom2"),
utils.ParseDec("0.5"), utils.ParseDec("2.0"), utils.ParseDec("1.0"), true)
})
}
1 change: 1 addition & 0 deletions x/liquidity/types/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,5 @@ var (
ErrDuplicatePairId = sdkerrors.Register(ModuleName, 16, "duplicate pair id presents in the pair id list")
ErrTooSmallOrder = sdkerrors.Register(ModuleName, 17, "too small order")
ErrTooLargePool = sdkerrors.Register(ModuleName, 18, "too large pool")
ErrTooManyPools = sdkerrors.Register(ModuleName, 19, "too many pools in the pair")
)
4 changes: 4 additions & 0 deletions x/liquidity/types/params.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ const (
PairEscrowAddressPrefix = "PairEscrowAddress"
ModuleAddressNameSplitter = "|"
AddressType = farmingtypes.AddressType32Bytes

// MaxNumActivePoolsPerPair is the maximum number of active(not disabled)
// pools per pair.
MaxNumActivePoolsPerPair = 50
)

var (
Expand Down

0 comments on commit 7ae07d3

Please sign in to comment.