Skip to content

Commit

Permalink
Merge pull request #49 from crescent-network/cherry-pick/340
Browse files Browse the repository at this point in the history
fix: limit the number of active pools in a pair #340
  • Loading branch information
crypin authored Jul 18, 2022
2 parents 7f77cb9 + 2b48702 commit 89a6348
Show file tree
Hide file tree
Showing 5 changed files with 77 additions and 1 deletion.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ Ref: https://keepachangelog.com/en/1.0.0/

## [Unreleased]

## v2.0.0
## v2.1.0

### Client Breaking Changes

Expand Down Expand Up @@ -76,6 +76,7 @@ Ref: https://keepachangelog.com/en/1.0.0/

### State Machine Breaking

* (x/liquidity) [\#49](https://github.com/crescent-network/crescent/pull/49) Add `MaxNumActivePoolsPerPair` global constant
* (x/liquidity) [\#37](https://github.com/crescent-network/crescent/pull/37) 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 89a6348

Please sign in to comment.