@strkfarm/sdk 1.0.56 → 1.0.57
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/index.browser.global.js +260 -83
- package/dist/index.browser.mjs +255 -66
- package/dist/index.d.ts +55 -9
- package/dist/index.js +255 -69
- package/dist/index.mjs +255 -69
- package/package.json +1 -1
- package/src/notifs/telegram.ts +0 -2
- package/src/strategies/base-strategy.ts +3 -23
- package/src/strategies/sensei.ts +13 -6
- package/src/strategies/universal-adapters/baseAdapter.ts +2 -1
- package/src/strategies/universal-adapters/vesu-adapter.ts +80 -10
- package/src/strategies/universal-strategy.ts +183 -31
- package/src/utils/cacheClass.ts +29 -0
- package/src/utils/oz-merkle.ts +0 -9
package/dist/index.mjs
CHANGED
|
@@ -1986,7 +1986,6 @@ import { toHex } from "@ericnordelo/strk-merkle-tree/dist/bytes";
|
|
|
1986
1986
|
import { processMultiProof, processProof } from "@ericnordelo/strk-merkle-tree/dist/core";
|
|
1987
1987
|
import { standardLeafHash } from "@ericnordelo/strk-merkle-tree/dist/hashes";
|
|
1988
1988
|
import { MerkleTreeImpl } from "@ericnordelo/strk-merkle-tree/dist/merkletree";
|
|
1989
|
-
import { validateArgument } from "@ericnordelo/strk-merkle-tree/src/utils/errors";
|
|
1990
1989
|
import { num as num2 } from "starknet";
|
|
1991
1990
|
|
|
1992
1991
|
// ../node_modules/@noble/hashes/esm/_assert.js
|
|
@@ -4044,13 +4043,6 @@ var StandardMerkleTree = class _StandardMerkleTree extends MerkleTreeImpl {
|
|
|
4044
4043
|
});
|
|
4045
4044
|
return new _StandardMerkleTree(tree, indexedValues, leafEncoding);
|
|
4046
4045
|
}
|
|
4047
|
-
static load(data) {
|
|
4048
|
-
validateArgument(data.format === "standard-v1", `Unknown format '${data.format}'`);
|
|
4049
|
-
validateArgument(data.leafEncoding !== void 0, "Expected leaf encoding");
|
|
4050
|
-
const tree = new _StandardMerkleTree(data.tree, data.values, data.leafEncoding);
|
|
4051
|
-
tree.validate();
|
|
4052
|
-
return tree;
|
|
4053
|
-
}
|
|
4054
4046
|
static verify(root, leafEncoding, leaf, proof) {
|
|
4055
4047
|
return toHex(root) === processProof(standardLeafHash(leafEncoding, leaf), proof);
|
|
4056
4048
|
}
|
|
@@ -5808,23 +5800,10 @@ var vesu_rebalance_abi_default = [
|
|
|
5808
5800
|
}
|
|
5809
5801
|
];
|
|
5810
5802
|
|
|
5811
|
-
// src/
|
|
5812
|
-
var
|
|
5813
|
-
constructor(
|
|
5803
|
+
// src/utils/cacheClass.ts
|
|
5804
|
+
var CacheClass = class {
|
|
5805
|
+
constructor() {
|
|
5814
5806
|
this.cache = /* @__PURE__ */ new Map();
|
|
5815
|
-
this.config = config;
|
|
5816
|
-
}
|
|
5817
|
-
async getUserTVL(user) {
|
|
5818
|
-
throw new Error("Not implemented");
|
|
5819
|
-
}
|
|
5820
|
-
async getTVL() {
|
|
5821
|
-
throw new Error("Not implemented");
|
|
5822
|
-
}
|
|
5823
|
-
async depositCall(amountInfo, receiver) {
|
|
5824
|
-
throw new Error("Not implemented");
|
|
5825
|
-
}
|
|
5826
|
-
async withdrawCall(amountInfo, receiver, owner) {
|
|
5827
|
-
throw new Error("Not implemented");
|
|
5828
5807
|
}
|
|
5829
5808
|
setCache(key, data, ttl = 6e4) {
|
|
5830
5809
|
const timestamp = Date.now();
|
|
@@ -5845,6 +5824,27 @@ var BaseStrategy = class {
|
|
|
5845
5824
|
}
|
|
5846
5825
|
};
|
|
5847
5826
|
|
|
5827
|
+
// src/strategies/base-strategy.ts
|
|
5828
|
+
var BaseStrategy = class extends CacheClass {
|
|
5829
|
+
constructor(config) {
|
|
5830
|
+
super();
|
|
5831
|
+
this.cache = /* @__PURE__ */ new Map();
|
|
5832
|
+
this.config = config;
|
|
5833
|
+
}
|
|
5834
|
+
async getUserTVL(user) {
|
|
5835
|
+
throw new Error("Not implemented");
|
|
5836
|
+
}
|
|
5837
|
+
async getTVL() {
|
|
5838
|
+
throw new Error("Not implemented");
|
|
5839
|
+
}
|
|
5840
|
+
async depositCall(amountInfo, receiver) {
|
|
5841
|
+
throw new Error("Not implemented");
|
|
5842
|
+
}
|
|
5843
|
+
async withdrawCall(amountInfo, receiver, owner) {
|
|
5844
|
+
throw new Error("Not implemented");
|
|
5845
|
+
}
|
|
5846
|
+
};
|
|
5847
|
+
|
|
5848
5848
|
// src/node/headless.browser.ts
|
|
5849
5849
|
import axios5 from "axios";
|
|
5850
5850
|
async function getAPIUsingHeadlessBrowser(url) {
|
|
@@ -20318,9 +20318,8 @@ var SenseiVault = class extends BaseStrategy {
|
|
|
20318
20318
|
}
|
|
20319
20319
|
async getPositionInfo() {
|
|
20320
20320
|
const CACHE_KEY = "positionInfo";
|
|
20321
|
-
|
|
20322
|
-
|
|
20323
|
-
}
|
|
20321
|
+
const existingCacheData = this.getCache(CACHE_KEY);
|
|
20322
|
+
if (existingCacheData) return existingCacheData;
|
|
20324
20323
|
const resp = await fetch(
|
|
20325
20324
|
`${getTrovesEndpoint()}/vesu/positions?walletAddress=${this.address.address}`
|
|
20326
20325
|
);
|
|
@@ -20364,9 +20363,8 @@ var SenseiVault = class extends BaseStrategy {
|
|
|
20364
20363
|
}
|
|
20365
20364
|
async getSecondaryTokenPriceRelativeToMain(retry = 0) {
|
|
20366
20365
|
const CACHE_KEY = "xSTRKPrice";
|
|
20367
|
-
|
|
20368
|
-
|
|
20369
|
-
}
|
|
20366
|
+
const existingCacheData = this.getCache(CACHE_KEY);
|
|
20367
|
+
if (existingCacheData) return existingCacheData;
|
|
20370
20368
|
const params = {
|
|
20371
20369
|
sellTokenAddress: this.metadata.additionalInfo.secondaryToken.address.address,
|
|
20372
20370
|
buyTokenAddress: this.metadata.additionalInfo.mainToken.address.address,
|
|
@@ -20520,7 +20518,7 @@ function toBigInt(value) {
|
|
|
20520
20518
|
}
|
|
20521
20519
|
|
|
20522
20520
|
// src/strategies/universal-adapters/baseAdapter.ts
|
|
20523
|
-
var BaseAdapter = class {
|
|
20521
|
+
var BaseAdapter = class extends CacheClass {
|
|
20524
20522
|
constructSimpleLeafData(params) {
|
|
20525
20523
|
const { id, target, method, packedArguments } = params;
|
|
20526
20524
|
return {
|
|
@@ -22895,7 +22893,6 @@ var VesuAdapter = class _VesuAdapter extends BaseAdapter {
|
|
|
22895
22893
|
constructor(config) {
|
|
22896
22894
|
super();
|
|
22897
22895
|
this.VESU_SINGLETON = ContractAddr.from("0x000d8d6dfec4d33bfb6895de9f3852143a17c6f92fd2a21da3d6924d34870160");
|
|
22898
|
-
this.cache = {};
|
|
22899
22896
|
this.getModifyPosition = () => {
|
|
22900
22897
|
const positionData = [0n];
|
|
22901
22898
|
const packedArguments = [
|
|
@@ -22924,17 +22921,19 @@ var VesuAdapter = class _VesuAdapter extends BaseAdapter {
|
|
|
22924
22921
|
denomination: this.formatAmountDenominationEnum(params.collateralAmount.denomination),
|
|
22925
22922
|
value: {
|
|
22926
22923
|
abs: uint2567.bnToUint256(params.collateralAmount.value.abs.toWei()),
|
|
22927
|
-
is_negative: params.collateralAmount.value.is_negative
|
|
22924
|
+
is_negative: params.collateralAmount.value.abs.isZero() ? false : params.collateralAmount.value.is_negative
|
|
22928
22925
|
}
|
|
22929
22926
|
};
|
|
22927
|
+
logger.verbose(`VesuAdapter::ConstructingModify::Collateral::${JSON.stringify(_collateral)}`);
|
|
22930
22928
|
const _debt = {
|
|
22931
22929
|
amount_type: this.formatAmountTypeEnum(params.debtAmount.amount_type),
|
|
22932
22930
|
denomination: this.formatAmountDenominationEnum(params.debtAmount.denomination),
|
|
22933
22931
|
value: {
|
|
22934
22932
|
abs: uint2567.bnToUint256(params.debtAmount.value.abs.toWei()),
|
|
22935
|
-
is_negative: params.debtAmount.value.is_negative
|
|
22933
|
+
is_negative: params.debtAmount.value.abs.isZero() ? false : params.debtAmount.value.is_negative
|
|
22936
22934
|
}
|
|
22937
22935
|
};
|
|
22936
|
+
logger.verbose(`VesuAdapter::ConstructingModify::Debt::${JSON.stringify(_debt)}`);
|
|
22938
22937
|
const singletonContract = new Contract8(vesu_singleton_abi_default, this.VESU_SINGLETON.toString(), new RpcProvider4({ nodeUrl: "" }));
|
|
22939
22938
|
const call = singletonContract.populate("modify_position", {
|
|
22940
22939
|
params: {
|
|
@@ -23003,20 +23002,22 @@ var VesuAdapter = class _VesuAdapter extends BaseAdapter {
|
|
|
23003
23002
|
}
|
|
23004
23003
|
async getLTVConfig(config) {
|
|
23005
23004
|
const CACHE_KEY = "ltv_config";
|
|
23006
|
-
|
|
23007
|
-
|
|
23005
|
+
const cacheData = this.getCache(CACHE_KEY);
|
|
23006
|
+
if (cacheData) {
|
|
23007
|
+
return cacheData;
|
|
23008
23008
|
}
|
|
23009
23009
|
const output2 = await this.getVesuSingletonContract(config).call("ltv_config", [this.config.poolId.address, this.config.collateral.address.address, this.config.debt.address.address]);
|
|
23010
|
-
this.
|
|
23011
|
-
return this.
|
|
23010
|
+
this.setCache(CACHE_KEY, Number(output2.max_ltv) / 1e18, 3e5);
|
|
23011
|
+
return this.getCache(CACHE_KEY);
|
|
23012
23012
|
}
|
|
23013
23013
|
async getPositions(config) {
|
|
23014
23014
|
if (!this.pricer) {
|
|
23015
23015
|
throw new Error("Pricer is not initialized");
|
|
23016
23016
|
}
|
|
23017
23017
|
const CACHE_KEY = "positions";
|
|
23018
|
-
|
|
23019
|
-
|
|
23018
|
+
const cacheData = this.getCache(CACHE_KEY);
|
|
23019
|
+
if (cacheData) {
|
|
23020
|
+
return cacheData;
|
|
23020
23021
|
}
|
|
23021
23022
|
const output2 = await this.getVesuSingletonContract(config).call("position_unsafe", [
|
|
23022
23023
|
this.config.poolId.address,
|
|
@@ -23039,9 +23040,65 @@ var VesuAdapter = class _VesuAdapter extends BaseAdapter {
|
|
|
23039
23040
|
usdValue: debtAmount.multipliedBy(token2Price.price).toNumber(),
|
|
23040
23041
|
remarks: "Debt"
|
|
23041
23042
|
}];
|
|
23042
|
-
this.
|
|
23043
|
+
this.setCache(CACHE_KEY, value, 6e4);
|
|
23044
|
+
return value;
|
|
23045
|
+
}
|
|
23046
|
+
async getCollateralization(config) {
|
|
23047
|
+
if (!this.pricer) {
|
|
23048
|
+
throw new Error("Pricer is not initialized");
|
|
23049
|
+
}
|
|
23050
|
+
const CACHE_KEY = "collateralization";
|
|
23051
|
+
const cacheData = this.getCache(CACHE_KEY);
|
|
23052
|
+
if (cacheData) {
|
|
23053
|
+
return cacheData;
|
|
23054
|
+
}
|
|
23055
|
+
const output2 = await this.getVesuSingletonContract(config).call("check_collateralization_unsafe", [
|
|
23056
|
+
this.config.poolId.address,
|
|
23057
|
+
this.config.collateral.address.address,
|
|
23058
|
+
this.config.debt.address.address,
|
|
23059
|
+
this.config.vaultAllocator.address
|
|
23060
|
+
]);
|
|
23061
|
+
const collateralAmount = Web3Number.fromWei(output2["1"].toString(), 18);
|
|
23062
|
+
const debtAmount = Web3Number.fromWei(output2["2"].toString(), 18);
|
|
23063
|
+
const value = [{
|
|
23064
|
+
token: this.config.collateral,
|
|
23065
|
+
usdValue: collateralAmount.toNumber(),
|
|
23066
|
+
remarks: "Collateral"
|
|
23067
|
+
}, {
|
|
23068
|
+
token: this.config.debt,
|
|
23069
|
+
usdValue: debtAmount.toNumber(),
|
|
23070
|
+
remarks: "Debt"
|
|
23071
|
+
}];
|
|
23072
|
+
this.setCache(CACHE_KEY, value, 6e4);
|
|
23043
23073
|
return value;
|
|
23044
23074
|
}
|
|
23075
|
+
async getAssetPrices() {
|
|
23076
|
+
const collateralizationProm = this.getCollateralization(this.networkConfig);
|
|
23077
|
+
const positionsProm = this.getPositions(this.networkConfig);
|
|
23078
|
+
const ltvProm = this.getLTVConfig(this.networkConfig);
|
|
23079
|
+
const output2 = await Promise.all([collateralizationProm, positionsProm, ltvProm]);
|
|
23080
|
+
const [collateralization, positions, ltv] = output2;
|
|
23081
|
+
const collateralTokenAmount = positions[0].amount;
|
|
23082
|
+
const collateralUSDAmount = collateralization[0].usdValue;
|
|
23083
|
+
const collateralPrice = collateralUSDAmount / collateralTokenAmount.toNumber();
|
|
23084
|
+
const debtTokenAmount = positions[1].amount;
|
|
23085
|
+
const debtUSDAmount = collateralization[1].usdValue;
|
|
23086
|
+
const debtPrice = debtUSDAmount / debtTokenAmount.toNumber();
|
|
23087
|
+
return {
|
|
23088
|
+
collateralTokenAmount,
|
|
23089
|
+
collateralUSDAmount,
|
|
23090
|
+
collateralPrice,
|
|
23091
|
+
debtTokenAmount,
|
|
23092
|
+
debtUSDAmount,
|
|
23093
|
+
debtPrice,
|
|
23094
|
+
ltv
|
|
23095
|
+
};
|
|
23096
|
+
}
|
|
23097
|
+
async getHealthFactor() {
|
|
23098
|
+
const ltv = await this.getLTVConfig(this.networkConfig);
|
|
23099
|
+
const collateralisation = await this.getCollateralization(this.networkConfig);
|
|
23100
|
+
return collateralisation[0].usdValue * ltv / collateralisation[1].usdValue;
|
|
23101
|
+
}
|
|
23045
23102
|
static async getVesuPools(retry = 0) {
|
|
23046
23103
|
const CACHE_KEY = "VESU_POOLS";
|
|
23047
23104
|
const cacheValue = Global.getGlobalCache(CACHE_KEY);
|
|
@@ -25413,19 +25470,32 @@ var UniversalStrategy = class _UniversalStrategy extends BaseStrategy {
|
|
|
25413
25470
|
const debtAsset1 = pool1.assets.find((a) => a.symbol === vesuAdapter1.config.debt.symbol)?.stats;
|
|
25414
25471
|
const collateralAsset2 = pool2.assets.find((a) => a.symbol === vesuAdapter2.config.collateral.symbol)?.stats;
|
|
25415
25472
|
const debtAsset2 = pool2.assets.find((a) => a.symbol === vesuAdapter2.config.debt.symbol)?.stats;
|
|
25416
|
-
const collateral1APY = Number(collateralAsset1.supplyApy.value) / 1e18
|
|
25473
|
+
const collateral1APY = Number(collateralAsset1.supplyApy.value) / 1e18;
|
|
25417
25474
|
const debt1APY = Number(debtAsset1.borrowApr.value) / 1e18;
|
|
25418
|
-
const collateral2APY = Number(collateralAsset2.supplyApy.value) / 1e18
|
|
25475
|
+
const collateral2APY = Number(collateralAsset2.supplyApy.value) / 1e18;
|
|
25419
25476
|
const debt2APY = Number(debtAsset2.borrowApr.value) / 1e18;
|
|
25420
|
-
const apys = [collateral1APY, debt1APY, collateral2APY, debt2APY];
|
|
25421
25477
|
const positions = await this.getVaultPositions();
|
|
25422
|
-
|
|
25423
|
-
const
|
|
25424
|
-
|
|
25425
|
-
|
|
25426
|
-
const
|
|
25427
|
-
const
|
|
25428
|
-
|
|
25478
|
+
const weights = positions.map((p, index) => p.usdValue * (index % 2 == 0 ? 1 : -1));
|
|
25479
|
+
const baseAPYs = [collateral1APY, debt1APY, collateral2APY, debt2APY];
|
|
25480
|
+
assert(positions.length == baseAPYs.length, "Positions and APYs length mismatch");
|
|
25481
|
+
const rewardAPYs = [Number(collateralAsset1.defiSpringSupplyApr.value) / 1e18, 0, Number(collateralAsset2.defiSpringSupplyApr.value) / 1e18, 0];
|
|
25482
|
+
const baseAPY = this.computeAPY(baseAPYs, weights);
|
|
25483
|
+
const rewardAPY = this.computeAPY(rewardAPYs, weights);
|
|
25484
|
+
const apys = [...baseAPYs, ...rewardAPYs];
|
|
25485
|
+
const netAPY = baseAPY + rewardAPY;
|
|
25486
|
+
return { net: netAPY, splits: [{
|
|
25487
|
+
apy: baseAPY,
|
|
25488
|
+
id: "base"
|
|
25489
|
+
}, {
|
|
25490
|
+
apy: rewardAPY,
|
|
25491
|
+
id: "defispring"
|
|
25492
|
+
}] };
|
|
25493
|
+
}
|
|
25494
|
+
computeAPY(apys, weights) {
|
|
25495
|
+
assert(apys.length === weights.length, "APYs and weights length mismatch");
|
|
25496
|
+
const weightedSum = apys.reduce((acc, apy, i) => acc + apy * weights[i], 0);
|
|
25497
|
+
const totalWeight = weights.reduce((acc, weight) => acc + weight, 0);
|
|
25498
|
+
return weightedSum / totalWeight;
|
|
25429
25499
|
}
|
|
25430
25500
|
/**
|
|
25431
25501
|
* Calculates the total TVL of the strategy.
|
|
@@ -25448,22 +25518,48 @@ var UniversalStrategy = class _UniversalStrategy extends BaseStrategy {
|
|
|
25448
25518
|
};
|
|
25449
25519
|
}
|
|
25450
25520
|
async getAUM() {
|
|
25521
|
+
const currentAUM = await this.contract.call("aum", []);
|
|
25522
|
+
const lastReportTime = await this.contract.call("last_report_timestamp", []);
|
|
25523
|
+
const token1Price = await this.pricer.getPrice(this.metadata.depositTokens[0].symbol);
|
|
25451
25524
|
const [vesuAdapter1, vesuAdapter2] = this.getVesuAdapters();
|
|
25452
25525
|
const leg1AUM = await vesuAdapter1.getPositions(this.config);
|
|
25453
25526
|
const leg2AUM = await vesuAdapter2.getPositions(this.config);
|
|
25454
|
-
const token1Price = await this.pricer.getPrice(vesuAdapter1.config.collateral.symbol);
|
|
25455
25527
|
const aumToken = leg1AUM[0].amount.plus(leg2AUM[0].usdValue / token1Price.price).minus(leg1AUM[1].usdValue / token1Price.price).minus(leg2AUM[1].amount);
|
|
25456
|
-
|
|
25528
|
+
logger.verbose(`${this.getTag()} Actual AUM: ${aumToken}`);
|
|
25529
|
+
const netAPY = await this.netAPY();
|
|
25530
|
+
const defispringAPY = netAPY.splits.find((s) => s.id === "defispring")?.apy || 0;
|
|
25531
|
+
if (!defispringAPY) throw new Error("DefiSpring APY not found");
|
|
25532
|
+
const timeDiff = Math.round(Date.now() / 1e3) - Number(lastReportTime);
|
|
25533
|
+
const growthRate = timeDiff * defispringAPY / (365 * 24 * 60 * 60);
|
|
25534
|
+
const prevAum = Web3Number.fromWei(currentAUM.toString(), this.asset().decimals);
|
|
25535
|
+
const rewardAssets = prevAum.multipliedBy(growthRate);
|
|
25536
|
+
logger.verbose(`${this.getTag()} DefiSpring AUM time difference: ${timeDiff}`);
|
|
25537
|
+
logger.verbose(`${this.getTag()} Current AUM: ${currentAUM}`);
|
|
25538
|
+
logger.verbose(`${this.getTag()} Net APY: ${JSON.stringify(netAPY)}`);
|
|
25539
|
+
logger.verbose(`${this.getTag()} rewards AUM: ${rewardAssets}`);
|
|
25540
|
+
const newAUM = aumToken.plus(rewardAssets);
|
|
25541
|
+
logger.verbose(`${this.getTag()} New AUM: ${newAUM}`);
|
|
25542
|
+
const net = {
|
|
25457
25543
|
tokenInfo: this.asset(),
|
|
25458
|
-
amount:
|
|
25459
|
-
usdValue:
|
|
25544
|
+
amount: newAUM,
|
|
25545
|
+
usdValue: newAUM.multipliedBy(token1Price.price).toNumber()
|
|
25460
25546
|
};
|
|
25547
|
+
const splits = [{
|
|
25548
|
+
id: "finalised",
|
|
25549
|
+
aum: aumToken
|
|
25550
|
+
}, {
|
|
25551
|
+
id: "defispring",
|
|
25552
|
+
aum: rewardAssets
|
|
25553
|
+
}];
|
|
25554
|
+
return { net, splits, prevAum };
|
|
25461
25555
|
}
|
|
25462
25556
|
getVesuAdapters() {
|
|
25463
25557
|
const vesuAdapter1 = this.getAdapter("vesu_leg1_adapter" /* VESU_LEG1 */);
|
|
25464
25558
|
const vesuAdapter2 = this.getAdapter("vesu_leg2_adapter" /* VESU_LEG2 */);
|
|
25465
25559
|
vesuAdapter1.pricer = this.pricer;
|
|
25466
25560
|
vesuAdapter2.pricer = this.pricer;
|
|
25561
|
+
vesuAdapter1.networkConfig = this.config;
|
|
25562
|
+
vesuAdapter2.networkConfig = this.config;
|
|
25467
25563
|
return [vesuAdapter1, vesuAdapter2];
|
|
25468
25564
|
}
|
|
25469
25565
|
async getVaultPositions() {
|
|
@@ -25505,12 +25601,14 @@ var UniversalStrategy = class _UniversalStrategy extends BaseStrategy {
|
|
|
25505
25601
|
}));
|
|
25506
25602
|
const output2 = [{
|
|
25507
25603
|
proofs: manage5Info.proofs,
|
|
25508
|
-
manageCall: manageCall5
|
|
25604
|
+
manageCall: manageCall5,
|
|
25605
|
+
step: STEP2_ID
|
|
25509
25606
|
}];
|
|
25510
25607
|
if (approveAmount.gt(0)) {
|
|
25511
25608
|
output2.unshift({
|
|
25512
25609
|
proofs: manage4Info.proofs,
|
|
25513
|
-
manageCall: manageCall4
|
|
25610
|
+
manageCall: manageCall4,
|
|
25611
|
+
step: STEP1_ID
|
|
25514
25612
|
});
|
|
25515
25613
|
}
|
|
25516
25614
|
return output2;
|
|
@@ -25518,9 +25616,96 @@ var UniversalStrategy = class _UniversalStrategy extends BaseStrategy {
|
|
|
25518
25616
|
getTag() {
|
|
25519
25617
|
return `${_UniversalStrategy.name}:${this.metadata.name}`;
|
|
25520
25618
|
}
|
|
25619
|
+
async getVesuHealthFactors() {
|
|
25620
|
+
return await Promise.all(this.getVesuAdapters().map((v) => v.getHealthFactor()));
|
|
25621
|
+
}
|
|
25622
|
+
async computeRebalanceConditionAndReturnCalls() {
|
|
25623
|
+
const vesuAdapters = this.getVesuAdapters();
|
|
25624
|
+
const healthFactors = await this.getVesuHealthFactors();
|
|
25625
|
+
const leg1HealthFactor = healthFactors[0];
|
|
25626
|
+
const leg2HealthFactor = healthFactors[1];
|
|
25627
|
+
logger.verbose(`${this.getTag()}: HealthFactorLeg1: ${leg1HealthFactor}`);
|
|
25628
|
+
logger.verbose(`${this.getTag()}: HealthFactorLeg2: ${leg2HealthFactor}`);
|
|
25629
|
+
const minHf = this.metadata.additionalInfo.minHealthFactor;
|
|
25630
|
+
const isRebalanceNeeded1 = leg1HealthFactor < minHf;
|
|
25631
|
+
const isRebalanceNeeded2 = leg2HealthFactor < minHf;
|
|
25632
|
+
if (!isRebalanceNeeded1 && !isRebalanceNeeded2) {
|
|
25633
|
+
return [];
|
|
25634
|
+
}
|
|
25635
|
+
if (isRebalanceNeeded1) {
|
|
25636
|
+
const amount = await this.getLegRebalanceAmount(vesuAdapters[0], leg1HealthFactor, false);
|
|
25637
|
+
const leg2HF = await this.getNewHealthFactor(vesuAdapters[1], amount, true);
|
|
25638
|
+
assert(leg2HF > minHf, `Rebalance Leg1 failed: Leg2 HF after rebalance would be too low: ${leg2HF}`);
|
|
25639
|
+
return [await this.getRebalanceCall({
|
|
25640
|
+
isLeg1toLeg2: false,
|
|
25641
|
+
amount
|
|
25642
|
+
})];
|
|
25643
|
+
} else {
|
|
25644
|
+
const amount = await this.getLegRebalanceAmount(vesuAdapters[1], leg2HealthFactor, true);
|
|
25645
|
+
const leg1HF = await this.getNewHealthFactor(vesuAdapters[0], amount, false);
|
|
25646
|
+
assert(leg1HF > minHf, `Rebalance Leg2 failed: Leg1 HF after rebalance would be too low: ${leg1HF}`);
|
|
25647
|
+
return [await this.getRebalanceCall({
|
|
25648
|
+
isLeg1toLeg2: true,
|
|
25649
|
+
amount
|
|
25650
|
+
})];
|
|
25651
|
+
}
|
|
25652
|
+
}
|
|
25653
|
+
async getNewHealthFactor(vesuAdapter, newAmount, isWithdraw) {
|
|
25654
|
+
const {
|
|
25655
|
+
collateralTokenAmount,
|
|
25656
|
+
collateralUSDAmount,
|
|
25657
|
+
collateralPrice,
|
|
25658
|
+
debtTokenAmount,
|
|
25659
|
+
debtUSDAmount,
|
|
25660
|
+
debtPrice,
|
|
25661
|
+
ltv
|
|
25662
|
+
} = await vesuAdapter.getAssetPrices();
|
|
25663
|
+
if (isWithdraw) {
|
|
25664
|
+
const newHF = (collateralTokenAmount.toNumber() - newAmount.toNumber()) * collateralPrice * ltv / debtUSDAmount;
|
|
25665
|
+
logger.verbose(`getNewHealthFactor:: HF: ${newHF}, amoutn: ${newAmount.toNumber()}, isDeposit`);
|
|
25666
|
+
return newHF;
|
|
25667
|
+
} else {
|
|
25668
|
+
const newHF = collateralUSDAmount * ltv / ((debtTokenAmount.toNumber() + newAmount.toNumber()) * debtPrice);
|
|
25669
|
+
logger.verbose(`getNewHealthFactor:: HF: ${newHF}, amoutn: ${newAmount.toNumber()}, isRepay`);
|
|
25670
|
+
return newHF;
|
|
25671
|
+
}
|
|
25672
|
+
}
|
|
25673
|
+
/**
|
|
25674
|
+
*
|
|
25675
|
+
* @param vesuAdapter
|
|
25676
|
+
* @param currentHf
|
|
25677
|
+
* @param isDeposit if true, attempt by adding collateral, else by repaying
|
|
25678
|
+
* @returns
|
|
25679
|
+
*/
|
|
25680
|
+
async getLegRebalanceAmount(vesuAdapter, currentHf, isDeposit) {
|
|
25681
|
+
const {
|
|
25682
|
+
collateralTokenAmount,
|
|
25683
|
+
collateralUSDAmount,
|
|
25684
|
+
collateralPrice,
|
|
25685
|
+
debtTokenAmount,
|
|
25686
|
+
debtUSDAmount,
|
|
25687
|
+
debtPrice,
|
|
25688
|
+
ltv
|
|
25689
|
+
} = await vesuAdapter.getAssetPrices();
|
|
25690
|
+
if (debtTokenAmount.isZero()) {
|
|
25691
|
+
return Web3Number.fromWei(0, 0);
|
|
25692
|
+
}
|
|
25693
|
+
assert(collateralPrice > 0 && debtPrice > 0, "getRebalanceAmount: Invalid price");
|
|
25694
|
+
const targetHF = this.metadata.additionalInfo.targetHealthFactor;
|
|
25695
|
+
if (currentHf > targetHF - 0.01)
|
|
25696
|
+
throw new Error("getLegRebalanceAmount: Current health factor is healthy");
|
|
25697
|
+
if (isDeposit) {
|
|
25698
|
+
const newAmount = targetHF * debtUSDAmount / (collateralPrice * ltv) - collateralTokenAmount.toNumber();
|
|
25699
|
+
logger.verbose(`${this.getTag()}:: getLegRebalanceAmount: addCollateral, currentHf: ${currentHf}, targetHF: ${targetHF}, collAmount: ${collateralTokenAmount.toString()}, collUSD: ${collateralUSDAmount}, collPrice: ${collateralPrice}, debtAmount: ${debtTokenAmount.toString()}, debtUSD: ${debtUSDAmount}, debtPrice: ${debtPrice}, ltv: ${ltv}, newAmount: ${newAmount}`);
|
|
25700
|
+
return new Web3Number(newAmount.toFixed(8), collateralTokenAmount.decimals);
|
|
25701
|
+
} else {
|
|
25702
|
+
const newAmount = debtTokenAmount.toNumber() - collateralUSDAmount * ltv / (targetHF * debtPrice);
|
|
25703
|
+
logger.verbose(`${this.getTag()}:: getLegRebalanceAmount: repayDebt, currentHf: ${currentHf}, targetHF: ${targetHF}, collAmount: ${collateralTokenAmount.toString()}, collUSD: ${collateralUSDAmount}, collPrice: ${collateralPrice}, debtAmount: ${debtTokenAmount.toString()}, debtUSD: ${debtUSDAmount}, debtPrice: ${debtPrice}, ltv: ${ltv}, newAmount: ${newAmount}`);
|
|
25704
|
+
return new Web3Number(newAmount.toFixed(8), debtTokenAmount.decimals);
|
|
25705
|
+
}
|
|
25706
|
+
}
|
|
25521
25707
|
async getVesuMultiplyCall(params) {
|
|
25522
|
-
const vesuAdapter1 = this.
|
|
25523
|
-
const vesuAdapter2 = this.getAdapter("vesu_leg2_adapter" /* VESU_LEG2 */);
|
|
25708
|
+
const [vesuAdapter1, vesuAdapter2] = this.getVesuAdapters();
|
|
25524
25709
|
const leg1LTV = await vesuAdapter1.getLTVConfig(this.config);
|
|
25525
25710
|
const leg2LTV = await vesuAdapter2.getLTVConfig(this.config);
|
|
25526
25711
|
logger.verbose(`${this.getTag()}: LTVLeg1: ${leg1LTV}`);
|
|
@@ -25529,7 +25714,7 @@ var UniversalStrategy = class _UniversalStrategy extends BaseStrategy {
|
|
|
25529
25714
|
const token2Price = await this.pricer.getPrice(vesuAdapter2.config.collateral.symbol);
|
|
25530
25715
|
logger.verbose(`${this.getTag()}: Price${vesuAdapter1.config.collateral.symbol}: ${token1Price.price}`);
|
|
25531
25716
|
logger.verbose(`${this.getTag()}: Price${vesuAdapter2.config.collateral.symbol}: ${token2Price.price}`);
|
|
25532
|
-
const TARGET_HF =
|
|
25717
|
+
const TARGET_HF = this.metadata.additionalInfo.targetHealthFactor;
|
|
25533
25718
|
const k1 = token1Price.price * leg1LTV / token2Price.price / TARGET_HF;
|
|
25534
25719
|
const k2 = token1Price.price * TARGET_HF / token2Price.price / leg2LTV;
|
|
25535
25720
|
const borrow2Amount = new Web3Number(
|
|
@@ -25587,14 +25772,14 @@ var UniversalStrategy = class _UniversalStrategy extends BaseStrategy {
|
|
|
25587
25772
|
});
|
|
25588
25773
|
if (params.isLeg1toLeg2) {
|
|
25589
25774
|
const manageCall = this.getManageCall([
|
|
25590
|
-
|
|
25591
|
-
|
|
25775
|
+
...callSet1.map((i) => i.step),
|
|
25776
|
+
...callSet2.map((i) => i.step)
|
|
25592
25777
|
], [...callSet1.map((i) => i.manageCall), ...callSet2.map((i) => i.manageCall)]);
|
|
25593
25778
|
return manageCall;
|
|
25594
25779
|
} else {
|
|
25595
25780
|
const manageCall = this.getManageCall([
|
|
25596
|
-
|
|
25597
|
-
|
|
25781
|
+
...callSet2.map((i) => i.step),
|
|
25782
|
+
...callSet1.map((i) => i.step)
|
|
25598
25783
|
], [...callSet2.map((i) => i.manageCall), ...callSet1.map((i) => i.manageCall)]);
|
|
25599
25784
|
return manageCall;
|
|
25600
25785
|
}
|
|
@@ -25662,14 +25847,18 @@ var usdcVaultSettings = {
|
|
|
25662
25847
|
vaultAllocator: ContractAddr.from("0x228cca1005d3f2b55cbaba27cb291dacf1b9a92d1d6b1638195fbd3d0c1e3ba"),
|
|
25663
25848
|
redeemRequestNFT: ContractAddr.from("0x906d03590010868cbf7590ad47043959d7af8e782089a605d9b22567b64fda"),
|
|
25664
25849
|
leafAdapters: [],
|
|
25665
|
-
adapters: []
|
|
25850
|
+
adapters: [],
|
|
25851
|
+
targetHealthFactor: 1.3,
|
|
25852
|
+
minHealthFactor: 1.25
|
|
25666
25853
|
};
|
|
25667
25854
|
var wbtcVaultSettings = {
|
|
25668
25855
|
manager: ContractAddr.from("0xef8a664ffcfe46a6af550766d27c28937bf1b77fb4ab54d8553e92bca5ba34"),
|
|
25669
25856
|
vaultAllocator: ContractAddr.from("0x1e01c25f0d9494570226ad28a7fa856c0640505e809c366a9fab4903320e735"),
|
|
25670
25857
|
redeemRequestNFT: ContractAddr.from("0x4fec59a12f8424281c1e65a80b5de51b4e754625c60cddfcd00d46941ec37b2"),
|
|
25671
25858
|
leafAdapters: [],
|
|
25672
|
-
adapters: []
|
|
25859
|
+
adapters: [],
|
|
25860
|
+
targetHealthFactor: 1.3,
|
|
25861
|
+
minHealthFactor: 1.25
|
|
25673
25862
|
};
|
|
25674
25863
|
var UniversalStrategies = [
|
|
25675
25864
|
{
|
|
@@ -25719,13 +25908,10 @@ var TelegramNotif = class {
|
|
|
25719
25908
|
this.subscribers = [
|
|
25720
25909
|
// '6820228303',
|
|
25721
25910
|
"1505578076",
|
|
25722
|
-
// '5434736198', // maaza
|
|
25723
25911
|
"1356705582",
|
|
25724
25912
|
// langs
|
|
25725
25913
|
"1388729514",
|
|
25726
25914
|
// hwashere
|
|
25727
|
-
"6020162572",
|
|
25728
|
-
//minato
|
|
25729
25915
|
"985902592"
|
|
25730
25916
|
];
|
|
25731
25917
|
this.bot = new TelegramBot(token, { polling: shouldPoll });
|
package/package.json
CHANGED
package/src/notifs/telegram.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ContractAddr, Web3Number } from "@/dataTypes";
|
|
2
2
|
import { IConfig, TokenInfo } from "@/interfaces";
|
|
3
|
+
import { CacheClass } from "@/utils/cacheClass";
|
|
3
4
|
import { Call } from "starknet";
|
|
4
5
|
|
|
5
6
|
export interface SingleActionAmount {
|
|
@@ -26,11 +27,12 @@ interface CacheData {
|
|
|
26
27
|
ttl: number;
|
|
27
28
|
data: any;
|
|
28
29
|
}
|
|
29
|
-
export class BaseStrategy<TVLInfo, ActionInfo> {
|
|
30
|
+
export class BaseStrategy<TVLInfo, ActionInfo> extends CacheClass {
|
|
30
31
|
readonly config: IConfig;
|
|
31
32
|
readonly cache: Map<string, CacheData> = new Map();
|
|
32
33
|
|
|
33
34
|
constructor(config: IConfig) {
|
|
35
|
+
super();
|
|
34
36
|
this.config = config;
|
|
35
37
|
}
|
|
36
38
|
|
|
@@ -49,26 +51,4 @@ export class BaseStrategy<TVLInfo, ActionInfo> {
|
|
|
49
51
|
async withdrawCall(amountInfo: ActionInfo, receiver: ContractAddr, owner: ContractAddr): Promise<Call[]> {
|
|
50
52
|
throw new Error("Not implemented");
|
|
51
53
|
}
|
|
52
|
-
|
|
53
|
-
setCache(key: string, data: any, ttl: number = 60000): void {
|
|
54
|
-
const timestamp = Date.now();
|
|
55
|
-
this.cache.set(key, { timestamp, ttl, data });
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
getCache(key: string): any | null {
|
|
59
|
-
const cachedData = this.cache.get(key);
|
|
60
|
-
if (!cachedData || !this.isCacheValid(key)) {
|
|
61
|
-
return null;
|
|
62
|
-
}
|
|
63
|
-
return cachedData.data;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
isCacheValid(key: string): boolean {
|
|
67
|
-
const cachedData = this.cache.get(key);
|
|
68
|
-
if (!cachedData) return false;
|
|
69
|
-
|
|
70
|
-
const { timestamp, ttl } = cachedData;
|
|
71
|
-
return Date.now() - timestamp <= ttl;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
54
|
}
|
package/src/strategies/sensei.ts
CHANGED
|
@@ -126,9 +126,16 @@ export class SenseiVault extends BaseStrategy<
|
|
|
126
126
|
collateralInSTRK: number;
|
|
127
127
|
}> {
|
|
128
128
|
const CACHE_KEY = 'positionInfo';
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
129
|
+
const existingCacheData = this.getCache<{
|
|
130
|
+
collateralXSTRK: Web3Number;
|
|
131
|
+
collateralUSDValue: Web3Number;
|
|
132
|
+
debtSTRK: Web3Number;
|
|
133
|
+
debtUSDValue: Web3Number;
|
|
134
|
+
xSTRKPrice: number;
|
|
135
|
+
collateralInSTRK: number;
|
|
136
|
+
}>(CACHE_KEY);
|
|
137
|
+
if (existingCacheData) return existingCacheData;
|
|
138
|
+
|
|
132
139
|
const resp = await fetch(
|
|
133
140
|
`${getTrovesEndpoint()}/vesu/positions?walletAddress=${this.address.address}`,
|
|
134
141
|
);
|
|
@@ -179,9 +186,9 @@ export class SenseiVault extends BaseStrategy<
|
|
|
179
186
|
|
|
180
187
|
async getSecondaryTokenPriceRelativeToMain(retry = 0): Promise<number> {
|
|
181
188
|
const CACHE_KEY = 'xSTRKPrice';
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
189
|
+
const existingCacheData = this.getCache<number>(CACHE_KEY);
|
|
190
|
+
if (existingCacheData) return existingCacheData;
|
|
191
|
+
|
|
185
192
|
const params: QuoteRequest = {
|
|
186
193
|
sellTokenAddress: this.metadata.additionalInfo.secondaryToken.address.address,
|
|
187
194
|
buyTokenAddress: this.metadata.additionalInfo.mainToken.address.address,
|
|
@@ -2,6 +2,7 @@ import { Call, hash, num, shortString } from "starknet";
|
|
|
2
2
|
import { SIMPLE_SANITIZER, toBigInt } from "./adapter-utils";
|
|
3
3
|
import { ContractAddr } from "@/dataTypes";
|
|
4
4
|
import { LeafData } from "@/utils";
|
|
5
|
+
import { CacheClass } from "@/utils/cacheClass";
|
|
5
6
|
|
|
6
7
|
export interface ManageCall {
|
|
7
8
|
sanitizer: ContractAddr,
|
|
@@ -16,7 +17,7 @@ export type GenerateCallFn<T> = (params: T) => ManageCall;
|
|
|
16
17
|
export type AdapterLeafType<T> = {leaf: LeafData, callConstructor: GenerateCallFn<T>}
|
|
17
18
|
export type LeafAdapterFn<T> = () => AdapterLeafType<T>;
|
|
18
19
|
|
|
19
|
-
export class BaseAdapter {
|
|
20
|
+
export class BaseAdapter extends CacheClass {
|
|
20
21
|
|
|
21
22
|
protected constructSimpleLeafData(params: {
|
|
22
23
|
id: string,
|