@gearbox-protocol/sdk 12.10.0 → 12.10.1
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/history/errors.js +2 -0
- package/dist/cjs/permissionless/utils/price-update/get-updatable-feeds.js +2 -16
- package/dist/cjs/sdk/GearboxSDK.js +0 -10
- package/dist/cjs/sdk/market/pricefeeds/PriceFeedsRegister.js +8 -3
- package/dist/cjs/sdk/market/pricefeeds/RedstonePriceFeed.js +2 -0
- package/dist/cjs/sdk/market/pricefeeds/updates/RedstoneUpdater.js +3 -202
- package/dist/cjs/sdk/market/pricefeeds/updates/fetchRedstonePayloads.js +4 -126
- package/dist/cjs/sdk/options.js +1 -1
- package/dist/esm/history/errors.js +2 -0
- package/dist/esm/permissionless/utils/price-update/get-updatable-feeds.js +2 -19
- package/dist/esm/sdk/GearboxSDK.js +0 -10
- package/dist/esm/sdk/market/pricefeeds/PriceFeedsRegister.js +8 -3
- package/dist/esm/sdk/market/pricefeeds/RedstonePriceFeed.js +2 -0
- package/dist/esm/sdk/market/pricefeeds/updates/RedstoneUpdater.js +3 -202
- package/dist/esm/sdk/market/pricefeeds/updates/fetchRedstonePayloads.js +4 -130
- package/dist/esm/sdk/options.js +1 -1
- package/dist/types/permissionless/utils/price-update/get-updatable-feeds.d.ts +4 -3
- package/dist/types/sdk/market/pricefeeds/PriceFeedsRegister.d.ts +1 -1
- package/dist/types/sdk/market/pricefeeds/updates/RedstoneUpdater.d.ts +5 -10
- package/dist/types/sdk/market/pricefeeds/updates/fetchRedstonePayloads.d.ts +2 -6
- package/package.json +2 -6
- package/dist/cjs/sdk/market/pricefeeds/updates/PriceUpdateTx.js +0 -55
- package/dist/cjs/sdk/market/pricefeeds/updates/PriceUpdatesCache.js +0 -78
- package/dist/esm/sdk/market/pricefeeds/updates/PriceUpdateTx.js +0 -31
- package/dist/esm/sdk/market/pricefeeds/updates/PriceUpdatesCache.js +0 -54
- package/dist/types/sdk/market/pricefeeds/updates/PriceUpdateTx.d.ts +0 -13
- package/dist/types/sdk/market/pricefeeds/updates/PriceUpdatesCache.d.ts +0 -24
|
@@ -21,22 +21,8 @@ __export(get_updatable_feeds_exports, {
|
|
|
21
21
|
getUpdatablePriceFeeds: () => getUpdatablePriceFeeds
|
|
22
22
|
});
|
|
23
23
|
module.exports = __toCommonJS(get_updatable_feeds_exports);
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
var import_sdk = require("../../../sdk/index.js");
|
|
27
|
-
async function getUpdatablePriceFeeds(args) {
|
|
28
|
-
const { sdk, client, pfCompressor, priceFeeds } = args;
|
|
29
|
-
const priceFeedCompressor = (0, import_viem.getContract)({
|
|
30
|
-
address: pfCompressor,
|
|
31
|
-
abi: import_priceFeedCompressor.priceFeedCompressorAbi,
|
|
32
|
-
client
|
|
33
|
-
});
|
|
34
|
-
const updatablePriceFeeds = (await priceFeedCompressor.read.loadPriceFeedTree([
|
|
35
|
-
priceFeeds
|
|
36
|
-
])).filter(
|
|
37
|
-
(data) => (0, import_sdk.bytes32ToString)(data.baseParams.contractType) === "PRICE_FEED::REDSTONE"
|
|
38
|
-
).map((data) => new import_sdk.RedstonePriceFeedContract(sdk, data));
|
|
39
|
-
return updatablePriceFeeds;
|
|
24
|
+
async function getUpdatablePriceFeeds(_args) {
|
|
25
|
+
return [];
|
|
40
26
|
}
|
|
41
27
|
// Annotate the CommonJS export names for ESM import in node:
|
|
42
28
|
0 && (module.exports = {
|
|
@@ -175,11 +175,6 @@ class GearboxSDK extends import_base.ChainContractsRegister {
|
|
|
175
175
|
},
|
|
176
176
|
`${re}attaching gearbox sdk`
|
|
177
177
|
);
|
|
178
|
-
if (!!blockNumber && !opts.redstone?.historicTimestamp) {
|
|
179
|
-
this.logger?.warn(
|
|
180
|
-
`${re}attaching to fixed block number, but redstone historicTimestamp is not set. price updates might fail`
|
|
181
|
-
);
|
|
182
|
-
}
|
|
183
178
|
this.#attachConfig = opts;
|
|
184
179
|
const time = Date.now();
|
|
185
180
|
const block = await this.client.getBlock(
|
|
@@ -350,11 +345,6 @@ class GearboxSDK extends import_base.ChainContractsRegister {
|
|
|
350
345
|
timestamp,
|
|
351
346
|
ignoreUpdateablePrices = this.#attachConfig?.ignoreUpdateablePrices
|
|
352
347
|
} = opts ?? {};
|
|
353
|
-
if (this.#attachConfig?.redstone?.historicTimestamp) {
|
|
354
|
-
throw new Error(
|
|
355
|
-
"syncState is not supported with redstone historicTimestamp"
|
|
356
|
-
);
|
|
357
|
-
}
|
|
358
348
|
if (!blockNumber || !timestamp) {
|
|
359
349
|
const block = await this.client.getBlock({
|
|
360
350
|
blockTag: "latest"
|
|
@@ -43,7 +43,6 @@ var import_MellowLRTPriceFeed = require("./MellowLRTPriceFeed.js");
|
|
|
43
43
|
var import_PendleTWAPPTPriceFeed = require("./PendleTWAPPTPriceFeed.js");
|
|
44
44
|
var import_PythPriceFeed = require("./PythPriceFeed.js");
|
|
45
45
|
var import_RedstonePriceFeed = require("./RedstonePriceFeed.js");
|
|
46
|
-
var import_updates = require("./updates/index.js");
|
|
47
46
|
var import_WstETHPriceFeed = require("./WstETHPriceFeed.js");
|
|
48
47
|
var import_YearnPriceFeed = require("./YearnPriceFeed.js");
|
|
49
48
|
var import_ZeroPriceFeed = require("./ZeroPriceFeed.js");
|
|
@@ -52,9 +51,9 @@ class PriceFeedRegister extends import_base.SDKConstruct {
|
|
|
52
51
|
#feeds = new import_utils.AddressMap(void 0, "priceFeeds");
|
|
53
52
|
#latestUpdate;
|
|
54
53
|
updaters;
|
|
55
|
-
constructor(sdk,
|
|
54
|
+
constructor(sdk, _opts = {}) {
|
|
56
55
|
super(sdk);
|
|
57
|
-
this.updaters = [
|
|
56
|
+
this.updaters = [];
|
|
58
57
|
}
|
|
59
58
|
addHook = this.#hooks.addHook.bind(this.#hooks);
|
|
60
59
|
removeHook = this.#hooks.removeHook.bind(this.#hooks);
|
|
@@ -146,6 +145,9 @@ class PriceFeedRegister extends import_base.SDKConstruct {
|
|
|
146
145
|
* @returns
|
|
147
146
|
*/
|
|
148
147
|
async generateExternalPriceFeedsUpdateTxs(feeds, block) {
|
|
148
|
+
if (this.updaters.length === 0) {
|
|
149
|
+
return this.generatePriceFeedsUpdateTxs([]);
|
|
150
|
+
}
|
|
149
151
|
const [priceFeedCompressorAddress] = this.sdk.addressProvider.mustGetLatest(
|
|
150
152
|
import_constants.AP_PRICE_FEED_COMPRESSOR,
|
|
151
153
|
import_constants.VERSION_RANGE_310
|
|
@@ -200,6 +202,9 @@ class PriceFeedRegister extends import_base.SDKConstruct {
|
|
|
200
202
|
* Discovered price feeds are not saved anywhere in PriceFeedRegister, and can later be used to load price feed updates
|
|
201
203
|
*/
|
|
202
204
|
async getPartialUpdatablePriceFeeds(configurators, pools) {
|
|
205
|
+
if (this.updaters.length === 0) {
|
|
206
|
+
return [];
|
|
207
|
+
}
|
|
203
208
|
const [priceFeedCompressorAddress] = this.sdk.addressProvider.mustGetLatest(
|
|
204
209
|
import_constants.AP_PRICE_FEED_COMPRESSOR,
|
|
205
210
|
import_constants.VERSION_RANGE_310
|
|
@@ -36,6 +36,8 @@ class RedstonePriceFeedContract extends import_AbstractPriceFeed.AbstractPriceFe
|
|
|
36
36
|
constructor(options, args) {
|
|
37
37
|
super(options, {
|
|
38
38
|
...args,
|
|
39
|
+
// RedStone updates are no longer pushed by the SDK.
|
|
40
|
+
updatable: false,
|
|
39
41
|
name: "RedstonePriceFeed",
|
|
40
42
|
abi: import_abi.redstonePriceFeedAbi
|
|
41
43
|
});
|
|
@@ -24,13 +24,6 @@ __export(RedstoneUpdater_exports, {
|
|
|
24
24
|
module.exports = __toCommonJS(RedstoneUpdater_exports);
|
|
25
25
|
var import_v4 = require("zod/v4");
|
|
26
26
|
var import_base = require("../../../base/index.js");
|
|
27
|
-
var import_utils = require("../../../utils/index.js");
|
|
28
|
-
var import_fetchRedstonePayloads = require("./fetchRedstonePayloads.js");
|
|
29
|
-
var import_PriceUpdatesCache = require("./PriceUpdatesCache.js");
|
|
30
|
-
var import_PriceUpdateTx = require("./PriceUpdateTx.js");
|
|
31
|
-
class RedstoneUpdateTx extends import_PriceUpdateTx.PriceUpdateTx {
|
|
32
|
-
name = "redstone";
|
|
33
|
-
}
|
|
34
27
|
const RedstoneOptions = import_v4.z.object({
|
|
35
28
|
/**
|
|
36
29
|
* Fixed redstone historic timestamp in ms
|
|
@@ -58,204 +51,12 @@ const RedstoneOptions = import_v4.z.object({
|
|
|
58
51
|
enableLogging: import_v4.z.boolean().optional()
|
|
59
52
|
});
|
|
60
53
|
class RedstoneUpdater extends import_base.SDKConstruct {
|
|
61
|
-
|
|
62
|
-
#historicalTimestampMs;
|
|
63
|
-
#gateways;
|
|
64
|
-
#ignoreMissingFeeds;
|
|
65
|
-
#enableLogging;
|
|
66
|
-
constructor(sdk, opts = {}) {
|
|
54
|
+
constructor(sdk, _opts = {}) {
|
|
67
55
|
super(sdk);
|
|
68
|
-
this.#ignoreMissingFeeds = opts.ignoreMissingFeeds;
|
|
69
|
-
this.#enableLogging = opts.enableLogging;
|
|
70
|
-
this.#gateways = opts.gateways?.length ? opts.gateways : void 0;
|
|
71
|
-
let ts = opts.historicTimestamp;
|
|
72
|
-
if (ts) {
|
|
73
|
-
ts = ts === true ? Number(this.sdk.timestamp) * 1e3 : ts;
|
|
74
|
-
this.#historicalTimestampMs = 6e4 * Math.floor(ts / 6e4);
|
|
75
|
-
this.logger?.debug(
|
|
76
|
-
`using historical timestamp ${this.#historicalTimestampMs}`
|
|
77
|
-
);
|
|
78
|
-
}
|
|
79
|
-
this.#cache = import_PriceUpdatesCache.PriceUpdatesCache.get("redstone", {
|
|
80
|
-
// currently staleness period is 240 seconds on all networks, add some buffer
|
|
81
|
-
// this period of 4 minutes is selected based on time that is required for user to sign transaction with wallet
|
|
82
|
-
// so it's unlikely to decrease
|
|
83
|
-
ttl: opts.cacheTTL ?? 225 * 1e3,
|
|
84
|
-
historical: !!ts
|
|
85
|
-
});
|
|
86
|
-
}
|
|
87
|
-
async getUpdateTxs(feeds) {
|
|
88
|
-
if (feeds.length === 0) {
|
|
89
|
-
return [];
|
|
90
|
-
}
|
|
91
|
-
this.logger?.debug(
|
|
92
|
-
`generating update transactions for ${feeds.length} redstone price feeds`
|
|
93
|
-
);
|
|
94
|
-
const groupedFeeds = {};
|
|
95
|
-
const priceFeeds = /* @__PURE__ */ new Map();
|
|
96
|
-
for (const feed of feeds) {
|
|
97
|
-
if (!isRedstone(feed)) {
|
|
98
|
-
continue;
|
|
99
|
-
}
|
|
100
|
-
const key = `${feed.dataServiceId}:${feed.signersThreshold}`;
|
|
101
|
-
if (!groupedFeeds[key]) {
|
|
102
|
-
groupedFeeds[key] = /* @__PURE__ */ new Set();
|
|
103
|
-
}
|
|
104
|
-
groupedFeeds[key].add(feed.dataId);
|
|
105
|
-
const pfsForDataId = priceFeeds.get(feed.dataId) ?? new import_utils.AddressMap();
|
|
106
|
-
pfsForDataId.upsert(feed.address, feed);
|
|
107
|
-
priceFeeds.set(feed.dataId, pfsForDataId);
|
|
108
|
-
}
|
|
109
|
-
const results = [];
|
|
110
|
-
let [minTimestamp, maxTimestamp] = [Number.POSITIVE_INFINITY, 0];
|
|
111
|
-
for (const [key, group] of Object.entries(groupedFeeds)) {
|
|
112
|
-
const [dataServiceId, signersStr] = key.split(":");
|
|
113
|
-
const uniqueSignersCount = parseInt(signersStr, 10);
|
|
114
|
-
const payloads = await this.#safeGetPayloads(
|
|
115
|
-
dataServiceId,
|
|
116
|
-
group,
|
|
117
|
-
uniqueSignersCount
|
|
118
|
-
);
|
|
119
|
-
for (const { dataFeedId, data, timestamp, cached } of payloads) {
|
|
120
|
-
const pfsForDataId = priceFeeds.get(dataFeedId);
|
|
121
|
-
if (!pfsForDataId) {
|
|
122
|
-
throw new Error(`cannot get price feed addresses for ${dataFeedId}`);
|
|
123
|
-
}
|
|
124
|
-
for (const priceFeed of pfsForDataId.values()) {
|
|
125
|
-
minTimestamp = Math.min(minTimestamp, timestamp);
|
|
126
|
-
maxTimestamp = Math.max(maxTimestamp, timestamp);
|
|
127
|
-
results.push(
|
|
128
|
-
new RedstoneUpdateTx(priceFeed.createPriceUpdateTx(data), {
|
|
129
|
-
dataFeedId,
|
|
130
|
-
dataServiceId,
|
|
131
|
-
priceFeed: priceFeed.address,
|
|
132
|
-
timestamp,
|
|
133
|
-
cached
|
|
134
|
-
})
|
|
135
|
-
);
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
let tsRange = "";
|
|
140
|
-
if (results.length) {
|
|
141
|
-
const minDelta = BigInt(minTimestamp) - this.sdk.timestamp;
|
|
142
|
-
tsRange = `, timestamps ${minTimestamp} (${minDelta})`;
|
|
143
|
-
if (minTimestamp !== maxTimestamp) {
|
|
144
|
-
const maxDelta = BigInt(maxTimestamp) - this.sdk.timestamp;
|
|
145
|
-
tsRange = `${tsRange} - ${maxTimestamp} (${maxDelta})`;
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
this.logger?.debug(
|
|
149
|
-
`generated ${results.length} update transactions for redstone price feeds: ${Array.from(priceFeeds.keys()).join(", ")}${tsRange}`
|
|
150
|
-
);
|
|
151
|
-
return results;
|
|
152
56
|
}
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
* @param dataServiceId
|
|
156
|
-
* @param dataFeedsIds
|
|
157
|
-
* @param uniqueSignersCount
|
|
158
|
-
* @returns
|
|
159
|
-
*/
|
|
160
|
-
async #safeGetPayloads(dataServiceId, dataFeedsIds, uniqueSignersCount) {
|
|
161
|
-
let result = await this.#getPayloads(
|
|
162
|
-
dataServiceId,
|
|
163
|
-
dataFeedsIds,
|
|
164
|
-
uniqueSignersCount
|
|
165
|
-
);
|
|
166
|
-
if (this.#historicalTimestampMs) {
|
|
167
|
-
return result;
|
|
168
|
-
}
|
|
169
|
-
let expired = false;
|
|
170
|
-
for (const { timestamp, dataFeedId } of result) {
|
|
171
|
-
const delta = Number(this.sdk.timestamp) - timestamp;
|
|
172
|
-
if (delta >= 240 && delta < 255) {
|
|
173
|
-
this.logger?.warn(
|
|
174
|
-
`payload for ${dataFeedId} has expired by ${delta} seconds`
|
|
175
|
-
);
|
|
176
|
-
expired = true;
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
if (expired) {
|
|
180
|
-
result = await this.#getPayloads(
|
|
181
|
-
dataServiceId,
|
|
182
|
-
dataFeedsIds,
|
|
183
|
-
uniqueSignersCount
|
|
184
|
-
);
|
|
185
|
-
}
|
|
186
|
-
return result;
|
|
57
|
+
async getUpdateTxs(_feeds) {
|
|
58
|
+
return [];
|
|
187
59
|
}
|
|
188
|
-
/**
|
|
189
|
-
* Gets redstone payloads in one request for multiple feeds with the same dataServiceId and uniqueSignersCount
|
|
190
|
-
* If historicalTimestamp is set, responses will be cached
|
|
191
|
-
* @param dataServiceId
|
|
192
|
-
* @param dataFeedsIds
|
|
193
|
-
* @param uniqueSignersCount
|
|
194
|
-
* @returns
|
|
195
|
-
*/
|
|
196
|
-
async #getPayloads(dataServiceId, dataFeedsIds, uniqueSignersCount) {
|
|
197
|
-
this.logger?.debug(
|
|
198
|
-
`getting redstone payloads for ${dataFeedsIds.size} data feeds in ${dataServiceId} with ${uniqueSignersCount} signers: ${Array.from(dataFeedsIds).join(", ")}`
|
|
199
|
-
);
|
|
200
|
-
const fromCache = [];
|
|
201
|
-
const uncached = [];
|
|
202
|
-
for (const dataFeedId of dataFeedsIds) {
|
|
203
|
-
const cached = this.#cache.get(
|
|
204
|
-
dataServiceId,
|
|
205
|
-
dataFeedId,
|
|
206
|
-
uniqueSignersCount
|
|
207
|
-
);
|
|
208
|
-
if (cached) {
|
|
209
|
-
fromCache.push({ ...cached, cached: true });
|
|
210
|
-
} else {
|
|
211
|
-
uncached.push(dataFeedId);
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
const fromRedstone = await this.#fetchPayloads(
|
|
215
|
-
dataServiceId,
|
|
216
|
-
new Set(uncached),
|
|
217
|
-
uniqueSignersCount
|
|
218
|
-
);
|
|
219
|
-
for (const resp of fromRedstone) {
|
|
220
|
-
this.#cache.set(resp, dataServiceId, resp.dataFeedId, uniqueSignersCount);
|
|
221
|
-
}
|
|
222
|
-
this.logger?.debug(
|
|
223
|
-
`got ${fromRedstone.length} new redstone updates and ${fromCache.length} from cache`
|
|
224
|
-
);
|
|
225
|
-
return [...fromCache, ...fromRedstone];
|
|
226
|
-
}
|
|
227
|
-
/**
|
|
228
|
-
* Fetches redstone payloads in one request for multiple feeds with the same dataServiceId and uniqueSignersCount
|
|
229
|
-
* Payloads are loaded in one request to avoid redstone rate limit
|
|
230
|
-
* @param dataServiceId
|
|
231
|
-
* @param dataFeedsIds
|
|
232
|
-
* @param uniqueSignersCount
|
|
233
|
-
* @returns
|
|
234
|
-
*/
|
|
235
|
-
async #fetchPayloads(dataServiceId, dataFeedsIds, uniqueSignersCount) {
|
|
236
|
-
if (dataFeedsIds.size === 0) {
|
|
237
|
-
return [];
|
|
238
|
-
}
|
|
239
|
-
const dataPackagesIds = Array.from(dataFeedsIds);
|
|
240
|
-
const tsStr = this.#historicalTimestampMs ? ` with historical timestamp ${this.#historicalTimestampMs}` : "";
|
|
241
|
-
this.logger?.debug(
|
|
242
|
-
`fetching redstone payloads for ${dataFeedsIds.size} data feeds in ${dataServiceId} with ${uniqueSignersCount} signers: ${dataPackagesIds.join(", ")}${tsStr}`
|
|
243
|
-
);
|
|
244
|
-
return (0, import_fetchRedstonePayloads.fetchRedstonePayloads)({
|
|
245
|
-
dataServiceId,
|
|
246
|
-
dataFeedsIds,
|
|
247
|
-
uniqueSignersCount,
|
|
248
|
-
historicalTimestampMs: this.#historicalTimestampMs,
|
|
249
|
-
gateways: this.#gateways,
|
|
250
|
-
ignoreMissingFeeds: this.#ignoreMissingFeeds,
|
|
251
|
-
enableLogging: this.#enableLogging,
|
|
252
|
-
logger: this.logger,
|
|
253
|
-
metadataTimestampMs: Number(this.sdk.timestamp) * 1e3
|
|
254
|
-
});
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
function isRedstone(pf) {
|
|
258
|
-
return pf.contractType === "PRICE_FEED::REDSTONE";
|
|
259
60
|
}
|
|
260
61
|
// Annotate the CommonJS export names for ESM import in node:
|
|
261
62
|
0 && (module.exports = {
|
|
@@ -21,135 +21,13 @@ __export(fetchRedstonePayloads_exports, {
|
|
|
21
21
|
fetchRedstonePayloads: () => fetchRedstonePayloads
|
|
22
22
|
});
|
|
23
23
|
module.exports = __toCommonJS(fetchRedstonePayloads_exports);
|
|
24
|
-
var import_evm_connector = require("@redstone-finance/evm-connector");
|
|
25
|
-
var import_protocol = require("@redstone-finance/protocol");
|
|
26
|
-
var import_sdk = require("@redstone-finance/sdk");
|
|
27
|
-
var import_utils = require("@redstone-finance/utils");
|
|
28
|
-
var import_viem = require("viem");
|
|
29
|
-
var import_utils2 = require("../../../utils/index.js");
|
|
30
24
|
async function fetchRedstonePayloads(options) {
|
|
31
|
-
const {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
uniqueSignersCount,
|
|
35
|
-
historicalTimestampMs,
|
|
36
|
-
gateways,
|
|
37
|
-
ignoreMissingFeeds,
|
|
38
|
-
enableLogging,
|
|
39
|
-
logger,
|
|
40
|
-
returnPrices
|
|
41
|
-
} = options;
|
|
42
|
-
const metadataTimestampMs = historicalTimestampMs ?? options.metadataTimestampMs;
|
|
43
|
-
const dataPackagesIds = Array.from(new Set(dataFeedsIds));
|
|
44
|
-
if (dataPackagesIds.length === 0) {
|
|
45
|
-
return [];
|
|
46
|
-
}
|
|
47
|
-
const wrapper = new import_evm_connector.DataServiceWrapper({
|
|
48
|
-
dataServiceId,
|
|
49
|
-
dataPackagesIds,
|
|
50
|
-
uniqueSignersCount,
|
|
51
|
-
authorizedSigners: (0, import_sdk.getSignersForDataServiceId)(
|
|
52
|
-
dataServiceId
|
|
53
|
-
),
|
|
54
|
-
historicalTimestamp: historicalTimestampMs,
|
|
55
|
-
urls: gateways,
|
|
56
|
-
ignoreMissingFeed: ignoreMissingFeeds,
|
|
57
|
-
enableEnhancedLogs: enableLogging
|
|
58
|
-
});
|
|
59
|
-
if (metadataTimestampMs) {
|
|
60
|
-
wrapper.setMetadataTimestamp(metadataTimestampMs);
|
|
61
|
-
}
|
|
62
|
-
const dataPayload = await (0, import_utils2.retry)(() => wrapper.prepareRedstonePayload(true), {
|
|
63
|
-
attempts: 5,
|
|
64
|
-
interval: historicalTimestampMs ? 30500 : 250
|
|
65
|
-
});
|
|
66
|
-
const parsed = import_protocol.RedstonePayload.parse((0, import_viem.toBytes)(`0x${dataPayload}`));
|
|
67
|
-
const packagesByDataFeedId = groupDataPackages(parsed.signedDataPackages);
|
|
68
|
-
const result = [];
|
|
69
|
-
for (const dataFeedId of dataFeedsIds) {
|
|
70
|
-
const signedDataPackages = packagesByDataFeedId[dataFeedId];
|
|
71
|
-
if (!signedDataPackages) {
|
|
72
|
-
if (ignoreMissingFeeds) {
|
|
73
|
-
logger?.warn(`cannot find data packages for ${dataFeedId}`);
|
|
74
|
-
continue;
|
|
75
|
-
}
|
|
76
|
-
throw new Error(`cannot find data packages for ${dataFeedId}`);
|
|
77
|
-
}
|
|
78
|
-
if (signedDataPackages.length !== uniqueSignersCount) {
|
|
79
|
-
if (ignoreMissingFeeds) {
|
|
80
|
-
logger?.warn(
|
|
81
|
-
`got ${signedDataPackages.length} data packages for ${dataFeedId}, but expected ${uniqueSignersCount}`
|
|
82
|
-
);
|
|
83
|
-
continue;
|
|
84
|
-
}
|
|
85
|
-
throw new Error(
|
|
86
|
-
`got ${signedDataPackages.length} data packages for ${dataFeedId}, but expected ${uniqueSignersCount}`
|
|
87
|
-
);
|
|
88
|
-
}
|
|
89
|
-
result.push(
|
|
90
|
-
getCalldataWithTimestamp(
|
|
91
|
-
dataFeedId,
|
|
92
|
-
signedDataPackages,
|
|
93
|
-
wrapper.getUnsignedMetadata(),
|
|
94
|
-
returnPrices
|
|
95
|
-
)
|
|
25
|
+
for (const _feed of options.dataFeedsIds) {
|
|
26
|
+
throw new Error(
|
|
27
|
+
"RedStone price updates are no longer supported by this SDK"
|
|
96
28
|
);
|
|
97
29
|
}
|
|
98
|
-
return
|
|
99
|
-
}
|
|
100
|
-
function groupDataPackages(signedDataPackages) {
|
|
101
|
-
const packagesByDataFeedId = {};
|
|
102
|
-
for (const p of signedDataPackages) {
|
|
103
|
-
const { dataPoints } = p.dataPackage;
|
|
104
|
-
const dataFeedId0 = dataPoints[0].dataFeedId;
|
|
105
|
-
for (const dp of dataPoints) {
|
|
106
|
-
if (dp.dataFeedId !== dataFeedId0) {
|
|
107
|
-
throw new Error(
|
|
108
|
-
`data package contains data points with different dataFeedIds: ${dp.dataFeedId} and ${dataFeedId0}`
|
|
109
|
-
);
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
if (!packagesByDataFeedId[dataFeedId0]) {
|
|
113
|
-
packagesByDataFeedId[dataFeedId0] = [];
|
|
114
|
-
}
|
|
115
|
-
packagesByDataFeedId[dataFeedId0].push(p);
|
|
116
|
-
}
|
|
117
|
-
return packagesByDataFeedId;
|
|
118
|
-
}
|
|
119
|
-
function getCalldataWithTimestamp(dataFeedId, packages, unsignedMetadata, returnPrices) {
|
|
120
|
-
const originalPayload = import_protocol.RedstonePayload.prepare(packages, unsignedMetadata);
|
|
121
|
-
const originalPayloadLength = originalPayload.length / 2;
|
|
122
|
-
const bytesToAdd = 32 - originalPayloadLength % 32;
|
|
123
|
-
const newUnsignedMetadata = unsignedMetadata + "_".repeat(bytesToAdd);
|
|
124
|
-
const payload = import_protocol.RedstonePayload.prepare(packages, newUnsignedMetadata);
|
|
125
|
-
let timestamp = 0;
|
|
126
|
-
for (const p of packages) {
|
|
127
|
-
const newTimestamp = p.dataPackage.timestampMilliseconds / 1e3;
|
|
128
|
-
if (timestamp === 0) {
|
|
129
|
-
timestamp = newTimestamp;
|
|
130
|
-
} else if (timestamp !== newTimestamp) {
|
|
131
|
-
throw new Error("Timestamps are not equal");
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
const base = {
|
|
135
|
-
dataFeedId,
|
|
136
|
-
data: (0, import_viem.encodeAbiParameters)(
|
|
137
|
-
[{ type: "uint256" }, { type: "bytes" }],
|
|
138
|
-
[BigInt(timestamp), `0x${payload}`]
|
|
139
|
-
),
|
|
140
|
-
timestamp,
|
|
141
|
-
cached: false
|
|
142
|
-
};
|
|
143
|
-
if (returnPrices) {
|
|
144
|
-
const prices = packages.flatMap((p) => p.dataPackage.dataPoints).map((dp) => BigInt(`0x${Buffer.from(dp.value).toString("hex")}`));
|
|
145
|
-
const medianPrice = BigInt(import_utils.MathUtils.getMedianOfBigNumbers(prices));
|
|
146
|
-
return {
|
|
147
|
-
...base,
|
|
148
|
-
price: medianPrice,
|
|
149
|
-
decimals: 8
|
|
150
|
-
};
|
|
151
|
-
}
|
|
152
|
-
return base;
|
|
30
|
+
return [];
|
|
153
31
|
}
|
|
154
32
|
// Annotate the CommonJS export names for ESM import in node:
|
|
155
33
|
0 && (module.exports = {
|
package/dist/cjs/sdk/options.js
CHANGED
|
@@ -59,7 +59,7 @@ const SDKOptions = import_v4.z.object({
|
|
|
59
59
|
*/
|
|
60
60
|
logger: import_v4.z.any(),
|
|
61
61
|
/**
|
|
62
|
-
*
|
|
62
|
+
* @deprecated RedStone options are accepted for compatibility and ignored.
|
|
63
63
|
*/
|
|
64
64
|
redstone: import_updates.RedstoneOptions.optional(),
|
|
65
65
|
/**
|
|
@@ -1,22 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
bytes32ToString,
|
|
5
|
-
RedstonePriceFeedContract
|
|
6
|
-
} from "../../../sdk/index.js";
|
|
7
|
-
async function getUpdatablePriceFeeds(args) {
|
|
8
|
-
const { sdk, client, pfCompressor, priceFeeds } = args;
|
|
9
|
-
const priceFeedCompressor = getContract({
|
|
10
|
-
address: pfCompressor,
|
|
11
|
-
abi: priceFeedCompressorAbi,
|
|
12
|
-
client
|
|
13
|
-
});
|
|
14
|
-
const updatablePriceFeeds = (await priceFeedCompressor.read.loadPriceFeedTree([
|
|
15
|
-
priceFeeds
|
|
16
|
-
])).filter(
|
|
17
|
-
(data) => bytes32ToString(data.baseParams.contractType) === "PRICE_FEED::REDSTONE"
|
|
18
|
-
).map((data) => new RedstonePriceFeedContract(sdk, data));
|
|
19
|
-
return updatablePriceFeeds;
|
|
1
|
+
async function getUpdatablePriceFeeds(_args) {
|
|
2
|
+
return [];
|
|
20
3
|
}
|
|
21
4
|
export {
|
|
22
5
|
getUpdatablePriceFeeds
|
|
@@ -174,11 +174,6 @@ class GearboxSDK extends ChainContractsRegister {
|
|
|
174
174
|
},
|
|
175
175
|
`${re}attaching gearbox sdk`
|
|
176
176
|
);
|
|
177
|
-
if (!!blockNumber && !opts.redstone?.historicTimestamp) {
|
|
178
|
-
this.logger?.warn(
|
|
179
|
-
`${re}attaching to fixed block number, but redstone historicTimestamp is not set. price updates might fail`
|
|
180
|
-
);
|
|
181
|
-
}
|
|
182
177
|
this.#attachConfig = opts;
|
|
183
178
|
const time = Date.now();
|
|
184
179
|
const block = await this.client.getBlock(
|
|
@@ -349,11 +344,6 @@ class GearboxSDK extends ChainContractsRegister {
|
|
|
349
344
|
timestamp,
|
|
350
345
|
ignoreUpdateablePrices = this.#attachConfig?.ignoreUpdateablePrices
|
|
351
346
|
} = opts ?? {};
|
|
352
|
-
if (this.#attachConfig?.redstone?.historicTimestamp) {
|
|
353
|
-
throw new Error(
|
|
354
|
-
"syncState is not supported with redstone historicTimestamp"
|
|
355
|
-
);
|
|
356
|
-
}
|
|
357
347
|
if (!blockNumber || !timestamp) {
|
|
358
348
|
const block = await this.client.getBlock({
|
|
359
349
|
blockTag: "latest"
|
|
@@ -27,7 +27,6 @@ import { MellowLRTPriceFeedContract } from "./MellowLRTPriceFeed.js";
|
|
|
27
27
|
import { PendleTWAPPTPriceFeed } from "./PendleTWAPPTPriceFeed.js";
|
|
28
28
|
import { PythPriceFeed } from "./PythPriceFeed.js";
|
|
29
29
|
import { RedstonePriceFeedContract } from "./RedstonePriceFeed.js";
|
|
30
|
-
import { RedstoneUpdater } from "./updates/index.js";
|
|
31
30
|
import { WstETHPriceFeedContract } from "./WstETHPriceFeed.js";
|
|
32
31
|
import { YearnPriceFeedContract } from "./YearnPriceFeed.js";
|
|
33
32
|
import { ZeroPriceFeedContract } from "./ZeroPriceFeed.js";
|
|
@@ -36,9 +35,9 @@ class PriceFeedRegister extends SDKConstruct {
|
|
|
36
35
|
#feeds = new AddressMap(void 0, "priceFeeds");
|
|
37
36
|
#latestUpdate;
|
|
38
37
|
updaters;
|
|
39
|
-
constructor(sdk,
|
|
38
|
+
constructor(sdk, _opts = {}) {
|
|
40
39
|
super(sdk);
|
|
41
|
-
this.updaters = [
|
|
40
|
+
this.updaters = [];
|
|
42
41
|
}
|
|
43
42
|
addHook = this.#hooks.addHook.bind(this.#hooks);
|
|
44
43
|
removeHook = this.#hooks.removeHook.bind(this.#hooks);
|
|
@@ -130,6 +129,9 @@ class PriceFeedRegister extends SDKConstruct {
|
|
|
130
129
|
* @returns
|
|
131
130
|
*/
|
|
132
131
|
async generateExternalPriceFeedsUpdateTxs(feeds, block) {
|
|
132
|
+
if (this.updaters.length === 0) {
|
|
133
|
+
return this.generatePriceFeedsUpdateTxs([]);
|
|
134
|
+
}
|
|
133
135
|
const [priceFeedCompressorAddress] = this.sdk.addressProvider.mustGetLatest(
|
|
134
136
|
AP_PRICE_FEED_COMPRESSOR,
|
|
135
137
|
VERSION_RANGE_310
|
|
@@ -184,6 +186,9 @@ class PriceFeedRegister extends SDKConstruct {
|
|
|
184
186
|
* Discovered price feeds are not saved anywhere in PriceFeedRegister, and can later be used to load price feed updates
|
|
185
187
|
*/
|
|
186
188
|
async getPartialUpdatablePriceFeeds(configurators, pools) {
|
|
189
|
+
if (this.updaters.length === 0) {
|
|
190
|
+
return [];
|
|
191
|
+
}
|
|
187
192
|
const [priceFeedCompressorAddress] = this.sdk.addressProvider.mustGetLatest(
|
|
188
193
|
AP_PRICE_FEED_COMPRESSOR,
|
|
189
194
|
VERSION_RANGE_310
|
|
@@ -13,6 +13,8 @@ class RedstonePriceFeedContract extends AbstractPriceFeedContract {
|
|
|
13
13
|
constructor(options, args) {
|
|
14
14
|
super(options, {
|
|
15
15
|
...args,
|
|
16
|
+
// RedStone updates are no longer pushed by the SDK.
|
|
17
|
+
updatable: false,
|
|
16
18
|
name: "RedstonePriceFeed",
|
|
17
19
|
abi: redstonePriceFeedAbi
|
|
18
20
|
});
|
|
@@ -1,12 +1,5 @@
|
|
|
1
1
|
import { z } from "zod/v4";
|
|
2
2
|
import { SDKConstruct } from "../../../base/index.js";
|
|
3
|
-
import { AddressMap } from "../../../utils/index.js";
|
|
4
|
-
import { fetchRedstonePayloads } from "./fetchRedstonePayloads.js";
|
|
5
|
-
import { PriceUpdatesCache } from "./PriceUpdatesCache.js";
|
|
6
|
-
import { PriceUpdateTx } from "./PriceUpdateTx.js";
|
|
7
|
-
class RedstoneUpdateTx extends PriceUpdateTx {
|
|
8
|
-
name = "redstone";
|
|
9
|
-
}
|
|
10
3
|
const RedstoneOptions = z.object({
|
|
11
4
|
/**
|
|
12
5
|
* Fixed redstone historic timestamp in ms
|
|
@@ -34,204 +27,12 @@ const RedstoneOptions = z.object({
|
|
|
34
27
|
enableLogging: z.boolean().optional()
|
|
35
28
|
});
|
|
36
29
|
class RedstoneUpdater extends SDKConstruct {
|
|
37
|
-
|
|
38
|
-
#historicalTimestampMs;
|
|
39
|
-
#gateways;
|
|
40
|
-
#ignoreMissingFeeds;
|
|
41
|
-
#enableLogging;
|
|
42
|
-
constructor(sdk, opts = {}) {
|
|
30
|
+
constructor(sdk, _opts = {}) {
|
|
43
31
|
super(sdk);
|
|
44
|
-
this.#ignoreMissingFeeds = opts.ignoreMissingFeeds;
|
|
45
|
-
this.#enableLogging = opts.enableLogging;
|
|
46
|
-
this.#gateways = opts.gateways?.length ? opts.gateways : void 0;
|
|
47
|
-
let ts = opts.historicTimestamp;
|
|
48
|
-
if (ts) {
|
|
49
|
-
ts = ts === true ? Number(this.sdk.timestamp) * 1e3 : ts;
|
|
50
|
-
this.#historicalTimestampMs = 6e4 * Math.floor(ts / 6e4);
|
|
51
|
-
this.logger?.debug(
|
|
52
|
-
`using historical timestamp ${this.#historicalTimestampMs}`
|
|
53
|
-
);
|
|
54
|
-
}
|
|
55
|
-
this.#cache = PriceUpdatesCache.get("redstone", {
|
|
56
|
-
// currently staleness period is 240 seconds on all networks, add some buffer
|
|
57
|
-
// this period of 4 minutes is selected based on time that is required for user to sign transaction with wallet
|
|
58
|
-
// so it's unlikely to decrease
|
|
59
|
-
ttl: opts.cacheTTL ?? 225 * 1e3,
|
|
60
|
-
historical: !!ts
|
|
61
|
-
});
|
|
62
|
-
}
|
|
63
|
-
async getUpdateTxs(feeds) {
|
|
64
|
-
if (feeds.length === 0) {
|
|
65
|
-
return [];
|
|
66
|
-
}
|
|
67
|
-
this.logger?.debug(
|
|
68
|
-
`generating update transactions for ${feeds.length} redstone price feeds`
|
|
69
|
-
);
|
|
70
|
-
const groupedFeeds = {};
|
|
71
|
-
const priceFeeds = /* @__PURE__ */ new Map();
|
|
72
|
-
for (const feed of feeds) {
|
|
73
|
-
if (!isRedstone(feed)) {
|
|
74
|
-
continue;
|
|
75
|
-
}
|
|
76
|
-
const key = `${feed.dataServiceId}:${feed.signersThreshold}`;
|
|
77
|
-
if (!groupedFeeds[key]) {
|
|
78
|
-
groupedFeeds[key] = /* @__PURE__ */ new Set();
|
|
79
|
-
}
|
|
80
|
-
groupedFeeds[key].add(feed.dataId);
|
|
81
|
-
const pfsForDataId = priceFeeds.get(feed.dataId) ?? new AddressMap();
|
|
82
|
-
pfsForDataId.upsert(feed.address, feed);
|
|
83
|
-
priceFeeds.set(feed.dataId, pfsForDataId);
|
|
84
|
-
}
|
|
85
|
-
const results = [];
|
|
86
|
-
let [minTimestamp, maxTimestamp] = [Number.POSITIVE_INFINITY, 0];
|
|
87
|
-
for (const [key, group] of Object.entries(groupedFeeds)) {
|
|
88
|
-
const [dataServiceId, signersStr] = key.split(":");
|
|
89
|
-
const uniqueSignersCount = parseInt(signersStr, 10);
|
|
90
|
-
const payloads = await this.#safeGetPayloads(
|
|
91
|
-
dataServiceId,
|
|
92
|
-
group,
|
|
93
|
-
uniqueSignersCount
|
|
94
|
-
);
|
|
95
|
-
for (const { dataFeedId, data, timestamp, cached } of payloads) {
|
|
96
|
-
const pfsForDataId = priceFeeds.get(dataFeedId);
|
|
97
|
-
if (!pfsForDataId) {
|
|
98
|
-
throw new Error(`cannot get price feed addresses for ${dataFeedId}`);
|
|
99
|
-
}
|
|
100
|
-
for (const priceFeed of pfsForDataId.values()) {
|
|
101
|
-
minTimestamp = Math.min(minTimestamp, timestamp);
|
|
102
|
-
maxTimestamp = Math.max(maxTimestamp, timestamp);
|
|
103
|
-
results.push(
|
|
104
|
-
new RedstoneUpdateTx(priceFeed.createPriceUpdateTx(data), {
|
|
105
|
-
dataFeedId,
|
|
106
|
-
dataServiceId,
|
|
107
|
-
priceFeed: priceFeed.address,
|
|
108
|
-
timestamp,
|
|
109
|
-
cached
|
|
110
|
-
})
|
|
111
|
-
);
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
let tsRange = "";
|
|
116
|
-
if (results.length) {
|
|
117
|
-
const minDelta = BigInt(minTimestamp) - this.sdk.timestamp;
|
|
118
|
-
tsRange = `, timestamps ${minTimestamp} (${minDelta})`;
|
|
119
|
-
if (minTimestamp !== maxTimestamp) {
|
|
120
|
-
const maxDelta = BigInt(maxTimestamp) - this.sdk.timestamp;
|
|
121
|
-
tsRange = `${tsRange} - ${maxTimestamp} (${maxDelta})`;
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
this.logger?.debug(
|
|
125
|
-
`generated ${results.length} update transactions for redstone price feeds: ${Array.from(priceFeeds.keys()).join(", ")}${tsRange}`
|
|
126
|
-
);
|
|
127
|
-
return results;
|
|
128
32
|
}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
* @param dataServiceId
|
|
132
|
-
* @param dataFeedsIds
|
|
133
|
-
* @param uniqueSignersCount
|
|
134
|
-
* @returns
|
|
135
|
-
*/
|
|
136
|
-
async #safeGetPayloads(dataServiceId, dataFeedsIds, uniqueSignersCount) {
|
|
137
|
-
let result = await this.#getPayloads(
|
|
138
|
-
dataServiceId,
|
|
139
|
-
dataFeedsIds,
|
|
140
|
-
uniqueSignersCount
|
|
141
|
-
);
|
|
142
|
-
if (this.#historicalTimestampMs) {
|
|
143
|
-
return result;
|
|
144
|
-
}
|
|
145
|
-
let expired = false;
|
|
146
|
-
for (const { timestamp, dataFeedId } of result) {
|
|
147
|
-
const delta = Number(this.sdk.timestamp) - timestamp;
|
|
148
|
-
if (delta >= 240 && delta < 255) {
|
|
149
|
-
this.logger?.warn(
|
|
150
|
-
`payload for ${dataFeedId} has expired by ${delta} seconds`
|
|
151
|
-
);
|
|
152
|
-
expired = true;
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
if (expired) {
|
|
156
|
-
result = await this.#getPayloads(
|
|
157
|
-
dataServiceId,
|
|
158
|
-
dataFeedsIds,
|
|
159
|
-
uniqueSignersCount
|
|
160
|
-
);
|
|
161
|
-
}
|
|
162
|
-
return result;
|
|
33
|
+
async getUpdateTxs(_feeds) {
|
|
34
|
+
return [];
|
|
163
35
|
}
|
|
164
|
-
/**
|
|
165
|
-
* Gets redstone payloads in one request for multiple feeds with the same dataServiceId and uniqueSignersCount
|
|
166
|
-
* If historicalTimestamp is set, responses will be cached
|
|
167
|
-
* @param dataServiceId
|
|
168
|
-
* @param dataFeedsIds
|
|
169
|
-
* @param uniqueSignersCount
|
|
170
|
-
* @returns
|
|
171
|
-
*/
|
|
172
|
-
async #getPayloads(dataServiceId, dataFeedsIds, uniqueSignersCount) {
|
|
173
|
-
this.logger?.debug(
|
|
174
|
-
`getting redstone payloads for ${dataFeedsIds.size} data feeds in ${dataServiceId} with ${uniqueSignersCount} signers: ${Array.from(dataFeedsIds).join(", ")}`
|
|
175
|
-
);
|
|
176
|
-
const fromCache = [];
|
|
177
|
-
const uncached = [];
|
|
178
|
-
for (const dataFeedId of dataFeedsIds) {
|
|
179
|
-
const cached = this.#cache.get(
|
|
180
|
-
dataServiceId,
|
|
181
|
-
dataFeedId,
|
|
182
|
-
uniqueSignersCount
|
|
183
|
-
);
|
|
184
|
-
if (cached) {
|
|
185
|
-
fromCache.push({ ...cached, cached: true });
|
|
186
|
-
} else {
|
|
187
|
-
uncached.push(dataFeedId);
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
const fromRedstone = await this.#fetchPayloads(
|
|
191
|
-
dataServiceId,
|
|
192
|
-
new Set(uncached),
|
|
193
|
-
uniqueSignersCount
|
|
194
|
-
);
|
|
195
|
-
for (const resp of fromRedstone) {
|
|
196
|
-
this.#cache.set(resp, dataServiceId, resp.dataFeedId, uniqueSignersCount);
|
|
197
|
-
}
|
|
198
|
-
this.logger?.debug(
|
|
199
|
-
`got ${fromRedstone.length} new redstone updates and ${fromCache.length} from cache`
|
|
200
|
-
);
|
|
201
|
-
return [...fromCache, ...fromRedstone];
|
|
202
|
-
}
|
|
203
|
-
/**
|
|
204
|
-
* Fetches redstone payloads in one request for multiple feeds with the same dataServiceId and uniqueSignersCount
|
|
205
|
-
* Payloads are loaded in one request to avoid redstone rate limit
|
|
206
|
-
* @param dataServiceId
|
|
207
|
-
* @param dataFeedsIds
|
|
208
|
-
* @param uniqueSignersCount
|
|
209
|
-
* @returns
|
|
210
|
-
*/
|
|
211
|
-
async #fetchPayloads(dataServiceId, dataFeedsIds, uniqueSignersCount) {
|
|
212
|
-
if (dataFeedsIds.size === 0) {
|
|
213
|
-
return [];
|
|
214
|
-
}
|
|
215
|
-
const dataPackagesIds = Array.from(dataFeedsIds);
|
|
216
|
-
const tsStr = this.#historicalTimestampMs ? ` with historical timestamp ${this.#historicalTimestampMs}` : "";
|
|
217
|
-
this.logger?.debug(
|
|
218
|
-
`fetching redstone payloads for ${dataFeedsIds.size} data feeds in ${dataServiceId} with ${uniqueSignersCount} signers: ${dataPackagesIds.join(", ")}${tsStr}`
|
|
219
|
-
);
|
|
220
|
-
return fetchRedstonePayloads({
|
|
221
|
-
dataServiceId,
|
|
222
|
-
dataFeedsIds,
|
|
223
|
-
uniqueSignersCount,
|
|
224
|
-
historicalTimestampMs: this.#historicalTimestampMs,
|
|
225
|
-
gateways: this.#gateways,
|
|
226
|
-
ignoreMissingFeeds: this.#ignoreMissingFeeds,
|
|
227
|
-
enableLogging: this.#enableLogging,
|
|
228
|
-
logger: this.logger,
|
|
229
|
-
metadataTimestampMs: Number(this.sdk.timestamp) * 1e3
|
|
230
|
-
});
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
function isRedstone(pf) {
|
|
234
|
-
return pf.contractType === "PRICE_FEED::REDSTONE";
|
|
235
36
|
}
|
|
236
37
|
export {
|
|
237
38
|
RedstoneOptions,
|
|
@@ -1,136 +1,10 @@
|
|
|
1
|
-
import { DataServiceWrapper } from "@redstone-finance/evm-connector";
|
|
2
|
-
import {
|
|
3
|
-
RedstonePayload
|
|
4
|
-
} from "@redstone-finance/protocol";
|
|
5
|
-
import {
|
|
6
|
-
getSignersForDataServiceId
|
|
7
|
-
} from "@redstone-finance/sdk";
|
|
8
|
-
import { MathUtils } from "@redstone-finance/utils";
|
|
9
|
-
import { encodeAbiParameters, toBytes } from "viem";
|
|
10
|
-
import { retry } from "../../../utils/index.js";
|
|
11
1
|
async function fetchRedstonePayloads(options) {
|
|
12
|
-
const {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
uniqueSignersCount,
|
|
16
|
-
historicalTimestampMs,
|
|
17
|
-
gateways,
|
|
18
|
-
ignoreMissingFeeds,
|
|
19
|
-
enableLogging,
|
|
20
|
-
logger,
|
|
21
|
-
returnPrices
|
|
22
|
-
} = options;
|
|
23
|
-
const metadataTimestampMs = historicalTimestampMs ?? options.metadataTimestampMs;
|
|
24
|
-
const dataPackagesIds = Array.from(new Set(dataFeedsIds));
|
|
25
|
-
if (dataPackagesIds.length === 0) {
|
|
26
|
-
return [];
|
|
27
|
-
}
|
|
28
|
-
const wrapper = new DataServiceWrapper({
|
|
29
|
-
dataServiceId,
|
|
30
|
-
dataPackagesIds,
|
|
31
|
-
uniqueSignersCount,
|
|
32
|
-
authorizedSigners: getSignersForDataServiceId(
|
|
33
|
-
dataServiceId
|
|
34
|
-
),
|
|
35
|
-
historicalTimestamp: historicalTimestampMs,
|
|
36
|
-
urls: gateways,
|
|
37
|
-
ignoreMissingFeed: ignoreMissingFeeds,
|
|
38
|
-
enableEnhancedLogs: enableLogging
|
|
39
|
-
});
|
|
40
|
-
if (metadataTimestampMs) {
|
|
41
|
-
wrapper.setMetadataTimestamp(metadataTimestampMs);
|
|
42
|
-
}
|
|
43
|
-
const dataPayload = await retry(() => wrapper.prepareRedstonePayload(true), {
|
|
44
|
-
attempts: 5,
|
|
45
|
-
interval: historicalTimestampMs ? 30500 : 250
|
|
46
|
-
});
|
|
47
|
-
const parsed = RedstonePayload.parse(toBytes(`0x${dataPayload}`));
|
|
48
|
-
const packagesByDataFeedId = groupDataPackages(parsed.signedDataPackages);
|
|
49
|
-
const result = [];
|
|
50
|
-
for (const dataFeedId of dataFeedsIds) {
|
|
51
|
-
const signedDataPackages = packagesByDataFeedId[dataFeedId];
|
|
52
|
-
if (!signedDataPackages) {
|
|
53
|
-
if (ignoreMissingFeeds) {
|
|
54
|
-
logger?.warn(`cannot find data packages for ${dataFeedId}`);
|
|
55
|
-
continue;
|
|
56
|
-
}
|
|
57
|
-
throw new Error(`cannot find data packages for ${dataFeedId}`);
|
|
58
|
-
}
|
|
59
|
-
if (signedDataPackages.length !== uniqueSignersCount) {
|
|
60
|
-
if (ignoreMissingFeeds) {
|
|
61
|
-
logger?.warn(
|
|
62
|
-
`got ${signedDataPackages.length} data packages for ${dataFeedId}, but expected ${uniqueSignersCount}`
|
|
63
|
-
);
|
|
64
|
-
continue;
|
|
65
|
-
}
|
|
66
|
-
throw new Error(
|
|
67
|
-
`got ${signedDataPackages.length} data packages for ${dataFeedId}, but expected ${uniqueSignersCount}`
|
|
68
|
-
);
|
|
69
|
-
}
|
|
70
|
-
result.push(
|
|
71
|
-
getCalldataWithTimestamp(
|
|
72
|
-
dataFeedId,
|
|
73
|
-
signedDataPackages,
|
|
74
|
-
wrapper.getUnsignedMetadata(),
|
|
75
|
-
returnPrices
|
|
76
|
-
)
|
|
2
|
+
for (const _feed of options.dataFeedsIds) {
|
|
3
|
+
throw new Error(
|
|
4
|
+
"RedStone price updates are no longer supported by this SDK"
|
|
77
5
|
);
|
|
78
6
|
}
|
|
79
|
-
return
|
|
80
|
-
}
|
|
81
|
-
function groupDataPackages(signedDataPackages) {
|
|
82
|
-
const packagesByDataFeedId = {};
|
|
83
|
-
for (const p of signedDataPackages) {
|
|
84
|
-
const { dataPoints } = p.dataPackage;
|
|
85
|
-
const dataFeedId0 = dataPoints[0].dataFeedId;
|
|
86
|
-
for (const dp of dataPoints) {
|
|
87
|
-
if (dp.dataFeedId !== dataFeedId0) {
|
|
88
|
-
throw new Error(
|
|
89
|
-
`data package contains data points with different dataFeedIds: ${dp.dataFeedId} and ${dataFeedId0}`
|
|
90
|
-
);
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
if (!packagesByDataFeedId[dataFeedId0]) {
|
|
94
|
-
packagesByDataFeedId[dataFeedId0] = [];
|
|
95
|
-
}
|
|
96
|
-
packagesByDataFeedId[dataFeedId0].push(p);
|
|
97
|
-
}
|
|
98
|
-
return packagesByDataFeedId;
|
|
99
|
-
}
|
|
100
|
-
function getCalldataWithTimestamp(dataFeedId, packages, unsignedMetadata, returnPrices) {
|
|
101
|
-
const originalPayload = RedstonePayload.prepare(packages, unsignedMetadata);
|
|
102
|
-
const originalPayloadLength = originalPayload.length / 2;
|
|
103
|
-
const bytesToAdd = 32 - originalPayloadLength % 32;
|
|
104
|
-
const newUnsignedMetadata = unsignedMetadata + "_".repeat(bytesToAdd);
|
|
105
|
-
const payload = RedstonePayload.prepare(packages, newUnsignedMetadata);
|
|
106
|
-
let timestamp = 0;
|
|
107
|
-
for (const p of packages) {
|
|
108
|
-
const newTimestamp = p.dataPackage.timestampMilliseconds / 1e3;
|
|
109
|
-
if (timestamp === 0) {
|
|
110
|
-
timestamp = newTimestamp;
|
|
111
|
-
} else if (timestamp !== newTimestamp) {
|
|
112
|
-
throw new Error("Timestamps are not equal");
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
const base = {
|
|
116
|
-
dataFeedId,
|
|
117
|
-
data: encodeAbiParameters(
|
|
118
|
-
[{ type: "uint256" }, { type: "bytes" }],
|
|
119
|
-
[BigInt(timestamp), `0x${payload}`]
|
|
120
|
-
),
|
|
121
|
-
timestamp,
|
|
122
|
-
cached: false
|
|
123
|
-
};
|
|
124
|
-
if (returnPrices) {
|
|
125
|
-
const prices = packages.flatMap((p) => p.dataPackage.dataPoints).map((dp) => BigInt(`0x${Buffer.from(dp.value).toString("hex")}`));
|
|
126
|
-
const medianPrice = BigInt(MathUtils.getMedianOfBigNumbers(prices));
|
|
127
|
-
return {
|
|
128
|
-
...base,
|
|
129
|
-
price: medianPrice,
|
|
130
|
-
decimals: 8
|
|
131
|
-
};
|
|
132
|
-
}
|
|
133
|
-
return base;
|
|
7
|
+
return [];
|
|
134
8
|
}
|
|
135
9
|
export {
|
|
136
10
|
fetchRedstonePayloads
|
package/dist/esm/sdk/options.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
1
|
+
import type { Address, PublicClient } from "viem";
|
|
2
|
+
import type { GearboxSDK, IPriceFeedContract } from "../../../sdk/index.js";
|
|
3
|
+
/** @deprecated Support for updatable price feeds is disabled. */
|
|
4
|
+
export declare function getUpdatablePriceFeeds(_args: {
|
|
4
5
|
sdk: GearboxSDK;
|
|
5
6
|
client: PublicClient;
|
|
6
7
|
pfCompressor: Address;
|
|
@@ -28,7 +28,7 @@ export interface LatestUpdate {
|
|
|
28
28
|
export declare class PriceFeedRegister extends SDKConstruct implements IHooks<PriceFeedRegisterHooks> {
|
|
29
29
|
#private;
|
|
30
30
|
readonly updaters: IPriceUpdater[];
|
|
31
|
-
constructor(sdk: GearboxSDK,
|
|
31
|
+
constructor(sdk: GearboxSDK, _opts?: PriceFeedRegisterOptions);
|
|
32
32
|
addHook: <K extends "updatesGenerated">(hookName: K, fn: (...args: PriceFeedRegisterHooks[K]) => void | Promise<void>) => void;
|
|
33
33
|
removeHook: <K extends "updatesGenerated">(hookName: K, fn: (...args: PriceFeedRegisterHooks[K]) => void | Promise<void>) => void;
|
|
34
34
|
/**
|
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
import { z } from "zod/v4";
|
|
2
2
|
import { SDKConstruct } from "../../../base/index.js";
|
|
3
3
|
import type { GearboxSDK } from "../../../GearboxSDK.js";
|
|
4
|
+
import type { IPriceUpdateTx } from "../../../types/index.js";
|
|
4
5
|
import type { IPriceFeedContract } from "../types.js";
|
|
5
|
-
import { PriceUpdateTx } from "./PriceUpdateTx.js";
|
|
6
6
|
import type { IPriceUpdater, IPriceUpdateTask } from "./types.js";
|
|
7
7
|
interface RedstoneUpdateTask extends IPriceUpdateTask {
|
|
8
8
|
dataServiceId: string;
|
|
9
9
|
}
|
|
10
|
-
|
|
11
|
-
readonly name = "redstone";
|
|
12
|
-
}
|
|
10
|
+
/** @deprecated RedStone options are accepted for compatibility and ignored. */
|
|
13
11
|
export declare const RedstoneOptions: z.ZodObject<{
|
|
14
12
|
historicTimestamp: z.ZodOptional<z.ZodUnion<readonly [z.ZodNumber, z.ZodLiteral<true>]>>;
|
|
15
13
|
gateways: z.ZodOptional<z.ZodArray<z.ZodURL>>;
|
|
@@ -18,12 +16,9 @@ export declare const RedstoneOptions: z.ZodObject<{
|
|
|
18
16
|
enableLogging: z.ZodOptional<z.ZodBoolean>;
|
|
19
17
|
}, z.core.$strip>;
|
|
20
18
|
export type RedstoneOptions = z.infer<typeof RedstoneOptions>;
|
|
21
|
-
/**
|
|
22
|
-
* Class to update multiple redstone price feeds at once
|
|
23
|
-
*/
|
|
19
|
+
/** @deprecated RedStone updates are no longer supported. */
|
|
24
20
|
export declare class RedstoneUpdater extends SDKConstruct implements IPriceUpdater<RedstoneUpdateTask> {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
getUpdateTxs(feeds: IPriceFeedContract[]): Promise<RedstoneUpdateTx[]>;
|
|
21
|
+
constructor(sdk: GearboxSDK, _opts?: RedstoneOptions);
|
|
22
|
+
getUpdateTxs(_feeds: IPriceFeedContract[]): Promise<IPriceUpdateTx<RedstoneUpdateTask>[]>;
|
|
28
23
|
}
|
|
29
24
|
export {};
|
|
@@ -45,15 +45,11 @@ export interface FetchRedstonePayloadsOptions {
|
|
|
45
45
|
*/
|
|
46
46
|
returnPrices?: boolean;
|
|
47
47
|
}
|
|
48
|
-
/**
|
|
49
|
-
* Fetches redstone payloads with price data
|
|
50
|
-
*/
|
|
48
|
+
/** @deprecated RedStone payload fetching is no longer supported. */
|
|
51
49
|
export declare function fetchRedstonePayloads(options: FetchRedstonePayloadsOptions & {
|
|
52
50
|
returnPrices: true;
|
|
53
51
|
}): Promise<TimestampedCalldataWithPrice[]>;
|
|
54
|
-
/**
|
|
55
|
-
* Fetches redstone payloads
|
|
56
|
-
*/
|
|
52
|
+
/** @deprecated RedStone payload fetching is no longer supported. */
|
|
57
53
|
export declare function fetchRedstonePayloads(options: FetchRedstonePayloadsOptions & {
|
|
58
54
|
returnPrices?: false;
|
|
59
55
|
}): Promise<TimestampedCalldata[]>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gearbox-protocol/sdk",
|
|
3
|
-
"version": "12.10.
|
|
3
|
+
"version": "12.10.1",
|
|
4
4
|
"description": "Gearbox SDK",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -61,10 +61,6 @@
|
|
|
61
61
|
},
|
|
62
62
|
"dependencies": {
|
|
63
63
|
"@gearbox-protocol/integrations-v3": "1.54.2",
|
|
64
|
-
"@redstone-finance/evm-connector": "^0.9.0",
|
|
65
|
-
"@redstone-finance/protocol": "^0.9.0",
|
|
66
|
-
"@redstone-finance/sdk": "^0.9.0",
|
|
67
|
-
"@redstone-finance/utils": "^0.9.0",
|
|
68
64
|
"@types/bn.js": "^5.2.0",
|
|
69
65
|
"abitype": "^1.2.3",
|
|
70
66
|
"bn.js": "^5.2.3",
|
|
@@ -105,5 +101,5 @@
|
|
|
105
101
|
"biome check --no-errors-on-unmatched --write"
|
|
106
102
|
]
|
|
107
103
|
},
|
|
108
|
-
"packageManager": "
|
|
104
|
+
"packageManager": "pnpm@12.3.1"
|
|
109
105
|
}
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __defProp = Object.defineProperty;
|
|
3
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
-
var __export = (target, all) => {
|
|
7
|
-
for (var name in all)
|
|
8
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
-
};
|
|
10
|
-
var __copyProps = (to, from, except, desc) => {
|
|
11
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
-
for (let key of __getOwnPropNames(from))
|
|
13
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
-
}
|
|
16
|
-
return to;
|
|
17
|
-
};
|
|
18
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
-
var PriceUpdateTx_exports = {};
|
|
20
|
-
__export(PriceUpdateTx_exports, {
|
|
21
|
-
PriceUpdateTx: () => PriceUpdateTx
|
|
22
|
-
});
|
|
23
|
-
module.exports = __toCommonJS(PriceUpdateTx_exports);
|
|
24
|
-
const MAX_DATA_TIMESTAMP_DELAY_SECONDS = 10n * 60n;
|
|
25
|
-
const MAX_DATA_TIMESTAMP_AHEAD_SECONDS = 60n;
|
|
26
|
-
class PriceUpdateTx {
|
|
27
|
-
/**
|
|
28
|
-
* raw tx with encoded `priceFeed.updatePrice` call
|
|
29
|
-
*/
|
|
30
|
-
raw;
|
|
31
|
-
data;
|
|
32
|
-
constructor(raw, data) {
|
|
33
|
-
this.raw = raw;
|
|
34
|
-
this.data = data;
|
|
35
|
-
}
|
|
36
|
-
get pretty() {
|
|
37
|
-
const cached = this.data.cached ? " (cached)" : "";
|
|
38
|
-
return `${this.name} feed ${this.data.dataFeedId} at ${this.data.priceFeed} with timestamp ${this.data.timestamp}${cached}`;
|
|
39
|
-
}
|
|
40
|
-
validateTimestamp(blockTimestamp) {
|
|
41
|
-
const { timestamp: expectedPayloadTimestamp } = this.data;
|
|
42
|
-
if (blockTimestamp < expectedPayloadTimestamp) {
|
|
43
|
-
if (BigInt(expectedPayloadTimestamp) - blockTimestamp > MAX_DATA_TIMESTAMP_AHEAD_SECONDS) {
|
|
44
|
-
return "in future";
|
|
45
|
-
}
|
|
46
|
-
} else if (blockTimestamp - BigInt(expectedPayloadTimestamp) > MAX_DATA_TIMESTAMP_DELAY_SECONDS) {
|
|
47
|
-
return "too old";
|
|
48
|
-
}
|
|
49
|
-
return "valid";
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
// Annotate the CommonJS export names for ESM import in node:
|
|
53
|
-
0 && (module.exports = {
|
|
54
|
-
PriceUpdateTx
|
|
55
|
-
});
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __defProp = Object.defineProperty;
|
|
3
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
-
var __export = (target, all) => {
|
|
7
|
-
for (var name in all)
|
|
8
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
-
};
|
|
10
|
-
var __copyProps = (to, from, except, desc) => {
|
|
11
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
-
for (let key of __getOwnPropNames(from))
|
|
13
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
-
}
|
|
16
|
-
return to;
|
|
17
|
-
};
|
|
18
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
-
var PriceUpdatesCache_exports = {};
|
|
20
|
-
__export(PriceUpdatesCache_exports, {
|
|
21
|
-
PriceUpdatesCache: () => PriceUpdatesCache
|
|
22
|
-
});
|
|
23
|
-
module.exports = __toCommonJS(PriceUpdatesCache_exports);
|
|
24
|
-
class PriceUpdatesCache {
|
|
25
|
-
static #caches = /* @__PURE__ */ new Map();
|
|
26
|
-
/**
|
|
27
|
-
* Price update caches can be shared across networks
|
|
28
|
-
* @param id - unique key to identify the cache
|
|
29
|
-
* @param opts
|
|
30
|
-
* @returns
|
|
31
|
-
*/
|
|
32
|
-
static get(id, opts) {
|
|
33
|
-
const key = `${id}:${opts.historical ? "historical" : "latest"}:${opts.ttl}`;
|
|
34
|
-
const cache = PriceUpdatesCache.#caches.get(key);
|
|
35
|
-
if (cache) {
|
|
36
|
-
return cache;
|
|
37
|
-
}
|
|
38
|
-
const newCache = new PriceUpdatesCache(opts);
|
|
39
|
-
PriceUpdatesCache.#caches.set(key, newCache);
|
|
40
|
-
return newCache;
|
|
41
|
-
}
|
|
42
|
-
#cache = /* @__PURE__ */ new Map();
|
|
43
|
-
#ttlMs;
|
|
44
|
-
#historical;
|
|
45
|
-
constructor(opts) {
|
|
46
|
-
this.#ttlMs = opts.ttl;
|
|
47
|
-
this.#historical = opts.historical;
|
|
48
|
-
}
|
|
49
|
-
get(...path) {
|
|
50
|
-
const key = this.#cacheKey(...path);
|
|
51
|
-
const data = this.#cache.get(key);
|
|
52
|
-
if (!data) {
|
|
53
|
-
return void 0;
|
|
54
|
-
}
|
|
55
|
-
if (this.#expired(data)) {
|
|
56
|
-
this.#cache.delete(key);
|
|
57
|
-
return void 0;
|
|
58
|
-
}
|
|
59
|
-
return data;
|
|
60
|
-
}
|
|
61
|
-
set(value, ...path) {
|
|
62
|
-
const key = this.#cacheKey(...path);
|
|
63
|
-
this.#cache.set(key, value);
|
|
64
|
-
}
|
|
65
|
-
#expired(value) {
|
|
66
|
-
if (this.#historical) {
|
|
67
|
-
return false;
|
|
68
|
-
}
|
|
69
|
-
return value.timestamp * 1e3 + this.#ttlMs < Date.now();
|
|
70
|
-
}
|
|
71
|
-
#cacheKey(...path) {
|
|
72
|
-
return path.join(":");
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
// Annotate the CommonJS export names for ESM import in node:
|
|
76
|
-
0 && (module.exports = {
|
|
77
|
-
PriceUpdatesCache
|
|
78
|
-
});
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
const MAX_DATA_TIMESTAMP_DELAY_SECONDS = 10n * 60n;
|
|
2
|
-
const MAX_DATA_TIMESTAMP_AHEAD_SECONDS = 60n;
|
|
3
|
-
class PriceUpdateTx {
|
|
4
|
-
/**
|
|
5
|
-
* raw tx with encoded `priceFeed.updatePrice` call
|
|
6
|
-
*/
|
|
7
|
-
raw;
|
|
8
|
-
data;
|
|
9
|
-
constructor(raw, data) {
|
|
10
|
-
this.raw = raw;
|
|
11
|
-
this.data = data;
|
|
12
|
-
}
|
|
13
|
-
get pretty() {
|
|
14
|
-
const cached = this.data.cached ? " (cached)" : "";
|
|
15
|
-
return `${this.name} feed ${this.data.dataFeedId} at ${this.data.priceFeed} with timestamp ${this.data.timestamp}${cached}`;
|
|
16
|
-
}
|
|
17
|
-
validateTimestamp(blockTimestamp) {
|
|
18
|
-
const { timestamp: expectedPayloadTimestamp } = this.data;
|
|
19
|
-
if (blockTimestamp < expectedPayloadTimestamp) {
|
|
20
|
-
if (BigInt(expectedPayloadTimestamp) - blockTimestamp > MAX_DATA_TIMESTAMP_AHEAD_SECONDS) {
|
|
21
|
-
return "in future";
|
|
22
|
-
}
|
|
23
|
-
} else if (blockTimestamp - BigInt(expectedPayloadTimestamp) > MAX_DATA_TIMESTAMP_DELAY_SECONDS) {
|
|
24
|
-
return "too old";
|
|
25
|
-
}
|
|
26
|
-
return "valid";
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
export {
|
|
30
|
-
PriceUpdateTx
|
|
31
|
-
};
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
class PriceUpdatesCache {
|
|
2
|
-
static #caches = /* @__PURE__ */ new Map();
|
|
3
|
-
/**
|
|
4
|
-
* Price update caches can be shared across networks
|
|
5
|
-
* @param id - unique key to identify the cache
|
|
6
|
-
* @param opts
|
|
7
|
-
* @returns
|
|
8
|
-
*/
|
|
9
|
-
static get(id, opts) {
|
|
10
|
-
const key = `${id}:${opts.historical ? "historical" : "latest"}:${opts.ttl}`;
|
|
11
|
-
const cache = PriceUpdatesCache.#caches.get(key);
|
|
12
|
-
if (cache) {
|
|
13
|
-
return cache;
|
|
14
|
-
}
|
|
15
|
-
const newCache = new PriceUpdatesCache(opts);
|
|
16
|
-
PriceUpdatesCache.#caches.set(key, newCache);
|
|
17
|
-
return newCache;
|
|
18
|
-
}
|
|
19
|
-
#cache = /* @__PURE__ */ new Map();
|
|
20
|
-
#ttlMs;
|
|
21
|
-
#historical;
|
|
22
|
-
constructor(opts) {
|
|
23
|
-
this.#ttlMs = opts.ttl;
|
|
24
|
-
this.#historical = opts.historical;
|
|
25
|
-
}
|
|
26
|
-
get(...path) {
|
|
27
|
-
const key = this.#cacheKey(...path);
|
|
28
|
-
const data = this.#cache.get(key);
|
|
29
|
-
if (!data) {
|
|
30
|
-
return void 0;
|
|
31
|
-
}
|
|
32
|
-
if (this.#expired(data)) {
|
|
33
|
-
this.#cache.delete(key);
|
|
34
|
-
return void 0;
|
|
35
|
-
}
|
|
36
|
-
return data;
|
|
37
|
-
}
|
|
38
|
-
set(value, ...path) {
|
|
39
|
-
const key = this.#cacheKey(...path);
|
|
40
|
-
this.#cache.set(key, value);
|
|
41
|
-
}
|
|
42
|
-
#expired(value) {
|
|
43
|
-
if (this.#historical) {
|
|
44
|
-
return false;
|
|
45
|
-
}
|
|
46
|
-
return value.timestamp * 1e3 + this.#ttlMs < Date.now();
|
|
47
|
-
}
|
|
48
|
-
#cacheKey(...path) {
|
|
49
|
-
return path.join(":");
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
export {
|
|
53
|
-
PriceUpdatesCache
|
|
54
|
-
};
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import type { IPriceUpdateTx, RawTx } from "../../../types/index.js";
|
|
2
|
-
import type { IPriceUpdateTask } from "./types.js";
|
|
3
|
-
export declare abstract class PriceUpdateTx<T extends IPriceUpdateTask = IPriceUpdateTask> implements IPriceUpdateTx<T> {
|
|
4
|
-
/**
|
|
5
|
-
* raw tx with encoded `priceFeed.updatePrice` call
|
|
6
|
-
*/
|
|
7
|
-
readonly raw: RawTx;
|
|
8
|
-
readonly data: T;
|
|
9
|
-
abstract readonly name: string;
|
|
10
|
-
constructor(raw: RawTx, data: T);
|
|
11
|
-
get pretty(): string;
|
|
12
|
-
validateTimestamp(blockTimestamp: bigint): "valid" | "too old" | "in future";
|
|
13
|
-
}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import type { TimestampedCalldata } from "./types.js";
|
|
2
|
-
export interface PriceUpdatesCacheOptions {
|
|
3
|
-
/**
|
|
4
|
-
* Assume that in historical mode we only need to fetch once and then reuse from cache forever
|
|
5
|
-
*/
|
|
6
|
-
historical: boolean;
|
|
7
|
-
/**
|
|
8
|
-
* TTL in milliseconds
|
|
9
|
-
*/
|
|
10
|
-
ttl: number;
|
|
11
|
-
}
|
|
12
|
-
export declare class PriceUpdatesCache {
|
|
13
|
-
#private;
|
|
14
|
-
/**
|
|
15
|
-
* Price update caches can be shared across networks
|
|
16
|
-
* @param id - unique key to identify the cache
|
|
17
|
-
* @param opts
|
|
18
|
-
* @returns
|
|
19
|
-
*/
|
|
20
|
-
static get(id: string, opts: PriceUpdatesCacheOptions): PriceUpdatesCache;
|
|
21
|
-
private constructor();
|
|
22
|
-
get(...path: Array<number | string>): Omit<TimestampedCalldata, "cached"> | undefined;
|
|
23
|
-
set(value: Omit<TimestampedCalldata, "cached">, ...path: Array<number | string>): void;
|
|
24
|
-
}
|