@gearbox-protocol/sdk 13.6.0-kyc.7 → 13.6.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.
Files changed (155) hide show
  1. package/dist/cjs/dev/AccountOpener.js +5 -45
  2. package/dist/cjs/dev/logSplitterTransport.js +10 -1
  3. package/dist/cjs/plugins/adapters/abi/actionAbi.js +1 -1
  4. package/dist/cjs/plugins/adapters/abi/conctructorAbi.js +1 -1
  5. package/dist/cjs/plugins/adapters/createAdapter.js +1 -1
  6. package/dist/cjs/plugins/adapters/types.js +1 -1
  7. package/dist/cjs/plugins/apy/ApyPlugin.js +266 -0
  8. package/dist/cjs/plugins/apy/apy-cache.js +120 -0
  9. package/dist/cjs/plugins/apy/apy-parser.js +169 -0
  10. package/dist/cjs/{sdk/market/kyc/securitize → plugins/apy}/constants.js +6 -3
  11. package/dist/cjs/{sdk/market/kyc/securitize → plugins/apy}/index.js +14 -6
  12. package/dist/cjs/{sdk/market/kyc/securitize/types.js → plugins/apy/pool-apy-types.js} +2 -2
  13. package/dist/cjs/plugins/apy/pool-apy-utils.js +141 -0
  14. package/dist/cjs/rewards/rewards/extra-apy.js +10 -8
  15. package/dist/cjs/sdk/GearboxSDK.js +5 -52
  16. package/dist/cjs/sdk/accounts/AbstractCreditAccountsService.js +16 -324
  17. package/dist/cjs/sdk/accounts/CreditAccountsServiceV310.js +1 -7
  18. package/dist/cjs/sdk/base/TokensMeta.js +43 -32
  19. package/dist/cjs/sdk/base/token-types.js +0 -9
  20. package/dist/cjs/sdk/chain/chains.js +32 -17
  21. package/dist/cjs/sdk/constants/address-provider.js +0 -3
  22. package/dist/cjs/sdk/market/MarketRegister.js +116 -70
  23. package/dist/cjs/sdk/market/MarketSuite.js +0 -3
  24. package/dist/cjs/sdk/market/index.js +0 -2
  25. package/dist/cjs/sdk/market/pool/PoolSuite.js +0 -3
  26. package/dist/cjs/sdk/market/pool/PoolV310Contract.js +2 -11
  27. package/dist/cjs/sdk/market/pool/index.js +0 -2
  28. package/dist/cjs/sdk/market/pricefeeds/PriceFeedsRegister.js +3 -3
  29. package/dist/cjs/sdk/options.js +1 -7
  30. package/dist/cjs/sdk/pools/PoolService.js +12 -104
  31. package/dist/cjs/sdk/utils/viem/index.js +0 -2
  32. package/dist/cjs/sdk/utils/viem/simulateWithPriceUpdates.js +39 -2
  33. package/dist/esm/dev/AccountOpener.js +6 -47
  34. package/dist/esm/dev/logSplitterTransport.js +10 -1
  35. package/dist/esm/plugins/adapters/abi/actionAbi.js +1 -1
  36. package/dist/esm/plugins/adapters/abi/conctructorAbi.js +1 -1
  37. package/dist/esm/plugins/adapters/createAdapter.js +1 -1
  38. package/dist/esm/plugins/adapters/types.js +1 -1
  39. package/dist/esm/plugins/apy/ApyPlugin.js +255 -0
  40. package/dist/esm/plugins/apy/apy-cache.js +86 -0
  41. package/dist/esm/plugins/apy/apy-parser.js +143 -0
  42. package/dist/esm/plugins/apy/constants.js +6 -0
  43. package/dist/esm/plugins/apy/index.js +7 -0
  44. package/dist/esm/plugins/apy/pool-apy-utils.js +113 -0
  45. package/dist/esm/rewards/rewards/extra-apy.js +10 -8
  46. package/dist/esm/sdk/GearboxSDK.js +6 -56
  47. package/dist/esm/sdk/accounts/AbstractCreditAccountsService.js +17 -328
  48. package/dist/esm/sdk/accounts/CreditAccountsServiceV310.js +1 -7
  49. package/dist/esm/sdk/base/TokensMeta.js +45 -32
  50. package/dist/esm/sdk/base/token-types.js +0 -6
  51. package/dist/esm/sdk/chain/chains.js +32 -17
  52. package/dist/esm/sdk/constants/address-provider.js +0 -2
  53. package/dist/esm/sdk/market/MarketRegister.js +118 -74
  54. package/dist/esm/sdk/market/MarketSuite.js +0 -3
  55. package/dist/esm/sdk/market/index.js +0 -1
  56. package/dist/esm/sdk/market/pool/PoolSuite.js +0 -3
  57. package/dist/esm/sdk/market/pool/PoolV310Contract.js +2 -11
  58. package/dist/esm/sdk/market/pool/index.js +0 -1
  59. package/dist/esm/sdk/market/pricefeeds/PriceFeedsRegister.js +3 -3
  60. package/dist/esm/sdk/options.js +1 -7
  61. package/dist/esm/sdk/pools/PoolService.js +13 -109
  62. package/dist/esm/sdk/utils/viem/index.js +0 -1
  63. package/dist/esm/sdk/utils/viem/simulateWithPriceUpdates.js +41 -2
  64. package/dist/types/dev/logSplitterTransport.d.ts +3 -1
  65. package/dist/types/plugins/adapters/types.d.ts +2 -2
  66. package/dist/types/plugins/apy/ApyPlugin.d.ts +46 -0
  67. package/dist/types/plugins/apy/apy-cache.d.ts +28 -0
  68. package/dist/types/plugins/apy/apy-parser.d.ts +5 -0
  69. package/dist/types/plugins/apy/constants.d.ts +2 -0
  70. package/dist/types/plugins/apy/index.d.ts +7 -0
  71. package/dist/types/plugins/apy/pool-apy-types.d.ts +41 -0
  72. package/dist/types/plugins/apy/pool-apy-utils.d.ts +73 -0
  73. package/dist/types/plugins/apy/types.d.ts +37 -0
  74. package/dist/types/rewards/rewards/api.d.ts +10 -1
  75. package/dist/types/rewards/rewards/common.d.ts +0 -10
  76. package/dist/types/rewards/rewards/extra-apy.d.ts +4 -6
  77. package/dist/types/sdk/GearboxSDK.d.ts +0 -7
  78. package/dist/types/sdk/accounts/AbstractCreditAccountsService.d.ts +2 -52
  79. package/dist/types/sdk/accounts/CreditAccountsServiceV310.d.ts +1 -1
  80. package/dist/types/sdk/accounts/types.d.ts +13 -93
  81. package/dist/types/sdk/base/TokensMeta.d.ts +3 -14
  82. package/dist/types/sdk/base/token-types.d.ts +4 -44
  83. package/dist/types/sdk/base/types.d.ts +11 -116
  84. package/dist/types/sdk/chain/chains.d.ts +5 -5
  85. package/dist/types/sdk/constants/address-provider.d.ts +0 -1
  86. package/dist/types/sdk/market/MarketRegister.d.ts +9 -6
  87. package/dist/types/sdk/market/MarketSuite.d.ts +0 -2
  88. package/dist/types/sdk/market/index.d.ts +0 -1
  89. package/dist/types/sdk/market/oracle/PriceOracleBaseContract.d.ts +2 -3
  90. package/dist/types/sdk/market/oracle/types.d.ts +10 -3
  91. package/dist/types/sdk/market/pool/PoolSuite.d.ts +0 -2
  92. package/dist/types/sdk/market/pool/PoolV310Contract.d.ts +2 -6
  93. package/dist/types/sdk/market/pool/index.d.ts +0 -1
  94. package/dist/types/sdk/market/pricefeeds/PriceFeedsRegister.d.ts +1 -1
  95. package/dist/types/sdk/market/types.d.ts +1 -1
  96. package/dist/types/sdk/options.d.ts +0 -1
  97. package/dist/types/sdk/pools/PoolService.d.ts +8 -8
  98. package/dist/types/sdk/pools/types.d.ts +1 -1
  99. package/dist/types/sdk/types/state-human.d.ts +0 -2
  100. package/dist/types/sdk/types/state.d.ts +0 -5
  101. package/dist/types/sdk/utils/viem/index.d.ts +0 -1
  102. package/package.json +2 -3
  103. package/dist/cjs/abi/kyc/iDSRegistryService.js +0 -70
  104. package/dist/cjs/abi/kyc/iDSToken.js +0 -71
  105. package/dist/cjs/abi/kyc/iKYCCompressor.js +0 -196
  106. package/dist/cjs/abi/kyc/iKYCFactory.js +0 -122
  107. package/dist/cjs/abi/kyc/iKYCUnderlying.js +0 -401
  108. package/dist/cjs/abi/kyc/iSecuritizeDegenNFT.js +0 -326
  109. package/dist/cjs/abi/kyc/iSecuritizeKYCFactory.js +0 -319
  110. package/dist/cjs/plugins/pools-history/Pools7DAgoPlugin.js +0 -108
  111. package/dist/cjs/plugins/pools-history/index.js +0 -24
  112. package/dist/cjs/sdk/market/kyc/KYCRegistry.js +0 -269
  113. package/dist/cjs/sdk/market/kyc/index.js +0 -26
  114. package/dist/cjs/sdk/market/kyc/securitize/SecuritizeKYCFactory.js +0 -244
  115. package/dist/cjs/sdk/market/kyc/types.js +0 -34
  116. package/dist/cjs/sdk/utils/viem/executeDelegatedMulticalls.js +0 -38
  117. package/dist/esm/abi/kyc/iDSRegistryService.js +0 -46
  118. package/dist/esm/abi/kyc/iDSToken.js +0 -47
  119. package/dist/esm/abi/kyc/iKYCCompressor.js +0 -172
  120. package/dist/esm/abi/kyc/iKYCFactory.js +0 -98
  121. package/dist/esm/abi/kyc/iKYCUnderlying.js +0 -377
  122. package/dist/esm/abi/kyc/iSecuritizeDegenNFT.js +0 -302
  123. package/dist/esm/abi/kyc/iSecuritizeKYCFactory.js +0 -295
  124. package/dist/esm/plugins/pools-history/Pools7DAgoPlugin.js +0 -90
  125. package/dist/esm/plugins/pools-history/index.js +0 -2
  126. package/dist/esm/sdk/market/kyc/KYCRegistry.js +0 -253
  127. package/dist/esm/sdk/market/kyc/index.js +0 -3
  128. package/dist/esm/sdk/market/kyc/securitize/SecuritizeKYCFactory.js +0 -220
  129. package/dist/esm/sdk/market/kyc/securitize/constants.js +0 -4
  130. package/dist/esm/sdk/market/kyc/securitize/index.js +0 -3
  131. package/dist/esm/sdk/market/kyc/types.js +0 -9
  132. package/dist/esm/sdk/utils/viem/executeDelegatedMulticalls.js +0 -14
  133. package/dist/types/abi/kyc/iDSRegistryService.d.ts +0 -71
  134. package/dist/types/abi/kyc/iDSToken.d.ts +0 -67
  135. package/dist/types/abi/kyc/iKYCCompressor.d.ts +0 -228
  136. package/dist/types/abi/kyc/iKYCFactory.d.ts +0 -139
  137. package/dist/types/abi/kyc/iKYCUnderlying.d.ts +0 -548
  138. package/dist/types/abi/kyc/iSecuritizeDegenNFT.d.ts +0 -404
  139. package/dist/types/abi/kyc/iSecuritizeKYCFactory.d.ts +0 -376
  140. package/dist/types/plugins/pools-history/Pools7DAgoPlugin.d.ts +0 -20
  141. package/dist/types/plugins/pools-history/index.d.ts +0 -2
  142. package/dist/types/plugins/pools-history/types.d.ts +0 -9
  143. package/dist/types/sdk/market/kyc/KYCRegistry.d.ts +0 -52
  144. package/dist/types/sdk/market/kyc/index.d.ts +0 -3
  145. package/dist/types/sdk/market/kyc/securitize/SecuritizeKYCFactory.d.ts +0 -428
  146. package/dist/types/sdk/market/kyc/securitize/constants.d.ts +0 -1
  147. package/dist/types/sdk/market/kyc/securitize/index.d.ts +0 -3
  148. package/dist/types/sdk/market/kyc/securitize/types.d.ts +0 -127
  149. package/dist/types/sdk/market/kyc/types.d.ts +0 -170
  150. package/dist/types/sdk/utils/viem/executeDelegatedMulticalls.d.ts +0 -28
  151. /package/dist/cjs/plugins/{pools-history → apy}/package.json +0 -0
  152. /package/dist/cjs/plugins/{pools-history → apy}/types.js +0 -0
  153. /package/dist/esm/plugins/{pools-history → apy}/package.json +0 -0
  154. /package/dist/esm/plugins/{pools-history/types.js → apy/pool-apy-types.js} +0 -0
  155. /package/dist/esm/{sdk/market/kyc/securitize → plugins/apy}/types.js +0 -0
