@gearbox-protocol/sdk 8.0.4 → 8.1.0-next.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/sdk/GearboxSDK.js +20 -8
- package/dist/cjs/sdk/abi/oracles.js +141 -0
- package/dist/cjs/sdk/market/pricefeeds/AbstractPriceFeed.js +2 -1
- package/dist/cjs/sdk/market/pricefeeds/PriceFeedsRegister.js +17 -23
- package/dist/cjs/sdk/market/pricefeeds/PythPriceFeed.js +9 -1
- package/dist/cjs/sdk/market/pricefeeds/RedstonePriceFeed.js +9 -7
- package/dist/cjs/sdk/market/pricefeeds/index.js +2 -0
- package/dist/cjs/sdk/market/pricefeeds/isUpdatablePriceFeed.js +30 -0
- package/dist/cjs/sdk/market/pricefeeds/updates/PriceUpdateTx.js +52 -0
- package/dist/cjs/sdk/market/pricefeeds/{RedstoneCache.js → updates/PriceUpdatesCache.js} +12 -12
- package/dist/cjs/sdk/market/pricefeeds/updates/PythUpdater.js +175 -0
- package/dist/cjs/sdk/market/pricefeeds/{RedstoneUpdater.js → updates/RedstoneUpdater.js} +21 -45
- package/dist/cjs/sdk/market/pricefeeds/updates/index.js +31 -0
- package/dist/cjs/sdk/market/pricefeeds/updates/types.js +16 -0
- package/dist/cjs/sdk/utils/retry.js +4 -2
- package/dist/esm/sdk/GearboxSDK.js +20 -8
- package/dist/esm/sdk/abi/oracles.js +140 -0
- package/dist/esm/sdk/market/pricefeeds/AbstractPriceFeed.js +2 -1
- package/dist/esm/sdk/market/pricefeeds/PriceFeedsRegister.js +18 -24
- package/dist/esm/sdk/market/pricefeeds/PythPriceFeed.js +9 -1
- package/dist/esm/sdk/market/pricefeeds/RedstonePriceFeed.js +8 -5
- package/dist/esm/sdk/market/pricefeeds/index.js +1 -0
- package/dist/esm/sdk/market/pricefeeds/isUpdatablePriceFeed.js +6 -0
- package/dist/esm/sdk/market/pricefeeds/updates/PriceUpdateTx.js +28 -0
- package/dist/esm/sdk/market/pricefeeds/{RedstoneCache.js → updates/PriceUpdatesCache.js} +8 -8
- package/dist/esm/sdk/market/pricefeeds/updates/PythUpdater.js +151 -0
- package/dist/esm/sdk/market/pricefeeds/{RedstoneUpdater.js → updates/RedstoneUpdater.js} +21 -44
- package/dist/esm/sdk/market/pricefeeds/updates/index.js +6 -0
- package/dist/esm/sdk/market/pricefeeds/updates/types.js +0 -0
- package/dist/esm/sdk/utils/retry.js +4 -2
- package/dist/types/sdk/GearboxSDK.d.ts +5 -1
- package/dist/types/sdk/abi/oracles.d.ts +212 -0
- package/dist/types/sdk/market/pricefeeds/AbstractPriceFeed.d.ts +2 -2
- package/dist/types/sdk/market/pricefeeds/PriceFeedsRegister.d.ts +4 -4
- package/dist/types/sdk/market/pricefeeds/PythPriceFeed.d.ts +218 -4
- package/dist/types/sdk/market/pricefeeds/RedstonePriceFeed.d.ts +4 -4
- package/dist/types/sdk/market/pricefeeds/index.d.ts +1 -0
- package/dist/types/sdk/market/pricefeeds/isUpdatablePriceFeed.d.ts +2 -0
- package/dist/types/sdk/market/pricefeeds/types.d.ts +5 -2
- package/dist/types/sdk/market/pricefeeds/updates/PriceUpdateTx.d.ts +10 -0
- package/dist/types/sdk/market/pricefeeds/updates/PriceUpdatesCache.d.ts +17 -0
- package/dist/types/sdk/market/pricefeeds/updates/PythUpdater.d.ts +40 -0
- package/dist/types/sdk/market/pricefeeds/{RedstoneUpdater.d.ts → updates/RedstoneUpdater.d.ts} +11 -18
- package/dist/types/sdk/market/pricefeeds/updates/RedstoneUpdater.test.d.ts +1 -0
- package/dist/types/sdk/market/pricefeeds/updates/index.d.ts +3 -0
- package/dist/types/sdk/market/pricefeeds/updates/types.d.ts +21 -0
- package/dist/types/sdk/utils/retry.d.ts +1 -0
- package/package.json +1 -1
- package/dist/types/sdk/market/pricefeeds/RedstoneCache.d.ts +0 -25
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { decodeAbiParameters } from "viem";
|
|
2
|
+
import { pythPriceFeedAbi } from "../../abi/oracles.js";
|
|
2
3
|
import { AbstractPriceFeedContract } from "./AbstractPriceFeed.js";
|
|
3
|
-
const abi =
|
|
4
|
+
const abi = pythPriceFeedAbi;
|
|
4
5
|
class PythPriceFeed extends AbstractPriceFeedContract {
|
|
5
6
|
token;
|
|
6
7
|
priceFeedId;
|
|
@@ -40,6 +41,13 @@ class PythPriceFeed extends AbstractPriceFeedContract {
|
|
|
40
41
|
this.pyth = decoded[2];
|
|
41
42
|
}
|
|
42
43
|
}
|
|
44
|
+
createPriceUpdateTx(data) {
|
|
45
|
+
return this.createRawTx({
|
|
46
|
+
functionName: "updatePrice",
|
|
47
|
+
args: [data],
|
|
48
|
+
description: `updating pyth price for ${this.priceFeedId} [${this.labelAddress(this.address)}]`
|
|
49
|
+
});
|
|
50
|
+
}
|
|
43
51
|
}
|
|
44
52
|
export {
|
|
45
53
|
PythPriceFeed
|
|
@@ -75,11 +75,14 @@ class RedstonePriceFeedContract extends AbstractPriceFeedContract {
|
|
|
75
75
|
lastPayloadTimestamp: this.lastPayloadTimestamp.toString()
|
|
76
76
|
};
|
|
77
77
|
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
78
|
+
createPriceUpdateTx(data) {
|
|
79
|
+
return this.createRawTx({
|
|
80
|
+
functionName: "updatePrice",
|
|
81
|
+
args: [data],
|
|
82
|
+
description: `updating redstone price for ${this.dataId} [${this.labelAddress(this.address)}]`
|
|
83
|
+
});
|
|
84
|
+
}
|
|
81
85
|
}
|
|
82
86
|
export {
|
|
83
|
-
RedstonePriceFeedContract
|
|
84
|
-
isRedstone
|
|
87
|
+
RedstonePriceFeedContract
|
|
85
88
|
};
|
|
@@ -8,6 +8,7 @@ export * from "./CurveStablePriceFeed.js";
|
|
|
8
8
|
export * from "./CurveUSDPriceFeed.js";
|
|
9
9
|
export * from "./Erc4626PriceFeed.js";
|
|
10
10
|
export * from "./ExternalPriceFeed.js";
|
|
11
|
+
export * from "./isUpdatablePriceFeed.js";
|
|
11
12
|
export * from "./MellowLRTPriceFeed.js";
|
|
12
13
|
export * from "./PendleTWAPPTPriceFeed.js";
|
|
13
14
|
export * from "./PriceFeedRef.js";
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
const MAX_DATA_TIMESTAMP_DELAY_SECONDS = 10n * 60n;
|
|
2
|
+
const MAX_DATA_TIMESTAMP_AHEAD_SECONDS = 60n;
|
|
3
|
+
class PriceUpdateTx {
|
|
4
|
+
raw;
|
|
5
|
+
data;
|
|
6
|
+
constructor(raw, data) {
|
|
7
|
+
this.raw = raw;
|
|
8
|
+
this.data = data;
|
|
9
|
+
}
|
|
10
|
+
get pretty() {
|
|
11
|
+
const cached = this.data.cached ? " (cached)" : "";
|
|
12
|
+
return `${this.name} feed ${this.data.dataFeedId} at ${this.data.priceFeed} with timestamp ${this.data.timestamp}${cached}`;
|
|
13
|
+
}
|
|
14
|
+
validateTimestamp(blockTimestamp) {
|
|
15
|
+
const { timestamp: expectedPayloadTimestamp } = this.data;
|
|
16
|
+
if (blockTimestamp < expectedPayloadTimestamp) {
|
|
17
|
+
if (BigInt(expectedPayloadTimestamp) - blockTimestamp > MAX_DATA_TIMESTAMP_AHEAD_SECONDS) {
|
|
18
|
+
return "in future";
|
|
19
|
+
}
|
|
20
|
+
} else if (blockTimestamp - BigInt(expectedPayloadTimestamp) > MAX_DATA_TIMESTAMP_DELAY_SECONDS) {
|
|
21
|
+
return "too old";
|
|
22
|
+
}
|
|
23
|
+
return "valid";
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
export {
|
|
27
|
+
PriceUpdateTx
|
|
28
|
+
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
class
|
|
1
|
+
class PriceUpdatesCache {
|
|
2
2
|
#cache = /* @__PURE__ */ new Map();
|
|
3
3
|
#ttlMs;
|
|
4
4
|
#historical;
|
|
@@ -6,8 +6,8 @@ class RedstoneCache {
|
|
|
6
6
|
this.#ttlMs = opts.ttl;
|
|
7
7
|
this.#historical = opts.historical;
|
|
8
8
|
}
|
|
9
|
-
get(
|
|
10
|
-
const key = this.#cacheKey(
|
|
9
|
+
get(...path) {
|
|
10
|
+
const key = this.#cacheKey(...path);
|
|
11
11
|
const data = this.#cache.get(key);
|
|
12
12
|
if (!data) {
|
|
13
13
|
return void 0;
|
|
@@ -18,8 +18,8 @@ class RedstoneCache {
|
|
|
18
18
|
}
|
|
19
19
|
return data;
|
|
20
20
|
}
|
|
21
|
-
set(
|
|
22
|
-
const key = this.#cacheKey(
|
|
21
|
+
set(value, ...path) {
|
|
22
|
+
const key = this.#cacheKey(...path);
|
|
23
23
|
this.#cache.set(key, value);
|
|
24
24
|
}
|
|
25
25
|
#expired(value) {
|
|
@@ -28,10 +28,10 @@ class RedstoneCache {
|
|
|
28
28
|
}
|
|
29
29
|
return value.timestamp * 1e3 + this.#ttlMs < Date.now();
|
|
30
30
|
}
|
|
31
|
-
#cacheKey(
|
|
32
|
-
return
|
|
31
|
+
#cacheKey(...path) {
|
|
32
|
+
return path.join(":");
|
|
33
33
|
}
|
|
34
34
|
}
|
|
35
35
|
export {
|
|
36
|
-
|
|
36
|
+
PriceUpdatesCache
|
|
37
37
|
};
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { decodeAbiParameters, encodeAbiParameters } from "viem";
|
|
2
|
+
import { SDKConstruct } from "../../../base/index.js";
|
|
3
|
+
import { childLogger, retry } from "../../../utils/index.js";
|
|
4
|
+
import { PriceUpdatesCache } from "./PriceUpdatesCache.js";
|
|
5
|
+
import { PriceUpdateTx } from "./PriceUpdateTx.js";
|
|
6
|
+
class PythUpdateTx extends PriceUpdateTx {
|
|
7
|
+
name = "pyth";
|
|
8
|
+
}
|
|
9
|
+
class PythUpdater extends SDKConstruct {
|
|
10
|
+
#logger;
|
|
11
|
+
#cache;
|
|
12
|
+
#historicalTimestamp;
|
|
13
|
+
#api;
|
|
14
|
+
#ignoreMissingFeeds;
|
|
15
|
+
constructor(sdk, opts = {}) {
|
|
16
|
+
super(sdk);
|
|
17
|
+
this.#logger = childLogger("PythUpdater", sdk.logger);
|
|
18
|
+
this.#ignoreMissingFeeds = opts.ignoreMissingFeeds;
|
|
19
|
+
this.#api = opts.apiProxy ?? "https://hermes.pyth.network/v2/updates/price/";
|
|
20
|
+
this.#api = this.#api.endsWith("/") ? this.#api : this.#api + "/";
|
|
21
|
+
let ts = opts.historicTimestamp;
|
|
22
|
+
if (ts) {
|
|
23
|
+
this.#historicalTimestamp = ts === true ? Number(this.sdk.timestamp) : ts;
|
|
24
|
+
}
|
|
25
|
+
this.#cache = new PriceUpdatesCache({
|
|
26
|
+
// currently staleness period is 240 seconds on all networks, add some buffer
|
|
27
|
+
// this period of 4 minutes is selected based on time that is required for user to sign transaction with wallet
|
|
28
|
+
// so it's unlikely to decrease
|
|
29
|
+
ttl: opts.cacheTTL ?? 225 * 1e3,
|
|
30
|
+
historical: !!ts
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
async getUpdateTxs(feeds, logContext = {}) {
|
|
34
|
+
this.#logger?.debug(
|
|
35
|
+
logContext,
|
|
36
|
+
`generating update transactions for ${feeds.length} pyth price feeds`
|
|
37
|
+
);
|
|
38
|
+
const pythFeeds = new Map(
|
|
39
|
+
feeds.filter(isPyth).map((f) => [f.priceFeedId, f])
|
|
40
|
+
);
|
|
41
|
+
const payloads = await this.#getPayloads(new Set(pythFeeds.keys()));
|
|
42
|
+
const results = payloads.map((p) => {
|
|
43
|
+
const priceFeed = pythFeeds.get(p.dataFeedId);
|
|
44
|
+
if (!priceFeed) {
|
|
45
|
+
throw new Error(`cannot find price feed for ${p.dataFeedId}`);
|
|
46
|
+
}
|
|
47
|
+
const { dataFeedId, timestamp, cached, data } = p;
|
|
48
|
+
return new PythUpdateTx(priceFeed.createPriceUpdateTx(data), {
|
|
49
|
+
dataFeedId,
|
|
50
|
+
priceFeed: priceFeed.address,
|
|
51
|
+
timestamp,
|
|
52
|
+
cached
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
this.#logger?.debug(
|
|
56
|
+
logContext,
|
|
57
|
+
`generated ${results.length} update transactions for pyth price feeds`
|
|
58
|
+
);
|
|
59
|
+
return results;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Gets pyth payloads
|
|
63
|
+
* @param dataFeedsIds
|
|
64
|
+
* @returns
|
|
65
|
+
*/
|
|
66
|
+
async #getPayloads(dataFeedsIds) {
|
|
67
|
+
this.#logger?.debug(
|
|
68
|
+
`getting pyth payloads for ${dataFeedsIds.size} price feeds: ${Array.from(dataFeedsIds).join(", ")}`
|
|
69
|
+
);
|
|
70
|
+
const fromCache = [];
|
|
71
|
+
const uncached = [];
|
|
72
|
+
for (const priceFeedsId of dataFeedsIds) {
|
|
73
|
+
const cached = this.#cache.get(priceFeedsId);
|
|
74
|
+
if (cached) {
|
|
75
|
+
fromCache.push({ ...cached, cached: true });
|
|
76
|
+
} else {
|
|
77
|
+
uncached.push(priceFeedsId);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
const fromPyth = await this.#fetchPayloads(
|
|
81
|
+
new Set(uncached)
|
|
82
|
+
);
|
|
83
|
+
for (const resp of fromPyth) {
|
|
84
|
+
this.#cache.set(resp, resp.dataFeedId);
|
|
85
|
+
}
|
|
86
|
+
this.#logger?.debug(
|
|
87
|
+
`got ${fromPyth.length} new pyth updates and ${fromCache.length} from cache`
|
|
88
|
+
);
|
|
89
|
+
return [...fromCache, ...fromPyth];
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Fetches pyth payloads from Hermes API
|
|
93
|
+
* @param dataFeedsIds
|
|
94
|
+
* @returns
|
|
95
|
+
*/
|
|
96
|
+
async #fetchPayloads(dataFeedsIds) {
|
|
97
|
+
if (dataFeedsIds.size === 0) {
|
|
98
|
+
return [];
|
|
99
|
+
}
|
|
100
|
+
const ids = Array.from(dataFeedsIds);
|
|
101
|
+
const tsStr = this.#historicalTimestamp ? ` with historical timestamp ${this.#historicalTimestamp}` : "";
|
|
102
|
+
this.#logger?.debug(
|
|
103
|
+
`fetching pyth payloads for ${dataFeedsIds.size} price feeds: ${ids.join(", ")}${tsStr}`
|
|
104
|
+
);
|
|
105
|
+
const url = new URL(this.#api + (this.#historicalTimestamp ?? "latest"));
|
|
106
|
+
if (this.#ignoreMissingFeeds) {
|
|
107
|
+
url.searchParams.append("ignore_invalid_price_ids", "true");
|
|
108
|
+
}
|
|
109
|
+
for (const id of dataFeedsIds) {
|
|
110
|
+
url.searchParams.append("ids[]", id);
|
|
111
|
+
}
|
|
112
|
+
const resp = await retry(
|
|
113
|
+
async () => {
|
|
114
|
+
const resp2 = await fetch(url.toString());
|
|
115
|
+
if (!resp2.ok) {
|
|
116
|
+
const body = await resp2.text();
|
|
117
|
+
throw new Error(
|
|
118
|
+
`failed to fetch pyth payloads: ${resp2.statusText}: ${body}`
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
const data = await resp2.json();
|
|
122
|
+
return data;
|
|
123
|
+
},
|
|
124
|
+
{ attempts: 3, exponent: 2, interval: 200 }
|
|
125
|
+
);
|
|
126
|
+
return respToCalldata(resp);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
function isPyth(pf) {
|
|
130
|
+
return pf.contractType === "PRICE_FEED::PYTH";
|
|
131
|
+
}
|
|
132
|
+
function respToCalldata(resp) {
|
|
133
|
+
const [datas] = decodeAbiParameters(
|
|
134
|
+
[{ type: "bytes[]" }],
|
|
135
|
+
`0x${resp.binary.data}`
|
|
136
|
+
);
|
|
137
|
+
return resp.parsed.map((pf, i) => {
|
|
138
|
+
return {
|
|
139
|
+
dataFeedId: pf.id,
|
|
140
|
+
data: encodeAbiParameters(
|
|
141
|
+
[{ type: "uint256" }, { type: "bytes" }],
|
|
142
|
+
[BigInt(pf.price.publish_time), datas[i]]
|
|
143
|
+
),
|
|
144
|
+
timestamp: pf.price.publish_time,
|
|
145
|
+
cached: false
|
|
146
|
+
};
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
export {
|
|
150
|
+
PythUpdater
|
|
151
|
+
};
|
|
@@ -1,33 +1,12 @@
|
|
|
1
1
|
import { DataServiceWrapper } from "@redstone-finance/evm-connector";
|
|
2
2
|
import { RedstonePayload } from "@redstone-finance/protocol";
|
|
3
3
|
import { encodeAbiParameters, toBytes } from "viem";
|
|
4
|
-
import { SDKConstruct } from "
|
|
5
|
-
import { AddressMap, childLogger, retry } from "
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
raw;
|
|
11
|
-
data;
|
|
12
|
-
constructor(raw, data) {
|
|
13
|
-
this.raw = raw;
|
|
14
|
-
this.data = data;
|
|
15
|
-
}
|
|
16
|
-
get pretty() {
|
|
17
|
-
const cached = this.data.cached ? " (cached)" : "";
|
|
18
|
-
return `redstone feed ${this.data.dataFeedId} at ${this.data.priceFeed} with timestamp ${this.data.timestamp}${cached}`;
|
|
19
|
-
}
|
|
20
|
-
validateTimestamp(blockTimestamp) {
|
|
21
|
-
const { timestamp: expectedPayloadTimestamp } = this.data;
|
|
22
|
-
if (blockTimestamp < expectedPayloadTimestamp) {
|
|
23
|
-
if (BigInt(expectedPayloadTimestamp) - blockTimestamp > MAX_DATA_TIMESTAMP_AHEAD_SECONDS) {
|
|
24
|
-
return "in future";
|
|
25
|
-
}
|
|
26
|
-
} else if (blockTimestamp - BigInt(expectedPayloadTimestamp) > MAX_DATA_TIMESTAMP_DELAY_SECONDS) {
|
|
27
|
-
return "too old";
|
|
28
|
-
}
|
|
29
|
-
return "valid";
|
|
30
|
-
}
|
|
4
|
+
import { SDKConstruct } from "../../../base/index.js";
|
|
5
|
+
import { AddressMap, childLogger, retry } from "../../../utils/index.js";
|
|
6
|
+
import { PriceUpdatesCache } from "./PriceUpdatesCache.js";
|
|
7
|
+
import { PriceUpdateTx } from "./PriceUpdateTx.js";
|
|
8
|
+
class RedstoneUpdateTx extends PriceUpdateTx {
|
|
9
|
+
name = "redstone";
|
|
31
10
|
}
|
|
32
11
|
class RedstoneUpdater extends SDKConstruct {
|
|
33
12
|
#logger;
|
|
@@ -47,7 +26,7 @@ class RedstoneUpdater extends SDKConstruct {
|
|
|
47
26
|
ts = ts === true ? Number(this.sdk.timestamp) * 1e3 : ts;
|
|
48
27
|
this.#historicalTimestampMs = 6e4 * Math.floor(ts / 6e4);
|
|
49
28
|
}
|
|
50
|
-
this.#cache = new
|
|
29
|
+
this.#cache = new PriceUpdatesCache({
|
|
51
30
|
// currently staleness period is 240 seconds on all networks, add some buffer
|
|
52
31
|
// this period of 4 minutes is selected based on time that is required for user to sign transaction with wallet
|
|
53
32
|
// so it's unlikely to decrease
|
|
@@ -63,6 +42,9 @@ class RedstoneUpdater extends SDKConstruct {
|
|
|
63
42
|
const groupedFeeds = {};
|
|
64
43
|
const priceFeeds = /* @__PURE__ */ new Map();
|
|
65
44
|
for (const feed of feeds) {
|
|
45
|
+
if (!isRedstone(feed)) {
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
66
48
|
const key = `${feed.dataServiceId}:${feed.signersThreshold}`;
|
|
67
49
|
if (!groupedFeeds[key]) {
|
|
68
50
|
groupedFeeds[key] = /* @__PURE__ */ new Set();
|
|
@@ -88,20 +70,13 @@ class RedstoneUpdater extends SDKConstruct {
|
|
|
88
70
|
}
|
|
89
71
|
for (const priceFeed of pfsForDataId.values()) {
|
|
90
72
|
results.push(
|
|
91
|
-
new RedstoneUpdateTx(
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
dataFeedId,
|
|
99
|
-
dataServiceId,
|
|
100
|
-
priceFeed: priceFeed.address,
|
|
101
|
-
timestamp,
|
|
102
|
-
cached
|
|
103
|
-
}
|
|
104
|
-
)
|
|
73
|
+
new RedstoneUpdateTx(priceFeed.createPriceUpdateTx(data), {
|
|
74
|
+
dataFeedId,
|
|
75
|
+
dataServiceId,
|
|
76
|
+
priceFeed: priceFeed.address,
|
|
77
|
+
timestamp,
|
|
78
|
+
cached
|
|
79
|
+
})
|
|
105
80
|
);
|
|
106
81
|
}
|
|
107
82
|
}
|
|
@@ -144,7 +119,7 @@ class RedstoneUpdater extends SDKConstruct {
|
|
|
144
119
|
uniqueSignersCount
|
|
145
120
|
);
|
|
146
121
|
for (const resp of fromRedstone) {
|
|
147
|
-
this.#cache.set(dataServiceId, resp.dataFeedId, uniqueSignersCount
|
|
122
|
+
this.#cache.set(resp, dataServiceId, resp.dataFeedId, uniqueSignersCount);
|
|
148
123
|
}
|
|
149
124
|
this.#logger?.debug(
|
|
150
125
|
`got ${fromRedstone.length} new redstone updates and ${fromCache.length} from cache`
|
|
@@ -245,7 +220,9 @@ function getCalldataWithTimestamp(dataFeedId, packages, unsignedMetadata) {
|
|
|
245
220
|
cached: false
|
|
246
221
|
};
|
|
247
222
|
}
|
|
223
|
+
function isRedstone(pf) {
|
|
224
|
+
return pf.contractType === "PRICE_FEED::REDSTONE";
|
|
225
|
+
}
|
|
248
226
|
export {
|
|
249
|
-
RedstoneUpdateTx,
|
|
250
227
|
RedstoneUpdater
|
|
251
228
|
};
|
|
File without changes
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
async function retry(fn, options = {}) {
|
|
2
|
-
const { attempts = 3, interval = 200 } = options;
|
|
2
|
+
const { attempts = 3, interval = 200, exponent = 1 } = options;
|
|
3
|
+
let wait = interval;
|
|
3
4
|
let cause;
|
|
4
5
|
for (let i = 0; i < attempts; i++) {
|
|
5
6
|
try {
|
|
@@ -8,8 +9,9 @@ async function retry(fn, options = {}) {
|
|
|
8
9
|
} catch (e) {
|
|
9
10
|
cause = e;
|
|
10
11
|
await new Promise((resolve) => {
|
|
11
|
-
setTimeout(resolve,
|
|
12
|
+
setTimeout(resolve, wait);
|
|
12
13
|
});
|
|
14
|
+
wait = wait * exponent;
|
|
13
15
|
}
|
|
14
16
|
}
|
|
15
17
|
throw new Error(`all attempts failed: ${cause}`);
|
|
@@ -8,7 +8,7 @@ import type { IAddressProviderContract } from "./core/index.js";
|
|
|
8
8
|
import { BotListContract, GearStakingContract } from "./core/index.js";
|
|
9
9
|
import { MarketRegister } from "./market/MarketRegister.js";
|
|
10
10
|
import { PriceFeedRegister } from "./market/pricefeeds/index.js";
|
|
11
|
-
import type { RedstoneOptions } from "./market/pricefeeds/
|
|
11
|
+
import type { PythOptions, RedstoneOptions } from "./market/pricefeeds/updates/index.js";
|
|
12
12
|
import { type PluginsMap } from "./plugins/index.js";
|
|
13
13
|
import { type IRouterContract } from "./router/index.js";
|
|
14
14
|
import type { GearboxState, GearboxStateHuman, ILogger, MultiCall } from "./types/index.js";
|
|
@@ -51,6 +51,10 @@ export interface SDKOptions<Plugins extends PluginsMap> {
|
|
|
51
51
|
* Options related to redstone price feeds
|
|
52
52
|
*/
|
|
53
53
|
redstone?: RedstoneOptions;
|
|
54
|
+
/**
|
|
55
|
+
* Options related to pyth price feeds
|
|
56
|
+
*/
|
|
57
|
+
pyth?: PythOptions;
|
|
54
58
|
}
|
|
55
59
|
export type HydrateOptions<Plugins extends PluginsMap> = Omit<SDKOptions<Plugins>, "blockNumber" | "addressProvider" | "marketConfigurators">;
|
|
56
60
|
export interface SyncStateOptions {
|
|
@@ -6157,3 +6157,215 @@ export declare const pendleTWAPPTPriceFeedAbi: readonly [{
|
|
|
6157
6157
|
readonly name: "StalePriceException";
|
|
6158
6158
|
readonly inputs: readonly [];
|
|
6159
6159
|
}];
|
|
6160
|
+
export declare const pythPriceFeedAbi: readonly [{
|
|
6161
|
+
readonly type: "constructor";
|
|
6162
|
+
readonly inputs: readonly [{
|
|
6163
|
+
readonly name: "_token";
|
|
6164
|
+
readonly type: "address";
|
|
6165
|
+
readonly internalType: "address";
|
|
6166
|
+
}, {
|
|
6167
|
+
readonly name: "_priceFeedId";
|
|
6168
|
+
readonly type: "bytes32";
|
|
6169
|
+
readonly internalType: "bytes32";
|
|
6170
|
+
}, {
|
|
6171
|
+
readonly name: "_pyth";
|
|
6172
|
+
readonly type: "address";
|
|
6173
|
+
readonly internalType: "address";
|
|
6174
|
+
}, {
|
|
6175
|
+
readonly name: "_maxConfToPriceRatio";
|
|
6176
|
+
readonly type: "uint256";
|
|
6177
|
+
readonly internalType: "uint256";
|
|
6178
|
+
}, {
|
|
6179
|
+
readonly name: "descriptionTicker";
|
|
6180
|
+
readonly type: "string";
|
|
6181
|
+
readonly internalType: "string";
|
|
6182
|
+
}];
|
|
6183
|
+
readonly stateMutability: "nonpayable";
|
|
6184
|
+
}, {
|
|
6185
|
+
readonly type: "receive";
|
|
6186
|
+
readonly stateMutability: "payable";
|
|
6187
|
+
}, {
|
|
6188
|
+
readonly type: "function";
|
|
6189
|
+
readonly name: "contractType";
|
|
6190
|
+
readonly inputs: readonly [];
|
|
6191
|
+
readonly outputs: readonly [{
|
|
6192
|
+
readonly name: "";
|
|
6193
|
+
readonly type: "bytes32";
|
|
6194
|
+
readonly internalType: "bytes32";
|
|
6195
|
+
}];
|
|
6196
|
+
readonly stateMutability: "view";
|
|
6197
|
+
}, {
|
|
6198
|
+
readonly type: "function";
|
|
6199
|
+
readonly name: "decimals";
|
|
6200
|
+
readonly inputs: readonly [];
|
|
6201
|
+
readonly outputs: readonly [{
|
|
6202
|
+
readonly name: "";
|
|
6203
|
+
readonly type: "uint8";
|
|
6204
|
+
readonly internalType: "uint8";
|
|
6205
|
+
}];
|
|
6206
|
+
readonly stateMutability: "view";
|
|
6207
|
+
}, {
|
|
6208
|
+
readonly type: "function";
|
|
6209
|
+
readonly name: "description";
|
|
6210
|
+
readonly inputs: readonly [];
|
|
6211
|
+
readonly outputs: readonly [{
|
|
6212
|
+
readonly name: "";
|
|
6213
|
+
readonly type: "string";
|
|
6214
|
+
readonly internalType: "string";
|
|
6215
|
+
}];
|
|
6216
|
+
readonly stateMutability: "view";
|
|
6217
|
+
}, {
|
|
6218
|
+
readonly type: "function";
|
|
6219
|
+
readonly name: "latestRoundData";
|
|
6220
|
+
readonly inputs: readonly [];
|
|
6221
|
+
readonly outputs: readonly [{
|
|
6222
|
+
readonly name: "";
|
|
6223
|
+
readonly type: "uint80";
|
|
6224
|
+
readonly internalType: "uint80";
|
|
6225
|
+
}, {
|
|
6226
|
+
readonly name: "";
|
|
6227
|
+
readonly type: "int256";
|
|
6228
|
+
readonly internalType: "int256";
|
|
6229
|
+
}, {
|
|
6230
|
+
readonly name: "";
|
|
6231
|
+
readonly type: "uint256";
|
|
6232
|
+
readonly internalType: "uint256";
|
|
6233
|
+
}, {
|
|
6234
|
+
readonly name: "";
|
|
6235
|
+
readonly type: "uint256";
|
|
6236
|
+
readonly internalType: "uint256";
|
|
6237
|
+
}, {
|
|
6238
|
+
readonly name: "";
|
|
6239
|
+
readonly type: "uint80";
|
|
6240
|
+
readonly internalType: "uint80";
|
|
6241
|
+
}];
|
|
6242
|
+
readonly stateMutability: "view";
|
|
6243
|
+
}, {
|
|
6244
|
+
readonly type: "function";
|
|
6245
|
+
readonly name: "maxConfToPriceRatio";
|
|
6246
|
+
readonly inputs: readonly [];
|
|
6247
|
+
readonly outputs: readonly [{
|
|
6248
|
+
readonly name: "";
|
|
6249
|
+
readonly type: "uint256";
|
|
6250
|
+
readonly internalType: "uint256";
|
|
6251
|
+
}];
|
|
6252
|
+
readonly stateMutability: "view";
|
|
6253
|
+
}, {
|
|
6254
|
+
readonly type: "function";
|
|
6255
|
+
readonly name: "priceFeedId";
|
|
6256
|
+
readonly inputs: readonly [];
|
|
6257
|
+
readonly outputs: readonly [{
|
|
6258
|
+
readonly name: "";
|
|
6259
|
+
readonly type: "bytes32";
|
|
6260
|
+
readonly internalType: "bytes32";
|
|
6261
|
+
}];
|
|
6262
|
+
readonly stateMutability: "view";
|
|
6263
|
+
}, {
|
|
6264
|
+
readonly type: "function";
|
|
6265
|
+
readonly name: "pyth";
|
|
6266
|
+
readonly inputs: readonly [];
|
|
6267
|
+
readonly outputs: readonly [{
|
|
6268
|
+
readonly name: "";
|
|
6269
|
+
readonly type: "address";
|
|
6270
|
+
readonly internalType: "address";
|
|
6271
|
+
}];
|
|
6272
|
+
readonly stateMutability: "view";
|
|
6273
|
+
}, {
|
|
6274
|
+
readonly type: "function";
|
|
6275
|
+
readonly name: "serialize";
|
|
6276
|
+
readonly inputs: readonly [];
|
|
6277
|
+
readonly outputs: readonly [{
|
|
6278
|
+
readonly name: "";
|
|
6279
|
+
readonly type: "bytes";
|
|
6280
|
+
readonly internalType: "bytes";
|
|
6281
|
+
}];
|
|
6282
|
+
readonly stateMutability: "view";
|
|
6283
|
+
}, {
|
|
6284
|
+
readonly type: "function";
|
|
6285
|
+
readonly name: "skipPriceCheck";
|
|
6286
|
+
readonly inputs: readonly [];
|
|
6287
|
+
readonly outputs: readonly [{
|
|
6288
|
+
readonly name: "";
|
|
6289
|
+
readonly type: "bool";
|
|
6290
|
+
readonly internalType: "bool";
|
|
6291
|
+
}];
|
|
6292
|
+
readonly stateMutability: "view";
|
|
6293
|
+
}, {
|
|
6294
|
+
readonly type: "function";
|
|
6295
|
+
readonly name: "token";
|
|
6296
|
+
readonly inputs: readonly [];
|
|
6297
|
+
readonly outputs: readonly [{
|
|
6298
|
+
readonly name: "";
|
|
6299
|
+
readonly type: "address";
|
|
6300
|
+
readonly internalType: "address";
|
|
6301
|
+
}];
|
|
6302
|
+
readonly stateMutability: "view";
|
|
6303
|
+
}, {
|
|
6304
|
+
readonly type: "function";
|
|
6305
|
+
readonly name: "updatable";
|
|
6306
|
+
readonly inputs: readonly [];
|
|
6307
|
+
readonly outputs: readonly [{
|
|
6308
|
+
readonly name: "";
|
|
6309
|
+
readonly type: "bool";
|
|
6310
|
+
readonly internalType: "bool";
|
|
6311
|
+
}];
|
|
6312
|
+
readonly stateMutability: "view";
|
|
6313
|
+
}, {
|
|
6314
|
+
readonly type: "function";
|
|
6315
|
+
readonly name: "updatePrice";
|
|
6316
|
+
readonly inputs: readonly [{
|
|
6317
|
+
readonly name: "data";
|
|
6318
|
+
readonly type: "bytes";
|
|
6319
|
+
readonly internalType: "bytes";
|
|
6320
|
+
}];
|
|
6321
|
+
readonly outputs: readonly [];
|
|
6322
|
+
readonly stateMutability: "nonpayable";
|
|
6323
|
+
}, {
|
|
6324
|
+
readonly type: "function";
|
|
6325
|
+
readonly name: "version";
|
|
6326
|
+
readonly inputs: readonly [];
|
|
6327
|
+
readonly outputs: readonly [{
|
|
6328
|
+
readonly name: "";
|
|
6329
|
+
readonly type: "uint256";
|
|
6330
|
+
readonly internalType: "uint256";
|
|
6331
|
+
}];
|
|
6332
|
+
readonly stateMutability: "view";
|
|
6333
|
+
}, {
|
|
6334
|
+
readonly type: "event";
|
|
6335
|
+
readonly name: "UpdatePrice";
|
|
6336
|
+
readonly inputs: readonly [{
|
|
6337
|
+
readonly name: "price";
|
|
6338
|
+
readonly type: "uint256";
|
|
6339
|
+
readonly indexed: false;
|
|
6340
|
+
readonly internalType: "uint256";
|
|
6341
|
+
}];
|
|
6342
|
+
readonly anonymous: false;
|
|
6343
|
+
}, {
|
|
6344
|
+
readonly type: "error";
|
|
6345
|
+
readonly name: "ConfToPriceRatioTooHighException";
|
|
6346
|
+
readonly inputs: readonly [];
|
|
6347
|
+
}, {
|
|
6348
|
+
readonly type: "error";
|
|
6349
|
+
readonly name: "IncorrectExpectedPublishTimestampException";
|
|
6350
|
+
readonly inputs: readonly [];
|
|
6351
|
+
}, {
|
|
6352
|
+
readonly type: "error";
|
|
6353
|
+
readonly name: "IncorrectParameterException";
|
|
6354
|
+
readonly inputs: readonly [];
|
|
6355
|
+
}, {
|
|
6356
|
+
readonly type: "error";
|
|
6357
|
+
readonly name: "IncorrectPriceDecimalsException";
|
|
6358
|
+
readonly inputs: readonly [];
|
|
6359
|
+
}, {
|
|
6360
|
+
readonly type: "error";
|
|
6361
|
+
readonly name: "IncorrectPriceException";
|
|
6362
|
+
readonly inputs: readonly [];
|
|
6363
|
+
}, {
|
|
6364
|
+
readonly type: "error";
|
|
6365
|
+
readonly name: "PriceTimestampTooFarAheadException";
|
|
6366
|
+
readonly inputs: readonly [];
|
|
6367
|
+
}, {
|
|
6368
|
+
readonly type: "error";
|
|
6369
|
+
readonly name: "PriceTimestampTooFarBehindException";
|
|
6370
|
+
readonly inputs: readonly [];
|
|
6371
|
+
}];
|
|
@@ -4,7 +4,7 @@ import { BaseContract } from "../../base/index.js";
|
|
|
4
4
|
import type { GearboxSDK } from "../../GearboxSDK.js";
|
|
5
5
|
import type { PriceFeedStateHuman } from "../../types/index.js";
|
|
6
6
|
import { PriceFeedRef } from "./PriceFeedRef.js";
|
|
7
|
-
import type { IPriceFeedContract, PriceFeedContractType } from "./types.js";
|
|
7
|
+
import type { IPriceFeedContract, IUpdatablePriceFeedContract, PriceFeedContractType } from "./types.js";
|
|
8
8
|
export type PartialPriceFeedTreeNode = RequiredBy<Partial<PriceFeedTreeNode>, "baseParams">;
|
|
9
9
|
export type PriceFeedConstructorArgs<abi extends Abi | readonly unknown[]> = PartialPriceFeedTreeNode & {
|
|
10
10
|
abi: abi;
|
|
@@ -30,5 +30,5 @@ export declare abstract class AbstractPriceFeedContract<const abi extends Abi |
|
|
|
30
30
|
answer(overrides?: {
|
|
31
31
|
blockNumber?: bigint;
|
|
32
32
|
}): Promise<bigint>;
|
|
33
|
-
updatableDependencies():
|
|
33
|
+
updatableDependencies(): IUpdatablePriceFeedContract[];
|
|
34
34
|
}
|