code.vegaprotocol.io/vega@v0.79.0/core/execution/amm/shape_test.go (about) 1 // Copyright (C) 2023 Gobalsky Labs Limited 2 // 3 // This program is free software: you can redistribute it and/or modify 4 // it under the terms of the GNU Affero General Public License as 5 // published by the Free Software Foundation, either version 3 of the 6 // License, or (at your option) any later version. 7 // 8 // This program is distributed in the hope that it will be useful, 9 // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 // GNU Affero General Public License for more details. 12 // 13 // You should have received a copy of the GNU Affero General Public License 14 // along with this program. If not, see <http://www.gnu.org/licenses/>. 15 16 package amm 17 18 import ( 19 "testing" 20 21 "code.vegaprotocol.io/vega/core/types" 22 vgcrypto "code.vegaprotocol.io/vega/libs/crypto" 23 "code.vegaprotocol.io/vega/libs/num" 24 "code.vegaprotocol.io/vega/libs/ptr" 25 26 "github.com/stretchr/testify/assert" 27 "github.com/stretchr/testify/require" 28 ) 29 30 func TestOrderbookShape(t *testing.T) { 31 t.Run("test orderbook shape pending AMM", testOrderbookShapePendingAMM) 32 t.Run("test orderbook shape when AMM is 0", testOrderbookShapeZeroPosition) 33 t.Run("test orderbook shape when AMM is long", testOrderbookShapeLong) 34 t.Run("test orderbook shape when AMM is short", testOrderbookShapeShort) 35 t.Run("test orderbook shape when calculations are capped", testOrderbookShapeLimited) 36 t.Run("test orderbook shape step over fair price", testOrderbookShapeStepOverFairPrice) 37 t.Run("test orderbook shape step fair price at boundary", testOrderbookShapeNoStepOverFairPrice) 38 t.Run("test orderbook shape AMM reduce only", testOrderbookShapeReduceOnly) 39 t.Run("test orderbook shape boundary order when approx", testOrderbookShapeBoundaryOrder) 40 t.Run("test orderbook shape region not divisible by tick", testOrderbookSubTick) 41 t.Run("test orderbook shape closing pool close to base", testClosingCloseToBase) 42 t.Run("test orderbook shape point expansion at fair price", testPointExpansionAtFairPrice) 43 } 44 45 func testOrderbookShapePendingAMM(t *testing.T) { 46 p := newTestPoolWithRanges(t, num.NewUint(7), num.NewUint(10), num.NewUint(13)) 47 defer p.ctrl.Finish() 48 49 p.pool.status = types.AMMPoolStatusPending 50 low := p.submission.Parameters.LowerBound 51 high := p.submission.Parameters.UpperBound 52 53 r := p.pool.OrderbookShape(low, high, nil) 54 assert.Equal(t, 0, len(r.Buys)) 55 assert.Equal(t, 0, len(r.Sells)) 56 } 57 58 func testOrderbookShapeZeroPosition(t *testing.T) { 59 p := newTestPoolWithRanges(t, num.NewUint(7), num.NewUint(10), num.NewUint(13)) 60 defer p.ctrl.Finish() 61 62 low := p.submission.Parameters.LowerBound 63 base := p.submission.Parameters.Base 64 high := p.submission.Parameters.UpperBound 65 66 // when range [7, 10] expect orders at prices (7, 8, 9) 67 // there will be no order at price 10 since that is the pools fair-price and it quotes +/-1 eitherside 68 ensurePositionN(t, p.pos, 0, num.UintZero(), 2) 69 r := p.pool.OrderbookShape(low, base, nil) 70 71 assertOrderPrices(t, r.Buys, types.SideBuy, 7, 9) 72 assert.Equal(t, 0, len(r.Sells)) 73 74 // when range [7, 9] expect orders at prices (7, 8, 9) 75 ensurePositionN(t, p.pos, 0, num.UintZero(), 2) 76 r = p.pool.OrderbookShape(low, num.NewUint(9), nil) 77 assertOrderPrices(t, r.Buys, types.SideBuy, 7, 9) 78 assert.Equal(t, 0, len(r.Sells)) 79 80 // when range [10, 13] expect orders at prices (11, 12, 13) 81 // there will be no order at price 10 since that is the pools fair-price and it quotes +/-1 eitherside 82 ensurePositionN(t, p.pos, 0, num.UintZero(), 2) 83 r = p.pool.OrderbookShape(base, high, nil) 84 assert.Equal(t, 0, len(r.Buys)) 85 assertOrderPrices(t, r.Sells, types.SideSell, 11, 13) 86 87 // when range [11, 13] expect orders at prices (11, 12, 13) 88 ensurePositionN(t, p.pos, 0, num.UintZero(), 2) 89 r = p.pool.OrderbookShape(num.NewUint(11), high, nil) 90 assert.Equal(t, 0, len(r.Buys)) 91 assertOrderPrices(t, r.Sells, types.SideSell, 11, 13) 92 93 // whole range from [7, 10] will have buys (7, 8, 9) and sells (11, 12, 13) 94 ensurePositionN(t, p.pos, 0, num.UintZero(), 2) 95 r = p.pool.OrderbookShape(low, high, nil) 96 assertOrderPrices(t, r.Buys, types.SideBuy, 7, 9) 97 assertOrderPrices(t, r.Sells, types.SideSell, 11, 13) 98 99 // mid both curves spanning buys and sells, range from [8, 12] will have buys (8, 9) and sells (11, 12) 100 ensurePositionN(t, p.pos, 0, num.UintZero(), 2) 101 r = p.pool.OrderbookShape(num.NewUint(8), num.NewUint(12), nil) 102 assertOrderPrices(t, r.Buys, types.SideBuy, 8, 9) 103 assertOrderPrices(t, r.Sells, types.SideSell, 11, 12) 104 105 // range (8, 8) should return a single buy order at price 8, which is a bit counter intuitive 106 ensurePositionN(t, p.pos, 0, num.UintZero(), 2) 107 r = p.pool.OrderbookShape(num.NewUint(8), num.NewUint(8), nil) 108 assertOrderPrices(t, r.Buys, types.SideBuy, 8, 8) 109 assert.Equal(t, 0, len(r.Sells)) 110 111 // range (10, 10) should return only the orders at the fair-price, which is 0 orders 112 ensurePositionN(t, p.pos, 0, num.UintZero(), 2) 113 r = p.pool.OrderbookShape(num.NewUint(10), num.NewUint(10), nil) 114 assert.Equal(t, 0, len(r.Buys)) 115 assert.Equal(t, 0, len(r.Sells)) 116 } 117 118 func testOrderbookShapeLong(t *testing.T) { 119 p := newTestPoolWithRanges(t, num.NewUint(7), num.NewUint(10), num.NewUint(13)) 120 defer p.ctrl.Finish() 121 122 low := p.submission.Parameters.LowerBound 123 base := p.submission.Parameters.Base 124 high := p.submission.Parameters.UpperBound 125 126 // AMM is long and will have a fair-price of 8 127 position := int64(17980) 128 ensurePosition(t, p.pos, position, num.UintZero()) 129 require.Equal(t, "8", p.pool.FairPrice().String()) 130 131 // range [7, 10] with have buy order (7) and sell orders (9, 10) 132 ensurePositionN(t, p.pos, position, num.UintZero(), 2) 133 r := p.pool.OrderbookShape(low, base, nil) 134 assertOrderPrices(t, r.Buys, types.SideBuy, 7, 7) 135 assertOrderPrices(t, r.Sells, types.SideSell, 9, 10) 136 137 // range [10, 13] with have sell orders (10, 11, 12, 13) 138 ensurePositionN(t, p.pos, position, num.UintZero(), 2) 139 r = p.pool.OrderbookShape(base, high, nil) 140 assert.Equal(t, 0, len(r.Buys)) 141 assertOrderPrices(t, r.Sells, types.SideSell, 10, 13) 142 143 // whole range will have buys at (7) and sells at (9, 10, 11, 12, 13) 144 ensurePositionN(t, p.pos, position, num.UintZero(), 2) 145 r = p.pool.OrderbookShape(low, high, nil) 146 assertOrderPrices(t, r.Buys, types.SideBuy, 7, 7) 147 assertOrderPrices(t, r.Sells, types.SideSell, 9, 13) 148 149 // query at fair price returns no orders 150 ensurePositionN(t, p.pos, position, num.UintZero(), 2) 151 r = p.pool.OrderbookShape(num.NewUint(8), num.NewUint(8), nil) 152 assert.Equal(t, 0, len(r.Buys)) 153 assert.Equal(t, 0, len(r.Sells)) 154 } 155 156 func testOrderbookShapeShort(t *testing.T) { 157 p := newTestPoolWithRanges(t, num.NewUint(7), num.NewUint(10), num.NewUint(13)) 158 defer p.ctrl.Finish() 159 160 low := p.submission.Parameters.LowerBound 161 base := p.submission.Parameters.Base 162 high := p.submission.Parameters.UpperBound 163 164 // AMM is short and will have a fair-price of 12 165 position := int64(-20000) 166 ensurePosition(t, p.pos, position, num.UintZero()) 167 require.Equal(t, "12", p.pool.FairPrice().String()) 168 169 // range [7, 10] with have buy order (7,8,9,10) 170 ensurePositionN(t, p.pos, position, num.UintZero(), 2) 171 r := p.pool.OrderbookShape(low, base, nil) 172 assertOrderPrices(t, r.Buys, types.SideBuy, 7, 10) 173 assert.Equal(t, 0, len(r.Sells)) 174 175 // range [10, 13] with have buy orders (10, 11) and sell orders (13) 176 ensurePositionN(t, p.pos, position, num.UintZero(), 2) 177 r = p.pool.OrderbookShape(base, high, nil) 178 assertOrderPrices(t, r.Buys, types.SideBuy, 10, 11) 179 assertOrderPrices(t, r.Sells, types.SideSell, 13, 13) 180 181 // whole range will have buys at (7,8,9,10,11) and sells at (13) 182 ensurePositionN(t, p.pos, position, num.UintZero(), 2) 183 r = p.pool.OrderbookShape(low, high, nil) 184 assertOrderPrices(t, r.Buys, types.SideBuy, 7, 11) 185 assertOrderPrices(t, r.Sells, types.SideSell, 13, 13) 186 187 // query at fair price returns no orders 188 ensurePositionN(t, p.pos, position, num.UintZero(), 2) 189 r = p.pool.OrderbookShape(num.NewUint(12), num.NewUint(12), nil) 190 assert.Equal(t, 0, len(r.Buys)) 191 assert.Equal(t, 0, len(r.Sells)) 192 } 193 194 func testOrderbookShapeLimited(t *testing.T) { 195 p := newTestPoolWithRanges(t, num.NewUint(20), num.NewUint(40), num.NewUint(60)) 196 defer p.ctrl.Finish() 197 198 low := p.submission.Parameters.LowerBound 199 base := p.submission.Parameters.Base 200 high := p.submission.Parameters.UpperBound 201 202 // position is zero but we're capping max calculations at ~10 203 position := int64(0) 204 p.pool.maxCalculationLevels = num.NewUint(10) 205 206 ensurePositionN(t, p.pos, position, num.UintZero(), 2) 207 r := p.pool.OrderbookShape(low, base, nil) 208 assert.Equal(t, 11, len(r.Buys)) 209 assert.Equal(t, 0, len(r.Sells)) 210 211 ensurePositionN(t, p.pos, position, num.UintZero(), 2) 212 r = p.pool.OrderbookShape(base, high, nil) 213 assert.Equal(t, 0, len(r.Buys)) 214 assert.Equal(t, 11, len(r.Sells)) 215 216 ensurePositionN(t, p.pos, position, num.UintZero(), 2) 217 r = p.pool.OrderbookShape(low, high, nil) 218 assert.Equal(t, 6, len(r.Buys)) 219 assert.Equal(t, 6, len(r.Sells)) 220 } 221 222 func testOrderbookShapeStepOverFairPrice(t *testing.T) { 223 p := newTestPoolWithRanges(t, num.NewUint(20), num.NewUint(40), num.NewUint(60)) 224 defer p.ctrl.Finish() 225 226 low := p.submission.Parameters.LowerBound 227 base := p.submission.Parameters.Base 228 high := p.submission.Parameters.UpperBound 229 230 // make levels of 10 makes the step price 2, and this position gives the pool a fair price of 25 231 // when we take the step from 24 -> 26 we want to make sure we split that order into two, so we 232 // will actually do maxCalculationLevels + 1 calculations but I think thats fine and keeps the calculations 233 // simple 234 position := int64(6000) 235 p.pool.maxCalculationLevels = num.NewUint(10) 236 ensurePosition(t, p.pos, position, num.UintZero()) 237 require.Equal(t, "26", p.pool.FairPrice().String()) 238 239 ensurePositionN(t, p.pos, position, num.UintZero(), 2) 240 r := p.pool.OrderbookShape(low, base, nil) 241 assert.Equal(t, 4, len(r.Buys)) 242 assert.Equal(t, 8, len(r.Sells)) 243 244 ensurePositionN(t, p.pos, position, num.UintZero(), 2) 245 r = p.pool.OrderbookShape(base, high, nil) 246 assert.Equal(t, 0, len(r.Buys)) 247 assert.Equal(t, 12, len(r.Sells)) 248 249 ensurePositionN(t, p.pos, position, num.UintZero(), 2) 250 r = p.pool.OrderbookShape(low, high, nil) 251 assert.Equal(t, 3, len(r.Buys)) 252 assert.Equal(t, 10, len(r.Sells)) 253 } 254 255 func testOrderbookShapeNoStepOverFairPrice(t *testing.T) { 256 p := newTestPoolWithRanges(t, num.NewUint(20), num.NewUint(40), num.NewUint(60)) 257 defer p.ctrl.Finish() 258 259 low := p.submission.Parameters.LowerBound 260 base := p.submission.Parameters.Base 261 high := p.submission.Parameters.UpperBound 262 263 position := int64(0) 264 p.pool.maxCalculationLevels = num.NewUint(6) 265 266 ensurePositionN(t, p.pos, position, num.UintZero(), 2) 267 r := p.pool.OrderbookShape(low, base, nil) 268 assert.Equal(t, 7, len(r.Buys)) 269 assert.Equal(t, 0, len(r.Sells)) 270 271 ensurePositionN(t, p.pos, position, num.UintZero(), 2) 272 r = p.pool.OrderbookShape(base, high, nil) 273 assert.Equal(t, 0, len(r.Buys)) 274 assert.Equal(t, 7, len(r.Sells)) 275 276 ensurePositionN(t, p.pos, position, num.UintZero(), 2) 277 r = p.pool.OrderbookShape(low, high, nil) 278 assert.Equal(t, 4, len(r.Buys)) 279 assert.Equal(t, 4, len(r.Sells)) 280 } 281 282 func testOrderbookShapeReduceOnly(t *testing.T) { 283 p := newTestPoolWithRanges(t, num.NewUint(7), num.NewUint(10), num.NewUint(13)) 284 defer p.ctrl.Finish() 285 286 low := p.submission.Parameters.LowerBound 287 base := p.submission.Parameters.Base 288 high := p.submission.Parameters.UpperBound 289 290 // pool is reduce only so will not have any orders above/below fair price depending on position 291 p.pool.status = types.AMMPoolStatusReduceOnly 292 293 // AMM is position 0 it will have no orders 294 position := int64(0) 295 ensurePositionN(t, p.pos, position, num.UintZero(), 2) 296 r := p.pool.OrderbookShape(low, base, nil) 297 assert.Equal(t, 0, len(r.Buys)) 298 assert.Equal(t, 0, len(r.Sells)) 299 300 // AMM is long and will have a fair-price of 8 and so will only have orders from 8 -> base 301 position = int64(17980) 302 ensurePosition(t, p.pos, position, num.UintZero()) 303 require.Equal(t, "8", p.pool.FairPrice().String()) 304 305 // range [7, 13] will have only sellf orders (9, 10) 306 ensurePositionN(t, p.pos, position, num.UintZero(), 2) 307 r = p.pool.OrderbookShape(low, high, nil) 308 assert.Equal(t, 0, len(r.Buys)) 309 assertOrderPrices(t, r.Sells, types.SideSell, 9, 10) 310 311 // AMM is short and will have a fair-price of 12 312 position = int64(-20000) 313 ensurePosition(t, p.pos, position, num.UintZero()) 314 require.Equal(t, "12", p.pool.FairPrice().String()) 315 316 // range [10, 13] with have buy orders (10, 11) 317 ensurePositionN(t, p.pos, position, num.UintZero(), 2) 318 r = p.pool.OrderbookShape(base, high, nil) 319 assertOrderPrices(t, r.Buys, types.SideBuy, 10, 11) 320 assert.Equal(t, 0, len(r.Sells)) 321 } 322 323 func testOrderbookShapeBoundaryOrder(t *testing.T) { 324 p := newTestPoolWithRanges(t, num.NewUint(100), num.NewUint(200), num.NewUint(300)) 325 defer p.ctrl.Finish() 326 327 midlow := num.NewUint(150) 328 midhigh := num.NewUint(250) 329 330 position := int64(0) 331 ensurePositionN(t, p.pos, position, num.UintZero(), 2) 332 333 // limit the number of orders in the expansion 334 p.pool.maxCalculationLevels = num.NewUint(5) 335 336 r := p.pool.OrderbookShape(midlow, midhigh, nil) 337 assert.Equal(t, 4, len(r.Buys)) 338 assert.Equal(t, 4, len(r.Sells)) 339 340 // we're in approximate mode but we still require an exact order at the boundaries of the shape range 341 // check that the price for the first by is midlow, and the last sell is midhigh 342 assert.Equal(t, midlow.String(), r.Buys[0].Price.String()) 343 assert.Equal(t, midhigh.String(), r.Sells[(len(r.Sells)-1)].Price.String()) 344 } 345 346 func testOrderbookSubTick(t *testing.T) { 347 p := newTestPoolWithSubmission(t, num.DecimalFromFloat(1), num.DecimalFromFloat(100), 348 &types.SubmitAMM{ 349 CommitmentAmount: num.NewUint(10000000), 350 Parameters: &types.ConcentratedLiquidityParameters{ 351 LowerBound: num.NewUint(10), 352 Base: num.NewUint(15), 353 UpperBound: num.NewUint(20), 354 }, 355 }, 356 0, 357 ) 358 359 defer p.ctrl.Finish() 360 361 // limit the number of orders in the expansion 362 p.pool.maxCalculationLevels = num.NewUint(1000) 363 364 position := int64(1000) 365 ensurePositionN(t, p.pos, position, num.UintZero(), 4) 366 367 // fair-price should be 1483, and so best buy should be 1383 (fair-price minus one-tick) 368 bp, _ := p.pool.BestPrice(types.SideBuy) 369 require.Equal(t, "1383", bp.String()) 370 371 // now pretend we are in auction and we have a sell order at 1000, so we need to expand the crossed 372 // region of 1000 -> 1383 373 from := num.NewUint(1000) 374 to := num.NewUint(1383) 375 r := p.pool.OrderbookShape(from, to, nil) 376 377 assert.Equal(t, 4, len(r.Buys)) 378 assert.Equal(t, bp.String(), r.Buys[3].Price.String()) 379 380 assert.Equal(t, 0, len(r.Sells)) 381 } 382 383 func testClosingCloseToBase(t *testing.T) { 384 p := newTestPoolWithSubmission(t, num.DecimalFromFloat(1), num.DecimalFromFloat(100), 385 &types.SubmitAMM{ 386 CommitmentAmount: num.NewUint(10000000), 387 Parameters: &types.ConcentratedLiquidityParameters{ 388 LowerBound: num.NewUint(10), 389 Base: num.NewUint(15), 390 UpperBound: num.NewUint(20), 391 }, 392 }, 393 0, 394 ) 395 396 defer p.ctrl.Finish() 397 398 // its reducing 399 p.pool.status = types.AMMPoolStatusReduceOnly 400 401 // and it is long one 402 position := int64(1) 403 ensurePositionN(t, p.pos, position, num.UintZero(), 2) 404 405 // now pretend we are in auction and we have a sell order at 1000, so we need to expand the crossed 406 // region of 1000 -> 1383 407 from := num.NewUint(1000) 408 to := num.NewUint(2000) 409 r := p.pool.OrderbookShape(from, to, nil) 410 411 // should have one sell of volume 1 412 assert.Equal(t, 0, len(r.Buys)) 413 assert.Equal(t, 1, len(r.Sells)) 414 assert.Equal(t, 1, int(r.Sells[0].Size)) 415 assert.Equal(t, "14", r.Sells[0].OriginalPrice.String()) 416 417 // and it is short one 418 position = int64(-1) 419 ensurePositionN(t, p.pos, position, num.UintZero(), 2) 420 421 r = p.pool.OrderbookShape(from, to, nil) 422 423 // should have one sell of volume 1 424 assert.Equal(t, 1, len(r.Buys)) 425 assert.Equal(t, 0, len(r.Sells)) 426 assert.Equal(t, 1, int(r.Buys[0].Size)) 427 assert.Equal(t, "16", r.Buys[0].OriginalPrice.String()) 428 429 // no position 430 position = int64(0) 431 ensurePositionN(t, p.pos, position, num.UintZero(), 2) 432 433 r = p.pool.OrderbookShape(from, to, nil) 434 435 // should have one sell of volume 1 436 assert.Equal(t, 0, len(r.Buys)) 437 assert.Equal(t, 0, len(r.Sells)) 438 } 439 440 func testPointExpansionAtFairPrice(t *testing.T) { 441 p := newTestPoolWithRanges(t, num.NewUint(7), num.NewUint(10), num.NewUint(13)) 442 defer p.ctrl.Finish() 443 444 base := p.submission.Parameters.Base 445 446 // range [10, 10] fair price is 10, no orders 447 ensurePositionN(t, p.pos, 0, num.UintZero(), 2) 448 r := p.pool.OrderbookShape(base, base, nil) 449 assert.Equal(t, 0, len(r.Buys)) 450 assert.Equal(t, 0, len(r.Sells)) 451 452 // now try with a one sided curve where the input range shrinks to a point-expansion 453 p = newTestPoolWithRanges(t, num.NewUint(7), num.NewUint(10), nil) 454 defer p.ctrl.Finish() 455 456 // range [10, 1000] but sell curve is empty so effective range is [10, 10] at fair-price 457 ensurePositionN(t, p.pos, 0, num.UintZero(), 2) 458 r = p.pool.OrderbookShape(base, num.NewUint(1000), nil) 459 assert.Equal(t, 0, len(r.Buys)) 460 assert.Equal(t, 0, len(r.Sells)) 461 462 // now try with a one sided curve where the input range shrinks to a point-expansion 463 p = newTestPoolWithRanges(t, nil, num.NewUint(10), num.NewUint(13)) 464 defer p.ctrl.Finish() 465 466 // range [1, 10] but buy curve is empty so effective range is [10, 10] at fair-price 467 ensurePositionN(t, p.pos, 0, num.UintZero(), 2) 468 r = p.pool.OrderbookShape(num.NewUint(1), base, nil) 469 assert.Equal(t, 0, len(r.Buys)) 470 assert.Equal(t, 0, len(r.Sells)) 471 } 472 473 func TestOrderbookShapeSparseAMM(t *testing.T) { 474 p := newTestPoolWithOpts(t, num.DecimalOne(), num.NewUint(99), num.NewUint(198), num.NewUint(297), num.NewUint(1000), 100) 475 476 defer p.ctrl.Finish() 477 478 low := p.submission.Parameters.LowerBound 479 base := p.submission.Parameters.Base 480 high := p.submission.Parameters.UpperBound 481 482 // when range [99, 198] expect orders at ticks of 9 from 99 -> 189 483 // there will be no order at price 200 since that is the pools fair-price and it quotes +/-1 eitherside 484 ensurePositionN(t, p.pos, 0, num.UintZero(), 2) 485 r := p.pool.OrderbookShape(low, base, nil) 486 assert.Equal(t, 14, len(r.Buys)) 487 assert.Equal(t, 0, len(r.Sells)) 488 489 // check boundary orders 490 assert.Equal(t, "99", r.Buys[0].Price.String()) 491 assert.Equal(t, "191", r.Buys[(len(r.Buys)-1)].Price.String()) 492 493 // when range [99, 191] expect orders at prices 100 -> 191 494 ensurePositionN(t, p.pos, 0, num.UintZero(), 2) 495 r = p.pool.OrderbookShape(low, num.NewUint(189), nil) 496 assert.Equal(t, 14, len(r.Buys)) 497 assert.Equal(t, 0, len(r.Sells)) 498 499 // check boundary orders 500 assert.Equal(t, "99", r.Buys[0].Price.String()) 501 assert.Equal(t, "189", r.Buys[(len(r.Buys)-1)].Price.String()) 502 503 // when range [198, 297] expect orders at prices 207 -> 297 504 // there will be no order at price 198 since that is the pools fair-price and it quotes +/-1 eitherside 505 ensurePositionN(t, p.pos, 0, num.UintZero(), 2) 506 r = p.pool.OrderbookShape(base, high, nil) 507 assert.Equal(t, 0, len(r.Buys)) 508 assert.Equal(t, 12, len(r.Sells)) 509 510 // check boundary orders 511 assert.Equal(t, "203", r.Sells[0].Price.String()) 512 assert.Equal(t, "297", r.Sells[(len(r.Sells)-1)].Price.String()) 513 514 // when range [207, 297] expect orders at prices 207 -> 297 515 ensurePositionN(t, p.pos, 0, num.UintZero(), 2) 516 r = p.pool.OrderbookShape(num.NewUint(207), high, nil) 517 assert.Equal(t, 0, len(r.Buys)) 518 assert.Equal(t, 11, len(r.Sells)) 519 520 // check boundary orders 521 assert.Equal(t, "207", r.Sells[0].Price.String()) 522 assert.Equal(t, "297", r.Sells[(len(r.Sells)-1)].Price.String()) 523 524 // range (8, 8) should return a single buy order at price 8, which is a bit counter intuitive 525 ensurePositionN(t, p.pos, 0, num.UintZero(), 2) 526 r = p.pool.OrderbookShape(num.NewUint(117), num.NewUint(117), nil) 527 assertOrderPrices(t, r.Buys, types.SideBuy, 117, 117) 528 assert.Equal(t, 0, len(r.Sells)) 529 530 // range (10, 10) should return only the orders at the fair-price, which is 0 orders 531 ensurePositionN(t, p.pos, 0, num.UintZero(), 2) 532 r = p.pool.OrderbookShape(num.NewUint(198), num.NewUint(198), nil) 533 assert.Equal(t, 0, len(r.Buys)) 534 assert.Equal(t, 0, len(r.Sells)) 535 } 536 537 func TestOrderbookShapeSparseAMMBoundaryOrders(t *testing.T) { 538 submit := &types.SubmitAMM{ 539 AMMBaseCommand: types.AMMBaseCommand{ 540 Party: vgcrypto.RandomHash(), 541 MarketID: vgcrypto.RandomHash(), 542 SlippageTolerance: num.DecimalFromFloat(0.1), 543 }, 544 CommitmentAmount: num.MustUintFromString("5960289358452040000000", 10), 545 Parameters: &types.ConcentratedLiquidityParameters{ 546 Base: num.NewUint(195836), 547 LowerBound: num.NewUint(92079), 548 UpperBound: num.NewUint(246109), 549 LeverageAtLowerBound: ptr.From(num.DecimalFromFloat(95.13295934001242)), 550 LeverageAtUpperBound: ptr.From(num.DecimalFromFloat(86.1204552842962)), 551 }, 552 } 553 p := newTestPoolWithSubmission(t, num.DecimalFromInt64(1000), num.DecimalFromFloat(10000000000000000), submit, 100) 554 defer p.ctrl.Finish() 555 556 ensurePositionN(t, p.pos, 0, nil, -1) 557 r := p.pool.OrderbookShape( 558 num.MustUintFromString("1958381716019393098944", 10), 559 num.MustUintFromString("4897350000000000000000", 10), 560 nil, 561 ) 562 assert.Equal(t, 0, len(r.Buys)) 563 require.Equal(t, "1958381716019393098944", r.Sells[0].Price.String()) 564 require.Equal(t, "2461090000000000000000", r.Sells[len(r.Sells)-1].Price.String()) 565 }