@the-situation/indexer 0.9.1 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/app.d.ts +4 -0
- package/dist/api/app.d.ts.map +1 -1
- package/dist/api/app.js +3 -3
- package/dist/api/app.js.map +1 -1
- package/dist/api/middleware/admin-auth.d.ts.map +1 -1
- package/dist/api/middleware/admin-auth.js +11 -3
- package/dist/api/middleware/admin-auth.js.map +1 -1
- package/dist/api/middleware/error-handler.d.ts.map +1 -1
- package/dist/api/middleware/error-handler.js +2 -2
- package/dist/api/middleware/error-handler.js.map +1 -1
- package/dist/api/routes/admin.d.ts +2 -0
- package/dist/api/routes/admin.d.ts.map +1 -1
- package/dist/api/routes/admin.js +29 -5
- package/dist/api/routes/admin.js.map +1 -1
- package/dist/api/routes/health.d.ts +3 -2
- package/dist/api/routes/health.d.ts.map +1 -1
- package/dist/api/routes/health.js +11 -4
- package/dist/api/routes/health.js.map +1 -1
- package/dist/api/routes/index.d.ts +3 -3
- package/dist/api/routes/index.d.ts.map +1 -1
- package/dist/api/routes/index.js +3 -3
- package/dist/api/routes/index.js.map +1 -1
- package/dist/api/routes/market-events.d.ts.map +1 -1
- package/dist/api/routes/market-events.js +14 -8
- package/dist/api/routes/market-events.js.map +1 -1
- package/dist/api/routes/market-traders.d.ts.map +1 -1
- package/dist/api/routes/market-traders.js +1 -1
- package/dist/api/routes/market-traders.js.map +1 -1
- package/dist/api/routes/markets.d.ts.map +1 -1
- package/dist/api/routes/markets.js +83 -5
- package/dist/api/routes/markets.js.map +1 -1
- package/dist/api/routes/rankings.d.ts.map +1 -1
- package/dist/api/routes/rankings.js +2 -1
- package/dist/api/routes/rankings.js.map +1 -1
- package/dist/api/routes/trader-events.d.ts +1 -1
- package/dist/api/routes/trader-events.d.ts.map +1 -1
- package/dist/api/routes/trader-events.js +11 -6
- package/dist/api/routes/trader-events.js.map +1 -1
- package/dist/api/routes/ws.d.ts.map +1 -1
- package/dist/api/routes/ws.js +4 -3
- package/dist/api/routes/ws.js.map +1 -1
- package/dist/client/IndexerClient.d.ts +10 -1
- package/dist/client/IndexerClient.d.ts.map +1 -1
- package/dist/client/IndexerClient.js.map +1 -1
- package/dist/client/IndexerClientLive.d.ts +1 -0
- package/dist/client/IndexerClientLive.d.ts.map +1 -1
- package/dist/client/IndexerClientLive.js +54 -8
- package/dist/client/IndexerClientLive.js.map +1 -1
- package/dist/client/convenience.d.ts +11 -2
- package/dist/client/convenience.d.ts.map +1 -1
- package/dist/client/convenience.js +4 -0
- package/dist/client/convenience.js.map +1 -1
- package/dist/client/index.d.ts +6 -5
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +4 -4
- package/dist/client/index.js.map +1 -1
- package/dist/client/trader-stats.d.ts +2 -2
- package/dist/client/trader-stats.d.ts.map +1 -1
- package/dist/client/trader-stats.js +1 -1
- package/dist/client/trader-stats.js.map +1 -1
- package/dist/config.d.ts +3 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +19 -6
- package/dist/config.js.map +1 -1
- package/dist/db/connection.d.ts.map +1 -1
- package/dist/db/connection.js +4 -1
- package/dist/db/connection.js.map +1 -1
- package/dist/db/repositories/event.d.ts +1 -1
- package/dist/db/repositories/event.d.ts.map +1 -1
- package/dist/db/repositories/event.js +11 -9
- package/dist/db/repositories/event.js.map +1 -1
- package/dist/db/repositories/index.d.ts +3 -2
- package/dist/db/repositories/index.d.ts.map +1 -1
- package/dist/db/repositories/index.js +3 -2
- package/dist/db/repositories/index.js.map +1 -1
- package/dist/db/repositories/market-state.d.ts +1 -0
- package/dist/db/repositories/market-state.d.ts.map +1 -1
- package/dist/db/repositories/market-state.js +8 -0
- package/dist/db/repositories/market-state.js.map +1 -1
- package/dist/db/repositories/market.d.ts +1 -1
- package/dist/db/repositories/market.d.ts.map +1 -1
- package/dist/db/repositories/market.js +39 -17
- package/dist/db/repositories/market.js.map +1 -1
- package/dist/db/repositories/multinoulli-market-state.d.ts +30 -0
- package/dist/db/repositories/multinoulli-market-state.d.ts.map +1 -0
- package/dist/db/repositories/multinoulli-market-state.js +48 -0
- package/dist/db/repositories/multinoulli-market-state.js.map +1 -0
- package/dist/db/repositories/position.d.ts +2 -1
- package/dist/db/repositories/position.d.ts.map +1 -1
- package/dist/db/repositories/position.js +14 -3
- package/dist/db/repositories/position.js.map +1 -1
- package/dist/db/schema.d.ts.map +1 -1
- package/dist/db/schema.js +68 -1
- package/dist/db/schema.js.map +1 -1
- package/dist/etl/decoder.d.ts +4 -3
- package/dist/etl/decoder.d.ts.map +1 -1
- package/dist/etl/decoder.js +149 -31
- package/dist/etl/decoder.js.map +1 -1
- package/dist/etl/event-indexer.d.ts +3 -2
- package/dist/etl/event-indexer.d.ts.map +1 -1
- package/dist/etl/event-indexer.js +140 -37
- package/dist/etl/event-indexer.js.map +1 -1
- package/dist/etl/position-refresher.d.ts +4 -3
- package/dist/etl/position-refresher.d.ts.map +1 -1
- package/dist/etl/position-refresher.js +54 -8
- package/dist/etl/position-refresher.js.map +1 -1
- package/dist/etl/scheduler.d.ts +2 -2
- package/dist/etl/scheduler.d.ts.map +1 -1
- package/dist/etl/scheduler.js +19 -23
- package/dist/etl/scheduler.js.map +1 -1
- package/dist/etl/state-refresher.d.ts +4 -3
- package/dist/etl/state-refresher.d.ts.map +1 -1
- package/dist/etl/state-refresher.js +39 -9
- package/dist/etl/state-refresher.js.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +129 -31
- package/dist/index.js.map +1 -1
- package/dist/layers/ChainReaderLive.d.ts.map +1 -1
- package/dist/layers/ChainReaderLive.js +96 -6
- package/dist/layers/ChainReaderLive.js.map +1 -1
- package/dist/layers/DatabaseLive.d.ts +1 -1
- package/dist/layers/DatabaseLive.d.ts.map +1 -1
- package/dist/layers/DatabaseLive.js +2 -1
- package/dist/layers/DatabaseLive.js.map +1 -1
- package/dist/layers/EventBusLive.d.ts.map +1 -1
- package/dist/layers/EventBusLive.js +2 -2
- package/dist/layers/EventBusLive.js.map +1 -1
- package/dist/layers/VoyagerClientLive.d.ts +3 -2
- package/dist/layers/VoyagerClientLive.d.ts.map +1 -1
- package/dist/layers/VoyagerClientLive.js +29 -10
- package/dist/layers/VoyagerClientLive.js.map +1 -1
- package/dist/layers/index.d.ts +2 -2
- package/dist/layers/index.d.ts.map +1 -1
- package/dist/layers/index.js +2 -2
- package/dist/layers/index.js.map +1 -1
- package/dist/services/ChainReader.d.ts +3 -0
- package/dist/services/ChainReader.d.ts.map +1 -1
- package/dist/services/ChainReader.js.map +1 -1
- package/dist/services/Database.d.ts +3 -2
- package/dist/services/Database.d.ts.map +1 -1
- package/dist/services/Database.js.map +1 -1
- package/dist/services/EventBus.d.ts.map +1 -1
- package/dist/services/EventBus.js.map +1 -1
- package/dist/services/VoyagerRateLimit.d.ts +40 -0
- package/dist/services/VoyagerRateLimit.d.ts.map +1 -0
- package/dist/services/VoyagerRateLimit.js +91 -0
- package/dist/services/VoyagerRateLimit.js.map +1 -0
- package/dist/services/index.d.ts +4 -4
- package/dist/services/index.d.ts.map +1 -1
- package/dist/services/index.js +2 -2
- package/dist/services/index.js.map +1 -1
- package/dist/types/api.d.ts +48 -1
- package/dist/types/api.d.ts.map +1 -1
- package/dist/types/event.d.ts +43 -2
- package/dist/types/event.d.ts.map +1 -1
- package/dist/types/index.d.ts +4 -4
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/market.d.ts +64 -0
- package/dist/types/market.d.ts.map +1 -1
- package/dist/types/position.d.ts +8 -0
- package/dist/types/position.d.ts.map +1 -1
- package/package.json +6 -6
|
@@ -2,16 +2,46 @@
|
|
|
2
2
|
* Position refresher — reads trader positions from chain.
|
|
3
3
|
*/
|
|
4
4
|
import { Effect } from 'effect';
|
|
5
|
-
import { DatabaseTag } from '../services/Database';
|
|
6
5
|
import { ChainReaderTag } from '../services/ChainReader';
|
|
6
|
+
import { DatabaseTag } from '../services/Database';
|
|
7
7
|
import { EventBusTag } from '../services/EventBus';
|
|
8
|
-
export const refreshPosition = (marketAddress, trader) => Effect.gen(function* () {
|
|
8
|
+
export const refreshPosition = (marketAddress, trader, marketType = 'normal') => Effect.gen(function* () {
|
|
9
9
|
const db = yield* DatabaseTag;
|
|
10
10
|
const chain = yield* ChainReaderTag;
|
|
11
11
|
const bus = yield* EventBusTag;
|
|
12
|
+
if (marketType === 'multinoulli') {
|
|
13
|
+
const posResult = yield* Effect.either(chain.readMultinoulliPosition(marketAddress, trader));
|
|
14
|
+
if (posResult._tag === 'Left') {
|
|
15
|
+
return {
|
|
16
|
+
marketAddress,
|
|
17
|
+
trader,
|
|
18
|
+
success: false,
|
|
19
|
+
error: posResult.left.message,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
const pos = posResult.right;
|
|
23
|
+
db.positions.upsert({
|
|
24
|
+
market_address: marketAddress,
|
|
25
|
+
trader,
|
|
26
|
+
has_position: pos.exists,
|
|
27
|
+
collateral_locked: pos.totalCollateralLocked,
|
|
28
|
+
settlement_state: pos.settlementState,
|
|
29
|
+
claimed: pos.claimed,
|
|
30
|
+
position_type: 'multinoulli',
|
|
31
|
+
outcome_count: pos.outcomeCount,
|
|
32
|
+
original_probs_json: JSON.stringify(pos.originalProbs),
|
|
33
|
+
collateral_locked_raw: pos.totalCollateralLocked,
|
|
34
|
+
});
|
|
35
|
+
bus.broadcast({
|
|
36
|
+
type: 'position_update',
|
|
37
|
+
marketAddress,
|
|
38
|
+
data: { trader, ...pos },
|
|
39
|
+
});
|
|
40
|
+
return { marketAddress, trader, success: true };
|
|
41
|
+
}
|
|
42
|
+
// Normal market
|
|
12
43
|
const posResult = yield* Effect.either(chain.readPosition(marketAddress, trader));
|
|
13
44
|
if (posResult._tag === 'Left') {
|
|
14
|
-
console.error(`[PositionRefresher] Error for ${trader} in ${marketAddress}:`, posResult.left.message);
|
|
15
45
|
return {
|
|
16
46
|
marketAddress,
|
|
17
47
|
trader,
|
|
@@ -31,6 +61,7 @@ export const refreshPosition = (marketAddress, trader) => Effect.gen(function* (
|
|
|
31
61
|
settlement_state: pos.settlementState,
|
|
32
62
|
delta_count: pos.deltaCount,
|
|
33
63
|
claimed: pos.claimed,
|
|
64
|
+
position_type: 'normal',
|
|
34
65
|
});
|
|
35
66
|
bus.broadcast({
|
|
36
67
|
type: 'position_update',
|
|
@@ -39,14 +70,29 @@ export const refreshPosition = (marketAddress, trader) => Effect.gen(function* (
|
|
|
39
70
|
});
|
|
40
71
|
return { marketAddress, trader, success: true };
|
|
41
72
|
});
|
|
73
|
+
const RPC_CONCURRENCY = 5;
|
|
42
74
|
export const refreshAllPositions = Effect.gen(function* () {
|
|
43
75
|
const db = yield* DatabaseTag;
|
|
44
76
|
const allPositions = db.positions.findAll();
|
|
45
|
-
const
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
77
|
+
const markets = db.markets.findAll(true);
|
|
78
|
+
// Build market type lookup from active markets only
|
|
79
|
+
const marketTypeMap = new Map();
|
|
80
|
+
for (const m of markets) {
|
|
81
|
+
marketTypeMap.set(m.address, (m.market_type ?? 'normal'));
|
|
49
82
|
}
|
|
50
|
-
|
|
83
|
+
// Only refresh positions for markets that are still active in the indexer.
|
|
84
|
+
// Positions for deleted/inactive markets are skipped to avoid calling
|
|
85
|
+
// the wrong contract entrypoint (e.g. normal ABI on a multinoulli contract).
|
|
86
|
+
const activePositions = allPositions.filter((pos) => {
|
|
87
|
+
if (marketTypeMap.has(pos.market_address)) {
|
|
88
|
+
return true;
|
|
89
|
+
}
|
|
90
|
+
return false;
|
|
91
|
+
});
|
|
92
|
+
const effects = activePositions.map((pos) => {
|
|
93
|
+
const marketType = marketTypeMap.get(pos.market_address);
|
|
94
|
+
return refreshPosition(pos.market_address, pos.trader, marketType);
|
|
95
|
+
});
|
|
96
|
+
return yield* Effect.all(effects, { concurrency: RPC_CONCURRENCY });
|
|
51
97
|
});
|
|
52
98
|
//# sourceMappingURL=position-refresher.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"position-refresher.js","sourceRoot":"","sources":["../../src/etl/position-refresher.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"position-refresher.js","sourceRoot":"","sources":["../../src/etl/position-refresher.ts"],"names":[],"mappings":"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"}
|
package/dist/etl/scheduler.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { IndexerConfig } from '../config';
|
|
2
|
-
import type { DatabaseService } from '../services/Database';
|
|
3
|
-
import { type VoyagerClientService } from '../services/VoyagerClient';
|
|
4
2
|
import { type ChainReaderService } from '../services/ChainReader';
|
|
3
|
+
import type { DatabaseService } from '../services/Database';
|
|
5
4
|
import { type EventBusService } from '../services/EventBus';
|
|
5
|
+
import { type VoyagerClientService } from '../services/VoyagerClient';
|
|
6
6
|
export interface SchedulerHandles {
|
|
7
7
|
readonly stop: () => void;
|
|
8
8
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scheduler.d.ts","sourceRoot":"","sources":["../../src/etl/scheduler.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC/C,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"scheduler.d.ts","sourceRoot":"","sources":["../../src/etl/scheduler.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC/C,OAAO,EAAE,KAAK,kBAAkB,EAAkB,MAAM,yBAAyB,CAAC;AAClF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAE5D,OAAO,EAAE,KAAK,eAAe,EAAe,MAAM,sBAAsB,CAAC;AACzE,OAAO,EAAE,KAAK,oBAAoB,EAAoB,MAAM,2BAA2B,CAAC;AAKxF,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,IAAI,CAAC;CAC3B;AAiCD,wBAAgB,cAAc,CAC5B,MAAM,EAAE,aAAa,EACrB,QAAQ,EAAE;IACR,QAAQ,EAAE,eAAe,CAAC;IAC1B,aAAa,EAAE,oBAAoB,CAAC;IACpC,WAAW,EAAE,kBAAkB,CAAC;IAChC,QAAQ,EAAE,eAAe,CAAC;CAC3B,GACA,gBAAgB,CA0DlB"}
|
package/dist/etl/scheduler.js
CHANGED
|
@@ -5,13 +5,13 @@
|
|
|
5
5
|
* the previous one finishes, preventing concurrent retry storms.
|
|
6
6
|
*/
|
|
7
7
|
import { Effect, Layer } from 'effect';
|
|
8
|
-
import { DatabaseTag } from '../services/Database';
|
|
9
|
-
import { VoyagerClientTag } from '../services/VoyagerClient';
|
|
10
8
|
import { ChainReaderTag } from '../services/ChainReader';
|
|
9
|
+
import { DatabaseTag } from '../services/Database';
|
|
11
10
|
import { EventBusTag } from '../services/EventBus';
|
|
11
|
+
import { VoyagerClientTag } from '../services/VoyagerClient';
|
|
12
12
|
import { indexAllMarkets } from './event-indexer';
|
|
13
|
-
import { refreshAllMarketStates } from './state-refresher';
|
|
14
13
|
import { refreshAllPositions } from './position-refresher';
|
|
14
|
+
import { refreshAllMarketStates } from './state-refresher';
|
|
15
15
|
/**
|
|
16
16
|
* Start a non-overlapping loop: run `fn`, wait `intervalMs`, repeat.
|
|
17
17
|
* The next cycle only starts after the previous one completes.
|
|
@@ -21,19 +21,22 @@ function startNonOverlappingLoop(fn, intervalMs) {
|
|
|
21
21
|
let stopped = false;
|
|
22
22
|
let timer = null;
|
|
23
23
|
async function loop() {
|
|
24
|
-
if (stopped)
|
|
24
|
+
if (stopped) {
|
|
25
25
|
return;
|
|
26
|
+
}
|
|
26
27
|
await fn();
|
|
27
|
-
if (stopped)
|
|
28
|
+
if (stopped) {
|
|
28
29
|
return;
|
|
30
|
+
}
|
|
29
31
|
timer = setTimeout(loop, intervalMs);
|
|
30
32
|
}
|
|
31
33
|
// Start the first cycle after the initial delay
|
|
32
34
|
timer = setTimeout(loop, intervalMs);
|
|
33
35
|
return () => {
|
|
34
36
|
stopped = true;
|
|
35
|
-
if (timer !== null)
|
|
37
|
+
if (timer !== null) {
|
|
36
38
|
clearTimeout(timer);
|
|
39
|
+
}
|
|
37
40
|
};
|
|
38
41
|
}
|
|
39
42
|
export function startScheduler(config, services) {
|
|
@@ -44,44 +47,38 @@ export function startScheduler(config, services) {
|
|
|
44
47
|
const results = await run(indexAllMarkets);
|
|
45
48
|
const total = results.reduce((sum, r) => sum + r.newEvents, 0);
|
|
46
49
|
if (total > 0) {
|
|
47
|
-
|
|
50
|
+
// Event refresh completed and detected new events.
|
|
48
51
|
}
|
|
49
52
|
}
|
|
50
|
-
catch (
|
|
51
|
-
|
|
53
|
+
catch (_err) {
|
|
54
|
+
// Keep scheduler loop alive; downstream monitoring handles surfaced failures.
|
|
52
55
|
}
|
|
53
56
|
}, config.eventPollIntervalMs);
|
|
54
57
|
const cancelState = startNonOverlappingLoop(async () => {
|
|
55
58
|
try {
|
|
56
59
|
await run(refreshAllMarketStates);
|
|
57
60
|
}
|
|
58
|
-
catch (
|
|
59
|
-
|
|
61
|
+
catch (_err) {
|
|
62
|
+
// Keep scheduler loop alive; downstream monitoring handles surfaced failures.
|
|
60
63
|
}
|
|
61
64
|
}, config.statePollIntervalMs);
|
|
62
65
|
const cancelPositions = startNonOverlappingLoop(async () => {
|
|
63
66
|
try {
|
|
64
67
|
await run(refreshAllPositions);
|
|
65
68
|
}
|
|
66
|
-
catch (
|
|
67
|
-
|
|
69
|
+
catch (_err) {
|
|
70
|
+
// Keep scheduler loop alive; downstream monitoring handles surfaced failures.
|
|
68
71
|
}
|
|
69
72
|
}, config.positionPollIntervalMs);
|
|
70
73
|
// Run immediately on start
|
|
71
74
|
void (async () => {
|
|
72
75
|
try {
|
|
73
|
-
|
|
74
|
-
const results = await run(indexAllMarkets);
|
|
75
|
-
const total = results.reduce((sum, r) => sum + r.newEvents, 0);
|
|
76
|
-
console.log(`[Scheduler] Initial: ${total} events across ${results.length} markets`);
|
|
77
|
-
console.log('[Scheduler] Initial state refresh...');
|
|
76
|
+
await run(indexAllMarkets);
|
|
78
77
|
await run(refreshAllMarketStates);
|
|
79
|
-
console.log('[Scheduler] Initial position refresh...');
|
|
80
78
|
await run(refreshAllPositions);
|
|
81
|
-
console.log('[Scheduler] Initialization complete');
|
|
82
79
|
}
|
|
83
|
-
catch (
|
|
84
|
-
|
|
80
|
+
catch (_err) {
|
|
81
|
+
// Keep scheduler boot sequence non-fatal; loops continue independently.
|
|
85
82
|
}
|
|
86
83
|
})();
|
|
87
84
|
return {
|
|
@@ -89,7 +86,6 @@ export function startScheduler(config, services) {
|
|
|
89
86
|
cancelEvents();
|
|
90
87
|
cancelState();
|
|
91
88
|
cancelPositions();
|
|
92
|
-
console.log('[Scheduler] Stopped');
|
|
93
89
|
},
|
|
94
90
|
};
|
|
95
91
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scheduler.js","sourceRoot":"","sources":["../../src/etl/scheduler.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"scheduler.js","sourceRoot":"","sources":["../../src/etl/scheduler.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,10 +2,11 @@
|
|
|
2
2
|
* State refresher — periodic RPC reads for market state.
|
|
3
3
|
*/
|
|
4
4
|
import { Effect } from 'effect';
|
|
5
|
-
import { DatabaseTag } from '../services/Database';
|
|
6
5
|
import { ChainReaderTag } from '../services/ChainReader';
|
|
6
|
+
import { DatabaseTag } from '../services/Database';
|
|
7
7
|
import { EventBusTag } from '../services/EventBus';
|
|
8
|
+
import type { MarketType } from '../types';
|
|
8
9
|
import type { StateRefreshResult } from './types';
|
|
9
|
-
export declare const refreshMarketState: (marketAddress: string) => Effect.Effect<StateRefreshResult, never, DatabaseTag | ChainReaderTag | EventBusTag>;
|
|
10
|
-
export declare const refreshAllMarketStates: Effect.Effect<StateRefreshResult[], never, DatabaseTag |
|
|
10
|
+
export declare const refreshMarketState: (marketAddress: string, marketType?: MarketType) => Effect.Effect<StateRefreshResult, never, DatabaseTag | ChainReaderTag | EventBusTag>;
|
|
11
|
+
export declare const refreshAllMarketStates: Effect.Effect<StateRefreshResult[], never, DatabaseTag | EventBusTag | ChainReaderTag>;
|
|
11
12
|
//# sourceMappingURL=state-refresher.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"state-refresher.d.ts","sourceRoot":"","sources":["../../src/etl/state-refresher.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"state-refresher.d.ts","sourceRoot":"","sources":["../../src/etl/state-refresher.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACnD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAC3C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAElD,eAAO,MAAM,kBAAkB,GAC7B,eAAe,MAAM,EACrB,aAAY,UAAqB,KAChC,MAAM,CAAC,MAAM,CAAC,kBAAkB,EAAE,KAAK,EAAE,WAAW,GAAG,cAAc,GAAG,WAAW,CAwElF,CAAC;AAIL,eAAO,MAAM,sBAAsB,wFAUjC,CAAC"}
|
|
@@ -2,16 +2,46 @@
|
|
|
2
2
|
* State refresher — periodic RPC reads for market state.
|
|
3
3
|
*/
|
|
4
4
|
import { Effect } from 'effect';
|
|
5
|
-
import { DatabaseTag } from '../services/Database';
|
|
6
5
|
import { ChainReaderTag } from '../services/ChainReader';
|
|
6
|
+
import { DatabaseTag } from '../services/Database';
|
|
7
7
|
import { EventBusTag } from '../services/EventBus';
|
|
8
|
-
export const refreshMarketState = (marketAddress) => Effect.gen(function* () {
|
|
8
|
+
export const refreshMarketState = (marketAddress, marketType = 'normal') => Effect.gen(function* () {
|
|
9
9
|
const db = yield* DatabaseTag;
|
|
10
10
|
const chain = yield* ChainReaderTag;
|
|
11
11
|
const bus = yield* EventBusTag;
|
|
12
|
+
if (marketType === 'multinoulli') {
|
|
13
|
+
const stateResult = yield* Effect.either(chain.readMultinoulliMarketState(marketAddress));
|
|
14
|
+
if (stateResult._tag === 'Left') {
|
|
15
|
+
return { marketAddress, success: false, error: stateResult.left.message };
|
|
16
|
+
}
|
|
17
|
+
const state = stateResult.right;
|
|
18
|
+
db.multinoulliMarketState.upsert({
|
|
19
|
+
market_address: marketAddress,
|
|
20
|
+
outcome_count: state.outcomeCount,
|
|
21
|
+
probs_json: JSON.stringify(state.probs),
|
|
22
|
+
k: state.k,
|
|
23
|
+
effective_k: state.effectiveK,
|
|
24
|
+
total_shares: state.totalShares,
|
|
25
|
+
total_backing: state.totalBacking,
|
|
26
|
+
is_initialized: state.isInitialized,
|
|
27
|
+
is_paused: state.isPaused,
|
|
28
|
+
is_settled: state.isSettled,
|
|
29
|
+
settlement_outcomes_json: JSON.stringify(state.settlementOutcomes),
|
|
30
|
+
matrix_enabled: state.matrixEnabled,
|
|
31
|
+
matrix_rows: state.matrixRows,
|
|
32
|
+
matrix_cols: state.matrixCols,
|
|
33
|
+
matrix_enforce_full_row: state.matrixEnforceFullRow,
|
|
34
|
+
});
|
|
35
|
+
bus.broadcast({
|
|
36
|
+
type: 'state_update',
|
|
37
|
+
marketAddress,
|
|
38
|
+
data: state,
|
|
39
|
+
});
|
|
40
|
+
return { marketAddress, success: true };
|
|
41
|
+
}
|
|
42
|
+
// Normal market
|
|
12
43
|
const stateResult = yield* Effect.either(chain.readMarketState(marketAddress));
|
|
13
44
|
if (stateResult._tag === 'Left') {
|
|
14
|
-
console.error(`[StateRefresher] Error for ${marketAddress}:`, stateResult.left.message);
|
|
15
45
|
return { marketAddress, success: false, error: stateResult.left.message };
|
|
16
46
|
}
|
|
17
47
|
const state = stateResult.right;
|
|
@@ -37,14 +67,14 @@ export const refreshMarketState = (marketAddress) => Effect.gen(function* () {
|
|
|
37
67
|
});
|
|
38
68
|
return { marketAddress, success: true };
|
|
39
69
|
});
|
|
70
|
+
const RPC_CONCURRENCY = 5;
|
|
40
71
|
export const refreshAllMarketStates = Effect.gen(function* () {
|
|
41
72
|
const db = yield* DatabaseTag;
|
|
42
73
|
const markets = db.markets.findAll(true);
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
}
|
|
48
|
-
return results;
|
|
74
|
+
const effects = markets.map((market) => {
|
|
75
|
+
const marketType = (market.market_type ?? 'normal');
|
|
76
|
+
return refreshMarketState(market.address, marketType);
|
|
77
|
+
});
|
|
78
|
+
return yield* Effect.all(effects, { concurrency: RPC_CONCURRENCY });
|
|
49
79
|
});
|
|
50
80
|
//# sourceMappingURL=state-refresher.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"state-refresher.js","sourceRoot":"","sources":["../../src/etl/state-refresher.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"state-refresher.js","sourceRoot":"","sources":["../../src/etl/state-refresher.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG"}
|
package/dist/index.js
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Indexer entry point — boots DB, ETL scheduler, and Elysia server.
|
|
3
3
|
*/
|
|
4
|
+
import { AMM_ABI, MULTINOULLI_AMM_ABI } from '@the-situation/artifacts';
|
|
5
|
+
import { SQ128x128 } from '@the-situation/core';
|
|
6
|
+
import { AMMContract, createProvider, MultinoulliAMMContract } from '@the-situation/starknet';
|
|
7
|
+
import { Duration, Effect, Schedule } from 'effect';
|
|
8
|
+
import { createApp } from './api/app';
|
|
4
9
|
import { loadConfig } from './config';
|
|
5
10
|
import { createDatabase } from './db/connection';
|
|
11
|
+
import { CursorRepository, EventRepository, MarketRepository, MarketStateRepository, MultinoulliMarketStateRepository, PositionRepository, RankingRepository, } from './db/repositories';
|
|
6
12
|
import { initializeSchema } from './db/schema';
|
|
7
|
-
import { MarketRepository, EventRepository, MarketStateRepository, PositionRepository, CursorRepository, RankingRepository, } from './db/repositories';
|
|
8
|
-
import { VoyagerApiError, isRetryableVoyagerError } from './services/VoyagerClient';
|
|
9
|
-
import { ChainReadError } from './services/ChainReader';
|
|
10
13
|
import { startScheduler } from './etl/scheduler';
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import { AMMContract, createProvider } from '@the-situation/starknet';
|
|
14
|
+
import { ChainReadError } from './services/ChainReader';
|
|
15
|
+
import { isRetryableVoyagerError, VoyagerApiError } from './services/VoyagerClient';
|
|
16
|
+
import { VoyagerRateLimitState } from './services/VoyagerRateLimit';
|
|
15
17
|
const config = loadConfig();
|
|
16
|
-
// Database
|
|
17
|
-
console.log(`[Indexer] Opening database at ${config.dbPath}`);
|
|
18
18
|
const db = createDatabase(config.dbPath);
|
|
19
19
|
initializeSchema(db);
|
|
20
20
|
const databaseService = {
|
|
@@ -22,19 +22,25 @@ const databaseService = {
|
|
|
22
22
|
markets: new MarketRepository(db),
|
|
23
23
|
events: new EventRepository(db),
|
|
24
24
|
marketState: new MarketStateRepository(db),
|
|
25
|
+
multinoulliMarketState: new MultinoulliMarketStateRepository(db),
|
|
25
26
|
positions: new PositionRepository(db),
|
|
26
27
|
cursors: new CursorRepository(db),
|
|
27
28
|
rankings: new RankingRepository(db),
|
|
28
29
|
};
|
|
29
|
-
// Voyager
|
|
30
|
+
// ── Voyager rate-limit state (shared, observable) ───────────────────────────
|
|
31
|
+
const voyagerRateLimit = new VoyagerRateLimitState(config.voyagerMinRequestIntervalMs);
|
|
32
|
+
// ── Voyager client ──────────────────────────────────────────────────────────
|
|
30
33
|
const VOYAGER_BASE_URL = 'https://sepolia-api.voyager.online/beta';
|
|
31
|
-
const
|
|
32
|
-
const VOYAGER_BASE_DELAY_MS = 2000;
|
|
33
|
-
const voyagerRetrySchedule = Schedule.compose(Schedule.jittered(Schedule.exponential(Duration.millis(VOYAGER_BASE_DELAY_MS))), Schedule.recurs(VOYAGER_MAX_RETRIES));
|
|
34
|
+
const voyagerRetrySchedule = Schedule.compose(Schedule.jittered(Schedule.exponential(Duration.millis(config.voyagerBaseDelayMs))), Schedule.recurs(config.voyagerMaxRetries));
|
|
34
35
|
const voyagerClientService = {
|
|
35
36
|
fetchEvents: (contractAddress, page, pageSize) => {
|
|
36
37
|
const fetchOnce = Effect.tryPromise({
|
|
37
38
|
try: async () => {
|
|
39
|
+
if (voyagerRateLimit.isLimited()) {
|
|
40
|
+
const status = voyagerRateLimit.getStatus();
|
|
41
|
+
throw new VoyagerApiError(`Rate limited — ${status.message}`, 429);
|
|
42
|
+
}
|
|
43
|
+
await voyagerRateLimit.throttle();
|
|
38
44
|
const url = new URL(`${VOYAGER_BASE_URL}/events`);
|
|
39
45
|
url.searchParams.set('contract', contractAddress);
|
|
40
46
|
url.searchParams.set('p', page.toString());
|
|
@@ -50,37 +56,60 @@ const voyagerClientService = {
|
|
|
50
56
|
const retryAfterMs = retryAfter && Number.isFinite(Number(retryAfter)) && Number(retryAfter) > 0
|
|
51
57
|
? Number(retryAfter) * 1000
|
|
52
58
|
: undefined;
|
|
59
|
+
if (response.status === 429 || response.status === 503) {
|
|
60
|
+
voyagerRateLimit.recordRateLimit();
|
|
61
|
+
}
|
|
53
62
|
throw new VoyagerApiError(`Voyager API ${response.status}: ${response.statusText}`, response.status, retryAfterMs);
|
|
54
63
|
}
|
|
64
|
+
voyagerRateLimit.recordSuccess();
|
|
55
65
|
const data = (await response.json());
|
|
56
66
|
return { events: data.items, lastPage: data.lastPage };
|
|
57
67
|
},
|
|
58
68
|
catch: (e) => {
|
|
59
|
-
if (e instanceof VoyagerApiError)
|
|
69
|
+
if (e instanceof VoyagerApiError) {
|
|
60
70
|
return e;
|
|
71
|
+
}
|
|
61
72
|
return new VoyagerApiError(e instanceof Error ? e.message : 'Unknown Voyager API error');
|
|
62
73
|
},
|
|
63
74
|
});
|
|
64
75
|
return fetchOnce.pipe(Effect.retry({
|
|
65
76
|
schedule: voyagerRetrySchedule,
|
|
66
77
|
while: (error) => {
|
|
78
|
+
if (voyagerRateLimit.isLimited()) {
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
67
81
|
const shouldRetry = isRetryableVoyagerError(error);
|
|
68
82
|
if (shouldRetry) {
|
|
69
|
-
|
|
83
|
+
// Retry continues according to configured schedule.
|
|
70
84
|
}
|
|
71
85
|
return shouldRetry;
|
|
72
86
|
},
|
|
73
87
|
}));
|
|
74
88
|
},
|
|
75
89
|
};
|
|
76
|
-
// Chain reader
|
|
90
|
+
// ── Chain reader ────────────────────────────────────────────────────────────
|
|
77
91
|
const provider = createProvider({
|
|
78
92
|
name: 'custom',
|
|
79
93
|
chainId: 'SN_SEPOLIA',
|
|
80
94
|
rpcUrl: config.starknetRpcUrl,
|
|
81
95
|
});
|
|
96
|
+
const ammCache = new Map();
|
|
97
|
+
const multinoulliAmmCache = new Map();
|
|
82
98
|
function getAmm(address) {
|
|
83
|
-
|
|
99
|
+
let amm = ammCache.get(address);
|
|
100
|
+
if (!amm) {
|
|
101
|
+
amm = new AMMContract({ address, abi: AMM_ABI, provider });
|
|
102
|
+
ammCache.set(address, amm);
|
|
103
|
+
}
|
|
104
|
+
return amm;
|
|
105
|
+
}
|
|
106
|
+
function getMultinoulliAmm(address) {
|
|
107
|
+
let amm = multinoulliAmmCache.get(address);
|
|
108
|
+
if (!amm) {
|
|
109
|
+
amm = new MultinoulliAMMContract({ address, abi: MULTINOULLI_AMM_ABI, provider });
|
|
110
|
+
multinoulliAmmCache.set(address, amm);
|
|
111
|
+
}
|
|
112
|
+
return amm;
|
|
84
113
|
}
|
|
85
114
|
const chainReaderService = {
|
|
86
115
|
readMarketState: (marketAddress) => Effect.tryPromise({
|
|
@@ -130,7 +159,7 @@ const chainReaderService = {
|
|
|
130
159
|
amm.getPositionCompact(trader),
|
|
131
160
|
amm.getPositionSummary(trader),
|
|
132
161
|
]);
|
|
133
|
-
if (!position
|
|
162
|
+
if (!(position && extended)) {
|
|
134
163
|
return {
|
|
135
164
|
hasPosition: false,
|
|
136
165
|
collateralLocked: null,
|
|
@@ -148,15 +177,89 @@ const chainReaderService = {
|
|
|
148
177
|
mean: position.originalMean?.toNumber() ?? null,
|
|
149
178
|
sigma: position.originalSigma?.toNumber() ?? null,
|
|
150
179
|
variance: position.originalVariance?.toNumber() ?? null,
|
|
151
|
-
settlementState: extended.claimed
|
|
180
|
+
settlementState: extended.claimed
|
|
181
|
+
? 'claimed'
|
|
182
|
+
: extended.tracksSettlementClaim
|
|
183
|
+
? 'pending_claim'
|
|
184
|
+
: 'active',
|
|
152
185
|
deltaCount: 0,
|
|
153
186
|
claimed: extended.claimed,
|
|
154
187
|
};
|
|
155
188
|
},
|
|
156
189
|
catch: (e) => new ChainReadError(`Failed to read position: ${e instanceof Error ? e.message : 'Unknown'}`, e),
|
|
157
190
|
}),
|
|
191
|
+
readMultinoulliMarketState: (marketAddress) => Effect.tryPromise({
|
|
192
|
+
try: async () => {
|
|
193
|
+
const amm = getMultinoulliAmm(marketAddress);
|
|
194
|
+
const [distribution, status, params, lpInfo, settlements, matrix] = await Promise.all([
|
|
195
|
+
amm.getDistribution(),
|
|
196
|
+
amm.getMarketStatus(),
|
|
197
|
+
amm.getParams(),
|
|
198
|
+
amm.getLPInfo(),
|
|
199
|
+
amm.getSettlementOutcomes(),
|
|
200
|
+
amm.getMatrixConstraints(),
|
|
201
|
+
]);
|
|
202
|
+
const probs = distribution.probs.map((raw) => {
|
|
203
|
+
const parsed = SQ128x128.fromRaw(raw);
|
|
204
|
+
return parsed?.toNumber() ?? 0;
|
|
205
|
+
});
|
|
206
|
+
return {
|
|
207
|
+
outcomeCount: probs.length,
|
|
208
|
+
probs,
|
|
209
|
+
k: params?.k.toNumber() ?? null,
|
|
210
|
+
effectiveK: params?.backing.toNumber() ?? null,
|
|
211
|
+
totalShares: lpInfo?.totalShares.toRaw().limb0.toString() ?? null,
|
|
212
|
+
totalBacking: lpInfo?.totalBackingDeposited.toRaw().limb0.toString() ?? null,
|
|
213
|
+
isInitialized: status.isInitialized,
|
|
214
|
+
isPaused: status.isPaused,
|
|
215
|
+
isSettled: status.isSettled,
|
|
216
|
+
settlementOutcomes: settlements,
|
|
217
|
+
matrixEnabled: matrix.enabled,
|
|
218
|
+
matrixRows: matrix.rowCount,
|
|
219
|
+
matrixCols: matrix.colCount,
|
|
220
|
+
matrixEnforceFullRow: matrix.enforceFullRowAssignmentSettlement,
|
|
221
|
+
};
|
|
222
|
+
},
|
|
223
|
+
catch: (e) => new ChainReadError(`Failed to read multinoulli market state: ${e instanceof Error ? e.message : 'Unknown'}`, e),
|
|
224
|
+
}),
|
|
225
|
+
readMultinoulliPosition: (marketAddress, trader) => Effect.tryPromise({
|
|
226
|
+
try: async () => {
|
|
227
|
+
const amm = getMultinoulliAmm(marketAddress);
|
|
228
|
+
const [summary, compact] = await Promise.all([
|
|
229
|
+
amm.getPositionSummary(trader),
|
|
230
|
+
amm.getPositionCompact(trader),
|
|
231
|
+
]);
|
|
232
|
+
if (!(summary && compact)) {
|
|
233
|
+
return {
|
|
234
|
+
exists: false,
|
|
235
|
+
claimed: false,
|
|
236
|
+
totalCollateralLocked: null,
|
|
237
|
+
outcomeCount: 0,
|
|
238
|
+
originalProbs: [],
|
|
239
|
+
settlementState: 'never_traded',
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
const originalProbs = compact.originalDistribution.probs.map((raw) => {
|
|
243
|
+
const parsed = SQ128x128.fromRaw(raw);
|
|
244
|
+
return parsed?.toNumber() ?? 0;
|
|
245
|
+
});
|
|
246
|
+
return {
|
|
247
|
+
exists: summary.exists,
|
|
248
|
+
claimed: summary.claimed,
|
|
249
|
+
totalCollateralLocked: summary.totalCollateralLocked.toRaw().limb0.toString(),
|
|
250
|
+
outcomeCount: summary.outcomeCount,
|
|
251
|
+
originalProbs,
|
|
252
|
+
settlementState: summary.claimed
|
|
253
|
+
? 'claimed'
|
|
254
|
+
: summary.tracksSettlementClaim
|
|
255
|
+
? 'pending_claim'
|
|
256
|
+
: 'active',
|
|
257
|
+
};
|
|
258
|
+
},
|
|
259
|
+
catch: (e) => new ChainReadError(`Failed to read multinoulli position: ${e instanceof Error ? e.message : 'Unknown'}`, e),
|
|
260
|
+
}),
|
|
158
261
|
};
|
|
159
|
-
// Event bus
|
|
262
|
+
// ── Event bus ───────────────────────────────────────────────────────────────
|
|
160
263
|
const busHandlers = new Set();
|
|
161
264
|
const eventBusService = {
|
|
162
265
|
broadcast: (event) => {
|
|
@@ -164,8 +267,8 @@ const eventBusService = {
|
|
|
164
267
|
try {
|
|
165
268
|
handler(event);
|
|
166
269
|
}
|
|
167
|
-
catch (
|
|
168
|
-
|
|
270
|
+
catch (_err) {
|
|
271
|
+
busHandlers.delete(handler);
|
|
169
272
|
}
|
|
170
273
|
}
|
|
171
274
|
},
|
|
@@ -176,33 +279,28 @@ const eventBusService = {
|
|
|
176
279
|
};
|
|
177
280
|
},
|
|
178
281
|
};
|
|
179
|
-
// Start ETL scheduler
|
|
282
|
+
// ── Start ETL scheduler ────────────────────────────────────────────────────
|
|
180
283
|
const scheduler = startScheduler(config, {
|
|
181
284
|
database: databaseService,
|
|
182
285
|
voyagerClient: voyagerClientService,
|
|
183
286
|
chainReader: chainReaderService,
|
|
184
287
|
eventBus: eventBusService,
|
|
185
288
|
});
|
|
186
|
-
// Start Elysia server
|
|
289
|
+
// ── Start Elysia server ────────────────────────────────────────────────────
|
|
187
290
|
const app = createApp({
|
|
188
291
|
db: databaseService,
|
|
189
292
|
eventBus: eventBusService,
|
|
190
293
|
adminApiKey: config.adminApiKey,
|
|
294
|
+
rateLimit: voyagerRateLimit,
|
|
191
295
|
});
|
|
192
296
|
app.listen({ port: config.port, hostname: '0.0.0.0' });
|
|
193
|
-
|
|
194
|
-
console.log(`[Indexer] Event poll: ${config.eventPollIntervalMs}ms`);
|
|
195
|
-
console.log(`[Indexer] State poll: ${config.statePollIntervalMs}ms`);
|
|
196
|
-
console.log(`[Indexer] Position poll: ${config.positionPollIntervalMs}ms`);
|
|
197
|
-
// Graceful shutdown
|
|
297
|
+
// ── Graceful shutdown ──────────────────────────────────────────────────────
|
|
198
298
|
process.on('SIGTERM', () => {
|
|
199
|
-
console.log('[Indexer] SIGTERM received, shutting down...');
|
|
200
299
|
scheduler.stop();
|
|
201
300
|
db.close();
|
|
202
301
|
process.exit(0);
|
|
203
302
|
});
|
|
204
303
|
process.on('SIGINT', () => {
|
|
205
|
-
console.log('[Indexer] SIGINT received, shutting down...');
|
|
206
304
|
scheduler.stop();
|
|
207
305
|
db.close();
|
|
208
306
|
process.exit(0);
|