@strkfarm/sdk 2.0.0-dev.5 → 2.0.0-dev.50
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/cli.js +190 -36
- package/dist/cli.mjs +188 -34
- package/dist/index.browser.global.js +119400 -92821
- package/dist/index.browser.mjs +13293 -11146
- package/dist/index.d.ts +2281 -1938
- package/dist/index.js +13532 -11179
- package/dist/index.mjs +14165 -11836
- package/package.json +59 -60
- package/src/data/avnu.abi.json +840 -0
- package/src/data/ekubo-price-fethcer.abi.json +265 -0
- package/src/data/redeem-request-nft.abi.json +752 -0
- package/src/data/universal-vault.abi.json +8 -7
- package/src/dataTypes/_bignumber.ts +13 -4
- package/src/dataTypes/bignumber.browser.ts +10 -1
- package/src/dataTypes/bignumber.node.ts +10 -1
- package/src/dataTypes/index.ts +3 -2
- package/src/dataTypes/mynumber.ts +141 -0
- package/src/global.ts +279 -233
- package/src/index.browser.ts +2 -1
- package/src/interfaces/common.tsx +228 -6
- package/src/modules/apollo-client-config.ts +28 -0
- package/src/modules/avnu.ts +21 -12
- package/src/modules/ekubo-pricer.ts +80 -0
- package/src/modules/ekubo-quoter.ts +48 -30
- package/src/modules/erc20.ts +17 -0
- package/src/modules/harvests.ts +43 -29
- package/src/modules/index.ts +2 -1
- package/src/modules/pragma.ts +23 -8
- package/src/modules/pricer-avnu-api.ts +114 -0
- package/src/modules/pricer-from-api.ts +156 -15
- package/src/modules/pricer-lst.ts +1 -1
- package/src/modules/pricer.ts +107 -41
- package/src/modules/pricerBase.ts +2 -1
- package/src/modules/zkLend.ts +3 -2
- package/src/node/deployer.ts +36 -1
- package/src/node/pricer-redis.ts +3 -1
- package/src/strategies/base-strategy.ts +168 -16
- package/src/strategies/constants.ts +8 -3
- package/src/strategies/ekubo-cl-vault.tsx +1048 -355
- package/src/strategies/factory.ts +199 -0
- package/src/strategies/index.ts +5 -3
- package/src/strategies/registry.ts +262 -0
- package/src/strategies/sensei.ts +354 -10
- package/src/strategies/svk-strategy.ts +292 -31
- package/src/strategies/token-boosted-xstrk-carry-strategy.tsx +1261 -0
- package/src/strategies/types.ts +4 -0
- package/src/strategies/universal-adapters/adapter-utils.ts +4 -1
- package/src/strategies/universal-adapters/avnu-adapter.ts +196 -272
- package/src/strategies/universal-adapters/baseAdapter.ts +263 -251
- package/src/strategies/universal-adapters/common-adapter.ts +206 -203
- package/src/strategies/universal-adapters/index.ts +10 -8
- package/src/strategies/universal-adapters/svk-troves-adapter.ts +511 -0
- package/src/strategies/universal-adapters/token-transfer-adapter.ts +200 -0
- package/src/strategies/universal-adapters/vesu-adapter.ts +120 -82
- package/src/strategies/universal-adapters/vesu-modify-position-adapter.ts +525 -0
- package/src/strategies/universal-adapters/vesu-multiply-adapter.ts +866 -860
- package/src/strategies/universal-adapters/vesu-position-common.ts +258 -0
- package/src/strategies/universal-adapters/vesu-supply-only-adapter.ts +18 -3
- package/src/strategies/universal-lst-muliplier-strategy.tsx +895 -416
- package/src/strategies/universal-strategy.tsx +1332 -1173
- package/src/strategies/vesu-rebalance.tsx +254 -153
- package/src/strategies/yoloVault.ts +1096 -0
- package/src/utils/cacheClass.ts +11 -2
- package/src/utils/health-factor-math.ts +33 -1
- package/src/utils/index.ts +3 -1
- package/src/utils/logger.browser.ts +22 -4
- package/src/utils/logger.node.ts +259 -24
- package/src/utils/starknet-call-parser.ts +1036 -0
- package/src/utils/strategy-utils.ts +61 -0
- package/src/modules/ExtendedWrapperSDk/index.ts +0 -62
- package/src/modules/ExtendedWrapperSDk/types.ts +0 -311
- package/src/modules/ExtendedWrapperSDk/wrapper.ts +0 -395
- package/src/strategies/universal-adapters/extended-adapter.ts +0 -662
- package/src/strategies/universal-adapters/unused-balance-adapter.ts +0 -109
- package/src/strategies/vesu-extended-strategy/services/operationService.ts +0 -34
- package/src/strategies/vesu-extended-strategy/utils/config.runtime.ts +0 -77
- package/src/strategies/vesu-extended-strategy/utils/constants.ts +0 -49
- package/src/strategies/vesu-extended-strategy/utils/helper.ts +0 -372
- package/src/strategies/vesu-extended-strategy/vesu-extended-strategy.tsx +0 -1140
package/src/strategies/sensei.ts
CHANGED
|
@@ -1,7 +1,13 @@
|
|
|
1
|
-
import { getNoRiskTags, highlightTextWithLinks, IConfig, IProtocol, IStrategyMetadata, RiskFactor, RiskType, TokenInfo } from "@/interfaces";
|
|
2
|
-
import {
|
|
1
|
+
import { getNoRiskTags, highlightTextWithLinks, IConfig, IProtocol, IStrategyMetadata, RiskFactor, RiskType, StrategyTag, TokenInfo, AuditStatus, SourceCodeType, AccessControlType, InstantWithdrawalVault, StrategyLiveStatus, VaultType, UnwrapLabsCurator } from "@/interfaces";
|
|
2
|
+
import {
|
|
3
|
+
BaseStrategy,
|
|
4
|
+
SingleActionAmount,
|
|
5
|
+
SingleTokenInfo,
|
|
6
|
+
UserPositionCard,
|
|
7
|
+
UserPositionCardsInput,
|
|
8
|
+
} from "./base-strategy";
|
|
3
9
|
import { ContractAddr, Web3Number } from "@/dataTypes";
|
|
4
|
-
import { Call, Contract, uint256 } from "starknet";
|
|
10
|
+
import { Call, Contract, num, uint256, BlockIdentifier } from "starknet";
|
|
5
11
|
import SenseiABI from "@/data/sensei.abi.json";
|
|
6
12
|
import { getTrovesEndpoint, logger } from "@/utils";
|
|
7
13
|
import { Global } from "@/global";
|
|
@@ -9,6 +15,10 @@ import { QuoteRequest } from "@avnu/avnu-sdk";
|
|
|
9
15
|
import { PricerBase } from "@/modules/pricerBase";
|
|
10
16
|
import ERC20ABI from "@/data/erc20.abi.json";
|
|
11
17
|
import { AvnuWrapper } from "@/modules";
|
|
18
|
+
import { gql } from "@apollo/client";
|
|
19
|
+
import apolloClient from "@/modules/apollo-client";
|
|
20
|
+
import { VesuAdapter, VesuPools } from "./universal-adapters/vesu-adapter";
|
|
21
|
+
import { LSTAPRService } from "@/modules/lst-apr";
|
|
12
22
|
|
|
13
23
|
export interface SenseiVaultSettings {
|
|
14
24
|
mainToken: TokenInfo;
|
|
@@ -37,17 +47,27 @@ export class SenseiVault extends BaseStrategy<
|
|
|
37
47
|
}
|
|
38
48
|
}
|
|
39
49
|
|
|
40
|
-
async getUserTVL(user: ContractAddr): Promise<SingleTokenInfo> {
|
|
50
|
+
async getUserTVL(user: ContractAddr, blockIdentifier: BlockIdentifier = "latest"): Promise<SingleTokenInfo> {
|
|
41
51
|
const result: any = await this.contract.call(
|
|
42
52
|
"describe_position",
|
|
43
53
|
[user.address],
|
|
54
|
+
{
|
|
55
|
+
blockIdentifier,
|
|
56
|
+
}
|
|
44
57
|
);
|
|
45
58
|
const amount = Web3Number.fromWei(
|
|
46
59
|
uint256.uint256ToBN(result[1].estimated_size).toString(),
|
|
47
60
|
this.metadata.depositTokens[0].decimals,
|
|
48
61
|
)
|
|
62
|
+
|
|
63
|
+
// Convert blockIdentifier to block number for pricer if it's a number
|
|
64
|
+
const blockNumber = typeof blockIdentifier === 'number' || typeof blockIdentifier === 'bigint'
|
|
65
|
+
? Number(blockIdentifier)
|
|
66
|
+
: undefined;
|
|
67
|
+
|
|
49
68
|
const price = await this.pricer.getPrice(
|
|
50
69
|
this.metadata.depositTokens[0].symbol,
|
|
70
|
+
blockNumber
|
|
51
71
|
);
|
|
52
72
|
return {
|
|
53
73
|
usdValue: Number(amount.toFixed(6)) * price.price,
|
|
@@ -80,7 +100,7 @@ export class SenseiVault extends BaseStrategy<
|
|
|
80
100
|
tokenInfo: this.metadata.depositTokens[0],
|
|
81
101
|
};
|
|
82
102
|
} catch (error) {
|
|
83
|
-
console.error(
|
|
103
|
+
console.error(`[SDK] Error fetching TVL for ${this.metadata.id}:`, error);
|
|
84
104
|
return {
|
|
85
105
|
usdValue: 0,
|
|
86
106
|
amount: new Web3Number('0', this.metadata.depositTokens[0].decimals),
|
|
@@ -108,7 +128,7 @@ export class SenseiVault extends BaseStrategy<
|
|
|
108
128
|
return calls;
|
|
109
129
|
}
|
|
110
130
|
|
|
111
|
-
async withdrawCall(amountInfo: SingleActionAmount, receiver: ContractAddr, owner: ContractAddr): Promise<Call[]> {
|
|
131
|
+
async withdrawCall(amountInfo: SingleActionAmount, receiver: ContractAddr, owner: ContractAddr, _isMaxWithdraw: boolean = false): Promise<Call[]> {
|
|
112
132
|
const call = this.contract.populate('withdraw', [
|
|
113
133
|
uint256.bnToUint256(amountInfo.amount.toWei()),
|
|
114
134
|
receiver.address,
|
|
@@ -223,7 +243,272 @@ export class SenseiVault extends BaseStrategy<
|
|
|
223
243
|
logger.verbose('getSettings', settings);
|
|
224
244
|
return settings;
|
|
225
245
|
};
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Calculate lifetime earnings for a user
|
|
249
|
+
* Not yet implemented for Sensei Vault strategy
|
|
250
|
+
*/
|
|
251
|
+
getLifetimeEarnings(
|
|
252
|
+
userTVL: SingleTokenInfo,
|
|
253
|
+
investmentFlows: Array<{ amount: string; type: string; timestamp: number; tx_hash: string }>
|
|
254
|
+
): any {
|
|
255
|
+
throw new Error("getLifetimeEarnings is not implemented yet for this strategy");
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
async netAPY(): Promise<number> {
|
|
259
|
+
try {
|
|
260
|
+
// Fetch Vesu pools and select the Re7 xSTRK pool
|
|
261
|
+
const { pools } = await VesuAdapter.getVesuPools();
|
|
262
|
+
const re7PoolId = VesuPools.Re7xSTRK;
|
|
263
|
+
const pool = pools.find((p: any) =>
|
|
264
|
+
ContractAddr.from(num.getHexString(p.id)).eq(re7PoolId),
|
|
265
|
+
);
|
|
266
|
+
|
|
267
|
+
if (!pool) {
|
|
268
|
+
logger.warn(`${SenseiVault.name}::netAPY - Re7 xSTRK pool not found`);
|
|
269
|
+
return 0;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
const mainSymbol = this.metadata.additionalInfo.mainToken.symbol.toLowerCase(); // STRK
|
|
273
|
+
const secondarySymbol =
|
|
274
|
+
this.metadata.additionalInfo.secondaryToken.symbol.toLowerCase(); // xSTRK
|
|
275
|
+
|
|
276
|
+
const collateralAssetStats = pool.assets.find(
|
|
277
|
+
(a: any) => String(a.symbol).toLowerCase() === secondarySymbol,
|
|
278
|
+
)?.stats;
|
|
279
|
+
const debtAssetStats = pool.assets.find(
|
|
280
|
+
(a: any) => String(a.symbol).toLowerCase() === mainSymbol,
|
|
281
|
+
)?.stats;
|
|
282
|
+
|
|
283
|
+
if (!collateralAssetStats || !debtAssetStats) {
|
|
284
|
+
logger.warn(
|
|
285
|
+
`${SenseiVault.name}::netAPY - Missing collateral/debt stats on Vesu pool`,
|
|
286
|
+
);
|
|
287
|
+
return 0;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// Base xSTRK lending APY from Vesu
|
|
291
|
+
const xstrkSupplyAPY =
|
|
292
|
+
Number(collateralAssetStats.supplyApy?.value || 0) / 1e18;
|
|
293
|
+
|
|
294
|
+
// STRK rewards APR on xSTRK collateral from Vesu
|
|
295
|
+
const strkRewardsAPR = collateralAssetStats.defiSpringSupplyApr
|
|
296
|
+
? Number(collateralAssetStats.defiSpringSupplyApr.value || 0) / 1e18
|
|
297
|
+
: 0;
|
|
298
|
+
|
|
299
|
+
// STRK borrow APY from Vesu
|
|
300
|
+
const borrowAPY =
|
|
301
|
+
Number(debtAssetStats.borrowApr?.value || 0) / 1e18;
|
|
302
|
+
|
|
303
|
+
// LST APR for xSTRK from Endur (based on underlying STRK asset)
|
|
304
|
+
const lstAPY = await LSTAPRService.getLSTAPR(
|
|
305
|
+
this.metadata.additionalInfo.mainToken.address,
|
|
306
|
+
);
|
|
307
|
+
|
|
308
|
+
// Collateral APY = Vesu xSTRK supply + Endur xSTRK APR + STRK rewards
|
|
309
|
+
const collateralAPY = xstrkSupplyAPY + lstAPY + strkRewardsAPR;
|
|
310
|
+
|
|
311
|
+
const feeFactor = this.metadata.additionalInfo.feeBps / 10000; // convert bps to decimal
|
|
312
|
+
const feeAdjustedColAPY =
|
|
313
|
+
collateralAPY - strkRewardsAPR * feeFactor;
|
|
314
|
+
|
|
315
|
+
// Position info (collateral & debt in USD terms)
|
|
316
|
+
const { collateralUSDValue, debtUSDValue } =
|
|
317
|
+
await this.getPositionInfo();
|
|
318
|
+
|
|
319
|
+
const collateralUSD = Number(collateralUSDValue.toFixed(6));
|
|
320
|
+
const debtUSD = Number(debtUSDValue.toFixed(6));
|
|
321
|
+
|
|
322
|
+
// Compute expected leverage using the same math as app-side strategy
|
|
323
|
+
const targetHf = this.metadata.additionalInfo.targetHfBps / 10000;
|
|
324
|
+
const xSTRKPrice = await this.getSecondaryTokenPriceRelativeToMain();
|
|
325
|
+
const denominator = targetHf * xSTRKPrice - 0.87;
|
|
326
|
+
if (denominator <= 0) {
|
|
327
|
+
logger.warn(
|
|
328
|
+
`${SenseiVault.name}::netAPY - Invalid denominator in leverage calc`,
|
|
329
|
+
);
|
|
330
|
+
return 0;
|
|
331
|
+
}
|
|
332
|
+
const borrowedSTRK = (0.87 * xSTRKPrice) / denominator;
|
|
333
|
+
const expectedLeverage = 1 + borrowedSTRK;
|
|
334
|
+
if (!Number.isFinite(expectedLeverage) || expectedLeverage <= 0) {
|
|
335
|
+
logger.warn(
|
|
336
|
+
`${SenseiVault.name}::netAPY - Non-positive or invalid expectedLeverage`,
|
|
337
|
+
);
|
|
338
|
+
return 0;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
const payoff =
|
|
342
|
+
collateralUSD * feeAdjustedColAPY - debtUSD * borrowAPY;
|
|
343
|
+
const investment = collateralUSD - debtUSD;
|
|
344
|
+
|
|
345
|
+
if (investment === 0) {
|
|
346
|
+
return 0;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
const netAPY = payoff / investment;
|
|
350
|
+
return Number.isFinite(netAPY) ? netAPY : 0;
|
|
351
|
+
} catch (error) {
|
|
352
|
+
logger.error(`${SenseiVault.name}::netAPY - Error`, error);
|
|
353
|
+
return 0;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* Calculates user realized APY based on position growth accounting for deposits and withdrawals.
|
|
359
|
+
* Returns the APY as a number.
|
|
360
|
+
* Not implemented for Sensei Strategy yet.
|
|
361
|
+
*/
|
|
362
|
+
async getUserRealizedAPY(
|
|
363
|
+
blockIdentifier: BlockIdentifier = "latest",
|
|
364
|
+
sinceBlocks = 600000
|
|
365
|
+
): Promise<number> {
|
|
366
|
+
throw new Error("getUserRealizedAPY not implemented yet for Sensei strategy");
|
|
226
367
|
|
|
368
|
+
/*
|
|
369
|
+
logger.verbose(
|
|
370
|
+
`${SenseiVault.name}: getUserRealizedAPY => starting with userAddress=${userAddress.address}, blockIdentifier=${blockIdentifier}, sinceBlocks=${sinceBlocks}`
|
|
371
|
+
);
|
|
372
|
+
|
|
373
|
+
// Determine current block number
|
|
374
|
+
let blockNow =
|
|
375
|
+
typeof blockIdentifier === "number" || typeof blockIdentifier === "bigint"
|
|
376
|
+
? Number(blockIdentifier)
|
|
377
|
+
: (await this.config.provider.getBlockLatestAccepted()).block_number;
|
|
378
|
+
|
|
379
|
+
// Look back window, but never before launch block
|
|
380
|
+
const blockBefore = Math.max(
|
|
381
|
+
blockNow - sinceBlocks,
|
|
382
|
+
this.metadata.launchBlock
|
|
383
|
+
);
|
|
384
|
+
|
|
385
|
+
logger.verbose(
|
|
386
|
+
`${SenseiVault.name}: getUserRealizedAPY => blockNow=${blockNow}, blockBefore=${blockBefore}`
|
|
387
|
+
);
|
|
388
|
+
|
|
389
|
+
// Get current estimated size
|
|
390
|
+
const currentResult: any = await this.contract.call(
|
|
391
|
+
"describe_position",
|
|
392
|
+
[userAddress.address],
|
|
393
|
+
{
|
|
394
|
+
blockIdentifier,
|
|
395
|
+
}
|
|
396
|
+
);
|
|
397
|
+
const currentEstimatedSize = Web3Number.fromWei(
|
|
398
|
+
uint256.uint256ToBN(currentResult[1].estimated_size).toString(),
|
|
399
|
+
this.metadata.depositTokens[0].decimals,
|
|
400
|
+
);
|
|
401
|
+
|
|
402
|
+
// Get previous estimated size
|
|
403
|
+
const previousResult: any = await this.contract.call(
|
|
404
|
+
"describe_position",
|
|
405
|
+
[userAddress.address],
|
|
406
|
+
{
|
|
407
|
+
blockIdentifier: blockBefore,
|
|
408
|
+
}
|
|
409
|
+
);
|
|
410
|
+
const previousEstimatedSize = Web3Number.fromWei(
|
|
411
|
+
uint256.uint256ToBN(previousResult[1].estimated_size).toString(),
|
|
412
|
+
this.metadata.depositTokens[0].decimals,
|
|
413
|
+
);
|
|
414
|
+
|
|
415
|
+
logger.verbose(
|
|
416
|
+
`${SenseiVault.name}: getUserRealizedAPY => currentEstimatedSize=${currentEstimatedSize.toString()}, previousEstimatedSize=${previousEstimatedSize.toString()}`
|
|
417
|
+
);
|
|
418
|
+
|
|
419
|
+
// Query GraphQL for deposits and withdrawals between blockBefore and blockNow
|
|
420
|
+
let newDeposits = Web3Number.fromWei("0", this.metadata.depositTokens[0].decimals);
|
|
421
|
+
let newWithdrawals = Web3Number.fromWei("0", this.metadata.depositTokens[0].decimals);
|
|
422
|
+
|
|
423
|
+
try {
|
|
424
|
+
const { data } = await apolloClient.query({
|
|
425
|
+
query: gql`
|
|
426
|
+
query Query($where: Investment_flowsWhereInput) {
|
|
427
|
+
findManyInvestment_flows(where: $where) {
|
|
428
|
+
block_number
|
|
429
|
+
amount
|
|
430
|
+
type
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
`,
|
|
434
|
+
variables: {
|
|
435
|
+
where: {
|
|
436
|
+
contract: {
|
|
437
|
+
equals: this.address.address.toLowerCase(),
|
|
438
|
+
},
|
|
439
|
+
owner: {
|
|
440
|
+
equals: userAddress.address.toLowerCase(),
|
|
441
|
+
},
|
|
442
|
+
block_number: {
|
|
443
|
+
gte: blockBefore,
|
|
444
|
+
lte: blockNow,
|
|
445
|
+
},
|
|
446
|
+
},
|
|
447
|
+
},
|
|
448
|
+
fetchPolicy: 'no-cache',
|
|
449
|
+
});
|
|
450
|
+
|
|
451
|
+
// Sum deposits and withdrawals
|
|
452
|
+
for (const flow of data.findManyInvestment_flows) {
|
|
453
|
+
const amount = Web3Number.fromWei(
|
|
454
|
+
flow.amount,
|
|
455
|
+
this.metadata.depositTokens[0].decimals
|
|
456
|
+
);
|
|
457
|
+
if (flow.type === 'deposit') {
|
|
458
|
+
newDeposits = newDeposits.plus(amount);
|
|
459
|
+
} else if (flow.type === 'withdraw') {
|
|
460
|
+
newWithdrawals = newWithdrawals.plus(amount);
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
logger.verbose(
|
|
465
|
+
`${SenseiVault.name}: getUserRealizedAPY => newDeposits=${newDeposits.toString()}, newWithdrawals=${newWithdrawals.toString()}`
|
|
466
|
+
);
|
|
467
|
+
} catch (error) {
|
|
468
|
+
logger.verbose(
|
|
469
|
+
`${SenseiVault.name}: getUserRealizedAPY => Error querying GraphQL, continuing with zero deposits/withdrawals:`,
|
|
470
|
+
error
|
|
471
|
+
);
|
|
472
|
+
// Continue with zero deposits/withdrawals if GraphQL query fails
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
// Calculate growth: Current estimated size - new deposits + new withdrawals - previous estimated size
|
|
476
|
+
const growth = currentEstimatedSize
|
|
477
|
+
.minus(newDeposits)
|
|
478
|
+
.plus(newWithdrawals)
|
|
479
|
+
.minus(previousEstimatedSize);
|
|
480
|
+
|
|
481
|
+
logger.verbose(
|
|
482
|
+
`${SenseiVault.name}: getUserRealizedAPY => growth=${growth.toString()}`
|
|
483
|
+
);
|
|
484
|
+
|
|
485
|
+
// Handle edge case where previous position is zero
|
|
486
|
+
if (previousEstimatedSize.isZero() || previousEstimatedSize.lte(0)) {
|
|
487
|
+
logger.verbose(
|
|
488
|
+
`${SenseiVault.name}: getUserRealizedAPY => Previous position is zero, returning 0`
|
|
489
|
+
);
|
|
490
|
+
return 0;
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
// Calculate actual block difference (in case limited by launch block)
|
|
494
|
+
const actualBlockDiff = blockNow - blockBefore;
|
|
495
|
+
|
|
496
|
+
// Calculate APY: 100 * 365/n * growth / previousEstimatedSize
|
|
497
|
+
// where n is the number of blocks (sinceBlocks or actual block difference)
|
|
498
|
+
const growthRatio = growth.dividedBy(previousEstimatedSize);
|
|
499
|
+
const apy = Number(growthRatio) * 100 * 365 / actualBlockDiff;
|
|
500
|
+
|
|
501
|
+
logger.verbose(
|
|
502
|
+
`${SenseiVault.name}: getUserRealizedAPY => actualBlockDiff=${actualBlockDiff}, growthRatio=${Number(growthRatio)}, apy=${apy}`
|
|
503
|
+
);
|
|
504
|
+
|
|
505
|
+
return apy;
|
|
506
|
+
*/
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
async getUserPositionCards(_input: UserPositionCardsInput): Promise<UserPositionCard[]> {
|
|
510
|
+
return [];
|
|
511
|
+
}
|
|
227
512
|
}
|
|
228
513
|
|
|
229
514
|
const senseiDescription = `Deposit your {{token1}} to automatically loop your funds via Endur ({{token2}}) and Vesu to create a delta neutral position. This strategy is designed to maximize your yield on {{token1}}. Your position is automatically adjusted periodically to maintain a healthy health factor. You receive a NFT as representation for your stake on Troves. You can withdraw anytime by redeeming your NFT for {{token1}}.`;
|
|
@@ -289,9 +574,10 @@ const FAQS = [
|
|
|
289
574
|
export const SenseiStrategies: IStrategyMetadata<SenseiVaultSettings>[] =
|
|
290
575
|
[
|
|
291
576
|
{
|
|
577
|
+
id: "xstrk_sensei",
|
|
292
578
|
name: "xSTRK Sensei",
|
|
293
579
|
description: highlightTextWithLinks(
|
|
294
|
-
senseiDescription.
|
|
580
|
+
senseiDescription.replace('{{token1}}', 'STRK').replace('{{token2}}', 'xSTRK'),
|
|
295
581
|
[{
|
|
296
582
|
highlight: "Endur",
|
|
297
583
|
link: "https://endur.fi"
|
|
@@ -308,11 +594,33 @@ export const SenseiStrategies: IStrategyMetadata<SenseiVaultSettings>[] =
|
|
|
308
594
|
),
|
|
309
595
|
launchBlock: 1053811,
|
|
310
596
|
type: "Other",
|
|
597
|
+
curator: UnwrapLabsCurator,
|
|
598
|
+
vaultType: {
|
|
599
|
+
type: VaultType.LOOPING,
|
|
600
|
+
description: "Creates leveraged looping position on xSTRK by borrowing STRK to increase yield"
|
|
601
|
+
},
|
|
311
602
|
depositTokens: [
|
|
312
603
|
Global.getDefaultTokens().find((t) => t.symbol === "STRK")!
|
|
313
604
|
],
|
|
314
605
|
protocols: [endurProtocol, vesuProtocol],
|
|
315
|
-
|
|
606
|
+
settings: {
|
|
607
|
+
alerts: [
|
|
608
|
+
{
|
|
609
|
+
type: "info",
|
|
610
|
+
text: "Depeg-risk: If xSTRK price on DEXes deviates from expected price, you may lose money or may have to wait for the price to recover.",
|
|
611
|
+
tab: "all"
|
|
612
|
+
}
|
|
613
|
+
],
|
|
614
|
+
liveStatus: StrategyLiveStatus.RETIRED,
|
|
615
|
+
isPaused: false,
|
|
616
|
+
isInMaintenance: false,
|
|
617
|
+
isAudited: false,
|
|
618
|
+
isInstantWithdrawal: true,
|
|
619
|
+
isTransactionHistDisabled: true,
|
|
620
|
+
quoteToken: Global.getDefaultTokens().find(
|
|
621
|
+
(t) => t.symbol === "STRK"
|
|
622
|
+
)!
|
|
623
|
+
},
|
|
316
624
|
risk: {
|
|
317
625
|
riskFactor: _riskFactor,
|
|
318
626
|
netRisk:
|
|
@@ -335,6 +643,42 @@ export const SenseiStrategies: IStrategyMetadata<SenseiVaultSettings>[] =
|
|
|
335
643
|
"Buy more xSTRK with borrowed STRK",
|
|
336
644
|
"Repeat the process to loop your position",
|
|
337
645
|
"Claim DeFi spring (STRK) rewards weekly and reinvest",
|
|
338
|
-
]
|
|
646
|
+
],
|
|
647
|
+
tags: [StrategyTag.LEVERED],
|
|
648
|
+
security: {
|
|
649
|
+
auditStatus: AuditStatus.AUDITED,
|
|
650
|
+
sourceCode: {
|
|
651
|
+
type: SourceCodeType.CLOSED_SOURCE,
|
|
652
|
+
contractLink: "https://github.com/trovesfi/troves-contracts",
|
|
653
|
+
},
|
|
654
|
+
accessControl: {
|
|
655
|
+
type: AccessControlType.ROLE_BASED_ACCESS,
|
|
656
|
+
addresses: [ContractAddr.from("0x0")],
|
|
657
|
+
timeLock: "2 Days",
|
|
658
|
+
},
|
|
659
|
+
},
|
|
660
|
+
redemptionInfo: {
|
|
661
|
+
instantWithdrawalVault: InstantWithdrawalVault.YES,
|
|
662
|
+
redemptionsInfo: [],
|
|
663
|
+
alerts: [],
|
|
664
|
+
},
|
|
665
|
+
usualTimeToEarnings: "2 weeks",
|
|
666
|
+
usualTimeToEarningsDescription: "Strategy returns depend on LST price on DEXes. Even though the true price of LST on Endur increases continuously, the DEX price may lag sometimes, and historically is seen to rebase at least once every 2 weeks. This is when you realise your earnings.",
|
|
667
|
+
points: [{
|
|
668
|
+
multiplier: 4,
|
|
669
|
+
logo: 'https://endur.fi/favicon.ico',
|
|
670
|
+
toolTip: "This strategy holds xSTRK. Earn 3-4x Endur points on your xSTRK due to the leverage. Points can be found on endur.fi.",
|
|
671
|
+
}],
|
|
672
|
+
discontinuationInfo: {
|
|
673
|
+
info: highlightTextWithLinks(
|
|
674
|
+
"This strategy is retired. All funds have been moved to Hyper xSTRK.",
|
|
675
|
+
[
|
|
676
|
+
{
|
|
677
|
+
highlight: "Hyper xSTRK",
|
|
678
|
+
link: "/strategy/hyper_xstrk",
|
|
679
|
+
},
|
|
680
|
+
]
|
|
681
|
+
),
|
|
682
|
+
},
|
|
339
683
|
},
|
|
340
|
-
];
|
|
684
|
+
];
|