@@ -0,0 +1,255 @@
1
+ import { marketCompressorAbi } from "../../abi/compressors/marketCompressor.js";
2
+ import { PoolPointsAPI } from "../../rewards/rewards/extra-apy.js";
3
+ import {
4
+ AddressMap,
5
+ AP_MARKET_COMPRESSOR,
6
+ BasePlugin,
7
+ BLOCKS_PER_WEEK_BY_NETWORK,
8
+ PERCENTAGE_DECIMALS,
9
+ VERSION_RANGE_310
10
+ } from "../../sdk/index.js";
11
+ import { rayToNumber } from "../../sdk/utils/formatter.js";
12
+ import { hexEq } from "../../sdk/utils/hex.js";
13
+ import { ApyOutputCache } from "./apy-cache.js";
14
+ import { parseGearStats, parseNetworkApy } from "./apy-parser.js";
15
+ import { APY_STATE_CACHE_URL, DEFAULT_APY_INTERVAL_MS } from "./constants.js";
16
+ import {
17
+ calculatePoolFullAPY,
18
+ calculatePoolFullAPY7DAgo,
19
+ calculatePoolPoints,
20
+ calculateSupplyApy7d,
21
+ getPoolExtraAPY
22
+ } from "./pool-apy-utils.js";
23
+ const MAP_LABEL = "pools7DAgo";
24
+ class ApyPlugin extends BasePlugin {
25
+ #apyUrl;
26
+ #cacheTtlMs;
27
+ #pools7DAgo;
28
+ #apySnapshot;
29
+ constructor(loadOnAttach = false, options) {
30
+ super(loadOnAttach);
31
+ this.#apyUrl = options?.apyUrl ?? APY_STATE_CACHE_URL;
32
+ this.#cacheTtlMs = options?.cacheTtlMs ?? DEFAULT_APY_INTERVAL_MS;
33
+ }
34
+ // ---------------------------------------------------------------------------
35
+ // Load — single entry point for all data (on-chain + state-cache)
36
+ // ---------------------------------------------------------------------------
37
+ async load(force, loadOptions) {
38
+ if (!force && this.loaded) {
39
+ return this.state;
40
+ }
41
+ const targetBlock = this.sdk.currentBlock - BLOCKS_PER_WEEK_BY_NETWORK[this.sdk.networkType];
42
+ const [marketCompressorAddress] = this.sdk.addressProvider.mustGetLatest(
43
+ AP_MARKET_COMPRESSOR,
44
+ VERSION_RANGE_310
45
+ );
46
+ this.#logger?.debug(
47
+ `loading pools 7d ago with market compressor ${marketCompressorAddress}`
48
+ );
49
+ const markets = this.sdk.marketRegister.markets;
50
+ const shouldLoadPools7DAgo = !this.#pools7DAgo || !!loadOptions?.loadPools7DAgo;
51
+ const [multicallResp, apySnapshot] = await Promise.all([
52
+ shouldLoadPools7DAgo ? this.client.multicall({
53
+ allowFailure: true,
54
+ contracts: markets.map(
55
+ (m) => ({
56
+ address: marketCompressorAddress,
57
+ abi: marketCompressorAbi,
58
+ functionName: "getPoolState",
59
+ args: [m.pool.pool.address]
60
+ })
61
+ ),
62
+ blockNumber: targetBlock > 0n ? targetBlock : void 0,
63
+ batchSize: 0
64
+ }) : null,
65
+ this.#fetchApy()
66
+ ]);
67
+ if (multicallResp !== null) {
68
+ this.#pools7DAgo = new AddressMap(void 0, MAP_LABEL);
69
+ multicallResp.forEach((r, index) => {
70
+ const m = markets[index];
71
+ const cfg = m.configurator.address;
72
+ const pool = m.pool.pool.address;
73
+ if (r.status === "success") {
74
+ this.#pools7DAgo?.upsert(m.pool.pool.address, {
75
+ dieselRate: r.result.dieselRate,
76
+ pool
77
+ });
78
+ } else {
79
+ this.#logger?.error(
80
+ `failed to load pools 7d ago for market configurator ${this.labelAddress(cfg)} and pool ${this.labelAddress(pool)}: ${r.error}`
81
+ );
82
+ }
83
+ });
84
+ }
85
+ if (apySnapshot) {
86
+ this.#apySnapshot = apySnapshot;
87
+ }
88
+ return this.state;
89
+ }
90
+ get loaded() {
91
+ return !!this.#pools7DAgo && !!this.#apySnapshot;
92
+ }
93
+ // ---------------------------------------------------------------------------
94
+ // Accessors
95
+ // ---------------------------------------------------------------------------
96
+ /**
97
+ * @throws if plugin is not loaded
98
+ */
99
+ get pools7DAgo() {
100
+ if (!this.#pools7DAgo) {
101
+ throw new Error("apy plugin not loaded");
102
+ }
103
+ return this.#pools7DAgo;
104
+ }
105
+ /**
106
+ * @throws if plugin is not loaded
107
+ */
108
+ get apySnapshot() {
109
+ if (!this.#apySnapshot) {
110
+ throw new Error("apy plugin not loaded");
111
+ }
112
+ return this.#apySnapshot;
113
+ }
114
+ // ---------------------------------------------------------------------------
115
+ // Aggregated APY / points
116
+ // ---------------------------------------------------------------------------
117
+ /**
118
+ * Computes per-pool APY (current + 7d-ago) and points for all markets.
119
+ *
120
+ * @throws if plugin is not loaded
121
+ */
122
+ getPoolsAPY() {
123
+ if (!this.loaded) {
124
+ throw new Error("apy plugin not loaded");
125
+ }
126
+ const markets = this.sdk.marketRegister.markets;
127
+ const { apy } = this.apySnapshot;
128
+ const totalTokenBalances = {};
129
+ const poolPointsBase = apy.poolRewardsList && Object.keys(apy.poolRewardsList).length > 0 ? PoolPointsAPI.getPointsByPool({
130
+ poolRewards: apy.poolRewardsList,
131
+ totalTokenBalances,
132
+ pools: markets,
133
+ tokensList: this.sdk.tokensMeta
134
+ }) : {};
135
+ const data = {};
136
+ const data7DAgo = {};
137
+ const points = {};
138
+ for (const market of markets) {
139
+ const pool = market.pool.pool;
140
+ const poolAddr = pool.address.toLowerCase();
141
+ const underlyingLc = pool.underlying.toLowerCase();
142
+ const depositAPY = rayToNumber(pool.supplyRate) * Number(PERCENTAGE_DECIMALS);
143
+ const underlyingAPY = apy.apyList?.[underlyingLc] ?? apy.apyList?.[pool.underlying] ?? 0;
144
+ const lookupAddresses = this.#getExtraAPYLookupAddresses(poolAddr);
145
+ const extraAPY = getPoolExtraAPY(lookupAddresses, apy.poolExtraAPYList);
146
+ const currentExternalList = apy.poolExternalAPYList?.[poolAddr];
147
+ const poolAPY = calculatePoolFullAPY({
148
+ depositAPY,
149
+ underlyingAPY,
150
+ extraAPY,
151
+ currentExternalList
152
+ });
153
+ data[poolAddr] = poolAPY;
154
+ const pool7DAgo = this.#pools7DAgo?.get(poolAddr);
155
+ const supplyAPY7DAgo = pool7DAgo ? calculateSupplyApy7d(
156
+ pool.dieselRate,
157
+ pool.supplyRate,
158
+ pool7DAgo.dieselRate
159
+ ) : void 0;
160
+ data7DAgo[poolAddr] = calculatePoolFullAPY7DAgo({
161
+ supplyAPY7DAgo,
162
+ depositAPY,
163
+ poolAPY
164
+ });
165
+ const poolTokenMeta = this.sdk.tokensMeta.get(pool.underlying);
166
+ points[poolAddr] = calculatePoolPoints({
167
+ poolTokenSymbol: poolTokenMeta?.symbol,
168
+ points: poolPointsBase[poolAddr],
169
+ tokensList: this.sdk.tokensMeta
170
+ });
171
+ }
172
+ return { data, data7DAgo, pointsBase: poolPointsBase, points };
173
+ }
174
+ // ---------------------------------------------------------------------------
175
+ // Plugin lifecycle
176
+ // ---------------------------------------------------------------------------
177
+ async syncState() {
178
+ await this.load();
179
+ }
180
+ stateHuman(_) {
181
+ return this.pools7DAgo.values().flatMap((p) => ({
182
+ address: p.pool,
183
+ version: this.version,
184
+ dieselRate: p.dieselRate
185
+ }));
186
+ }
187
+ get state() {
188
+ return {
189
+ pools7DAgo: this.pools7DAgo.asRecord(),
190
+ apySnapshot: this.apySnapshot
191
+ };
192
+ }
193
+ hydrate(state) {
194
+ this.#pools7DAgo = new AddressMap(
195
+ Object.entries(state.pools7DAgo),
196
+ MAP_LABEL
197
+ );
198
+ this.#apySnapshot = state.apySnapshot;
199
+ }
200
+ // ---------------------------------------------------------------------------
201
+ // Internal
202
+ // ---------------------------------------------------------------------------
203
+ async #fetchApy() {
204
+ try {
205
+ const cache = ApyOutputCache.get(
206
+ this.#apyUrl,
207
+ this.#cacheTtlMs,
208
+ this.#logger
209
+ );
210
+ const output = await cache.fetch();
211
+ if (!output) return void 0;
212
+ const chainData = output.chains[this.sdk.chainId];
213
+ if (!chainData) {
214
+ this.#logger?.debug(
215
+ `apy state-cache: no data for chainId ${this.sdk.chainId}`
216
+ );
217
+ return void 0;
218
+ }
219
+ const apy = parseNetworkApy(chainData.tokens, chainData.pools);
220
+ if (!apy) return void 0;
221
+ return {
222
+ apy,
223
+ gearStats: parseGearStats(output),
224
+ timestamp: output.timestamp
225
+ };
226
+ } catch (e) {
227
+ this.#logger?.error(e, "failed to fetch apy state-cache");
228
+ return void 0;
229
+ }
230
+ }
231
+ /**
232
+ * Collects addresses to look up in poolExtraAPYList for a given pool.
233
+ * Includes pool address (= diesel token) + any staked diesel token
234
+ * outputs discovered from zappers.
235
+ */
236
+ #getExtraAPYLookupAddresses(poolAddr) {
237
+ const addresses = [poolAddr];
238
+ try {
239
+ const zappers = this.sdk.marketRegister.poolZappers(poolAddr);
240
+ for (const z of zappers) {
241
+ if (!hexEq(z.tokenOut.addr, poolAddr)) {
242
+ addresses.push(z.tokenOut.addr);
243
+ }
244
+ }
245
+ } catch {
246
+ }
247
+ return addresses;
248
+ }
249
+ get #logger() {
250
+ return this.logger;
251
+ }
252
+ }
253
+ export {
254
+ ApyPlugin
255
+ };
@@ -0,0 +1,86 @@
1
+ import axios from "axios";
2
+ class ApyOutputCache {
3
+ static #instances = /* @__PURE__ */ new Map();
4
+ #url;
5
+ #ttlMs;
6
+ #cache;
7
+ #pending;
8
+ #logger;
9
+ constructor(url, ttlMs, logger) {
10
+ this.#url = url;
11
+ this.#ttlMs = ttlMs;
12
+ this.#logger = logger;
13
+ }
14
+ /**
15
+ * Returns a shared cache instance for the given URL.
16
+ * The same instance is reused across all callers with identical URL.
17
+ */
18
+ static get(url, ttlMs, logger) {
19
+ let instance = ApyOutputCache.#instances.get(url);
20
+ if (!instance) {
21
+ instance = new ApyOutputCache(url, ttlMs, logger);
22
+ ApyOutputCache.#instances.set(url, instance);
23
+ }
24
+ if (logger) {
25
+ instance.#logger = logger;
26
+ }
27
+ return instance;
28
+ }
29
+ /**
30
+ * Returns cached Output if fresh, otherwise fetches from the network.
31
+ * Concurrent calls are de-duplicated.
32
+ */
33
+ async fetch() {
34
+ if (this.#cache && Date.now() - this.#cache.fetchedAt < this.#ttlMs) {
35
+ this.#logger?.debug("apy cache: TTL still valid, returning cached data");
36
+ return this.#cache.data;
37
+ }
38
+ if (this.#pending) {
39
+ this.#logger?.debug("apy cache: request in flight, waiting");
40
+ return this.#pending;
41
+ }
42
+ this.#pending = this.#doFetch();
43
+ try {
44
+ return await this.#pending;
45
+ } finally {
46
+ this.#pending = void 0;
47
+ }
48
+ }
49
+ async #doFetch() {
50
+ try {
51
+ const headers = {};
52
+ if (this.#cache?.etag) {
53
+ headers["If-None-Match"] = this.#cache.etag;
54
+ }
55
+ const response = await axios.get(this.#url, {
56
+ headers,
57
+ validateStatus: (status) => status === 200 || status === 304
58
+ });
59
+ if (response.status === 304 && this.#cache) {
60
+ this.#cache.fetchedAt = Date.now();
61
+ this.#logger?.debug("apy cache: 304 Not Modified, extended TTL");
62
+ return this.#cache.data;
63
+ }
64
+ const etag = response.headers["etag"];
65
+ this.#cache = {
66
+ data: response.data,
67
+ etag,
68
+ fetchedAt: Date.now()
69
+ };
70
+ this.#logger?.debug(
71
+ `apy cache: fetched fresh data (timestamp: ${response.data.timestamp})`
72
+ );
73
+ return response.data;
74
+ } catch (e) {
75
+ this.#logger?.error(e, "apy cache: fetch failed");
76
+ return this.#cache?.data;
77
+ }
78
+ }
79
+ /** Evicts all cached entries. Mainly useful for tests. */
80
+ static clearAll() {
81
+ ApyOutputCache.#instances.clear();
82
+ }
83
+ }
84
+ export {
85
+ ApyOutputCache
86
+ };
@@ -0,0 +1,143 @@
1
+ import { PERCENTAGE_FACTOR } from "../../sdk/index.js";
2
+ function numberToAPY(baseApy) {
3
+ return Math.round(baseApy * Number(PERCENTAGE_FACTOR));
4
+ }
5
+ function parseGearStats(output) {
6
+ const d = output.gearApy?.status === "ok" ? output.gearApy.data : void 0;
7
+ if (!d) return null;
8
+ return {
9
+ base: numberToAPY(d.base ?? 0),
10
+ crv: numberToAPY(d.crv ?? 0),
11
+ gear: numberToAPY(d.gear ?? 0),
12
+ gearPrice: d.gearPrice ?? 0
13
+ };
14
+ }
15
+ function parseNetworkApy(apyResp, poolResp) {
16
+ const baseAPYList = {};
17
+ const extraCollateralAPYList = {};
18
+ const basePointsList = {};
19
+ const extraCollateralPointsList = {};
20
+ const tokenExtraRewardsList = {};
21
+ const apyData = apyResp?.status === "ok" ? apyResp.data : void 0;
22
+ for (const d of apyData ?? []) {
23
+ const tokenAddress = d.address.toLowerCase();
24
+ const tokenSymbol = d.symbol;
25
+ const apy = d.rewards.apy?.[0];
26
+ if (apy) {
27
+ baseAPYList[tokenAddress] = numberToAPY(apy.value ?? 0);
28
+ }
29
+ const points = d.rewards.points?.[0];
30
+ if (points) {
31
+ basePointsList[tokenAddress] = {
32
+ address: tokenAddress,
33
+ symbol: tokenSymbol,
34
+ rewards: points.rewards.map((p) => ({
35
+ ...p,
36
+ multiplier: p.multiplier === "soon" ? p.multiplier : BigInt(p.multiplier || 0)
37
+ })),
38
+ debtRewards: points.debtRewards?.map((p) => ({
39
+ ...p,
40
+ cm: (p.cm || "").toLowerCase(),
41
+ multiplier: p.multiplier === "soon" ? p.multiplier : BigInt(p.multiplier || 0)
42
+ }))
43
+ };
44
+ }
45
+ const extraRewards = d.rewards.extraRewards;
46
+ if (extraRewards && extraRewards.length > 0) {
47
+ tokenExtraRewardsList[tokenAddress] = extraRewards.map((r) => ({
48
+ address: tokenAddress,
49
+ symbol: r.rewardSymbol,
50
+ rewardToken: r.rewardToken.toLowerCase(),
51
+ rewardSymbol: r.rewardSymbol,
52
+ token: r.rewardToken.toLowerCase(),
53
+ finished: BigInt(r.finished || 0),
54
+ duration: BigInt(r.duration || 0),
55
+ reward: BigInt(r.reward || 0),
56
+ balance: BigInt(r.balance || 0)
57
+ }));
58
+ }
59
+ const ecApy = d.rewards.extraCollateralAPY;
60
+ if (ecApy && ecApy.length > 0) {
61
+ for (const ea of ecApy) {
62
+ const pool = ea.pool.toLowerCase();
63
+ if (!extraCollateralAPYList[pool]) extraCollateralAPYList[pool] = {};
64
+ extraCollateralAPYList[pool][tokenAddress] = {
65
+ ...ea,
66
+ address: tokenAddress,
67
+ symbol: tokenSymbol,
68
+ pool,
69
+ value: numberToAPY(ea.value ?? 0)
70
+ };
71
+ }
72
+ }
73
+ const ecPoints = d.rewards.extraCollateralPoints;
74
+ if (ecPoints && ecPoints.length > 0) {
75
+ for (const ea of ecPoints) {
76
+ const pool = ea.pool.toLowerCase();
77
+ if (!extraCollateralPointsList[pool])
78
+ extraCollateralPointsList[pool] = {};
79
+ extraCollateralPointsList[pool][tokenAddress] = {
80
+ address: tokenAddress,
81
+ symbol: tokenSymbol,
82
+ rewards: ea.rewards.map((p) => ({
83
+ ...p,
84
+ multiplier: p.multiplier === "soon" ? p.multiplier : BigInt(p.multiplier || 0)
85
+ })),
86
+ debtRewards: ea.debtRewards?.map((p) => ({
87
+ ...p,
88
+ cm: (p.cm || "").toLowerCase(),
89
+ multiplier: p.multiplier === "soon" ? p.multiplier : BigInt(p.multiplier || 0)
90
+ }))
91
+ };
92
+ }
93
+ }
94
+ }
95
+ const poolRewardsList = {};
96
+ const poolExternalAPYList = {};
97
+ const poolExtraAPYList = {};
98
+ const poolData = poolResp?.status === "ok" ? poolResp.data : void 0;
99
+ for (const r of poolData ?? []) {
100
+ const pool = (r.pool || "").toLowerCase();
101
+ const points = r.rewards.points;
102
+ if (points && points.length > 0) {
103
+ poolRewardsList[pool] = points.map((p) => ({
104
+ ...p,
105
+ token: p.token.toLowerCase(),
106
+ pool,
107
+ amount: BigInt(p.amount || 0)
108
+ }));
109
+ }
110
+ const externalAPY = r.rewards.externalAPY;
111
+ if (externalAPY && externalAPY.length > 0) {
112
+ poolExternalAPYList[pool] = externalAPY.map((ex) => ({ ...ex, pool }));
113
+ }
114
+ const extraAPY = r.rewards.extraAPY;
115
+ if (extraAPY && extraAPY.length > 0) {
116
+ poolExtraAPYList[extraAPY[0].token.toLowerCase()] = extraAPY.map((ex) => ({
117
+ ...ex,
118
+ token: ex.token.toLowerCase(),
119
+ rewardToken: ex.rewardToken.toLowerCase()
120
+ }));
121
+ }
122
+ }
123
+ const allResponses = [apyResp, poolResp];
124
+ const allErrors = allResponses.filter((r) => r?.status === "error");
125
+ if (allResponses.length > 0 && allErrors.length === allResponses.length) {
126
+ return void 0;
127
+ }
128
+ return {
129
+ apyList: Object.keys(baseAPYList).length > 0 ? baseAPYList : void 0,
130
+ extraCollateralAPYList: Object.keys(extraCollateralAPYList).length > 0 ? extraCollateralAPYList : void 0,
131
+ pointsList: Object.keys(basePointsList).length > 0 ? basePointsList : void 0,
132
+ extraCollateralPointsList: Object.keys(extraCollateralPointsList).length > 0 ? extraCollateralPointsList : void 0,
133
+ poolRewardsList: Object.keys(poolRewardsList).length > 0 ? poolRewardsList : void 0,
134
+ tokenExtraRewardsList: Object.keys(tokenExtraRewardsList).length > 0 ? tokenExtraRewardsList : void 0,
135
+ poolExternalAPYList: Object.keys(poolExternalAPYList).length > 0 ? poolExternalAPYList : void 0,
136
+ poolExtraAPYList: Object.keys(poolExtraAPYList).length > 0 ? poolExtraAPYList : void 0
137
+ };
138
+ }
139
+ export {
140
+ numberToAPY,
141
+ parseGearStats,
142
+ parseNetworkApy
143
+ };
@@ -0,0 +1,6 @@
1
+ const APY_STATE_CACHE_URL = "https://state-cache.gearbox.foundation/apy-server/latest.json";
2
+ const DEFAULT_APY_INTERVAL_MS = 10 * 60 * 1e3;
3
+ export {
4
+ APY_STATE_CACHE_URL,
5
+ DEFAULT_APY_INTERVAL_MS
6
+ };
@@ -0,0 +1,7 @@
1
+ export * from "./ApyPlugin.js";
2
+ export * from "./apy-cache.js";
3
+ export * from "./apy-parser.js";
4
+ export * from "./constants.js";
5
+ export * from "./pool-apy-types.js";
6
+ export * from "./pool-apy-utils.js";
7
+ export * from "./types.js";
@@ -0,0 +1,113 @@
1
+ import { PERCENTAGE_FACTOR, RAY } from "../../sdk/constants/index.js";
2
+ import { formatBN, rayToNumber } from "../../sdk/utils/formatter.js";
3
+ const SCALE = 1000000n;
4
+ const WEEKS_PER_YEAR = 54n;
5
+ function getPoolExtraAPY(lookupAddresses, poolExtraAPYList) {
6
+ if (!poolExtraAPYList) return [];
7
+ const result = [];
8
+ for (const addr of lookupAddresses) {
9
+ const extra = poolExtraAPYList[addr.toLowerCase()];
10
+ if (extra) {
11
+ result.push(...extra);
12
+ }
13
+ }
14
+ return result;
15
+ }
16
+ function calculateSupplyApy7d(currentDieselRate, currentSupplyRate, dieselRate7DAgo) {
17
+ if (dieselRate7DAgo > currentDieselRate) {
18
+ return rayToNumber(currentSupplyRate * SCALE) / Number(PERCENTAGE_FACTOR);
19
+ }
20
+ const apy = (currentDieselRate * RAY / dieselRate7DAgo - RAY) * WEEKS_PER_YEAR;
21
+ return rayToNumber(apy * SCALE) / Number(PERCENTAGE_FACTOR);
22
+ }
23
+ function calculatePoolFullAPY({
24
+ depositAPY,
25
+ underlyingAPY,
26
+ extraAPY,
27
+ currentExternalList
28
+ }) {
29
+ const baseAPY = [
30
+ { type: "supplyAPY", apy: depositAPY },
31
+ ...underlyingAPY > 0 ? [
32
+ {
33
+ type: "tokenYield",
34
+ apy: Number(underlyingAPY) / Number(PERCENTAGE_FACTOR)
35
+ }
36
+ ] : []
37
+ ];
38
+ const filteredExtra = [...extraAPY ?? []].filter((r) => r.apy > 0);
39
+ const baseAPYTotal = baseAPY.reduce((s, r) => s + (r.apy || 0), 0);
40
+ const extraAPYTotal = filteredExtra.reduce((s, r) => s + (r.apy || 0), 0);
41
+ const total = baseAPYTotal + extraAPYTotal;
42
+ const externalAPY = resolveExternalAPY(currentExternalList, total);
43
+ return {
44
+ totalAPY: total,
45
+ baseAPY,
46
+ extraAPY: filteredExtra,
47
+ extraAPYTotal,
48
+ externalAPY
49
+ };
50
+ }
51
+ function resolveExternalAPY(list, baseTotal) {
52
+ const first = list?.[0];
53
+ if (!first) return void 0;
54
+ return {
55
+ ...first,
56
+ totalValue: baseTotal + first.value
57
+ };
58
+ }
59
+ function calculatePoolFullAPY7DAgo({
60
+ supplyAPY7DAgo,
61
+ depositAPY,
62
+ poolAPY
63
+ }) {
64
+ const {
65
+ baseAPY = [],
66
+ extraAPYTotal = 0,
67
+ extraAPY = [],
68
+ externalAPY
69
+ } = poolAPY ?? {};
70
+ const base = [
71
+ { apy: supplyAPY7DAgo || depositAPY, type: "supplyAPY" },
72
+ ...baseAPY.filter((r) => r.type !== "supplyAPY")
73
+ ];
74
+ const baseTotal = base.reduce((acc, r) => acc + r.apy, 0);
75
+ const total = baseTotal + extraAPYTotal;
76
+ return {
77
+ totalAPY: total,
78
+ extraAPYTotal,
79
+ baseAPY: base,
80
+ extraAPY,
81
+ externalAPY,
82
+ loading7DAgo: supplyAPY7DAgo === void 0
83
+ };
84
+ }
85
+ function calculatePoolPoints({
86
+ poolTokenSymbol,
87
+ points,
88
+ tokensList
89
+ }) {
90
+ return points?.map(({ info, points: pts }) => {
91
+ const { decimals = 18 } = tokensList.get(info.token) || {};
92
+ const amount = formatBN(pts, decimals);
93
+ const { name = "Points", duration } = info ?? {};
94
+ return {
95
+ reward: info,
96
+ name,
97
+ amount,
98
+ tokenTitle: poolTokenSymbol,
99
+ fullTip: [
100
+ `${amount} ${name}`,
101
+ ...duration ? [duration] : [],
102
+ ...poolTokenSymbol ? [poolTokenSymbol] : []
103
+ ].join(" per ")
104
+ };
105
+ });
106
+ }
107
+ export {
108
+ calculatePoolFullAPY,
109
+ calculatePoolFullAPY7DAgo,
110
+ calculatePoolPoints,
111
+ calculateSupplyApy7d,
112
+ getPoolExtraAPY
113
+ };
@@ -52,11 +52,13 @@ class PoolPointsAPI {
52
52
  tokensList
53
53
  }) {
54
54
  const r = pools.reduce((acc, p) => {
55
- const pointsInfo = poolRewards[p.address] || [];
55
+ const poolAddress = p.pool.pool.address.toLowerCase();
56
+ const pointsInfo = poolRewards[poolAddress] || [];
56
57
  const poolPointsList = pointsInfo.reduce(
57
58
  (acc2, pointsInfo2) => {
58
- const { address: tokenAddress } = tokensList[pointsInfo2.token] || {};
59
- const tokenBalance = totalTokenBalances[tokenAddress || ""];
59
+ const { addr: tokenAddress } = tokensList.get(pointsInfo2.token) || {};
60
+ const tokenAddressLower = (tokenAddress || "").toLowerCase();
61
+ const tokenBalance = totalTokenBalances[tokenAddressLower];
60
62
  const points = PoolPointsAPI.getPoolTokenPoints(
61
63
  tokenBalance,
62
64
  p,
@@ -74,22 +76,22 @@ class PoolPointsAPI {
74
76
  },
75
77
  []
76
78
  );
77
- acc[p.address] = poolPointsList;
79
+ acc[poolAddress] = poolPointsList;
78
80
  return acc;
79
81
  }, {});
80
82
  return r;
81
83
  }
82
84
  static getPoolTokenPoints(tokenBalanceInPool, pool, tokensList, pointsInfo) {
83
- if (pool.expectedLiquidity <= 0) return 0n;
85
+ if (pool.pool.pool.expectedLiquidity <= 0) return 0n;
84
86
  if (pointsInfo.estimation === "relative" && !tokenBalanceInPool)
85
87
  return null;
86
- const { decimals = 18 } = tokensList[pointsInfo.token] || {};
88
+ const { decimals = 18 } = tokensList.get(pointsInfo.token) || {};
87
89
  const targetFactor = 10n ** BigInt(decimals);
88
90
  const defaultPoints = pointsInfo.amount * targetFactor / PERCENTAGE_FACTOR;
89
91
  if (pointsInfo.estimation === "absolute") return defaultPoints;
90
- const { decimals: underlyingDecimals = 18 } = tokensList[pool.underlyingToken] || {};
92
+ const { decimals: underlyingDecimals = 18 } = tokensList.get(pool.pool.pool.underlying) || {};
91
93
  const underlyingFactor = 10n ** BigInt(underlyingDecimals);
92
- const points = (tokenBalanceInPool?.balance || 0n) * defaultPoints / (pool.expectedLiquidity * targetFactor / underlyingFactor);
94
+ const points = (tokenBalanceInPool?.balance || 0n) * defaultPoints / (pool.pool.pool.expectedLiquidity * targetFactor / underlyingFactor);
93
95
  return BigIntMath.min(points, defaultPoints);
94
96
  }
95
97
  }