@strkfarm/sdk 1.1.70 → 1.1.71
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 +2 -2
- package/dist/cli.mjs +2 -2
- package/dist/index.browser.global.js +8522 -7751
- package/dist/index.browser.mjs +121 -84
- package/dist/index.d.ts +12 -2
- package/dist/index.js +124 -87
- package/dist/index.mjs +124 -87
- package/package.json +1 -1
- package/src/modules/harvests.ts +15 -14
- package/src/strategies/universal-adapters/vesu-adapter.ts +5 -3
- package/src/strategies/universal-lst-muliplier-strategy.tsx +138 -76
package/dist/index.mjs
CHANGED
|
@@ -96,7 +96,7 @@ var Web3Number = class _Web3Number2 extends _Web3Number {
|
|
|
96
96
|
[util.inspect.custom](depth, opts) {
|
|
97
97
|
return this.toString();
|
|
98
98
|
}
|
|
99
|
-
[
|
|
99
|
+
[Symbol.for("nodejs.util.inspect.custom")](depth, inspectOptions, inspect) {
|
|
100
100
|
return this.toString();
|
|
101
101
|
}
|
|
102
102
|
inspect(depth, opts) {
|
|
@@ -158,8 +158,8 @@ var logger = winston.createLogger({
|
|
|
158
158
|
// Add timestamp to log messages
|
|
159
159
|
format.printf(({ timestamp, level, message, ...meta }) => {
|
|
160
160
|
let msg = `${timestamp} ${level}: ${message}`;
|
|
161
|
-
if (meta && meta[
|
|
162
|
-
for (const arg of meta[
|
|
161
|
+
if (meta && meta[Symbol.for("splat")]) {
|
|
162
|
+
for (const arg of meta[Symbol.for("splat")]) {
|
|
163
163
|
if (arg instanceof Error) {
|
|
164
164
|
msg += `
|
|
165
165
|
${arg.stack}`;
|
|
@@ -4099,26 +4099,27 @@ var STRK = "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d";
|
|
|
4099
4099
|
var EkuboHarvests = class _EkuboHarvests extends Harvests {
|
|
4100
4100
|
async getHarvests(addr) {
|
|
4101
4101
|
logger.verbose(`${_EkuboHarvests.name}: getHarvests => addr: ${addr.address}`);
|
|
4102
|
-
const EKUBO_API = `https://
|
|
4102
|
+
const EKUBO_API = `https://prod-api.ekubo.org/claims/${addr.address}`;
|
|
4103
4103
|
const resultEkubo = await fetch(EKUBO_API);
|
|
4104
|
-
const
|
|
4105
|
-
|
|
4104
|
+
const data = await resultEkubo.json();
|
|
4105
|
+
const claims = data.claims || [];
|
|
4106
|
+
logger.verbose(`${_EkuboHarvests.name}: getHarvests => claims length: ${claims.length}`);
|
|
4106
4107
|
const rewards = [];
|
|
4107
|
-
for (let i = 0; i <
|
|
4108
|
-
const
|
|
4109
|
-
assert(
|
|
4108
|
+
for (let i = 0; i < claims.length; ++i) {
|
|
4109
|
+
const claimData = claims[i];
|
|
4110
|
+
assert(claimData.key.token == STRK, "expected strk token only");
|
|
4110
4111
|
rewards.push({
|
|
4111
|
-
rewardsContract: ContractAddr.from(
|
|
4112
|
+
rewardsContract: ContractAddr.from(claimData.dropAddress),
|
|
4112
4113
|
token: ContractAddr.from(STRK),
|
|
4113
|
-
startDate: new Date(
|
|
4114
|
-
endDate: new Date(
|
|
4114
|
+
startDate: /* @__PURE__ */ new Date(0),
|
|
4115
|
+
endDate: /* @__PURE__ */ new Date(0),
|
|
4115
4116
|
claim: {
|
|
4116
|
-
id:
|
|
4117
|
-
amount: Web3Number.fromWei(
|
|
4118
|
-
claimee: ContractAddr.from(
|
|
4117
|
+
id: claimData.claim.index,
|
|
4118
|
+
amount: Web3Number.fromWei(claimData.claim.amount, 18),
|
|
4119
|
+
claimee: ContractAddr.from(claimData.claim.account)
|
|
4119
4120
|
},
|
|
4120
|
-
actualReward: Web3Number.fromWei(
|
|
4121
|
-
proof:
|
|
4121
|
+
actualReward: Web3Number.fromWei(claimData.claim.amount, 18),
|
|
4122
|
+
proof: claimData.proof
|
|
4122
4123
|
});
|
|
4123
4124
|
}
|
|
4124
4125
|
return rewards.sort((a, b) => b.endDate.getTime() - a.endDate.getTime());
|
|
@@ -26976,7 +26977,8 @@ function getVesuMultiplyParams(isIncrease, params) {
|
|
|
26976
26977
|
var VesuPools = {
|
|
26977
26978
|
Genesis: ContractAddr.from("0x4dc4f0ca6ea4961e4c8373265bfd5317678f4fe374d76f3fd7135f57763bf28"),
|
|
26978
26979
|
Re7xSTRK: ContractAddr.from("0x052fb52363939c3aa848f8f4ac28f0a51379f8d1b971d8444de25fbd77d8f161"),
|
|
26979
|
-
Re7xBTC: ContractAddr.from("0x3a8416bf20d036df5b1cf3447630a2e1cb04685f6b0c3a70ed7fb1473548ecf")
|
|
26980
|
+
Re7xBTC: ContractAddr.from("0x3a8416bf20d036df5b1cf3447630a2e1cb04685f6b0c3a70ed7fb1473548ecf"),
|
|
26981
|
+
Prime: ContractAddr.from("0x451fe483d5921a2919ddd81d0de6696669bccdacd859f72a4fba7656b97c3b5")
|
|
26980
26982
|
};
|
|
26981
26983
|
var extensionMap = {};
|
|
26982
26984
|
extensionMap[VesuPools.Re7xSTRK.address] = ContractAddr.from("0x04e06e04b8d624d039aa1c3ca8e0aa9e21dc1ccba1d88d0d650837159e0ee054");
|
|
@@ -27303,14 +27305,15 @@ var VesuAdapter = class _VesuAdapter extends BaseAdapter {
|
|
|
27303
27305
|
const assetConfig = isV2 ? _assetConfig : _assetConfig["0"];
|
|
27304
27306
|
const timeDelta = assetConfig.last_updated;
|
|
27305
27307
|
const lastFullUtilizationRate = assetConfig.last_full_utilization_rate;
|
|
27306
|
-
const
|
|
27308
|
+
const debtSharePrice = Web3Number.fromWei(assetConfig.last_rate_accumulator, 18);
|
|
27309
|
+
const currentDebt = new Web3Number((Number(assetConfig.total_nominal_debt) / 1e18).toFixed(9), asset.decimals).multipliedBy(debtSharePrice);
|
|
27307
27310
|
const totalSupply = currentDebt.plus(Web3Number.fromWei(assetConfig.reserve, asset.decimals));
|
|
27308
27311
|
const ratePerSecond = BigInt(Math.round(maxBorrowAPY / 365 / 24 / 60 / 60 * Number(SCALE)));
|
|
27309
27312
|
const maxUtilisation = this.getMaxUtilizationGivenRatePerSecond(interestRateConfig, ratePerSecond, timeDelta, lastFullUtilizationRate);
|
|
27310
27313
|
logger.verbose(`${asset.symbol}::VesuAdapter::getMaxBorrowableByInterestRate maxUtilisation: ${Number(maxUtilisation) / 1e18}, totalSupply: ${totalSupply.toString()}`);
|
|
27311
27314
|
const maxDebtToHave = totalSupply.multipliedBy(Number(maxUtilisation) / 1e18);
|
|
27312
27315
|
logger.verbose(`${asset.symbol}::VesuAdapter::getMaxBorrowableByInterestRate currentDebt: ${currentDebt.toString()}, maxDebtToHave: ${maxDebtToHave.toString()}`);
|
|
27313
|
-
return maxDebtToHave.minus(currentDebt);
|
|
27316
|
+
return { maxDebtToHave: maxDebtToHave.minus(currentDebt), currentDebt, totalSupply };
|
|
27314
27317
|
}
|
|
27315
27318
|
async getLTVConfig(config, blockNumber = "latest") {
|
|
27316
27319
|
const CACHE_KEY = `ltv_config_${blockNumber}`;
|
|
@@ -30812,14 +30815,14 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
|
|
|
30812
30815
|
}
|
|
30813
30816
|
}
|
|
30814
30817
|
asset() {
|
|
30815
|
-
return this.getVesuSameTokenAdapter().config.collateral;
|
|
30818
|
+
return this.getVesuSameTokenAdapter(this.metadata.additionalInfo.defaultPoolId).config.collateral;
|
|
30816
30819
|
}
|
|
30817
30820
|
getTag() {
|
|
30818
30821
|
return `${_UniversalLstMultiplierStrategy.name}:${this.metadata.name}`;
|
|
30819
30822
|
}
|
|
30820
30823
|
// Vesu adapter with LST and base token match
|
|
30821
|
-
getVesuSameTokenAdapter() {
|
|
30822
|
-
const baseAdapter = this.getAdapter(getVesuLegId("vesu_leg1" /* VESU_LEG1 */, this.metadata.additionalInfo.underlyingToken.symbol));
|
|
30824
|
+
getVesuSameTokenAdapter(poolId) {
|
|
30825
|
+
const baseAdapter = this.getAdapter(getVesuLegId("vesu_leg1" /* VESU_LEG1 */, this.metadata.additionalInfo.underlyingToken.symbol, poolId.toString()));
|
|
30823
30826
|
baseAdapter.networkConfig = this.config;
|
|
30824
30827
|
baseAdapter.pricer = this.pricer;
|
|
30825
30828
|
return baseAdapter;
|
|
@@ -30828,18 +30831,20 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
|
|
|
30828
30831
|
// todo support lending assets of underlying as well (like if xSTRK looping is not viable, simply supply STRK)
|
|
30829
30832
|
getVesuAdapters() {
|
|
30830
30833
|
const adapters = [];
|
|
30831
|
-
const
|
|
30832
|
-
|
|
30833
|
-
const
|
|
30834
|
-
|
|
30835
|
-
|
|
30836
|
-
|
|
30837
|
-
|
|
30838
|
-
|
|
30839
|
-
|
|
30840
|
-
|
|
30841
|
-
|
|
30842
|
-
|
|
30834
|
+
for (const poolId of [this.metadata.additionalInfo.defaultPoolId, ...this.metadata.additionalInfo.altSupportedPoolIds]) {
|
|
30835
|
+
const baseAdapter = this.getVesuSameTokenAdapter(poolId);
|
|
30836
|
+
for (const asset of this.metadata.additionalInfo.borrowable_assets) {
|
|
30837
|
+
const vesuAdapter1 = new VesuAdapter({
|
|
30838
|
+
poolId: baseAdapter.config.poolId,
|
|
30839
|
+
collateral: this.asset(),
|
|
30840
|
+
debt: asset,
|
|
30841
|
+
vaultAllocator: this.metadata.additionalInfo.vaultAllocator,
|
|
30842
|
+
id: ""
|
|
30843
|
+
});
|
|
30844
|
+
vesuAdapter1.pricer = this.pricer;
|
|
30845
|
+
vesuAdapter1.networkConfig = this.config;
|
|
30846
|
+
adapters.push(vesuAdapter1);
|
|
30847
|
+
}
|
|
30843
30848
|
}
|
|
30844
30849
|
return adapters;
|
|
30845
30850
|
}
|
|
@@ -30960,7 +30965,8 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
|
|
|
30960
30965
|
const debtAmountInLST = debtAmount.abs().dividedBy(lstDEXPrice);
|
|
30961
30966
|
const calls = await this.getVesuMultiplyCall({
|
|
30962
30967
|
isDeposit: false,
|
|
30963
|
-
leg1DepositAmount: debtAmountInLST
|
|
30968
|
+
leg1DepositAmount: debtAmountInLST,
|
|
30969
|
+
poolId: vesuAdapter.config.poolId
|
|
30964
30970
|
});
|
|
30965
30971
|
assert(calls.length == 1, `Expected 1 call for unwind, got ${calls.length}`);
|
|
30966
30972
|
return calls[0];
|
|
@@ -30971,7 +30977,7 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
|
|
|
30971
30977
|
const manageCall0 = manage0Info.callConstructor({
|
|
30972
30978
|
amount: newDepositAmount
|
|
30973
30979
|
});
|
|
30974
|
-
const STEP1 = getVesuLegId("vesu_leg1" /* VESU_LEG1 */, vesuAdapter.config.debt.symbol);
|
|
30980
|
+
const STEP1 = getVesuLegId("vesu_leg1" /* VESU_LEG1 */, vesuAdapter.config.debt.symbol, vesuAdapter.config.poolId.toString());
|
|
30975
30981
|
const manage1Info = this.getProofs(STEP1);
|
|
30976
30982
|
const manageCall1 = manage1Info.callConstructor(VesuAdapter.getDefaultModifyPositionCallParams({
|
|
30977
30983
|
collateralAmount: newDepositAmount,
|
|
@@ -31026,7 +31032,7 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
|
|
|
31026
31032
|
const manageCall4 = manage4Info.callConstructor({
|
|
31027
31033
|
amount: minAmount
|
|
31028
31034
|
});
|
|
31029
|
-
const STEP5 = getVesuLegId("vesu_leg1" /* VESU_LEG1 */, vesuAdapter.config.debt.symbol);
|
|
31035
|
+
const STEP5 = getVesuLegId("vesu_leg1" /* VESU_LEG1 */, vesuAdapter.config.debt.symbol, vesuAdapter.config.poolId.toString());
|
|
31030
31036
|
const manage5Info = this.getProofs(STEP5);
|
|
31031
31037
|
const manageCall5 = manage5Info.callConstructor(VesuAdapter.getDefaultModifyPositionCallParams({
|
|
31032
31038
|
collateralAmount: minAmount,
|
|
@@ -31126,7 +31132,7 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
|
|
|
31126
31132
|
*/
|
|
31127
31133
|
async getVesuMultiplyCall(params) {
|
|
31128
31134
|
const maxEkuboPriceImpact = params.maxEkuboPriceImpact || 0.01;
|
|
31129
|
-
const vesuAdapter1 = this.getVesuSameTokenAdapter();
|
|
31135
|
+
const vesuAdapter1 = this.getVesuSameTokenAdapter(params.poolId);
|
|
31130
31136
|
const legLTV = await vesuAdapter1.getLTVConfig(this.config);
|
|
31131
31137
|
logger.verbose(`${this.getTag()}::getVesuMultiplyCall legLTV: ${legLTV}`);
|
|
31132
31138
|
if (!params.isDeposit) {
|
|
@@ -31165,11 +31171,12 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
|
|
|
31165
31171
|
debtAmount,
|
|
31166
31172
|
lstDexPriceInUnderlying: dexPrice,
|
|
31167
31173
|
isIncrease: debtAmount.greaterThan(0),
|
|
31168
|
-
maxEkuboPriceImpact
|
|
31174
|
+
maxEkuboPriceImpact,
|
|
31175
|
+
poolId: params.poolId
|
|
31169
31176
|
});
|
|
31170
31177
|
}
|
|
31171
31178
|
getLSTUnderlyingTokenInfo() {
|
|
31172
|
-
const vesuAdapter1 = this.getVesuSameTokenAdapter();
|
|
31179
|
+
const vesuAdapter1 = this.getVesuSameTokenAdapter(this.metadata.additionalInfo.defaultPoolId);
|
|
31173
31180
|
return vesuAdapter1.config.debt;
|
|
31174
31181
|
}
|
|
31175
31182
|
async getMaxBorrowableAmount(params = { isAPYComputation: false }) {
|
|
@@ -31177,7 +31184,9 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
|
|
|
31177
31184
|
let netMaxBorrowableAmount = Web3Number.fromWei("0", this.getLSTUnderlyingTokenInfo().decimals);
|
|
31178
31185
|
const maxBorrowables = [];
|
|
31179
31186
|
for (const vesuAdapter of vesuAdapters) {
|
|
31180
|
-
|
|
31187
|
+
const output = await this.getMaxBorrowableAmountByVesuAdapter(vesuAdapter, params.isAPYComputation);
|
|
31188
|
+
const ltv = await vesuAdapter.getLTVConfig(this.config);
|
|
31189
|
+
maxBorrowables.push({ ...output, ltv });
|
|
31181
31190
|
}
|
|
31182
31191
|
maxBorrowables.sort((a, b) => b.amount.toNumber() - a.amount.toNumber());
|
|
31183
31192
|
netMaxBorrowableAmount = maxBorrowables.reduce((acc, curr) => acc.plus(curr.amount), Web3Number.fromWei("0", this.getLSTUnderlyingTokenInfo().decimals));
|
|
@@ -31203,9 +31212,13 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
|
|
|
31203
31212
|
async getMaxBorrowableAmountByVesuAdapter(vesuAdapter, isAPYComputation) {
|
|
31204
31213
|
const lstAPY = await this.getLSTAPR(this.getLSTUnderlyingTokenInfo().address);
|
|
31205
31214
|
const maxInterestRate = lstAPY * 0.8;
|
|
31206
|
-
const maxBorrowableAmount = await vesuAdapter.getMaxBorrowableByInterestRate(this.config, vesuAdapter.config.debt, maxInterestRate);
|
|
31215
|
+
const { maxDebtToHave: maxBorrowableAmount, currentDebt } = await vesuAdapter.getMaxBorrowableByInterestRate(this.config, vesuAdapter.config.debt, maxInterestRate);
|
|
31207
31216
|
const debtCap = await vesuAdapter.getDebtCap(this.config);
|
|
31208
|
-
|
|
31217
|
+
if (currentDebt.gte(debtCap)) {
|
|
31218
|
+
return { amount: Web3Number.fromWei("0", vesuAdapter.config.debt.decimals), dexSwappableAmount: Web3Number.fromWei("0", vesuAdapter.config.debt.decimals), maxBorrowableAmount: Web3Number.fromWei("0", vesuAdapter.config.debt.decimals), borrowableAsset: vesuAdapter.config.debt };
|
|
31219
|
+
}
|
|
31220
|
+
const availableToBorrow = debtCap.minus(currentDebt);
|
|
31221
|
+
const maxBorrowable = maxBorrowableAmount.minimum(availableToBorrow).multipliedBy(0.999);
|
|
31209
31222
|
if (vesuAdapter.config.debt.address.eq(this.getLSTUnderlyingTokenInfo().address) || isAPYComputation) {
|
|
31210
31223
|
return { amount: maxBorrowable, dexSwappableAmount: maxBorrowable, maxBorrowableAmount: maxBorrowable, borrowableAsset: vesuAdapter.config.debt };
|
|
31211
31224
|
}
|
|
@@ -31227,7 +31240,7 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
|
|
|
31227
31240
|
*/
|
|
31228
31241
|
async getLSTAPR(_address) {
|
|
31229
31242
|
try {
|
|
31230
|
-
const vesuAdapter1 = this.getVesuSameTokenAdapter();
|
|
31243
|
+
const vesuAdapter1 = this.getVesuSameTokenAdapter(this.metadata.additionalInfo.defaultPoolId);
|
|
31231
31244
|
const apr = await LSTAPRService.getLSTAPR(vesuAdapter1.config.debt.address);
|
|
31232
31245
|
if (!apr) {
|
|
31233
31246
|
throw new Error("Failed to get LST APR");
|
|
@@ -31260,29 +31273,21 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
|
|
|
31260
31273
|
}
|
|
31261
31274
|
async maxNewDeposits(params = { isAPYComputation: false }) {
|
|
31262
31275
|
const maxBorrowableAmounts = await this.getMaxBorrowableAmount(params);
|
|
31276
|
+
let numerator = 0;
|
|
31263
31277
|
let ltv = void 0;
|
|
31264
31278
|
for (let adapter of this.getVesuAdapters()) {
|
|
31265
|
-
const
|
|
31266
|
-
if (!
|
|
31279
|
+
const maxBorrowableAmountInfo = maxBorrowableAmounts.maxBorrowables.find((b) => b.borrowableAsset.address.eq(adapter.config.debt.address));
|
|
31280
|
+
if (!maxBorrowableAmountInfo || !maxBorrowableAmountInfo?.amount) {
|
|
31267
31281
|
throw new Error(`Max borrowable amount not found for adapter: ${adapter.config.debt.symbol}`);
|
|
31268
31282
|
}
|
|
31269
|
-
|
|
31270
|
-
if (!ltv) {
|
|
31271
|
-
ltv = maxLTV;
|
|
31272
|
-
} else if (ltv != maxLTV) {
|
|
31273
|
-
throw new Error(`LTV mismatch for adapter: ${adapter.config.debt.symbol}`);
|
|
31274
|
-
}
|
|
31275
|
-
}
|
|
31276
|
-
if (!ltv) {
|
|
31277
|
-
throw new Error("LTV not found");
|
|
31283
|
+
numerator += this.metadata.additionalInfo.targetHealthFactor * maxBorrowableAmountInfo.amount.toNumber() / maxBorrowableAmountInfo.ltv;
|
|
31278
31284
|
}
|
|
31279
|
-
const numerator = this.metadata.additionalInfo.targetHealthFactor * maxBorrowableAmounts.netMaxBorrowableAmount.toNumber() / ltv;
|
|
31280
31285
|
return numerator - maxBorrowableAmounts.netMaxBorrowableAmount.toNumber();
|
|
31281
31286
|
}
|
|
31282
31287
|
// todo revisit cases where 0th adapters is used
|
|
31283
31288
|
async getUnusedBalanceAPY() {
|
|
31284
31289
|
const unusedBalance = await this.getUnusedBalance();
|
|
31285
|
-
const vesuAdapter = this.getVesuSameTokenAdapter();
|
|
31290
|
+
const vesuAdapter = this.getVesuSameTokenAdapter(this.metadata.additionalInfo.defaultPoolId);
|
|
31286
31291
|
const underlying = vesuAdapter.config.debt;
|
|
31287
31292
|
const lstAPY = await this.getLSTAPR(underlying.address);
|
|
31288
31293
|
return {
|
|
@@ -31291,7 +31296,7 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
|
|
|
31291
31296
|
};
|
|
31292
31297
|
}
|
|
31293
31298
|
async getLSTExchangeRate() {
|
|
31294
|
-
const vesuAdapter1 = this.getVesuSameTokenAdapter();
|
|
31299
|
+
const vesuAdapter1 = this.getVesuSameTokenAdapter(this.metadata.additionalInfo.defaultPoolId);
|
|
31295
31300
|
const lstTokenInfo = vesuAdapter1.config.collateral;
|
|
31296
31301
|
const lstABI = new Contract10({
|
|
31297
31302
|
abi: erc4626_abi_default,
|
|
@@ -31310,7 +31315,7 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
|
|
|
31310
31315
|
async getModifyLeverCall(params) {
|
|
31311
31316
|
logger.verbose(`${this.getTag()}::getModifyLeverCall marginAmount: ${params.marginAmount}, debtAmount: ${params.debtAmount}, lstDexPriceInUnderlying: ${params.lstDexPriceInUnderlying}, isIncrease: ${params.isIncrease}`);
|
|
31312
31317
|
assert(!params.marginAmount.isZero() || !params.debtAmount.isZero(), "Deposit/debt must be non-0");
|
|
31313
|
-
const vesuAdapter1 = this.getVesuSameTokenAdapter();
|
|
31318
|
+
const vesuAdapter1 = this.getVesuSameTokenAdapter(params.poolId);
|
|
31314
31319
|
const lstTokenInfo = this.asset();
|
|
31315
31320
|
const lstUnderlyingTokenInfo = vesuAdapter1.config.debt;
|
|
31316
31321
|
const maxAmounts = lstTokenInfo.symbol == "xSTRK" ? 5e5 : 0.5;
|
|
@@ -31320,7 +31325,7 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
|
|
|
31320
31325
|
const proofsIDs = [];
|
|
31321
31326
|
const manageCalls = [];
|
|
31322
31327
|
if (params.marginAmount.greaterThan(0)) {
|
|
31323
|
-
const STEP1_ID = "multiple_approve" /* MULTIPLE_APPROVE
|
|
31328
|
+
const STEP1_ID = getVesuGenericLegId(params.poolId.toString(), "multiple_approve" /* MULTIPLE_APPROVE */);
|
|
31324
31329
|
const manage1Info = this.getProofs(STEP1_ID);
|
|
31325
31330
|
const depositAmount = params.marginAmount;
|
|
31326
31331
|
const manageCall1 = manage1Info.callConstructor({
|
|
@@ -31353,12 +31358,12 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
|
|
|
31353
31358
|
const maxUsedCollateralInLST = params.debtAmount.abs().dividedBy(lstTrueExchangeRate).multipliedBy(1.005);
|
|
31354
31359
|
logger.verbose(`${this.getTag()}::getModifyLeverCall maxUsedCollateralInLST: ${maxUsedCollateralInLST}, maxUsedCollateral: ${maxUsedCollateral}`);
|
|
31355
31360
|
maxUsedCollateral = maxUsedCollateralInLST;
|
|
31356
|
-
const STEP2_ID = "switch_delegation_on" /* SWITCH_DELEGATION_ON
|
|
31361
|
+
const STEP2_ID = getVesuGenericLegId(params.poolId.toString(), "switch_delegation_on" /* SWITCH_DELEGATION_ON */);
|
|
31357
31362
|
const manage2Info = this.getProofs(STEP2_ID);
|
|
31358
31363
|
const manageCall2 = manage2Info.callConstructor({
|
|
31359
31364
|
delegation: true
|
|
31360
31365
|
});
|
|
31361
|
-
const STEP3_ID = getVesuLegId("multiply_vesu" /* MULTIPLY_VESU */, vesuAdapter1.config.debt.symbol);
|
|
31366
|
+
const STEP3_ID = getVesuLegId("multiply_vesu" /* MULTIPLY_VESU */, vesuAdapter1.config.debt.symbol, vesuAdapter1.config.poolId.toString());
|
|
31362
31367
|
const manage3Info = this.getProofs(STEP3_ID);
|
|
31363
31368
|
const multiplyParams = params.isIncrease ? {
|
|
31364
31369
|
isIncrease: true,
|
|
@@ -31385,7 +31390,7 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
|
|
|
31385
31390
|
}
|
|
31386
31391
|
};
|
|
31387
31392
|
const manageCall3 = manage3Info.callConstructor(multiplyParams);
|
|
31388
|
-
const STEP4_ID = "switch_delegation_off" /* SWITCH_DELEGATION_OFF
|
|
31393
|
+
const STEP4_ID = getVesuGenericLegId(params.poolId.toString(), "switch_delegation_off" /* SWITCH_DELEGATION_OFF */);
|
|
31389
31394
|
const manage4Info = this.getProofs(STEP4_ID);
|
|
31390
31395
|
const manageCall4 = manage4Info.callConstructor({
|
|
31391
31396
|
delegation: false
|
|
@@ -31445,20 +31450,46 @@ function getDescription2(tokenSymbol, underlyingSymbol) {
|
|
|
31445
31450
|
function getAvnuManageIDs(baseID, debtTokenSymbol) {
|
|
31446
31451
|
return `${baseID}_${debtTokenSymbol.toLowerCase()}`;
|
|
31447
31452
|
}
|
|
31448
|
-
function
|
|
31449
|
-
return `${
|
|
31453
|
+
function getVesuGenericLegId(poolId, action) {
|
|
31454
|
+
return `${action}_${poolId.slice(-4).toLowerCase()}`;
|
|
31450
31455
|
}
|
|
31451
|
-
function
|
|
31452
|
-
|
|
31456
|
+
function getVesuLegId(baseID, debtTokenSymbol, poolId) {
|
|
31457
|
+
return `${baseID}_${debtTokenSymbol.toLowerCase()}_${poolId.slice(-4).toLowerCase()}`;
|
|
31458
|
+
}
|
|
31459
|
+
function addVesuLeaves(poolId, lstSymbol, underlyingSymbol, vaultSettings, commonAdapter) {
|
|
31453
31460
|
const lstToken = Global.getDefaultTokens().find((token) => token.symbol === lstSymbol);
|
|
31454
31461
|
const underlyingToken = Global.getDefaultTokens().find((token) => token.symbol === underlyingSymbol);
|
|
31455
31462
|
const vesuAdapterLST = new VesuAdapter({
|
|
31456
|
-
poolId
|
|
31463
|
+
poolId,
|
|
31457
31464
|
collateral: lstToken,
|
|
31458
31465
|
debt: underlyingToken,
|
|
31459
31466
|
vaultAllocator: vaultSettings.vaultAllocator,
|
|
31460
|
-
id: getVesuLegId("vesu_leg1" /* VESU_LEG1 */, underlyingToken.symbol)
|
|
31467
|
+
id: getVesuLegId("vesu_leg1" /* VESU_LEG1 */, underlyingToken.symbol, poolId.toString())
|
|
31461
31468
|
});
|
|
31469
|
+
vaultSettings.adapters.push(...[{
|
|
31470
|
+
id: getVesuLegId("vesu_leg1" /* VESU_LEG1 */, underlyingToken.symbol, poolId.toString()),
|
|
31471
|
+
adapter: vesuAdapterLST
|
|
31472
|
+
}]);
|
|
31473
|
+
const { isV2, addr: _ } = getVesuSingletonAddress(poolId);
|
|
31474
|
+
const VESU_MULTIPLY = isV2 ? vesuAdapterLST.VESU_MULTIPLY : vesuAdapterLST.VESU_MULTIPLY_V1;
|
|
31475
|
+
const leafIdApprove = getVesuGenericLegId(poolId.toString(), "multiple_approve" /* MULTIPLE_APPROVE */);
|
|
31476
|
+
vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(lstToken.address, VESU_MULTIPLY, leafIdApprove).bind(commonAdapter));
|
|
31477
|
+
const leafIdDelegationOn = getVesuGenericLegId(poolId.toString(), "switch_delegation_on" /* SWITCH_DELEGATION_ON */);
|
|
31478
|
+
vaultSettings.leafAdapters.push(vesuAdapterLST.getVesuModifyDelegationAdapter(leafIdDelegationOn).bind(vesuAdapterLST));
|
|
31479
|
+
const leafIdDelegationOff = getVesuGenericLegId(poolId.toString(), "switch_delegation_off" /* SWITCH_DELEGATION_OFF */);
|
|
31480
|
+
vaultSettings.leafAdapters.push(vesuAdapterLST.getVesuModifyDelegationAdapter(leafIdDelegationOff).bind(vesuAdapterLST));
|
|
31481
|
+
const multiplID = getVesuLegId("multiply_vesu" /* MULTIPLY_VESU */, underlyingToken.symbol, poolId.toString());
|
|
31482
|
+
vaultSettings.leafAdapters.push(vesuAdapterLST.getMultiplyAdapter(multiplID).bind(vesuAdapterLST));
|
|
31483
|
+
return vesuAdapterLST;
|
|
31484
|
+
}
|
|
31485
|
+
function getLooperSettings2(lstSymbol, underlyingSymbol, vaultSettings, defaultPoolId, altSupportedPoolIds = []) {
|
|
31486
|
+
vaultSettings.leafAdapters = [];
|
|
31487
|
+
const pool1 = vaultSettings.defaultPoolId;
|
|
31488
|
+
if (!pool1.eq(defaultPoolId)) {
|
|
31489
|
+
throw new Error(`Dont include default pool id in supported pool ids`);
|
|
31490
|
+
}
|
|
31491
|
+
const lstToken = Global.getDefaultTokens().find((token) => token.symbol === lstSymbol);
|
|
31492
|
+
const underlyingToken = Global.getDefaultTokens().find((token) => token.symbol === underlyingSymbol);
|
|
31462
31493
|
const commonAdapter = new CommonAdapter({
|
|
31463
31494
|
manager: vaultSettings.manager,
|
|
31464
31495
|
asset: lstToken.address,
|
|
@@ -31467,17 +31498,11 @@ function getLooperSettings2(lstSymbol, underlyingSymbol, vaultSettings, pool1) {
|
|
|
31467
31498
|
vaultAllocator: vaultSettings.vaultAllocator
|
|
31468
31499
|
});
|
|
31469
31500
|
vaultSettings.adapters.push(...[{
|
|
31470
|
-
id: getVesuLegId("vesu_leg1" /* VESU_LEG1 */, underlyingToken.symbol),
|
|
31471
|
-
adapter: vesuAdapterLST
|
|
31472
|
-
}, {
|
|
31473
31501
|
id: "common_adapter" /* COMMON */,
|
|
31474
31502
|
adapter: commonAdapter
|
|
31475
31503
|
}]);
|
|
31476
|
-
const
|
|
31477
|
-
|
|
31478
|
-
vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(lstToken.address, VESU_MULTIPLY, "multiple_approve" /* MULTIPLE_APPROVE */).bind(commonAdapter));
|
|
31479
|
-
vaultSettings.leafAdapters.push(vesuAdapterLST.getVesuModifyDelegationAdapter("switch_delegation_on" /* SWITCH_DELEGATION_ON */).bind(vesuAdapterLST));
|
|
31480
|
-
vaultSettings.leafAdapters.push(vesuAdapterLST.getVesuModifyDelegationAdapter("switch_delegation_off" /* SWITCH_DELEGATION_OFF */).bind(vesuAdapterLST));
|
|
31504
|
+
const vesuAdapterLST = addVesuLeaves(defaultPoolId, lstSymbol, underlyingSymbol, vaultSettings, commonAdapter);
|
|
31505
|
+
altSupportedPoolIds.map((poolId) => addVesuLeaves(poolId, lstSymbol, underlyingSymbol, vaultSettings, commonAdapter));
|
|
31481
31506
|
vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(lstToken.address, AVNU_EXCHANGE, "avnu_mul_approve_withdr" /* AVNU_MULTIPLY_APPROVE_WITHDRAW */).bind(commonAdapter));
|
|
31482
31507
|
for (let borrowableAsset of vaultSettings.borrowable_assets) {
|
|
31483
31508
|
const debtAsset = borrowableAsset;
|
|
@@ -31492,12 +31517,14 @@ function getLooperSettings2(lstSymbol, underlyingSymbol, vaultSettings, pool1) {
|
|
|
31492
31517
|
collateral: lstToken,
|
|
31493
31518
|
debt: debtAsset,
|
|
31494
31519
|
vaultAllocator: vaultSettings.vaultAllocator,
|
|
31495
|
-
id: getVesuLegId("vesu_leg1" /* VESU_LEG1 */, debtAsset.symbol)
|
|
31520
|
+
id: getVesuLegId("vesu_leg1" /* VESU_LEG1 */, debtAsset.symbol, pool1.toString())
|
|
31496
31521
|
});
|
|
31522
|
+
const { isV2, addr: poolAddr } = getVesuSingletonAddress(pool1);
|
|
31497
31523
|
vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(lstToken.address, poolAddr, "approve_token1" /* APPROVE_TOKEN1 */).bind(commonAdapter));
|
|
31498
31524
|
vaultSettings.leafAdapters.push(vesuAdapter.getModifyPosition.bind(vesuAdapter));
|
|
31499
|
-
|
|
31500
|
-
|
|
31525
|
+
if (borrowableAsset.address.eq(underlyingToken.address)) {
|
|
31526
|
+
continue;
|
|
31527
|
+
}
|
|
31501
31528
|
}
|
|
31502
31529
|
vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(lstToken.address, vaultSettings.vaultAddress, "approve_bring_liquidity" /* APPROVE_BRING_LIQUIDITY */).bind(commonAdapter));
|
|
31503
31530
|
vaultSettings.leafAdapters.push(commonAdapter.getBringLiquidityAdapter("bring_liquidity" /* BRING_LIQUIDITY */).bind(commonAdapter));
|
|
@@ -31577,7 +31604,9 @@ var hyperxSTRK = {
|
|
|
31577
31604
|
targetHealthFactor: 1.1,
|
|
31578
31605
|
minHealthFactor: 1.05,
|
|
31579
31606
|
borrowable_assets: Global.getDefaultTokens().filter((token) => token.symbol === "STRK"),
|
|
31580
|
-
underlyingToken: Global.getDefaultTokens().find((token) => token.symbol === "STRK")
|
|
31607
|
+
underlyingToken: Global.getDefaultTokens().find((token) => token.symbol === "STRK"),
|
|
31608
|
+
defaultPoolId: VesuPools.Re7xSTRK,
|
|
31609
|
+
altSupportedPoolIds: [VesuPools.Prime]
|
|
31581
31610
|
};
|
|
31582
31611
|
var hyperxWBTC = {
|
|
31583
31612
|
vaultAddress: ContractAddr.from("0x2da9d0f96a46b453f55604313785dc866424240b1c6811d13bef594343db818"),
|
|
@@ -31590,7 +31619,9 @@ var hyperxWBTC = {
|
|
|
31590
31619
|
targetHealthFactor: 1.1,
|
|
31591
31620
|
minHealthFactor: 1.05,
|
|
31592
31621
|
borrowable_assets: borrowableAssets.map((asset) => Global.getDefaultTokens().find((token) => token.symbol === asset)),
|
|
31593
|
-
underlyingToken: Global.getDefaultTokens().find((token) => token.symbol === "WBTC")
|
|
31622
|
+
underlyingToken: Global.getDefaultTokens().find((token) => token.symbol === "WBTC"),
|
|
31623
|
+
defaultPoolId: VesuPools.Re7xBTC,
|
|
31624
|
+
altSupportedPoolIds: []
|
|
31594
31625
|
};
|
|
31595
31626
|
var hyperxtBTC = {
|
|
31596
31627
|
vaultAddress: ContractAddr.from("0x47d5f68477e5637ce0e56436c6b5eee5a354e6828995dae106b11a48679328"),
|
|
@@ -31603,7 +31634,9 @@ var hyperxtBTC = {
|
|
|
31603
31634
|
targetHealthFactor: 1.1,
|
|
31604
31635
|
minHealthFactor: 1.05,
|
|
31605
31636
|
borrowable_assets: Global.getDefaultTokens().filter((token) => token.symbol === "tBTC" || token.symbol === "WBTC"),
|
|
31606
|
-
underlyingToken: Global.getDefaultTokens().find((token) => token.symbol === "tBTC")
|
|
31637
|
+
underlyingToken: Global.getDefaultTokens().find((token) => token.symbol === "tBTC"),
|
|
31638
|
+
defaultPoolId: VesuPools.Re7xBTC,
|
|
31639
|
+
altSupportedPoolIds: []
|
|
31607
31640
|
};
|
|
31608
31641
|
var hyperxsBTC = {
|
|
31609
31642
|
vaultAddress: ContractAddr.from("0x437ef1e7d0f100b2e070b7a65cafec0b2be31b0290776da8b4112f5473d8d9"),
|
|
@@ -31616,7 +31649,9 @@ var hyperxsBTC = {
|
|
|
31616
31649
|
targetHealthFactor: 1.1,
|
|
31617
31650
|
minHealthFactor: 1.05,
|
|
31618
31651
|
borrowable_assets: Global.getDefaultTokens().filter((token) => token.symbol === "solvBTC"),
|
|
31619
|
-
underlyingToken: Global.getDefaultTokens().find((token) => token.symbol === "solvBTC")
|
|
31652
|
+
underlyingToken: Global.getDefaultTokens().find((token) => token.symbol === "solvBTC"),
|
|
31653
|
+
defaultPoolId: VesuPools.Re7xBTC,
|
|
31654
|
+
altSupportedPoolIds: []
|
|
31620
31655
|
};
|
|
31621
31656
|
var hyperxLBTC = {
|
|
31622
31657
|
vaultAddress: ContractAddr.from("0x64cf24d4883fe569926419a0569ab34497c6956a1a308fa883257f7486d7030"),
|
|
@@ -31629,7 +31664,9 @@ var hyperxLBTC = {
|
|
|
31629
31664
|
targetHealthFactor: 1.1,
|
|
31630
31665
|
minHealthFactor: 1.05,
|
|
31631
31666
|
borrowable_assets: Global.getDefaultTokens().filter((token) => token.symbol === "LBTC"),
|
|
31632
|
-
underlyingToken: Global.getDefaultTokens().find((token) => token.symbol === "LBTC")
|
|
31667
|
+
underlyingToken: Global.getDefaultTokens().find((token) => token.symbol === "LBTC"),
|
|
31668
|
+
defaultPoolId: VesuPools.Re7xBTC,
|
|
31669
|
+
altSupportedPoolIds: []
|
|
31633
31670
|
};
|
|
31634
31671
|
function getInvestmentSteps(lstSymbol, underlyingSymbol) {
|
|
31635
31672
|
return [
|
|
@@ -31648,7 +31685,7 @@ function getStrategySettings(lstSymbol, underlyingSymbol, addresses, isPreview =
|
|
|
31648
31685
|
launchBlock: 0,
|
|
31649
31686
|
type: "Other",
|
|
31650
31687
|
depositTokens: [Global.getDefaultTokens().find((token) => token.symbol === lstSymbol)],
|
|
31651
|
-
additionalInfo: getLooperSettings2(lstSymbol, underlyingSymbol, addresses, lstSymbol === "xSTRK" ? VesuPools.
|
|
31688
|
+
additionalInfo: getLooperSettings2(lstSymbol, underlyingSymbol, addresses, addresses.defaultPoolId, lstSymbol === "xSTRK" ? [VesuPools.Prime] : []),
|
|
31652
31689
|
risk: {
|
|
31653
31690
|
riskFactor: _riskFactor4,
|
|
31654
31691
|
netRisk: _riskFactor4.reduce((acc, curr) => acc + curr.value * curr.weight, 0) / _riskFactor4.reduce((acc, curr) => acc + curr.weight, 0),
|
package/package.json
CHANGED
package/src/modules/harvests.ts
CHANGED
|
@@ -68,26 +68,27 @@ const STRK = '0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d'
|
|
|
68
68
|
export class EkuboHarvests extends Harvests {
|
|
69
69
|
async getHarvests(addr: ContractAddr) {
|
|
70
70
|
logger.verbose(`${EkuboHarvests.name}: getHarvests => addr: ${addr.address}`);
|
|
71
|
-
const EKUBO_API = `https://
|
|
71
|
+
const EKUBO_API = `https://prod-api.ekubo.org/claims/${addr.address}`
|
|
72
72
|
const resultEkubo = await fetch(EKUBO_API);
|
|
73
|
-
const
|
|
74
|
-
|
|
73
|
+
const data = (await resultEkubo.json());
|
|
74
|
+
const claims = data.claims || [];
|
|
75
|
+
logger.verbose(`${EkuboHarvests.name}: getHarvests => claims length: ${claims.length}`);
|
|
75
76
|
const rewards: HarvestInfo[] = [];
|
|
76
|
-
for (let i=0; i<
|
|
77
|
-
const
|
|
78
|
-
assert(
|
|
77
|
+
for (let i=0; i<claims.length; ++i) {
|
|
78
|
+
const claimData = claims[i];
|
|
79
|
+
assert(claimData.key.token == STRK, 'expected strk token only')
|
|
79
80
|
rewards.push({
|
|
80
|
-
rewardsContract: ContractAddr.from(
|
|
81
|
+
rewardsContract: ContractAddr.from(claimData.dropAddress),
|
|
81
82
|
token: ContractAddr.from(STRK),
|
|
82
|
-
startDate: new Date(
|
|
83
|
-
endDate: new Date(
|
|
83
|
+
startDate: new Date(0),
|
|
84
|
+
endDate: new Date(0),
|
|
84
85
|
claim: {
|
|
85
|
-
id:
|
|
86
|
-
amount: Web3Number.fromWei(
|
|
87
|
-
claimee: ContractAddr.from(
|
|
86
|
+
id: claimData.claim.index,
|
|
87
|
+
amount: Web3Number.fromWei(claimData.claim.amount, 18),
|
|
88
|
+
claimee: ContractAddr.from(claimData.claim.account)
|
|
88
89
|
},
|
|
89
|
-
actualReward: Web3Number.fromWei(
|
|
90
|
-
proof:
|
|
90
|
+
actualReward: Web3Number.fromWei(claimData.claim.amount, 18),
|
|
91
|
+
proof: claimData.proof
|
|
91
92
|
});
|
|
92
93
|
}
|
|
93
94
|
return rewards.sort((a, b) => b.endDate.getTime() - a.endDate.getTime());
|
|
@@ -232,7 +232,8 @@ function getVesuMultiplyParams(isIncrease: boolean, params: IncreaseLeverParams
|
|
|
232
232
|
export const VesuPools = {
|
|
233
233
|
Genesis: ContractAddr.from('0x4dc4f0ca6ea4961e4c8373265bfd5317678f4fe374d76f3fd7135f57763bf28'),
|
|
234
234
|
Re7xSTRK: ContractAddr.from('0x052fb52363939c3aa848f8f4ac28f0a51379f8d1b971d8444de25fbd77d8f161'),
|
|
235
|
-
Re7xBTC: ContractAddr.from('0x3a8416bf20d036df5b1cf3447630a2e1cb04685f6b0c3a70ed7fb1473548ecf')
|
|
235
|
+
Re7xBTC: ContractAddr.from('0x3a8416bf20d036df5b1cf3447630a2e1cb04685f6b0c3a70ed7fb1473548ecf'),
|
|
236
|
+
Prime: ContractAddr.from('0x451fe483d5921a2919ddd81d0de6696669bccdacd859f72a4fba7656b97c3b5'),
|
|
236
237
|
}
|
|
237
238
|
|
|
238
239
|
export const extensionMap: {[key: string]: ContractAddr} = {};
|
|
@@ -587,7 +588,8 @@ export class VesuAdapter extends BaseAdapter {
|
|
|
587
588
|
const assetConfig = isV2 ? _assetConfig : _assetConfig['0'];
|
|
588
589
|
const timeDelta = assetConfig.last_updated;
|
|
589
590
|
const lastFullUtilizationRate = assetConfig.last_full_utilization_rate;
|
|
590
|
-
const
|
|
591
|
+
const debtSharePrice = Web3Number.fromWei(assetConfig.last_rate_accumulator, 18);
|
|
592
|
+
const currentDebt = (new Web3Number((Number(assetConfig.total_nominal_debt) / 1e18).toFixed(9), asset.decimals)).multipliedBy(debtSharePrice);
|
|
591
593
|
const totalSupply = currentDebt.plus(Web3Number.fromWei(assetConfig.reserve, asset.decimals));
|
|
592
594
|
|
|
593
595
|
const ratePerSecond = BigInt(Math.round(maxBorrowAPY / 365 / 24 / 60 / 60 * Number(SCALE)));
|
|
@@ -596,7 +598,7 @@ export class VesuAdapter extends BaseAdapter {
|
|
|
596
598
|
|
|
597
599
|
const maxDebtToHave = totalSupply.multipliedBy(Number(maxUtilisation) / 1e18);
|
|
598
600
|
logger.verbose(`${asset.symbol}::VesuAdapter::getMaxBorrowableByInterestRate currentDebt: ${currentDebt.toString()}, maxDebtToHave: ${maxDebtToHave.toString()}`);
|
|
599
|
-
return maxDebtToHave.minus(currentDebt);
|
|
601
|
+
return {maxDebtToHave: maxDebtToHave.minus(currentDebt), currentDebt: currentDebt, totalSupply: totalSupply};
|
|
600
602
|
}
|
|
601
603
|
|
|
602
604
|
async getLTVConfig(config: IConfig, blockNumber: BlockIdentifier = 'latest') {
|