Skip to content

Commit dfeff78

Browse files
committed
feat: recalculate LP position values using current prices in pool stats
1 parent 6c61b4a commit dfeff78

File tree

7 files changed

+170
-8
lines changed

7 files changed

+170
-8
lines changed

config.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,3 +343,4 @@ networks:
343343
- event: Swap(address indexed sender, address indexed recipient, int256 amount0, int256 amount1, uint160 sqrtPriceX96, uint128 liquidity, int24 tick)
344344
- event: Mint(address sender, address indexed owner, int24 indexed tickLower, int24 indexed tickUpper, uint128 amount, uint256 amount0, uint256 amount1)
345345
- event: Burn(address indexed owner, int24 indexed tickLower, int24 indexed tickUpper, uint128 amount, uint256 amount0, uint256 amount1)
346+
- event: SetFeeProtocol(uint8 feeProtocol0Old, uint8 feeProtocol1Old, uint8 feeProtocol0New, uint8 feeProtocol1New)

schema.graphql

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1520,6 +1520,8 @@ type LPPoolState {
15201520
sqrtPriceX96: BigInt!
15211521
token0Price: BigInt!
15221522
token1Price: BigInt!
1523+
feeProtocol0: Int!
1524+
feeProtocol1: Int!
15231525
lastUpdate: Int!
15241526
}
15251527

