@gearbox-protocol/sdk 13.6.0-apy-plugin.3 → 13.6.0-apy-plugin.5
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/cjs/plugins/pools-history/ApyPlugin.js +67 -3
- package/dist/cjs/sdk/GearboxSDK.js +11 -0
- package/dist/esm/plugins/pools-history/ApyPlugin.js +67 -3
- package/dist/esm/sdk/GearboxSDK.js +11 -0
- package/dist/types/plugins/pools-history/ApyPlugin.d.ts +26 -2
- package/dist/types/sdk/GearboxSDK.d.ts +19 -0
- package/package.json +1 -1
|
@@ -31,15 +31,40 @@ var import_apy_parser = require("./apy-parser.js");
|
|
|
31
31
|
var import_constants = require("./constants.js");
|
|
32
32
|
var import_pool_apy_utils = require("./pool-apy-utils.js");
|
|
33
33
|
const MAP_LABEL = "pools7DAgo";
|
|
34
|
+
const PLUGIN_KEY = "ApyPlugin";
|
|
34
35
|
class ApyPlugin extends import_sdk.BasePlugin {
|
|
36
|
+
#timerInterval;
|
|
35
37
|
#apyUrl;
|
|
36
38
|
#cacheTtlMs;
|
|
37
39
|
#pools7DAgo;
|
|
38
40
|
#apySnapshot;
|
|
39
|
-
|
|
41
|
+
/**
|
|
42
|
+
* Default timer options
|
|
43
|
+
* @see PluginTimerOptions
|
|
44
|
+
*/
|
|
45
|
+
#defaultTimerOptions;
|
|
46
|
+
/**
|
|
47
|
+
* When `true`, the timer is started eagerly during the `attach` phase
|
|
48
|
+
* rather than waiting for an explicit `load` call.
|
|
49
|
+
**/
|
|
50
|
+
startTimerOnAttach;
|
|
51
|
+
constructor(loadOnAttach = false, startTimerOnAttach = false, options) {
|
|
40
52
|
super(loadOnAttach);
|
|
53
|
+
this.startTimerOnAttach = startTimerOnAttach;
|
|
41
54
|
this.#apyUrl = options?.apyUrl ?? import_constants.APY_STATE_CACHE_URL;
|
|
42
55
|
this.#cacheTtlMs = options?.cacheTtlMs ?? import_constants.DEFAULT_APY_INTERVAL_MS;
|
|
56
|
+
this.#defaultTimerOptions = options?.timer ?? {
|
|
57
|
+
refreshPools7DAgoOnTick: false,
|
|
58
|
+
intervalMs: import_constants.DEFAULT_APY_INTERVAL_MS,
|
|
59
|
+
onChange: () => {
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
async attach() {
|
|
64
|
+
await super.attach();
|
|
65
|
+
if (this.startTimerOnAttach) {
|
|
66
|
+
this.startTimer();
|
|
67
|
+
}
|
|
43
68
|
}
|
|
44
69
|
// ---------------------------------------------------------------------------
|
|
45
70
|
// Load — single entry point for all data (on-chain + state-cache)
|
|
@@ -148,8 +173,9 @@ class ApyPlugin extends import_sdk.BasePlugin {
|
|
|
148
173
|
for (const market of markets) {
|
|
149
174
|
const pool = market.pool.pool;
|
|
150
175
|
const poolAddr = pool.address.toLowerCase();
|
|
176
|
+
const underlyingLc = pool.underlying.toLowerCase();
|
|
151
177
|
const depositAPY = (0, import_formatter.rayToNumber)(pool.supplyRate) * Number(import_sdk.PERCENTAGE_DECIMALS);
|
|
152
|
-
const underlyingAPY = apy.apyList?.[pool.underlying] ?? 0;
|
|
178
|
+
const underlyingAPY = apy.apyList?.[underlyingLc] ?? apy.apyList?.[pool.underlying] ?? 0;
|
|
153
179
|
const lookupAddresses = this.#getExtraAPYLookupAddresses(poolAddr);
|
|
154
180
|
const extraAPY = (0, import_pool_apy_utils.getPoolExtraAPY)(lookupAddresses, apy.poolExtraAPYList);
|
|
155
181
|
const currentExternalList = apy.poolExternalAPYList?.[poolAddr];
|
|
@@ -181,10 +207,48 @@ class ApyPlugin extends import_sdk.BasePlugin {
|
|
|
181
207
|
return { data, data7DAgo, pointsBase: poolPointsBase, points };
|
|
182
208
|
}
|
|
183
209
|
// ---------------------------------------------------------------------------
|
|
210
|
+
// Periodic full refresh
|
|
211
|
+
// ---------------------------------------------------------------------------
|
|
212
|
+
/**
|
|
213
|
+
* Starts a periodic timer that performs a full plugin state refresh.
|
|
214
|
+
* Only one timer can be active; calling again is a no-op.
|
|
215
|
+
* @returns Cleanup function that stops the timer.
|
|
216
|
+
*/
|
|
217
|
+
startTimer(opts) {
|
|
218
|
+
if (this.#timerInterval) {
|
|
219
|
+
this.#logger?.debug("plugin timer already running");
|
|
220
|
+
return () => this.stopTimer();
|
|
221
|
+
}
|
|
222
|
+
const intervalMs = opts?.intervalMs ?? this.#defaultTimerOptions.intervalMs;
|
|
223
|
+
this.#logger?.debug(`starting plugin timer (interval: ${intervalMs}ms)`);
|
|
224
|
+
this.#timerInterval = setInterval(async () => {
|
|
225
|
+
try {
|
|
226
|
+
const prevTimestamp = this.#apySnapshot?.timestamp;
|
|
227
|
+
await this.load(true, {
|
|
228
|
+
loadPools7DAgo: opts?.refreshPools7DAgoOnTick ?? this.#defaultTimerOptions.refreshPools7DAgoOnTick
|
|
229
|
+
});
|
|
230
|
+
if (this.#apySnapshot?.timestamp !== prevTimestamp) {
|
|
231
|
+
opts?.onChange?.() ?? this.#defaultTimerOptions.onChange?.();
|
|
232
|
+
await this.sdk.triggerPluginUpdate(PLUGIN_KEY);
|
|
233
|
+
}
|
|
234
|
+
} catch (e) {
|
|
235
|
+
this.#logger?.error(e, "periodic refresh failed");
|
|
236
|
+
}
|
|
237
|
+
}, intervalMs);
|
|
238
|
+
return () => this.stopTimer();
|
|
239
|
+
}
|
|
240
|
+
stopTimer() {
|
|
241
|
+
if (this.#timerInterval) {
|
|
242
|
+
clearInterval(this.#timerInterval);
|
|
243
|
+
this.#timerInterval = void 0;
|
|
244
|
+
this.#logger?.debug("plugin timer stopped");
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
// ---------------------------------------------------------------------------
|
|
184
248
|
// Plugin lifecycle
|
|
185
249
|
// ---------------------------------------------------------------------------
|
|
186
250
|
async syncState() {
|
|
187
|
-
await this.load();
|
|
251
|
+
await this.load(true);
|
|
188
252
|
}
|
|
189
253
|
stateHuman(_) {
|
|
190
254
|
return this.pools7DAgo.values().flatMap((p) => ({
|
|
@@ -110,6 +110,17 @@ class GearboxSDK extends import_base.ChainContractsRegister {
|
|
|
110
110
|
* @see {@link SDKHooks} for available event names.
|
|
111
111
|
**/
|
|
112
112
|
removeHook = this.#hooks.removeHook.bind(this.#hooks);
|
|
113
|
+
/**
|
|
114
|
+
* Triggers the `pluginUpdate` hook.
|
|
115
|
+
*
|
|
116
|
+
* Intended to be called by plugins when they update their internal state
|
|
117
|
+
* outside of the normal `syncState`/`rehydrate` cycle (e.g. via an
|
|
118
|
+
* internal timer). Frontend listeners registered with
|
|
119
|
+
* `sdk.addHook("pluginUpdate", …)` will be notified.
|
|
120
|
+
**/
|
|
121
|
+
async triggerPluginUpdate(plugin) {
|
|
122
|
+
await this.#hooks.triggerHooks("pluginUpdate", { plugin });
|
|
123
|
+
}
|
|
113
124
|
/**
|
|
114
125
|
* Creates and initialises a new SDK instance by reading live on-chain state.
|
|
115
126
|
*
|
|
@@ -21,15 +21,40 @@ import {
|
|
|
21
21
|
getPoolExtraAPY
|
|
22
22
|
} from "./pool-apy-utils.js";
|
|
23
23
|
const MAP_LABEL = "pools7DAgo";
|
|
24
|
+
const PLUGIN_KEY = "ApyPlugin";
|
|
24
25
|
class ApyPlugin extends BasePlugin {
|
|
26
|
+
#timerInterval;
|
|
25
27
|
#apyUrl;
|
|
26
28
|
#cacheTtlMs;
|
|
27
29
|
#pools7DAgo;
|
|
28
30
|
#apySnapshot;
|
|
29
|
-
|
|
31
|
+
/**
|
|
32
|
+
* Default timer options
|
|
33
|
+
* @see PluginTimerOptions
|
|
34
|
+
*/
|
|
35
|
+
#defaultTimerOptions;
|
|
36
|
+
/**
|
|
37
|
+
* When `true`, the timer is started eagerly during the `attach` phase
|
|
38
|
+
* rather than waiting for an explicit `load` call.
|
|
39
|
+
**/
|
|
40
|
+
startTimerOnAttach;
|
|
41
|
+
constructor(loadOnAttach = false, startTimerOnAttach = false, options) {
|
|
30
42
|
super(loadOnAttach);
|
|
43
|
+
this.startTimerOnAttach = startTimerOnAttach;
|
|
31
44
|
this.#apyUrl = options?.apyUrl ?? APY_STATE_CACHE_URL;
|
|
32
45
|
this.#cacheTtlMs = options?.cacheTtlMs ?? DEFAULT_APY_INTERVAL_MS;
|
|
46
|
+
this.#defaultTimerOptions = options?.timer ?? {
|
|
47
|
+
refreshPools7DAgoOnTick: false,
|
|
48
|
+
intervalMs: DEFAULT_APY_INTERVAL_MS,
|
|
49
|
+
onChange: () => {
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
async attach() {
|
|
54
|
+
await super.attach();
|
|
55
|
+
if (this.startTimerOnAttach) {
|
|
56
|
+
this.startTimer();
|
|
57
|
+
}
|
|
33
58
|
}
|
|
34
59
|
// ---------------------------------------------------------------------------
|
|
35
60
|
// Load — single entry point for all data (on-chain + state-cache)
|
|
@@ -138,8 +163,9 @@ class ApyPlugin extends BasePlugin {
|
|
|
138
163
|
for (const market of markets) {
|
|
139
164
|
const pool = market.pool.pool;
|
|
140
165
|
const poolAddr = pool.address.toLowerCase();
|
|
166
|
+
const underlyingLc = pool.underlying.toLowerCase();
|
|
141
167
|
const depositAPY = rayToNumber(pool.supplyRate) * Number(PERCENTAGE_DECIMALS);
|
|
142
|
-
const underlyingAPY = apy.apyList?.[pool.underlying] ?? 0;
|
|
168
|
+
const underlyingAPY = apy.apyList?.[underlyingLc] ?? apy.apyList?.[pool.underlying] ?? 0;
|
|
143
169
|
const lookupAddresses = this.#getExtraAPYLookupAddresses(poolAddr);
|
|
144
170
|
const extraAPY = getPoolExtraAPY(lookupAddresses, apy.poolExtraAPYList);
|
|
145
171
|
const currentExternalList = apy.poolExternalAPYList?.[poolAddr];
|
|
@@ -171,10 +197,48 @@ class ApyPlugin extends BasePlugin {
|
|
|
171
197
|
return { data, data7DAgo, pointsBase: poolPointsBase, points };
|
|
172
198
|
}
|
|
173
199
|
// ---------------------------------------------------------------------------
|
|
200
|
+
// Periodic full refresh
|
|
201
|
+
// ---------------------------------------------------------------------------
|
|
202
|
+
/**
|
|
203
|
+
* Starts a periodic timer that performs a full plugin state refresh.
|
|
204
|
+
* Only one timer can be active; calling again is a no-op.
|
|
205
|
+
* @returns Cleanup function that stops the timer.
|
|
206
|
+
*/
|
|
207
|
+
startTimer(opts) {
|
|
208
|
+
if (this.#timerInterval) {
|
|
209
|
+
this.#logger?.debug("plugin timer already running");
|
|
210
|
+
return () => this.stopTimer();
|
|
211
|
+
}
|
|
212
|
+
const intervalMs = opts?.intervalMs ?? this.#defaultTimerOptions.intervalMs;
|
|
213
|
+
this.#logger?.debug(`starting plugin timer (interval: ${intervalMs}ms)`);
|
|
214
|
+
this.#timerInterval = setInterval(async () => {
|
|
215
|
+
try {
|
|
216
|
+
const prevTimestamp = this.#apySnapshot?.timestamp;
|
|
217
|
+
await this.load(true, {
|
|
218
|
+
loadPools7DAgo: opts?.refreshPools7DAgoOnTick ?? this.#defaultTimerOptions.refreshPools7DAgoOnTick
|
|
219
|
+
});
|
|
220
|
+
if (this.#apySnapshot?.timestamp !== prevTimestamp) {
|
|
221
|
+
opts?.onChange?.() ?? this.#defaultTimerOptions.onChange?.();
|
|
222
|
+
await this.sdk.triggerPluginUpdate(PLUGIN_KEY);
|
|
223
|
+
}
|
|
224
|
+
} catch (e) {
|
|
225
|
+
this.#logger?.error(e, "periodic refresh failed");
|
|
226
|
+
}
|
|
227
|
+
}, intervalMs);
|
|
228
|
+
return () => this.stopTimer();
|
|
229
|
+
}
|
|
230
|
+
stopTimer() {
|
|
231
|
+
if (this.#timerInterval) {
|
|
232
|
+
clearInterval(this.#timerInterval);
|
|
233
|
+
this.#timerInterval = void 0;
|
|
234
|
+
this.#logger?.debug("plugin timer stopped");
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
// ---------------------------------------------------------------------------
|
|
174
238
|
// Plugin lifecycle
|
|
175
239
|
// ---------------------------------------------------------------------------
|
|
176
240
|
async syncState() {
|
|
177
|
-
await this.load();
|
|
241
|
+
await this.load(true);
|
|
178
242
|
}
|
|
179
243
|
stateHuman(_) {
|
|
180
244
|
return this.pools7DAgo.values().flatMap((p) => ({
|
|
@@ -101,6 +101,17 @@ class GearboxSDK extends ChainContractsRegister {
|
|
|
101
101
|
* @see {@link SDKHooks} for available event names.
|
|
102
102
|
**/
|
|
103
103
|
removeHook = this.#hooks.removeHook.bind(this.#hooks);
|
|
104
|
+
/**
|
|
105
|
+
* Triggers the `pluginUpdate` hook.
|
|
106
|
+
*
|
|
107
|
+
* Intended to be called by plugins when they update their internal state
|
|
108
|
+
* outside of the normal `syncState`/`rehydrate` cycle (e.g. via an
|
|
109
|
+
* internal timer). Frontend listeners registered with
|
|
110
|
+
* `sdk.addHook("pluginUpdate", …)` will be notified.
|
|
111
|
+
**/
|
|
112
|
+
async triggerPluginUpdate(plugin) {
|
|
113
|
+
await this.#hooks.triggerHooks("pluginUpdate", { plugin });
|
|
114
|
+
}
|
|
104
115
|
/**
|
|
105
116
|
* Creates and initialises a new SDK instance by reading live on-chain state.
|
|
106
117
|
*
|
|
@@ -9,8 +9,9 @@ export interface ApyPluginState {
|
|
|
9
9
|
}
|
|
10
10
|
export interface ApyPluginConstructorOptions {
|
|
11
11
|
apyUrl?: string;
|
|
12
|
-
/** TTL for the shared HTTP cache in milliseconds (default:
|
|
12
|
+
/** TTL for the shared HTTP cache in milliseconds (default: same as timer interval) */
|
|
13
13
|
cacheTtlMs?: number;
|
|
14
|
+
timer?: PluginTimerOptions;
|
|
14
15
|
}
|
|
15
16
|
export interface ApyPluginLoadOptions {
|
|
16
17
|
/**
|
|
@@ -20,9 +21,25 @@ export interface ApyPluginLoadOptions {
|
|
|
20
21
|
*/
|
|
21
22
|
loadPools7DAgo?: boolean;
|
|
22
23
|
}
|
|
24
|
+
export interface PluginTimerOptions {
|
|
25
|
+
/** Polling interval in milliseconds (default: 10 minutes) */
|
|
26
|
+
intervalMs?: number;
|
|
27
|
+
/** Callback fired after each successful refresh */
|
|
28
|
+
onChange?: () => void;
|
|
29
|
+
/**
|
|
30
|
+
* When `true`, each tick also refreshes 7d-ago pool state on-chain.
|
|
31
|
+
*/
|
|
32
|
+
refreshPools7DAgoOnTick?: boolean;
|
|
33
|
+
}
|
|
23
34
|
export declare class ApyPlugin extends BasePlugin<ApyPluginState> implements IGearboxSDKPlugin<ApyPluginState> {
|
|
24
35
|
#private;
|
|
25
|
-
|
|
36
|
+
/**
|
|
37
|
+
* When `true`, the timer is started eagerly during the `attach` phase
|
|
38
|
+
* rather than waiting for an explicit `load` call.
|
|
39
|
+
**/
|
|
40
|
+
readonly startTimerOnAttach: boolean;
|
|
41
|
+
constructor(loadOnAttach?: boolean, startTimerOnAttach?: boolean, options?: ApyPluginConstructorOptions);
|
|
42
|
+
attach(): Promise<void>;
|
|
26
43
|
load(force?: boolean, loadOptions?: ApyPluginLoadOptions): Promise<ApyPluginState>;
|
|
27
44
|
get loaded(): boolean;
|
|
28
45
|
/**
|
|
@@ -39,6 +56,13 @@ export declare class ApyPlugin extends BasePlugin<ApyPluginState> implements IGe
|
|
|
39
56
|
* @throws if plugin is not loaded
|
|
40
57
|
*/
|
|
41
58
|
getPoolsAPY(): GetPoolsAPYResult;
|
|
59
|
+
/**
|
|
60
|
+
* Starts a periodic timer that performs a full plugin state refresh.
|
|
61
|
+
* Only one timer can be active; calling again is a no-op.
|
|
62
|
+
* @returns Cleanup function that stops the timer.
|
|
63
|
+
*/
|
|
64
|
+
startTimer(opts?: PluginTimerOptions): () => void;
|
|
65
|
+
stopTimer(): void;
|
|
42
66
|
syncState(): Promise<void>;
|
|
43
67
|
stateHuman(_?: boolean): Pools7DAgoStateHuman[];
|
|
44
68
|
get state(): ApyPluginState;
|
|
@@ -115,6 +115,13 @@ export interface SyncStateOptions {
|
|
|
115
115
|
**/
|
|
116
116
|
ignoreUpdateablePrices?: boolean;
|
|
117
117
|
}
|
|
118
|
+
/**
|
|
119
|
+
* Payload carried by the `pluginUpdate` hook.
|
|
120
|
+
**/
|
|
121
|
+
export interface PluginUpdateInfo {
|
|
122
|
+
/** Identifier of the plugin that triggered the update (e.g. `"pools7DAgo"`). */
|
|
123
|
+
plugin: string;
|
|
124
|
+
}
|
|
118
125
|
/**
|
|
119
126
|
* Hook event map for the SDK lifecycle.
|
|
120
127
|
*
|
|
@@ -123,10 +130,13 @@ export interface SyncStateOptions {
|
|
|
123
130
|
*
|
|
124
131
|
* - `syncState` — fired after {@link GearboxSDK.syncState} completes.
|
|
125
132
|
* - `rehydrate` — fired after {@link GearboxSDK.rehydrate} completes.
|
|
133
|
+
* - `pluginUpdate` — fired by a plugin when its internal state changes
|
|
134
|
+
* outside of the normal `syncState`/`rehydrate` cycle (e.g. timer tick).
|
|
126
135
|
**/
|
|
127
136
|
export type SDKHooks = {
|
|
128
137
|
syncState: [SyncStateOptions];
|
|
129
138
|
rehydrate: [SyncStateOptions];
|
|
139
|
+
pluginUpdate: [PluginUpdateInfo];
|
|
130
140
|
};
|
|
131
141
|
/**
|
|
132
142
|
* Main entry point for the Gearbox SDK.
|
|
@@ -175,6 +185,15 @@ export declare class GearboxSDK<const Plugins extends PluginsMap = {}> extends C
|
|
|
175
185
|
* @see {@link SDKHooks} for available event names.
|
|
176
186
|
**/
|
|
177
187
|
removeHook: <K extends keyof SDKHooks>(hookName: K, fn: (...args: SDKHooks[K]) => void | Promise<void>) => void;
|
|
188
|
+
/**
|
|
189
|
+
* Triggers the `pluginUpdate` hook.
|
|
190
|
+
*
|
|
191
|
+
* Intended to be called by plugins when they update their internal state
|
|
192
|
+
* outside of the normal `syncState`/`rehydrate` cycle (e.g. via an
|
|
193
|
+
* internal timer). Frontend listeners registered with
|
|
194
|
+
* `sdk.addHook("pluginUpdate", …)` will be notified.
|
|
195
|
+
**/
|
|
196
|
+
triggerPluginUpdate(plugin: string): Promise<void>;
|
|
178
197
|
/**
|
|
179
198
|
* Creates and initialises a new SDK instance by reading live on-chain state.
|
|
180
199
|
*
|