Skip to content

Commit 75e2970

Browse files
committed
feat: externalDataDriftClientSubscriber
1 parent 32e7915 commit 75e2970

File tree

4 files changed

+87
-3
lines changed

4 files changed

+87
-3
lines changed

sdk/src/accounts/customizedCadenceBulkAccountLoader.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,9 @@ export class CustomizedCadenceBulkAccountLoader extends BulkAccountLoader {
3535

3636
for (const [key, frequency] of this.accountFrequencies.entries()) {
3737
const lastPollTime = this.lastPollingTimes.get(key) || 0;
38-
if (currentTime - lastPollTime >= frequency) {
38+
// Add 200ms buffer to account for timing wiggle room with js execution
39+
const timeDiff = currentTime - lastPollTime;
40+
if (timeDiff >= frequency - 200) {
3941
const account = this.accountsToLoad.get(key);
4042
if (account) {
4143
accountsToLoad.push(account);
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import {
2+
PollingDriftClientAccountSubscriber
3+
} from './pollingDriftClientAccountSubscriber';
4+
5+
import {
6+
OraclePriceData,
7+
OracleInfo
8+
} from '../oracles/types';
9+
10+
import { getOracleId } from '../oracles/oracleId';
11+
12+
13+
// allowing app UI state to incrementally replace RPC fetched acconut data with data from our infra that is pre-indexed and decoded
14+
export class ExternalDataDriftClientSubscriber extends PollingDriftClientAccountSubscriber {
15+
private oracleLastUpdate = new Map<string, number>();
16+
private pollingOracles = new Map<string, boolean>();
17+
private oraclePollIntervalId: NodeJS.Timeout;
18+
19+
constructor(...args: ConstructorParameters<typeof PollingDriftClientAccountSubscriber>) {
20+
super(...args);
21+
22+
}
23+
24+
/** Override to prevent oracles from being automatically polled later */
25+
public override updateOraclesToPoll(): boolean {
26+
return true;
27+
}
28+
29+
/** Public method to be called externally with fresh oracle data */
30+
public feedOracle(oracleInfo: OracleInfo, priceData: OraclePriceData, slot: number) {
31+
const oracleId = getOracleId(oracleInfo.publicKey, oracleInfo.source);
32+
this.oracles.set(oracleId, { data: priceData, slot });
33+
this.oracleLastUpdate.set(oracleId, Date.now());
34+
if (this.pollingOracles.has(oracleId) || this.accountLoader.accountsToLoad.has(oracleInfo.publicKey.toBase58())) {
35+
const oracleToPoll = this.oraclesToPoll.get(oracleId);
36+
if (oracleToPoll) {
37+
this.accountLoader.removeAccount(
38+
oracleToPoll.publicKey,
39+
oracleToPoll.callbackId
40+
);
41+
this.pollingOracles.delete(oracleId);
42+
}
43+
}
44+
}
45+
46+
public override async subscribe(): Promise<boolean> {
47+
await super.subscribe();
48+
this.startOraclePollingWatchdog();
49+
return true;
50+
}
51+
52+
private startOraclePollingWatchdog() {
53+
if(this.oraclePollIntervalId) {
54+
clearInterval(this.oraclePollIntervalId);
55+
}
56+
// how do we handle not polling bet markets every 1s from this change?
57+
this.oraclePollIntervalId = setInterval(async () => {
58+
for (const [oracleId, lastUpdate] of this.oracleLastUpdate.entries()) {
59+
const oracleToPoll = this.oraclesToPoll.get(oracleId);
60+
if(!oracleToPoll) continue;
61+
const now = Date.now();
62+
if (now - lastUpdate > 130_000 && !this.pollingOracles.has(oracleId)) {
63+
await this.addOracleToAccountLoader(oracleToPoll);
64+
this.pollingOracles.set(oracleId, true);
65+
}
66+
}
67+
}, 60_000);
68+
}
69+
70+
public override async unsubscribe(): Promise<void> {
71+
clearInterval(this.oraclePollIntervalId);
72+
await super.unsubscribe();
73+
this.oracleLastUpdate.clear();
74+
this.pollingOracles.clear();
75+
}
76+
}

sdk/src/accounts/pollingDriftClientAccountSubscriber.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -546,8 +546,13 @@ export class PollingDriftClientAccountSubscriber
546546

547547
for (const oracle of oracles) {
548548
const oracleId = getOracleId(oracle.publicKey, oracle.source);
549-
const callbackId = this.oraclesToPoll.get(oracleId).callbackId;
550-
this.accountLoader.removeAccount(oracle.publicKey, callbackId);
549+
const oracleToPoll = this.oraclesToPoll.get(oracleId);
550+
if (oracleToPoll) {
551+
this.accountLoader.removeAccount(
552+
oracleToPoll.publicKey,
553+
oracleToPoll.callbackId
554+
);
555+
}
551556
if (this.delistedMarketSetting === DelistedMarketSetting.Discard) {
552557
this.oracles.delete(oracleId);
553558
}

sdk/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export * from './accounts/bulkAccountLoader';
1616
export * from './accounts/bulkUserSubscription';
1717
export * from './accounts/bulkUserStatsSubscription';
1818
export { CustomizedCadenceBulkAccountLoader } from './accounts/customizedCadenceBulkAccountLoader';
19+
export { ExternalDataDriftClientSubscriber } from './accounts/externalDataDriftClientSubscriber';
1920
export * from './accounts/pollingDriftClientAccountSubscriber';
2021
export * from './accounts/pollingOracleAccountSubscriber';
2122
export * from './accounts/pollingTokenAccountSubscriber';

0 commit comments

Comments
 (0)