src/__tests__/lp-coverage.test.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,8 @@ test('lp chain sync creates positions and updates indices/prices', async () => {
363363
sqrtPriceX96: 2n ** 96n,
364364
token0Price: 7n,
365365
token1Price: 11n,
366+
feeProtocol0: 0,
367+
feeProtocol1: 0,
366368
lastUpdate: 0,
367369
});
368370
stores.TokenInfo.set({
@@ -442,6 +444,8 @@ test('lp chain sync uses token1 ausd pricing', async () => {
442444
sqrtPriceX96: 2n ** 96n,
443445
token0Price: 9n,
444446
token1Price: 9n,
447+
feeProtocol0: 0,
448+
feeProtocol1: 0,
445449
lastUpdate: 0,
446450
});
447451
stores.TokenInfo.set({
@@ -516,6 +520,8 @@ test('lp chain sync uses token1 ausd pricing with higher token0 decimals', async
516520
sqrtPriceX96: 2n ** 96n,
517521
token0Price: 9n,
518522
token1Price: 9n,
523+
feeProtocol0: 0,
524+
feeProtocol1: 0,
519525
lastUpdate: 0,
520526
});
521527
stores.TokenInfo.set({
@@ -594,6 +600,8 @@ test('lp chain sync updates existing position indices', async () => {
594600
sqrtPriceX96: 2n ** 96n,
595601
token0Price: 1n,
596602
token1Price: 1n,
603+
feeProtocol0: 0,
604+
feeProtocol1: 0,
597605
lastUpdate: 0,
598606
});
599607
stores.UserLPPosition.set({
@@ -667,6 +675,8 @@ test('settleUserLPPositions settles points and skips empty', async () => {
667675
sqrtPriceX96: 2n ** 96n,
668676
token0Price: 100000000n,
669677
token1Price: 100000000n,
678+
feeProtocol0: 0,
679+
feeProtocol1: 0,
670680
lastUpdate: 0,
671681
});
672682
stores.TokenInfo.set({
@@ -765,6 +775,8 @@ test('settleUserLPPositions handles missing epoch', async () => {
765775
sqrtPriceX96: 2n ** 96n,
766776
token0Price: 100000000n,
767777
token1Price: 100000000n,
778+
feeProtocol0: 0,
779+
feeProtocol1: 0,
768780
lastUpdate: 0,
769781
});
770782
stores.UserLPPosition.set({
@@ -817,6 +829,8 @@ test('settleLPPoolPositions handles empty and active pools', async () => {
817829
sqrtPriceX96: 2n ** 96n,
818830
token0Price: 100000000n,
819831
token1Price: 100000000n,
832+
feeProtocol0: 0,
833+
feeProtocol1: 0,
820834
lastUpdate: 0,
821835
});
822836
stores.TokenInfo.set({
@@ -902,6 +916,8 @@ test('swap fee stats handle missing stores and windowed volume', async () => {
902916
sqrtPriceX96: 2n ** 96n,
903917
token0Price: 100000000n,
904918
token1Price: 100000000n,
919+
feeProtocol0: 0,
920+
feeProtocol1: 0,
905921
lastUpdate: 0,
906922
});
907923
stores.TokenInfo.set({
@@ -1306,6 +1322,8 @@ test('settleUserLPPositions uses single active pool config fallback', async () =
13061322
sqrtPriceX96: 2n ** 96n,
13071323
token0Price: 100000000n,
13081324
token1Price: 100000000n,
1325+
feeProtocol0: 0,
1326+
feeProtocol1: 0,
13091327
lastUpdate: 0,
13101328
});
13111329

src/__tests__/lp-events.test.ts

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,8 @@ test('increase liquidity before transfer uses cached mint amounts', async () =>
129129
sqrtPriceX96: 0n,
130130
token0Price: PRICE_E8,
131131
token1Price: PRICE_E8,
132+
feeProtocol0: 0,
133+
feeProtocol1: 0,
132134
lastUpdate: 0,
133135
});
134136
mockDb = mockDb.entities.TokenInfo.set({
@@ -239,6 +241,8 @@ test('increase liquidity uses pool mint data when eth_call is unavailable', asyn
239241
sqrtPriceX96: 0n,
240242
token0Price: PRICE_E8,
241243
token1Price: PRICE_E8,
244+
feeProtocol0: 0,
245+
feeProtocol1: 0,
242246
lastUpdate: 0,
243247
});
244248
mockDb = mockDb.entities.TokenInfo.set({
@@ -398,6 +402,8 @@ test('swap accrues lp points when position stays in range', async () => {
398402
sqrtPriceX96: 0n,
399403
token0Price: PRICE_E8,
400404
token1Price: PRICE_E8,
405+
feeProtocol0: 0,
406+
feeProtocol1: 0,
401407
lastUpdate: 0,
402408
});
403409
mockDb = mockDb.entities.TokenInfo.set({
@@ -515,6 +521,8 @@ test('swap updates fee apr stats', async () => {
515521
sqrtPriceX96: 0n,
516522
token0Price: PRICE_E8,
517523
token1Price: PRICE_E8,
524+
feeProtocol0: 0,
525+
feeProtocol1: 0,
518526
lastUpdate: 0,
519527
});
520528
mockDb = mockDb.entities.TokenInfo.set({
@@ -552,9 +560,10 @@ test('swap updates fee apr stats', async () => {
552560

553561
const feeStats = mockDb.entities.LPPoolFeeStats.get(ADDRESSES.pool);
554562
assert.ok(feeStats);
555-
assert.equal(feeStats?.volumeUsd24h, 200000000n);
556-
assert.equal(feeStats?.feesUsd24h, 2000000n);
557-
assert.equal(feeStats?.feeAprBps, 73n);
563+
// Volume is average: amount0=1M, amount1=2M at same price → (100000000 + 200000000) / 2 = 150000000
564+
assert.equal(feeStats?.volumeUsd24h, 150000000n);
565+
assert.equal(feeStats?.feesUsd24h, 1500000n);
566+
assert.equal(feeStats?.feeAprBps, 54n);
558567
});
559568

560569
test('increase/decrease liquidity update existing position', async () => {
@@ -601,6 +610,8 @@ test('increase/decrease liquidity update existing position', async () => {
601610
sqrtPriceX96: 2n ** 96n,
602611
token0Price: PRICE_E8,
603612
token1Price: PRICE_E8,
613+
feeProtocol0: 0,
614+
feeProtocol1: 0,
604615
lastUpdate: 0,
605616
});
606617
mockDb = mockDb.entities.TokenInfo.set({
@@ -828,6 +839,8 @@ test('swap handles ausd pricing and empty positions', async () => {
828839
sqrtPriceX96: 2n ** 96n,
829840
token0Price: 0n,
830841
token1Price: 0n,
842+
feeProtocol0: 0,
843+
feeProtocol1: 0,
831844
lastUpdate: 0,
832845
});
833846
mockDb = mockDb.entities.TokenInfo.set({
@@ -903,6 +916,8 @@ test('swap handles out-of-range positions', async () => {
903916
sqrtPriceX96: 2n ** 96n,
904917
token0Price: PRICE_E8,
905918
token1Price: PRICE_E8,
919+
feeProtocol0: 0,
920+
feeProtocol1: 0,
906921
lastUpdate: 0,
907922
});
908923
mockDb = mockDb.entities.TokenInfo.set({
@@ -1097,6 +1112,8 @@ test('increase liquidity updates in-range transitions', async () => {
10971112
sqrtPriceX96: 2n ** 96n,
10981113
token0Price: PRICE_E8,
10991114
token1Price: PRICE_E8,
1115+
feeProtocol0: 0,
1116+
feeProtocol1: 0,
11001117
lastUpdate: 0,
11011118
});
11021119
mockDb = mockDb.entities.TokenInfo.set({
@@ -1157,6 +1174,8 @@ test('increase liquidity updates in-range transitions', async () => {
11571174
sqrtPriceX96: 2n ** 96n,
11581175
token0Price: PRICE_E8,
11591176
token1Price: PRICE_E8,
1177+
feeProtocol0: 0,
1178+
feeProtocol1: 0,
11601179
lastUpdate: 0,
11611180
});
11621181
const exit = TestHelpers.NonfungiblePositionManager.IncreaseLiquidity.createMockEvent({
@@ -1218,6 +1237,8 @@ test('decrease liquidity updates in-range transitions', async () => {
12181237
sqrtPriceX96: 2n ** 96n,
12191238
token0Price: PRICE_E8,
12201239
token1Price: PRICE_E8,
1240+
feeProtocol0: 0,
1241+
feeProtocol1: 0,
12211242
lastUpdate: 0,
12221243
});
12231244
mockDb = mockDb.entities.TokenInfo.set({
@@ -1278,6 +1299,8 @@ test('decrease liquidity updates in-range transitions', async () => {
12781299
sqrtPriceX96: 2n ** 96n,
12791300
token0Price: PRICE_E8,
12801301
token1Price: PRICE_E8,
1302+
feeProtocol0: 0,
1303+
feeProtocol1: 0,
12811304
lastUpdate: 0,
12821305
});
12831306
const exit = TestHelpers.NonfungiblePositionManager.DecreaseLiquidity.createMockEvent({
@@ -1329,6 +1352,8 @@ test('transfer mint uses ausd pricing for token0', async () => {
13291352
sqrtPriceX96: 2n ** 96n,
13301353
token0Price: PRICE_E8,
13311354
token1Price: 0n,
1355+
feeProtocol0: 0,
1356+
feeProtocol1: 0,
13321357
lastUpdate: 0,
13331358
});
13341359
mockDb = mockDb.entities.TokenInfo.set({
@@ -1444,6 +1469,8 @@ test('transfer mint selects matching pool config when multiple fees exist', asyn
14441469
sqrtPriceX96: 0n,
14451470
token0Price: PRICE_E8,
14461471
token1Price: PRICE_E8,
1472+
feeProtocol0: 0,
1473+
feeProtocol1: 0,
14471474
lastUpdate: 0,
14481475
});
14491476
mockDb = mockDb.entities.TokenInfo.set({
@@ -1520,6 +1547,8 @@ test('swap leaves out-of-range positions untouched', async () => {
15201547
sqrtPriceX96: 2n ** 96n,
15211548
token0Price: PRICE_E8,
15221549
token1Price: PRICE_E8,
1550+
feeProtocol0: 0,
1551+
feeProtocol1: 0,
15231552
lastUpdate: 0,
15241553
});
15251554
mockDb = mockDb.entities.TokenInfo.set({

src/__tests__/shared-external.test.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,8 @@ test('settlements sync LP positions from chain when enabled', async () => {
396396
sqrtPriceX96: LP_SQRT_PRICE_X96,
397397
token0Price: LP_PRICE_E8,
398398
token1Price: LP_PRICE_E8,
399+
feeProtocol0: 0,
400+
feeProtocol1: 0,
399401
lastUpdate: 0,
400402
});
401403
tokenInfo.set({

src/handlers/leaderboard.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -670,6 +670,8 @@ LeaderboardConfigContract.LPPoolConfigured.handler(async ({ event, context }) =>
670670
sqrtPriceX96: 0n,
671671
token0Price: 0n,
672672
token1Price: 0n,
673+
feeProtocol0: 0,
674+
feeProtocol1: 0,
673675
lastUpdate: timestamp,
674676
});
675677

0 commit comments

Comments
 (0)