@strkfarm/sdk 2.0.0-dev.33 → 2.0.0-dev.35
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 +1708 -141
- package/dist/index.browser.mjs +1762 -194
- package/dist/index.d.ts +104 -2
- package/dist/index.js +1600 -29
- package/dist/index.mjs +1873 -305
- package/package.json +1 -1
- package/src/data/redeem-request-nft.abi.json +752 -0
- package/src/strategies/index.ts +1 -0
- package/src/strategies/svk-strategy.ts +3 -2
- package/src/strategies/universal-adapters/adapter-utils.ts +2 -0
- package/src/strategies/universal-adapters/avnu-adapter.ts +3 -2
- package/src/strategies/universal-adapters/extended-adapter.ts +25 -0
- package/src/strategies/universal-adapters/svk-troves-adapter.ts +141 -7
- package/src/strategies/universal-adapters/vesu-modify-position-adapter.ts +69 -39
- package/src/strategies/usdc-boosted-strategy.tsx +693 -0
- package/src/strategies/vesu-extended-strategy/services/executionService.ts +1 -0
- package/src/strategies/vesu-extended-strategy/services/extended-vesu-state-manager.ts +172 -5
package/dist/index.browser.mjs
CHANGED
|
@@ -22065,6 +22065,7 @@ import { CairoCustomEnum as CairoCustomEnum2, Contract as Contract10, hash as ha
|
|
|
22065
22065
|
|
|
22066
22066
|
// src/strategies/universal-adapters/adapter-utils.ts
|
|
22067
22067
|
var SIMPLE_SANITIZER = ContractAddr.from("0x5a2e3ceb3da368b983a8717898427ab7b6daf04014b70f321e777f9aad940b4");
|
|
22068
|
+
var SVK_SIMPLE_SANITIZER = ContractAddr.from("0x03dcde04343257c3ce14574676cb9c5b2eda16e332c1b8caf5dc4c95ac568d2f");
|
|
22068
22069
|
var EXTENDED_SANITIZER = ContractAddr.from("0x65891708362b24dcf4c40c8e218cce6e82d1d6b3a3404c9ab00a48f08e2c110");
|
|
22069
22070
|
var AVNU_LEGACY_SANITIZER = ContractAddr.from("0x0656fBE853f116DD53956176a553eDe8fE65632252f8aceB50C1B9B6c8237309");
|
|
22070
22071
|
var SIMPLE_SANITIZER_V2 = ContractAddr.from("0x7b6f98311af8aa425278570e62abf523e6462eaa01a38c1feab9b2f416492e2");
|
|
@@ -35928,7 +35929,14 @@ var VesuModifyPositionAdapter = class _VesuModifyPositionAdapter extends BaseAda
|
|
|
35928
35929
|
}
|
|
35929
35930
|
const normalizedDebtAmount = this._normalizeDebtAmountFromHelper(
|
|
35930
35931
|
helperOutput
|
|
35931
|
-
);
|
|
35932
|
+
).minus(state.currentDebt);
|
|
35933
|
+
if (normalizedDebtAmount.lessThan(0)) {
|
|
35934
|
+
logger.warn(`VesuModifyPositionAdapter: deposit debt delta is negative (${normalizedDebtAmount.toNumber()}), clamping to zero`);
|
|
35935
|
+
return {
|
|
35936
|
+
collateral: this._toSigned(collateralToAdd, false),
|
|
35937
|
+
debt: this._toSigned(Web3Number.fromWei(0, this.config.debt.decimals), false)
|
|
35938
|
+
};
|
|
35939
|
+
}
|
|
35932
35940
|
return {
|
|
35933
35941
|
collateral: this._toSigned(collateralToAdd, false),
|
|
35934
35942
|
debt: this._toSigned(normalizedDebtAmount, false)
|
|
@@ -35946,8 +35954,8 @@ var VesuModifyPositionAdapter = class _VesuModifyPositionAdapter extends BaseAda
|
|
|
35946
35954
|
state.debtPrice,
|
|
35947
35955
|
this.config.debt
|
|
35948
35956
|
);
|
|
35949
|
-
if (!helperOutput || helperOutput.
|
|
35950
|
-
throw new Error(`Failed to calculate
|
|
35957
|
+
if (!helperOutput || helperOutput.lessThan(0)) {
|
|
35958
|
+
throw new Error(`Failed to calculate max debt amount for withdraw: ${helperOutput?.toNumber()}`);
|
|
35951
35959
|
}
|
|
35952
35960
|
const normalizedDebtAmount = this._normalizeDebtAmountFromHelper(
|
|
35953
35961
|
helperOutput
|
|
@@ -36144,6 +36152,24 @@ var VesuModifyPositionAdapter = class _VesuModifyPositionAdapter extends BaseAda
|
|
|
36144
36152
|
this._prepareVesuAdapter();
|
|
36145
36153
|
return this._vesuAdapter.getHealthFactor();
|
|
36146
36154
|
}
|
|
36155
|
+
/**
|
|
36156
|
+
* Simulates a deposit of `depositAmount` collateral and returns how much
|
|
36157
|
+
* debt (STRK) would be incrementally borrowed to reach the target LTV.
|
|
36158
|
+
* Used upstream to size the AVNU swap call in the same transaction batch.
|
|
36159
|
+
*/
|
|
36160
|
+
async getExpectedDepositDebtDelta(depositAmount) {
|
|
36161
|
+
const defaults = await this._buildDefaultDepositDeltas({ amount: depositAmount });
|
|
36162
|
+
return defaults.debt.amount;
|
|
36163
|
+
}
|
|
36164
|
+
/**
|
|
36165
|
+
* Simulates a withdrawal of `withdrawAmount` collateral and returns the
|
|
36166
|
+
* incremental debt delta needed to keep the target health factor.
|
|
36167
|
+
* Positive means borrow, negative means repay.
|
|
36168
|
+
*/
|
|
36169
|
+
async getExpectedWithdrawDebtDelta(withdrawAmount) {
|
|
36170
|
+
const defaults = await this._buildDefaultWithdrawDeltas({ amount: withdrawAmount });
|
|
36171
|
+
return defaults.debt.amount;
|
|
36172
|
+
}
|
|
36147
36173
|
};
|
|
36148
36174
|
|
|
36149
36175
|
// src/strategies/universal-adapters/extended-adapter.ts
|
|
@@ -36205,6 +36231,25 @@ var ExtendedAdapter = class _ExtendedAdapter extends BaseAdapter {
|
|
|
36205
36231
|
return { success: false, data: [] };
|
|
36206
36232
|
}
|
|
36207
36233
|
}
|
|
36234
|
+
/** Account funding payment history via `GET /api/v1/account/funding-payments` (USDC amounts). */
|
|
36235
|
+
async getFundingPayments(side, startTime, limit) {
|
|
36236
|
+
try {
|
|
36237
|
+
const response = await this.client.getUserFundingPayments(
|
|
36238
|
+
this.config.extendedMarketName,
|
|
36239
|
+
side,
|
|
36240
|
+
startTime ?? Date.now() - 30 * 24 * 60 * 60 * 1e3,
|
|
36241
|
+
limit ?? 200
|
|
36242
|
+
);
|
|
36243
|
+
if (response.status !== "OK") {
|
|
36244
|
+
logger.error("error getting funding payments", response.data);
|
|
36245
|
+
return { success: false, data: [] };
|
|
36246
|
+
}
|
|
36247
|
+
return { success: true, data: response.data ?? [] };
|
|
36248
|
+
} catch (err) {
|
|
36249
|
+
logger.error("error getting funding payments", err);
|
|
36250
|
+
return { success: false, data: [] };
|
|
36251
|
+
}
|
|
36252
|
+
}
|
|
36208
36253
|
async getPosition(supportedPosition) {
|
|
36209
36254
|
const holdings = await this.getExtendedDepositAmount();
|
|
36210
36255
|
if (!holdings) {
|
|
@@ -38844,117 +38889,965 @@ var universal_vault_abi_default = [
|
|
|
38844
38889
|
}
|
|
38845
38890
|
];
|
|
38846
38891
|
|
|
38847
|
-
// src/
|
|
38848
|
-
var
|
|
38849
|
-
|
|
38850
|
-
|
|
38851
|
-
|
|
38852
|
-
|
|
38853
|
-
|
|
38854
|
-
|
|
38855
|
-
|
|
38856
|
-
|
|
38857
|
-
|
|
38858
|
-
|
|
38859
|
-
|
|
38860
|
-
|
|
38861
|
-
|
|
38862
|
-
|
|
38863
|
-
|
|
38864
|
-
|
|
38865
|
-
}
|
|
38866
|
-
/** Owner used for share balance + `due_assets_from_owner`. */
|
|
38867
|
-
_positionOwner() {
|
|
38868
|
-
return this.config.positionOwner ?? this.config.vaultAllocator;
|
|
38869
|
-
}
|
|
38870
|
-
/**
|
|
38871
|
-
* Proof readable IDs must stay ≤ 31 chars (Cairo short string). We derive a short ASCII suffix from
|
|
38872
|
-
* `strategyVault` address so multiple SVK adapters in one tree stay distinct.
|
|
38873
|
-
*/
|
|
38874
|
-
_proofSuffix() {
|
|
38875
|
-
return this.config.strategyVault.address.replace(/^0x/, "").slice(-6);
|
|
38876
|
-
}
|
|
38877
|
-
_depositApproveProofReadableId() {
|
|
38878
|
-
return `appr_dep_svk_${this._proofSuffix()}`;
|
|
38879
|
-
}
|
|
38880
|
-
_depositCallProofReadableId() {
|
|
38881
|
-
return `dep_svk_${this._proofSuffix()}`;
|
|
38882
|
-
}
|
|
38883
|
-
_withdrawCallProofReadableId() {
|
|
38884
|
-
return `wtdrw_svk_${this._proofSuffix()}`;
|
|
38885
|
-
}
|
|
38886
|
-
async getAPY(supportedPosition) {
|
|
38887
|
-
const CACHE_KEY = `svk_apy_${this.config.trovesStrategyId}`;
|
|
38888
|
-
const cached = this.getCache(CACHE_KEY);
|
|
38889
|
-
if (cached) {
|
|
38890
|
-
return cached;
|
|
38891
|
-
}
|
|
38892
|
-
const url = this.config.trovesStrategiesApiUrl ?? DEFAULT_TROVES_STRATEGIES_API;
|
|
38893
|
-
try {
|
|
38894
|
-
const res = await fetch(url);
|
|
38895
|
-
if (!res.ok) {
|
|
38896
|
-
logger.warn(`${_SvkTrovesAdapter.name}::getAPY: HTTP ${res.status} from ${url}`);
|
|
38897
|
-
const fallback = { apy: 0, type: "base" /* BASE */ };
|
|
38898
|
-
this.setCache(CACHE_KEY, fallback, 3e5);
|
|
38899
|
-
return fallback;
|
|
38892
|
+
// src/data/redeem-request-nft.abi.json
|
|
38893
|
+
var redeem_request_nft_abi_default = [
|
|
38894
|
+
{
|
|
38895
|
+
type: "impl",
|
|
38896
|
+
name: "RedeemRequestImpl",
|
|
38897
|
+
interface_name: "vault::redeem_request::interface::IRedeemRequest"
|
|
38898
|
+
},
|
|
38899
|
+
{
|
|
38900
|
+
type: "struct",
|
|
38901
|
+
name: "core::integer::u256",
|
|
38902
|
+
members: [
|
|
38903
|
+
{
|
|
38904
|
+
name: "low",
|
|
38905
|
+
type: "core::integer::u128"
|
|
38906
|
+
},
|
|
38907
|
+
{
|
|
38908
|
+
name: "high",
|
|
38909
|
+
type: "core::integer::u128"
|
|
38900
38910
|
}
|
|
38901
|
-
|
|
38902
|
-
|
|
38903
|
-
|
|
38904
|
-
|
|
38905
|
-
|
|
38906
|
-
|
|
38907
|
-
|
|
38908
|
-
|
|
38909
|
-
|
|
38911
|
+
]
|
|
38912
|
+
},
|
|
38913
|
+
{
|
|
38914
|
+
type: "struct",
|
|
38915
|
+
name: "vault::redeem_request::interface::RedeemRequestInfo",
|
|
38916
|
+
members: [
|
|
38917
|
+
{
|
|
38918
|
+
name: "epoch",
|
|
38919
|
+
type: "core::integer::u256"
|
|
38920
|
+
},
|
|
38921
|
+
{
|
|
38922
|
+
name: "nominal",
|
|
38923
|
+
type: "core::integer::u256"
|
|
38910
38924
|
}
|
|
38911
|
-
|
|
38912
|
-
|
|
38913
|
-
|
|
38914
|
-
|
|
38915
|
-
|
|
38916
|
-
|
|
38917
|
-
|
|
38918
|
-
|
|
38919
|
-
|
|
38920
|
-
|
|
38921
|
-
|
|
38922
|
-
|
|
38923
|
-
|
|
38924
|
-
|
|
38925
|
-
|
|
38926
|
-
|
|
38927
|
-
|
|
38928
|
-
|
|
38929
|
-
|
|
38930
|
-
|
|
38931
|
-
|
|
38932
|
-
|
|
38933
|
-
|
|
38934
|
-
|
|
38935
|
-
|
|
38936
|
-
|
|
38937
|
-
|
|
38938
|
-
|
|
38939
|
-
|
|
38940
|
-
|
|
38941
|
-
|
|
38942
|
-
|
|
38943
|
-
|
|
38944
|
-
|
|
38925
|
+
]
|
|
38926
|
+
},
|
|
38927
|
+
{
|
|
38928
|
+
type: "interface",
|
|
38929
|
+
name: "vault::redeem_request::interface::IRedeemRequest",
|
|
38930
|
+
items: [
|
|
38931
|
+
{
|
|
38932
|
+
type: "function",
|
|
38933
|
+
name: "vault",
|
|
38934
|
+
inputs: [],
|
|
38935
|
+
outputs: [
|
|
38936
|
+
{
|
|
38937
|
+
type: "core::starknet::contract_address::ContractAddress"
|
|
38938
|
+
}
|
|
38939
|
+
],
|
|
38940
|
+
state_mutability: "view"
|
|
38941
|
+
},
|
|
38942
|
+
{
|
|
38943
|
+
type: "function",
|
|
38944
|
+
name: "id_to_info",
|
|
38945
|
+
inputs: [
|
|
38946
|
+
{
|
|
38947
|
+
name: "id",
|
|
38948
|
+
type: "core::integer::u256"
|
|
38949
|
+
}
|
|
38950
|
+
],
|
|
38951
|
+
outputs: [
|
|
38952
|
+
{
|
|
38953
|
+
type: "vault::redeem_request::interface::RedeemRequestInfo"
|
|
38954
|
+
}
|
|
38955
|
+
],
|
|
38956
|
+
state_mutability: "view"
|
|
38957
|
+
},
|
|
38958
|
+
{
|
|
38959
|
+
type: "function",
|
|
38960
|
+
name: "id_len",
|
|
38961
|
+
inputs: [],
|
|
38962
|
+
outputs: [
|
|
38963
|
+
{
|
|
38964
|
+
type: "core::integer::u256"
|
|
38965
|
+
}
|
|
38966
|
+
],
|
|
38967
|
+
state_mutability: "view"
|
|
38968
|
+
},
|
|
38969
|
+
{
|
|
38970
|
+
type: "function",
|
|
38971
|
+
name: "mint",
|
|
38972
|
+
inputs: [
|
|
38973
|
+
{
|
|
38974
|
+
name: "to",
|
|
38975
|
+
type: "core::starknet::contract_address::ContractAddress"
|
|
38976
|
+
},
|
|
38977
|
+
{
|
|
38978
|
+
name: "redeem_request_info",
|
|
38979
|
+
type: "vault::redeem_request::interface::RedeemRequestInfo"
|
|
38980
|
+
}
|
|
38981
|
+
],
|
|
38982
|
+
outputs: [
|
|
38983
|
+
{
|
|
38984
|
+
type: "core::integer::u256"
|
|
38985
|
+
}
|
|
38986
|
+
],
|
|
38987
|
+
state_mutability: "external"
|
|
38988
|
+
},
|
|
38989
|
+
{
|
|
38990
|
+
type: "function",
|
|
38991
|
+
name: "burn",
|
|
38992
|
+
inputs: [
|
|
38993
|
+
{
|
|
38994
|
+
name: "id",
|
|
38995
|
+
type: "core::integer::u256"
|
|
38996
|
+
}
|
|
38997
|
+
],
|
|
38998
|
+
outputs: [],
|
|
38999
|
+
state_mutability: "external"
|
|
39000
|
+
}
|
|
39001
|
+
]
|
|
39002
|
+
},
|
|
39003
|
+
{
|
|
39004
|
+
type: "impl",
|
|
39005
|
+
name: "UpgradeableImpl",
|
|
39006
|
+
interface_name: "openzeppelin_interfaces::upgrades::IUpgradeable"
|
|
39007
|
+
},
|
|
39008
|
+
{
|
|
39009
|
+
type: "interface",
|
|
39010
|
+
name: "openzeppelin_interfaces::upgrades::IUpgradeable",
|
|
39011
|
+
items: [
|
|
39012
|
+
{
|
|
39013
|
+
type: "function",
|
|
39014
|
+
name: "upgrade",
|
|
39015
|
+
inputs: [
|
|
39016
|
+
{
|
|
39017
|
+
name: "new_class_hash",
|
|
39018
|
+
type: "core::starknet::class_hash::ClassHash"
|
|
39019
|
+
}
|
|
39020
|
+
],
|
|
39021
|
+
outputs: [],
|
|
39022
|
+
state_mutability: "external"
|
|
39023
|
+
}
|
|
39024
|
+
]
|
|
39025
|
+
},
|
|
39026
|
+
{
|
|
39027
|
+
type: "impl",
|
|
39028
|
+
name: "ERC721MixinImpl",
|
|
39029
|
+
interface_name: "openzeppelin_interfaces::token::erc721::ERC721ABI"
|
|
39030
|
+
},
|
|
39031
|
+
{
|
|
39032
|
+
type: "struct",
|
|
39033
|
+
name: "core::array::Span::<core::felt252>",
|
|
39034
|
+
members: [
|
|
39035
|
+
{
|
|
39036
|
+
name: "snapshot",
|
|
39037
|
+
type: "@core::array::Array::<core::felt252>"
|
|
39038
|
+
}
|
|
39039
|
+
]
|
|
39040
|
+
},
|
|
39041
|
+
{
|
|
39042
|
+
type: "enum",
|
|
39043
|
+
name: "core::bool",
|
|
39044
|
+
variants: [
|
|
39045
|
+
{
|
|
39046
|
+
name: "False",
|
|
39047
|
+
type: "()"
|
|
39048
|
+
},
|
|
39049
|
+
{
|
|
39050
|
+
name: "True",
|
|
39051
|
+
type: "()"
|
|
39052
|
+
}
|
|
39053
|
+
]
|
|
39054
|
+
},
|
|
39055
|
+
{
|
|
39056
|
+
type: "struct",
|
|
39057
|
+
name: "core::byte_array::ByteArray",
|
|
39058
|
+
members: [
|
|
39059
|
+
{
|
|
39060
|
+
name: "data",
|
|
39061
|
+
type: "core::array::Array::<core::bytes_31::bytes31>"
|
|
39062
|
+
},
|
|
39063
|
+
{
|
|
39064
|
+
name: "pending_word",
|
|
39065
|
+
type: "core::felt252"
|
|
39066
|
+
},
|
|
39067
|
+
{
|
|
39068
|
+
name: "pending_word_len",
|
|
39069
|
+
type: "core::integer::u32"
|
|
39070
|
+
}
|
|
39071
|
+
]
|
|
39072
|
+
},
|
|
39073
|
+
{
|
|
39074
|
+
type: "interface",
|
|
39075
|
+
name: "openzeppelin_interfaces::token::erc721::ERC721ABI",
|
|
39076
|
+
items: [
|
|
39077
|
+
{
|
|
39078
|
+
type: "function",
|
|
39079
|
+
name: "balance_of",
|
|
39080
|
+
inputs: [
|
|
39081
|
+
{
|
|
39082
|
+
name: "account",
|
|
39083
|
+
type: "core::starknet::contract_address::ContractAddress"
|
|
39084
|
+
}
|
|
39085
|
+
],
|
|
39086
|
+
outputs: [
|
|
39087
|
+
{
|
|
39088
|
+
type: "core::integer::u256"
|
|
39089
|
+
}
|
|
39090
|
+
],
|
|
39091
|
+
state_mutability: "view"
|
|
39092
|
+
},
|
|
39093
|
+
{
|
|
39094
|
+
type: "function",
|
|
39095
|
+
name: "owner_of",
|
|
39096
|
+
inputs: [
|
|
39097
|
+
{
|
|
39098
|
+
name: "token_id",
|
|
39099
|
+
type: "core::integer::u256"
|
|
39100
|
+
}
|
|
39101
|
+
],
|
|
39102
|
+
outputs: [
|
|
39103
|
+
{
|
|
39104
|
+
type: "core::starknet::contract_address::ContractAddress"
|
|
39105
|
+
}
|
|
39106
|
+
],
|
|
39107
|
+
state_mutability: "view"
|
|
39108
|
+
},
|
|
39109
|
+
{
|
|
39110
|
+
type: "function",
|
|
39111
|
+
name: "safe_transfer_from",
|
|
39112
|
+
inputs: [
|
|
39113
|
+
{
|
|
39114
|
+
name: "from",
|
|
39115
|
+
type: "core::starknet::contract_address::ContractAddress"
|
|
39116
|
+
},
|
|
39117
|
+
{
|
|
39118
|
+
name: "to",
|
|
39119
|
+
type: "core::starknet::contract_address::ContractAddress"
|
|
39120
|
+
},
|
|
39121
|
+
{
|
|
39122
|
+
name: "token_id",
|
|
39123
|
+
type: "core::integer::u256"
|
|
39124
|
+
},
|
|
39125
|
+
{
|
|
39126
|
+
name: "data",
|
|
39127
|
+
type: "core::array::Span::<core::felt252>"
|
|
39128
|
+
}
|
|
39129
|
+
],
|
|
39130
|
+
outputs: [],
|
|
39131
|
+
state_mutability: "external"
|
|
39132
|
+
},
|
|
39133
|
+
{
|
|
39134
|
+
type: "function",
|
|
39135
|
+
name: "transfer_from",
|
|
39136
|
+
inputs: [
|
|
39137
|
+
{
|
|
39138
|
+
name: "from",
|
|
39139
|
+
type: "core::starknet::contract_address::ContractAddress"
|
|
39140
|
+
},
|
|
39141
|
+
{
|
|
39142
|
+
name: "to",
|
|
39143
|
+
type: "core::starknet::contract_address::ContractAddress"
|
|
39144
|
+
},
|
|
39145
|
+
{
|
|
39146
|
+
name: "token_id",
|
|
39147
|
+
type: "core::integer::u256"
|
|
39148
|
+
}
|
|
39149
|
+
],
|
|
39150
|
+
outputs: [],
|
|
39151
|
+
state_mutability: "external"
|
|
39152
|
+
},
|
|
39153
|
+
{
|
|
39154
|
+
type: "function",
|
|
39155
|
+
name: "approve",
|
|
39156
|
+
inputs: [
|
|
39157
|
+
{
|
|
39158
|
+
name: "to",
|
|
39159
|
+
type: "core::starknet::contract_address::ContractAddress"
|
|
39160
|
+
},
|
|
39161
|
+
{
|
|
39162
|
+
name: "token_id",
|
|
39163
|
+
type: "core::integer::u256"
|
|
39164
|
+
}
|
|
39165
|
+
],
|
|
39166
|
+
outputs: [],
|
|
39167
|
+
state_mutability: "external"
|
|
39168
|
+
},
|
|
39169
|
+
{
|
|
39170
|
+
type: "function",
|
|
39171
|
+
name: "set_approval_for_all",
|
|
39172
|
+
inputs: [
|
|
39173
|
+
{
|
|
39174
|
+
name: "operator",
|
|
39175
|
+
type: "core::starknet::contract_address::ContractAddress"
|
|
39176
|
+
},
|
|
39177
|
+
{
|
|
39178
|
+
name: "approved",
|
|
39179
|
+
type: "core::bool"
|
|
39180
|
+
}
|
|
39181
|
+
],
|
|
39182
|
+
outputs: [],
|
|
39183
|
+
state_mutability: "external"
|
|
39184
|
+
},
|
|
39185
|
+
{
|
|
39186
|
+
type: "function",
|
|
39187
|
+
name: "get_approved",
|
|
39188
|
+
inputs: [
|
|
39189
|
+
{
|
|
39190
|
+
name: "token_id",
|
|
39191
|
+
type: "core::integer::u256"
|
|
39192
|
+
}
|
|
39193
|
+
],
|
|
39194
|
+
outputs: [
|
|
39195
|
+
{
|
|
39196
|
+
type: "core::starknet::contract_address::ContractAddress"
|
|
39197
|
+
}
|
|
39198
|
+
],
|
|
39199
|
+
state_mutability: "view"
|
|
39200
|
+
},
|
|
39201
|
+
{
|
|
39202
|
+
type: "function",
|
|
39203
|
+
name: "is_approved_for_all",
|
|
39204
|
+
inputs: [
|
|
39205
|
+
{
|
|
39206
|
+
name: "owner",
|
|
39207
|
+
type: "core::starknet::contract_address::ContractAddress"
|
|
39208
|
+
},
|
|
39209
|
+
{
|
|
39210
|
+
name: "operator",
|
|
39211
|
+
type: "core::starknet::contract_address::ContractAddress"
|
|
39212
|
+
}
|
|
39213
|
+
],
|
|
39214
|
+
outputs: [
|
|
39215
|
+
{
|
|
39216
|
+
type: "core::bool"
|
|
39217
|
+
}
|
|
39218
|
+
],
|
|
39219
|
+
state_mutability: "view"
|
|
39220
|
+
},
|
|
39221
|
+
{
|
|
39222
|
+
type: "function",
|
|
39223
|
+
name: "supports_interface",
|
|
39224
|
+
inputs: [
|
|
39225
|
+
{
|
|
39226
|
+
name: "interface_id",
|
|
39227
|
+
type: "core::felt252"
|
|
39228
|
+
}
|
|
39229
|
+
],
|
|
39230
|
+
outputs: [
|
|
39231
|
+
{
|
|
39232
|
+
type: "core::bool"
|
|
39233
|
+
}
|
|
39234
|
+
],
|
|
39235
|
+
state_mutability: "view"
|
|
39236
|
+
},
|
|
39237
|
+
{
|
|
39238
|
+
type: "function",
|
|
39239
|
+
name: "name",
|
|
39240
|
+
inputs: [],
|
|
39241
|
+
outputs: [
|
|
39242
|
+
{
|
|
39243
|
+
type: "core::byte_array::ByteArray"
|
|
39244
|
+
}
|
|
39245
|
+
],
|
|
39246
|
+
state_mutability: "view"
|
|
39247
|
+
},
|
|
39248
|
+
{
|
|
39249
|
+
type: "function",
|
|
39250
|
+
name: "symbol",
|
|
39251
|
+
inputs: [],
|
|
39252
|
+
outputs: [
|
|
39253
|
+
{
|
|
39254
|
+
type: "core::byte_array::ByteArray"
|
|
39255
|
+
}
|
|
39256
|
+
],
|
|
39257
|
+
state_mutability: "view"
|
|
39258
|
+
},
|
|
39259
|
+
{
|
|
39260
|
+
type: "function",
|
|
39261
|
+
name: "token_uri",
|
|
39262
|
+
inputs: [
|
|
39263
|
+
{
|
|
39264
|
+
name: "token_id",
|
|
39265
|
+
type: "core::integer::u256"
|
|
39266
|
+
}
|
|
39267
|
+
],
|
|
39268
|
+
outputs: [
|
|
39269
|
+
{
|
|
39270
|
+
type: "core::byte_array::ByteArray"
|
|
39271
|
+
}
|
|
39272
|
+
],
|
|
39273
|
+
state_mutability: "view"
|
|
39274
|
+
},
|
|
39275
|
+
{
|
|
39276
|
+
type: "function",
|
|
39277
|
+
name: "balanceOf",
|
|
39278
|
+
inputs: [
|
|
39279
|
+
{
|
|
39280
|
+
name: "account",
|
|
39281
|
+
type: "core::starknet::contract_address::ContractAddress"
|
|
39282
|
+
}
|
|
39283
|
+
],
|
|
39284
|
+
outputs: [
|
|
39285
|
+
{
|
|
39286
|
+
type: "core::integer::u256"
|
|
39287
|
+
}
|
|
39288
|
+
],
|
|
39289
|
+
state_mutability: "view"
|
|
39290
|
+
},
|
|
39291
|
+
{
|
|
39292
|
+
type: "function",
|
|
39293
|
+
name: "ownerOf",
|
|
39294
|
+
inputs: [
|
|
39295
|
+
{
|
|
39296
|
+
name: "tokenId",
|
|
39297
|
+
type: "core::integer::u256"
|
|
39298
|
+
}
|
|
39299
|
+
],
|
|
39300
|
+
outputs: [
|
|
39301
|
+
{
|
|
39302
|
+
type: "core::starknet::contract_address::ContractAddress"
|
|
39303
|
+
}
|
|
39304
|
+
],
|
|
39305
|
+
state_mutability: "view"
|
|
39306
|
+
},
|
|
39307
|
+
{
|
|
39308
|
+
type: "function",
|
|
39309
|
+
name: "safeTransferFrom",
|
|
39310
|
+
inputs: [
|
|
39311
|
+
{
|
|
39312
|
+
name: "from",
|
|
39313
|
+
type: "core::starknet::contract_address::ContractAddress"
|
|
39314
|
+
},
|
|
39315
|
+
{
|
|
39316
|
+
name: "to",
|
|
39317
|
+
type: "core::starknet::contract_address::ContractAddress"
|
|
39318
|
+
},
|
|
39319
|
+
{
|
|
39320
|
+
name: "tokenId",
|
|
39321
|
+
type: "core::integer::u256"
|
|
39322
|
+
},
|
|
39323
|
+
{
|
|
39324
|
+
name: "data",
|
|
39325
|
+
type: "core::array::Span::<core::felt252>"
|
|
39326
|
+
}
|
|
39327
|
+
],
|
|
39328
|
+
outputs: [],
|
|
39329
|
+
state_mutability: "external"
|
|
39330
|
+
},
|
|
39331
|
+
{
|
|
39332
|
+
type: "function",
|
|
39333
|
+
name: "transferFrom",
|
|
39334
|
+
inputs: [
|
|
39335
|
+
{
|
|
39336
|
+
name: "from",
|
|
39337
|
+
type: "core::starknet::contract_address::ContractAddress"
|
|
39338
|
+
},
|
|
39339
|
+
{
|
|
39340
|
+
name: "to",
|
|
39341
|
+
type: "core::starknet::contract_address::ContractAddress"
|
|
39342
|
+
},
|
|
39343
|
+
{
|
|
39344
|
+
name: "tokenId",
|
|
39345
|
+
type: "core::integer::u256"
|
|
39346
|
+
}
|
|
39347
|
+
],
|
|
39348
|
+
outputs: [],
|
|
39349
|
+
state_mutability: "external"
|
|
39350
|
+
},
|
|
39351
|
+
{
|
|
39352
|
+
type: "function",
|
|
39353
|
+
name: "setApprovalForAll",
|
|
39354
|
+
inputs: [
|
|
39355
|
+
{
|
|
39356
|
+
name: "operator",
|
|
39357
|
+
type: "core::starknet::contract_address::ContractAddress"
|
|
39358
|
+
},
|
|
39359
|
+
{
|
|
39360
|
+
name: "approved",
|
|
39361
|
+
type: "core::bool"
|
|
39362
|
+
}
|
|
39363
|
+
],
|
|
39364
|
+
outputs: [],
|
|
39365
|
+
state_mutability: "external"
|
|
39366
|
+
},
|
|
39367
|
+
{
|
|
39368
|
+
type: "function",
|
|
39369
|
+
name: "getApproved",
|
|
39370
|
+
inputs: [
|
|
39371
|
+
{
|
|
39372
|
+
name: "tokenId",
|
|
39373
|
+
type: "core::integer::u256"
|
|
39374
|
+
}
|
|
39375
|
+
],
|
|
39376
|
+
outputs: [
|
|
39377
|
+
{
|
|
39378
|
+
type: "core::starknet::contract_address::ContractAddress"
|
|
39379
|
+
}
|
|
39380
|
+
],
|
|
39381
|
+
state_mutability: "view"
|
|
39382
|
+
},
|
|
39383
|
+
{
|
|
39384
|
+
type: "function",
|
|
39385
|
+
name: "isApprovedForAll",
|
|
39386
|
+
inputs: [
|
|
39387
|
+
{
|
|
39388
|
+
name: "owner",
|
|
39389
|
+
type: "core::starknet::contract_address::ContractAddress"
|
|
39390
|
+
},
|
|
39391
|
+
{
|
|
39392
|
+
name: "operator",
|
|
39393
|
+
type: "core::starknet::contract_address::ContractAddress"
|
|
39394
|
+
}
|
|
39395
|
+
],
|
|
39396
|
+
outputs: [
|
|
39397
|
+
{
|
|
39398
|
+
type: "core::bool"
|
|
39399
|
+
}
|
|
39400
|
+
],
|
|
39401
|
+
state_mutability: "view"
|
|
39402
|
+
},
|
|
39403
|
+
{
|
|
39404
|
+
type: "function",
|
|
39405
|
+
name: "tokenURI",
|
|
39406
|
+
inputs: [
|
|
39407
|
+
{
|
|
39408
|
+
name: "tokenId",
|
|
39409
|
+
type: "core::integer::u256"
|
|
39410
|
+
}
|
|
39411
|
+
],
|
|
39412
|
+
outputs: [
|
|
39413
|
+
{
|
|
39414
|
+
type: "core::byte_array::ByteArray"
|
|
39415
|
+
}
|
|
39416
|
+
],
|
|
39417
|
+
state_mutability: "view"
|
|
39418
|
+
}
|
|
39419
|
+
]
|
|
39420
|
+
},
|
|
39421
|
+
{
|
|
39422
|
+
type: "impl",
|
|
39423
|
+
name: "ERC721EnumerableImpl",
|
|
39424
|
+
interface_name: "openzeppelin_interfaces::token::erc721::IERC721Enumerable"
|
|
39425
|
+
},
|
|
39426
|
+
{
|
|
39427
|
+
type: "interface",
|
|
39428
|
+
name: "openzeppelin_interfaces::token::erc721::IERC721Enumerable",
|
|
39429
|
+
items: [
|
|
39430
|
+
{
|
|
39431
|
+
type: "function",
|
|
39432
|
+
name: "total_supply",
|
|
39433
|
+
inputs: [],
|
|
39434
|
+
outputs: [
|
|
39435
|
+
{
|
|
39436
|
+
type: "core::integer::u256"
|
|
39437
|
+
}
|
|
39438
|
+
],
|
|
39439
|
+
state_mutability: "view"
|
|
39440
|
+
},
|
|
39441
|
+
{
|
|
39442
|
+
type: "function",
|
|
39443
|
+
name: "token_by_index",
|
|
39444
|
+
inputs: [
|
|
39445
|
+
{
|
|
39446
|
+
name: "index",
|
|
39447
|
+
type: "core::integer::u256"
|
|
39448
|
+
}
|
|
39449
|
+
],
|
|
39450
|
+
outputs: [
|
|
39451
|
+
{
|
|
39452
|
+
type: "core::integer::u256"
|
|
39453
|
+
}
|
|
39454
|
+
],
|
|
39455
|
+
state_mutability: "view"
|
|
39456
|
+
},
|
|
39457
|
+
{
|
|
39458
|
+
type: "function",
|
|
39459
|
+
name: "token_of_owner_by_index",
|
|
39460
|
+
inputs: [
|
|
39461
|
+
{
|
|
39462
|
+
name: "owner",
|
|
39463
|
+
type: "core::starknet::contract_address::ContractAddress"
|
|
39464
|
+
},
|
|
39465
|
+
{
|
|
39466
|
+
name: "index",
|
|
39467
|
+
type: "core::integer::u256"
|
|
39468
|
+
}
|
|
39469
|
+
],
|
|
39470
|
+
outputs: [
|
|
39471
|
+
{
|
|
39472
|
+
type: "core::integer::u256"
|
|
39473
|
+
}
|
|
39474
|
+
],
|
|
39475
|
+
state_mutability: "view"
|
|
39476
|
+
}
|
|
39477
|
+
]
|
|
39478
|
+
},
|
|
39479
|
+
{
|
|
39480
|
+
type: "constructor",
|
|
39481
|
+
name: "constructor",
|
|
39482
|
+
inputs: [
|
|
39483
|
+
{
|
|
39484
|
+
name: "owner",
|
|
39485
|
+
type: "core::starknet::contract_address::ContractAddress"
|
|
39486
|
+
},
|
|
39487
|
+
{
|
|
39488
|
+
name: "vault",
|
|
39489
|
+
type: "core::starknet::contract_address::ContractAddress"
|
|
39490
|
+
}
|
|
39491
|
+
]
|
|
39492
|
+
},
|
|
39493
|
+
{
|
|
39494
|
+
type: "event",
|
|
39495
|
+
name: "openzeppelin_token::erc721::erc721::ERC721Component::Transfer",
|
|
39496
|
+
kind: "struct",
|
|
39497
|
+
members: [
|
|
39498
|
+
{
|
|
39499
|
+
name: "from",
|
|
39500
|
+
type: "core::starknet::contract_address::ContractAddress",
|
|
39501
|
+
kind: "key"
|
|
39502
|
+
},
|
|
39503
|
+
{
|
|
39504
|
+
name: "to",
|
|
39505
|
+
type: "core::starknet::contract_address::ContractAddress",
|
|
39506
|
+
kind: "key"
|
|
39507
|
+
},
|
|
39508
|
+
{
|
|
39509
|
+
name: "token_id",
|
|
39510
|
+
type: "core::integer::u256",
|
|
39511
|
+
kind: "key"
|
|
39512
|
+
}
|
|
39513
|
+
]
|
|
39514
|
+
},
|
|
39515
|
+
{
|
|
39516
|
+
type: "event",
|
|
39517
|
+
name: "openzeppelin_token::erc721::erc721::ERC721Component::Approval",
|
|
39518
|
+
kind: "struct",
|
|
39519
|
+
members: [
|
|
39520
|
+
{
|
|
39521
|
+
name: "owner",
|
|
39522
|
+
type: "core::starknet::contract_address::ContractAddress",
|
|
39523
|
+
kind: "key"
|
|
39524
|
+
},
|
|
39525
|
+
{
|
|
39526
|
+
name: "approved",
|
|
39527
|
+
type: "core::starknet::contract_address::ContractAddress",
|
|
39528
|
+
kind: "key"
|
|
39529
|
+
},
|
|
39530
|
+
{
|
|
39531
|
+
name: "token_id",
|
|
39532
|
+
type: "core::integer::u256",
|
|
39533
|
+
kind: "key"
|
|
39534
|
+
}
|
|
39535
|
+
]
|
|
39536
|
+
},
|
|
39537
|
+
{
|
|
39538
|
+
type: "event",
|
|
39539
|
+
name: "openzeppelin_token::erc721::erc721::ERC721Component::ApprovalForAll",
|
|
39540
|
+
kind: "struct",
|
|
39541
|
+
members: [
|
|
39542
|
+
{
|
|
39543
|
+
name: "owner",
|
|
39544
|
+
type: "core::starknet::contract_address::ContractAddress",
|
|
39545
|
+
kind: "key"
|
|
39546
|
+
},
|
|
39547
|
+
{
|
|
39548
|
+
name: "operator",
|
|
39549
|
+
type: "core::starknet::contract_address::ContractAddress",
|
|
39550
|
+
kind: "key"
|
|
39551
|
+
},
|
|
39552
|
+
{
|
|
39553
|
+
name: "approved",
|
|
39554
|
+
type: "core::bool",
|
|
39555
|
+
kind: "data"
|
|
39556
|
+
}
|
|
39557
|
+
]
|
|
39558
|
+
},
|
|
39559
|
+
{
|
|
39560
|
+
type: "event",
|
|
39561
|
+
name: "openzeppelin_token::erc721::erc721::ERC721Component::Event",
|
|
39562
|
+
kind: "enum",
|
|
39563
|
+
variants: [
|
|
39564
|
+
{
|
|
39565
|
+
name: "Transfer",
|
|
39566
|
+
type: "openzeppelin_token::erc721::erc721::ERC721Component::Transfer",
|
|
39567
|
+
kind: "nested"
|
|
39568
|
+
},
|
|
39569
|
+
{
|
|
39570
|
+
name: "Approval",
|
|
39571
|
+
type: "openzeppelin_token::erc721::erc721::ERC721Component::Approval",
|
|
39572
|
+
kind: "nested"
|
|
39573
|
+
},
|
|
39574
|
+
{
|
|
39575
|
+
name: "ApprovalForAll",
|
|
39576
|
+
type: "openzeppelin_token::erc721::erc721::ERC721Component::ApprovalForAll",
|
|
39577
|
+
kind: "nested"
|
|
39578
|
+
}
|
|
39579
|
+
]
|
|
39580
|
+
},
|
|
39581
|
+
{
|
|
39582
|
+
type: "event",
|
|
39583
|
+
name: "openzeppelin_token::erc721::extensions::erc721_enumerable::erc721_enumerable::ERC721EnumerableComponent::Event",
|
|
39584
|
+
kind: "enum",
|
|
39585
|
+
variants: []
|
|
39586
|
+
},
|
|
39587
|
+
{
|
|
39588
|
+
type: "event",
|
|
39589
|
+
name: "openzeppelin_introspection::src5::SRC5Component::Event",
|
|
39590
|
+
kind: "enum",
|
|
39591
|
+
variants: []
|
|
39592
|
+
},
|
|
39593
|
+
{
|
|
39594
|
+
type: "event",
|
|
39595
|
+
name: "openzeppelin_upgrades::upgradeable::UpgradeableComponent::Upgraded",
|
|
39596
|
+
kind: "struct",
|
|
39597
|
+
members: [
|
|
39598
|
+
{
|
|
39599
|
+
name: "class_hash",
|
|
39600
|
+
type: "core::starknet::class_hash::ClassHash",
|
|
39601
|
+
kind: "data"
|
|
39602
|
+
}
|
|
39603
|
+
]
|
|
39604
|
+
},
|
|
39605
|
+
{
|
|
39606
|
+
type: "event",
|
|
39607
|
+
name: "openzeppelin_upgrades::upgradeable::UpgradeableComponent::Event",
|
|
39608
|
+
kind: "enum",
|
|
39609
|
+
variants: [
|
|
39610
|
+
{
|
|
39611
|
+
name: "Upgraded",
|
|
39612
|
+
type: "openzeppelin_upgrades::upgradeable::UpgradeableComponent::Upgraded",
|
|
39613
|
+
kind: "nested"
|
|
39614
|
+
}
|
|
39615
|
+
]
|
|
39616
|
+
},
|
|
39617
|
+
{
|
|
39618
|
+
type: "event",
|
|
39619
|
+
name: "vault::redeem_request::redeem_request::RedeemRequest::Event",
|
|
39620
|
+
kind: "enum",
|
|
39621
|
+
variants: [
|
|
39622
|
+
{
|
|
39623
|
+
name: "ERC721Event",
|
|
39624
|
+
type: "openzeppelin_token::erc721::erc721::ERC721Component::Event",
|
|
39625
|
+
kind: "flat"
|
|
39626
|
+
},
|
|
39627
|
+
{
|
|
39628
|
+
name: "ERC721EnumerableEvent",
|
|
39629
|
+
type: "openzeppelin_token::erc721::extensions::erc721_enumerable::erc721_enumerable::ERC721EnumerableComponent::Event",
|
|
39630
|
+
kind: "flat"
|
|
39631
|
+
},
|
|
39632
|
+
{
|
|
39633
|
+
name: "SRC5Event",
|
|
39634
|
+
type: "openzeppelin_introspection::src5::SRC5Component::Event",
|
|
39635
|
+
kind: "flat"
|
|
39636
|
+
},
|
|
39637
|
+
{
|
|
39638
|
+
name: "UpgradeableEvent",
|
|
39639
|
+
type: "openzeppelin_upgrades::upgradeable::UpgradeableComponent::Event",
|
|
39640
|
+
kind: "flat"
|
|
39641
|
+
}
|
|
39642
|
+
]
|
|
39643
|
+
}
|
|
39644
|
+
];
|
|
39645
|
+
|
|
39646
|
+
// src/strategies/universal-adapters/svk-troves-adapter.ts
|
|
39647
|
+
var DEFAULT_TROVES_STRATEGIES_API = "https://app.troves.fi/api/strategies";
|
|
39648
|
+
function parseTrovesApyField(raw) {
|
|
39649
|
+
if (typeof raw === "number" && Number.isFinite(raw)) {
|
|
39650
|
+
return raw;
|
|
39651
|
+
}
|
|
39652
|
+
if (typeof raw === "string") {
|
|
39653
|
+
const n = Number.parseFloat(raw);
|
|
39654
|
+
if (Number.isFinite(n)) {
|
|
39655
|
+
return n;
|
|
39656
|
+
}
|
|
39657
|
+
}
|
|
39658
|
+
return 0;
|
|
39659
|
+
}
|
|
39660
|
+
var SvkTrovesAdapter = class _SvkTrovesAdapter extends BaseAdapter {
|
|
39661
|
+
constructor(config) {
|
|
39662
|
+
super(config, _SvkTrovesAdapter.name, Protocols.TROVES);
|
|
39663
|
+
this.config = config;
|
|
39664
|
+
}
|
|
39665
|
+
/** Owner used for share balance + `due_assets_from_owner`. */
|
|
39666
|
+
_positionOwner() {
|
|
39667
|
+
return this.config.positionOwner ?? this.config.vaultAllocator;
|
|
39668
|
+
}
|
|
39669
|
+
/**
|
|
39670
|
+
* Proof readable IDs must stay ≤ 31 chars (Cairo short string). We derive a short ASCII suffix from
|
|
39671
|
+
* `strategyVault` address so multiple SVK adapters in one tree stay distinct.
|
|
39672
|
+
*/
|
|
39673
|
+
_proofSuffix() {
|
|
39674
|
+
return this.config.strategyVault.address.replace(/^0x/, "").slice(-6);
|
|
39675
|
+
}
|
|
39676
|
+
_depositApproveProofReadableId() {
|
|
39677
|
+
return `appr_dep_svk_${this._proofSuffix()}`;
|
|
39678
|
+
}
|
|
39679
|
+
_depositCallProofReadableId() {
|
|
39680
|
+
return `dep_svk_${this._proofSuffix()}`;
|
|
39681
|
+
}
|
|
39682
|
+
_withdrawCallProofReadableId() {
|
|
39683
|
+
return `wtdrw_svk_${this._proofSuffix()}`;
|
|
39684
|
+
}
|
|
39685
|
+
async getAPY(supportedPosition) {
|
|
39686
|
+
const CACHE_KEY = `svk_apy_${this.config.trovesStrategyId}`;
|
|
39687
|
+
const cached = this.getCache(CACHE_KEY);
|
|
39688
|
+
if (cached) {
|
|
39689
|
+
return cached;
|
|
39690
|
+
}
|
|
39691
|
+
const url = this.config.trovesStrategiesApiUrl ?? DEFAULT_TROVES_STRATEGIES_API;
|
|
39692
|
+
try {
|
|
39693
|
+
const res = await fetch(url);
|
|
39694
|
+
if (!res.ok) {
|
|
39695
|
+
logger.warn(`${_SvkTrovesAdapter.name}::getAPY: HTTP ${res.status} from ${url}`);
|
|
39696
|
+
const fallback = { apy: 0, type: "base" /* BASE */ };
|
|
39697
|
+
this.setCache(CACHE_KEY, fallback, 3e5);
|
|
39698
|
+
return fallback;
|
|
39699
|
+
}
|
|
39700
|
+
const body = await res.json();
|
|
39701
|
+
const row = body.strategies?.find((s) => s.id === this.config.trovesStrategyId);
|
|
39702
|
+
if (!row) {
|
|
39703
|
+
logger.warn(
|
|
39704
|
+
`${_SvkTrovesAdapter.name}::getAPY: strategy id not found: ${this.config.trovesStrategyId}`
|
|
39705
|
+
);
|
|
39706
|
+
const fallback = { apy: 0, type: "base" /* BASE */ };
|
|
39707
|
+
this.setCache(CACHE_KEY, fallback, 3e5);
|
|
39708
|
+
return fallback;
|
|
39709
|
+
}
|
|
39710
|
+
const apy = parseTrovesApyField(row.apy);
|
|
39711
|
+
const result = { apy, type: "base" /* BASE */ };
|
|
39712
|
+
this.setCache(CACHE_KEY, result, 3e5);
|
|
39713
|
+
return result;
|
|
39714
|
+
} catch (error) {
|
|
39715
|
+
logger.error(`${_SvkTrovesAdapter.name}::getAPY:`, error);
|
|
39716
|
+
throw error;
|
|
39717
|
+
}
|
|
39718
|
+
}
|
|
39719
|
+
async getPosition(supportedPosition) {
|
|
39720
|
+
const CACHE_KEY = `svk_pos_${this.config.strategyVault.address}_${this._positionOwner().address}`;
|
|
39721
|
+
const cached = this.getCache(CACHE_KEY);
|
|
39722
|
+
if (cached) {
|
|
39723
|
+
return cached;
|
|
39724
|
+
}
|
|
39725
|
+
try {
|
|
39726
|
+
const vault = new Contract14({
|
|
39727
|
+
abi: universal_vault_abi_default,
|
|
39728
|
+
address: this.config.strategyVault.address,
|
|
39729
|
+
providerOrAccount: this.config.networkConfig.provider
|
|
39730
|
+
});
|
|
39731
|
+
const owner = this._positionOwner();
|
|
39732
|
+
const decimals = supportedPosition.asset.decimals;
|
|
39733
|
+
const shares = await vault.balance_of(owner.address);
|
|
39734
|
+
const shareU256 = uint25619.bnToUint256(shares);
|
|
39735
|
+
const liquidAssetsRaw = await vault.convert_to_assets(shareU256);
|
|
39736
|
+
const liquid = Web3Number.fromWei(liquidAssetsRaw.toString(), decimals);
|
|
39737
|
+
let pending = Web3Number.fromWei("0", decimals);
|
|
39738
|
+
try {
|
|
39739
|
+
const dueRaw = await vault.call("due_assets_from_owner", [owner.address]);
|
|
39740
|
+
pending = Web3Number.fromWei(dueRaw.toString(), decimals);
|
|
39741
|
+
} catch (e) {
|
|
39742
|
+
logger.warn(
|
|
39743
|
+
`${_SvkTrovesAdapter.name}::getPosition: due_assets_from_owner failed (treating as 0): ${e.message}`
|
|
39744
|
+
);
|
|
39745
|
+
}
|
|
39746
|
+
const total = liquid.plus(pending);
|
|
39747
|
+
const remarks = `Troves ${this.config.trovesStrategyId} holdings`;
|
|
39748
|
+
const result = {
|
|
39749
|
+
amount: total,
|
|
39750
|
+
remarks
|
|
39751
|
+
};
|
|
39752
|
+
this.setCache(CACHE_KEY, result, 6e4);
|
|
39753
|
+
return result;
|
|
39754
|
+
} catch (error) {
|
|
39755
|
+
logger.error(`${_SvkTrovesAdapter.name}::getPosition:`, error);
|
|
39756
|
+
throw error;
|
|
39757
|
+
}
|
|
39758
|
+
}
|
|
39759
|
+
async getPendingAssetsFromOwner(owner = this._positionOwner(), decimals = this.config.baseToken.decimals) {
|
|
39760
|
+
const vault = new Contract14({
|
|
39761
|
+
abi: universal_vault_abi_default,
|
|
39762
|
+
address: this.config.strategyVault.address,
|
|
39763
|
+
providerOrAccount: this.config.networkConfig.provider
|
|
39764
|
+
});
|
|
39765
|
+
try {
|
|
39766
|
+
const dueRaw = await vault.call("due_assets_from_owner", [owner.address]);
|
|
39767
|
+
return Web3Number.fromWei(dueRaw.toString(), decimals);
|
|
39768
|
+
} catch (e) {
|
|
39769
|
+
logger.warn(
|
|
39770
|
+
`${_SvkTrovesAdapter.name}::getPendingAssetsFromOwner: due_assets_from_owner failed (treating as 0): ${e.message}`
|
|
39771
|
+
);
|
|
39772
|
+
return Web3Number.fromWei("0", decimals);
|
|
39773
|
+
}
|
|
39774
|
+
}
|
|
39775
|
+
/**
|
|
39776
|
+
* Get pending assets from owner by scanning redeem request NFTs.
|
|
39777
|
+
* This method iterates backwards through NFT IDs to find all pending redemptions for a specific owner.
|
|
39778
|
+
*
|
|
39779
|
+
* @param redeemRequestNFT - The redeem request NFT contract address
|
|
39780
|
+
* @param owner - The owner address to check for pending redemptions (defaults to positionOwner)
|
|
39781
|
+
* @param decimals - Token decimals for conversion (defaults to baseToken decimals)
|
|
39782
|
+
* @returns Total pending assets from all NFTs owned by the specified address
|
|
39783
|
+
*/
|
|
39784
|
+
async getPendingAssetsFromOwnerNFTMethod(redeemRequestNFT, owner = this._positionOwner(), decimals = this.config.baseToken.decimals) {
|
|
39785
|
+
try {
|
|
39786
|
+
const nftContract = new Contract14({
|
|
39787
|
+
abi: redeem_request_nft_abi_default,
|
|
39788
|
+
address: redeemRequestNFT.address,
|
|
39789
|
+
providerOrAccount: this.config.networkConfig.provider
|
|
39790
|
+
});
|
|
39791
|
+
const idLenRaw = await nftContract.id_len();
|
|
39792
|
+
const latestId = BigInt(idLenRaw.toString());
|
|
39793
|
+
if (latestId === 0n) {
|
|
39794
|
+
logger.info(
|
|
39795
|
+
`${_SvkTrovesAdapter.name}::getPendingAssetsFromOwnerNFTMethod: No NFTs minted yet`
|
|
38945
39796
|
);
|
|
39797
|
+
return Web3Number.fromWei("0", decimals);
|
|
38946
39798
|
}
|
|
38947
|
-
const
|
|
38948
|
-
|
|
38949
|
-
|
|
38950
|
-
|
|
38951
|
-
|
|
38952
|
-
|
|
38953
|
-
|
|
38954
|
-
|
|
39799
|
+
const matchingIds = [];
|
|
39800
|
+
let currentId = latestId - 1n;
|
|
39801
|
+
while (currentId >= 0n) {
|
|
39802
|
+
try {
|
|
39803
|
+
const idU256 = uint25619.bnToUint256(currentId);
|
|
39804
|
+
const ownerRaw = await nftContract.owner_of(idU256);
|
|
39805
|
+
const nftOwnerAddr = ContractAddr.from(ownerRaw.toString());
|
|
39806
|
+
if (nftOwnerAddr.eq(owner)) {
|
|
39807
|
+
matchingIds.push(currentId);
|
|
39808
|
+
logger.debug(
|
|
39809
|
+
`${_SvkTrovesAdapter.name}::getPendingAssetsFromOwnerNFTMethod: Found matching NFT ID ${currentId} for owner ${owner.address}`
|
|
39810
|
+
);
|
|
39811
|
+
}
|
|
39812
|
+
currentId--;
|
|
39813
|
+
} catch (e) {
|
|
39814
|
+
logger.info(
|
|
39815
|
+
`${_SvkTrovesAdapter.name}::getPendingAssetsFromOwnerNFTMethod: Reached last pending NFT at id ${currentId}`
|
|
39816
|
+
);
|
|
39817
|
+
break;
|
|
39818
|
+
}
|
|
39819
|
+
}
|
|
39820
|
+
if (matchingIds.length === 0) {
|
|
39821
|
+
logger.info(
|
|
39822
|
+
`${_SvkTrovesAdapter.name}::getPendingAssetsFromOwnerNFTMethod: No matching NFTs found for owner ${owner.address}`
|
|
39823
|
+
);
|
|
39824
|
+
return Web3Number.fromWei("0", decimals);
|
|
39825
|
+
}
|
|
39826
|
+
let totalNominal = 0n;
|
|
39827
|
+
for (const nftId of matchingIds) {
|
|
39828
|
+
try {
|
|
39829
|
+
const idU256 = uint25619.bnToUint256(nftId);
|
|
39830
|
+
const infoRaw = await nftContract.id_to_info(idU256);
|
|
39831
|
+
const nominal = BigInt(infoRaw.nominal.toString());
|
|
39832
|
+
totalNominal += nominal;
|
|
39833
|
+
logger.debug(
|
|
39834
|
+
`${_SvkTrovesAdapter.name}::getPendingAssetsFromOwnerNFTMethod: NFT ID ${nftId} has nominal ${nominal}`
|
|
39835
|
+
);
|
|
39836
|
+
} catch (e) {
|
|
39837
|
+
logger.warn(
|
|
39838
|
+
`${_SvkTrovesAdapter.name}::getPendingAssetsFromOwnerNFTMethod: Failed to get info for NFT ID ${nftId}: ${e.message}`
|
|
39839
|
+
);
|
|
39840
|
+
}
|
|
39841
|
+
}
|
|
39842
|
+
logger.info(
|
|
39843
|
+
`${_SvkTrovesAdapter.name}::getPendingAssetsFromOwnerNFTMethod: Found ${matchingIds.length} NFTs with total nominal ${totalNominal}`
|
|
39844
|
+
);
|
|
39845
|
+
return Web3Number.fromWei(totalNominal.toString(), decimals);
|
|
38955
39846
|
} catch (error) {
|
|
38956
|
-
logger.error(
|
|
38957
|
-
|
|
39847
|
+
logger.error(
|
|
39848
|
+
`${_SvkTrovesAdapter.name}::getPendingAssetsFromOwnerNFTMethod: ${error.message}`
|
|
39849
|
+
);
|
|
39850
|
+
return Web3Number.fromWei("0", decimals);
|
|
38958
39851
|
}
|
|
38959
39852
|
}
|
|
38960
39853
|
async maxDeposit(amount) {
|
|
@@ -39021,9 +39914,9 @@ var SvkTrovesAdapter = class _SvkTrovesAdapter extends BaseAdapter {
|
|
|
39021
39914
|
return [
|
|
39022
39915
|
{
|
|
39023
39916
|
target: strategyVault,
|
|
39024
|
-
method: "
|
|
39917
|
+
method: "request_redeem",
|
|
39025
39918
|
packedArguments: [recv.toBigInt(), owner.toBigInt()],
|
|
39026
|
-
sanitizer:
|
|
39919
|
+
sanitizer: SVK_SIMPLE_SANITIZER,
|
|
39027
39920
|
id: this._withdrawCallProofReadableId()
|
|
39028
39921
|
}
|
|
39029
39922
|
];
|
|
@@ -39085,16 +39978,23 @@ var SvkTrovesAdapter = class _SvkTrovesAdapter extends BaseAdapter {
|
|
|
39085
39978
|
const uint256Amount = uint25619.bnToUint256(amount.toWei());
|
|
39086
39979
|
const recv = this.config.vaultAllocator;
|
|
39087
39980
|
const owner = this.config.vaultAllocator;
|
|
39981
|
+
const vault = new Contract14({
|
|
39982
|
+
abi: universal_vault_abi_default,
|
|
39983
|
+
address: strategyVault.address,
|
|
39984
|
+
providerOrAccount: this.config.networkConfig.provider
|
|
39985
|
+
});
|
|
39986
|
+
const sharesRaw = await vault.convert_to_shares(uint256Amount);
|
|
39987
|
+
const sharesU256 = uint25619.bnToUint256(sharesRaw.toString());
|
|
39088
39988
|
return [
|
|
39089
39989
|
{
|
|
39090
39990
|
proofReadableId: this._withdrawCallProofReadableId(),
|
|
39091
|
-
sanitizer:
|
|
39991
|
+
sanitizer: SVK_SIMPLE_SANITIZER,
|
|
39092
39992
|
call: {
|
|
39093
39993
|
contractAddress: strategyVault,
|
|
39094
|
-
selector: hash11.getSelectorFromName("
|
|
39994
|
+
selector: hash11.getSelectorFromName("request_redeem"),
|
|
39095
39995
|
calldata: [
|
|
39096
|
-
toBigInt(
|
|
39097
|
-
toBigInt(
|
|
39996
|
+
toBigInt(sharesU256.low.toString()),
|
|
39997
|
+
toBigInt(sharesU256.high.toString()),
|
|
39098
39998
|
recv.toBigInt(),
|
|
39099
39999
|
owner.toBigInt()
|
|
39100
40000
|
]
|
|
@@ -40879,9 +41779,9 @@ var SVKStrategy = class extends BaseStrategy {
|
|
|
40879
41779
|
* Builds a manage call from an adapter's proof tree.
|
|
40880
41780
|
* DRY helper for the repeated getProofs → getManageCall pattern.
|
|
40881
41781
|
*/
|
|
40882
|
-
async buildManageCallFromAdapter(adapter, isDeposit, amount) {
|
|
41782
|
+
async buildManageCallFromAdapter(adapter, isDeposit, amount, additionalParams) {
|
|
40883
41783
|
const proofsInfo = adapter.getProofs(isDeposit, this.getMerkleTree());
|
|
40884
|
-
const manageCalls = await proofsInfo.callConstructor({ amount });
|
|
41784
|
+
const manageCalls = await proofsInfo.callConstructor({ amount, ...additionalParams });
|
|
40885
41785
|
return this.getManageCall(
|
|
40886
41786
|
this.getProofGroupsForManageCalls(manageCalls),
|
|
40887
41787
|
manageCalls
|
|
@@ -41983,95 +42883,615 @@ function createHyperLSTSettings(lstSymbol, underlyingSymbol) {
|
|
|
41983
42883
|
] }),
|
|
41984
42884
|
type: "info"
|
|
41985
42885
|
},
|
|
41986
|
-
{
|
|
41987
|
-
tab: "deposit",
|
|
41988
|
-
text: "It may take up to one week for your deposit to appreciate in value. This delay occurs because the LST price is sourced from DEXes and liquidity is usually rebased once a week.",
|
|
41989
|
-
type: "info"
|
|
41990
|
-
}
|
|
41991
|
-
]
|
|
41992
|
-
};
|
|
41993
|
-
}
|
|
41994
|
-
var HYPER_LST_SECURITY = {
|
|
41995
|
-
auditStatus: "Audited" /* AUDITED */,
|
|
41996
|
-
sourceCode: {
|
|
41997
|
-
type: "Closed Source" /* CLOSED_SOURCE */,
|
|
41998
|
-
contractLink: "https://github.com/trovesfi/troves-contracts"
|
|
41999
|
-
},
|
|
42000
|
-
accessControl: {
|
|
42001
|
-
type: "Standard Account" /* STANDARD_ACCOUNT */,
|
|
42002
|
-
addresses: [ContractAddr.from("0x0")],
|
|
42003
|
-
timeLock: "2 Days"
|
|
42886
|
+
{
|
|
42887
|
+
tab: "deposit",
|
|
42888
|
+
text: "It may take up to one week for your deposit to appreciate in value. This delay occurs because the LST price is sourced from DEXes and liquidity is usually rebased once a week.",
|
|
42889
|
+
type: "info"
|
|
42890
|
+
}
|
|
42891
|
+
]
|
|
42892
|
+
};
|
|
42893
|
+
}
|
|
42894
|
+
var HYPER_LST_SECURITY = {
|
|
42895
|
+
auditStatus: "Audited" /* AUDITED */,
|
|
42896
|
+
sourceCode: {
|
|
42897
|
+
type: "Closed Source" /* CLOSED_SOURCE */,
|
|
42898
|
+
contractLink: "https://github.com/trovesfi/troves-contracts"
|
|
42899
|
+
},
|
|
42900
|
+
accessControl: {
|
|
42901
|
+
type: "Standard Account" /* STANDARD_ACCOUNT */,
|
|
42902
|
+
addresses: [ContractAddr.from("0x0")],
|
|
42903
|
+
timeLock: "2 Days"
|
|
42904
|
+
}
|
|
42905
|
+
};
|
|
42906
|
+
var HYPER_LST_REDEMPTION_INFO = {
|
|
42907
|
+
instantWithdrawalVault: "No" /* NO */,
|
|
42908
|
+
redemptionsInfo: [
|
|
42909
|
+
{
|
|
42910
|
+
title: "Typical Duration",
|
|
42911
|
+
description: "1-2 hours"
|
|
42912
|
+
}
|
|
42913
|
+
],
|
|
42914
|
+
alerts: [
|
|
42915
|
+
{
|
|
42916
|
+
type: "info",
|
|
42917
|
+
text: "In cases of low liquidity, high slippages, the redemptions can take longer time. Redemption times are estimates and may vary based on network conditions and liquidity requirements.",
|
|
42918
|
+
tab: "withdraw"
|
|
42919
|
+
}
|
|
42920
|
+
]
|
|
42921
|
+
};
|
|
42922
|
+
function getStrategySettings(lstSymbol, underlyingSymbol, settings, isPreview = false, isLST) {
|
|
42923
|
+
return {
|
|
42924
|
+
id: `hyper_${lstSymbol.toLowerCase()}`,
|
|
42925
|
+
name: `Hyper ${lstSymbol}`,
|
|
42926
|
+
description: getDescription2(lstSymbol, underlyingSymbol),
|
|
42927
|
+
address: settings.vaultAddress,
|
|
42928
|
+
launchBlock: 0,
|
|
42929
|
+
type: "Other",
|
|
42930
|
+
vaultType: {
|
|
42931
|
+
type: "Looping" /* LOOPING */,
|
|
42932
|
+
description: `Creates leveraged looping position on ${lstSymbol} by borrowing ${underlyingSymbol} to increase yield`
|
|
42933
|
+
},
|
|
42934
|
+
depositTokens: [Global.getDefaultTokens().find((token) => token.symbol === lstSymbol)],
|
|
42935
|
+
additionalInfo: getLooperSettings2(lstSymbol, underlyingSymbol, settings, lstSymbol === "xSTRK" ? VesuPools.Re7xSTRK : VesuPools.Re7xBTC),
|
|
42936
|
+
risk: {
|
|
42937
|
+
riskFactor: _riskFactor4,
|
|
42938
|
+
netRisk: _riskFactor4.reduce((acc, curr) => acc + curr.value * curr.weight, 0) / _riskFactor4.reduce((acc, curr) => acc + curr.weight, 0),
|
|
42939
|
+
notARisks: getNoRiskTags(_riskFactor4)
|
|
42940
|
+
},
|
|
42941
|
+
auditUrl: AUDIT_URL4,
|
|
42942
|
+
protocols: [Protocols.ENDUR, Protocols.VESU],
|
|
42943
|
+
curator: {
|
|
42944
|
+
name: "Unwrap Labs",
|
|
42945
|
+
logo: "https://assets.troves.fi/integrations/unwraplabs/white.png"
|
|
42946
|
+
},
|
|
42947
|
+
settings: createHyperLSTSettings(lstSymbol, underlyingSymbol),
|
|
42948
|
+
contractDetails: getContractDetails(settings),
|
|
42949
|
+
faqs: getFAQs2(lstSymbol, underlyingSymbol, isLST),
|
|
42950
|
+
investmentSteps: getInvestmentSteps(lstSymbol, underlyingSymbol),
|
|
42951
|
+
isPreview,
|
|
42952
|
+
apyMethodology: "Current annualized APY in terms of base asset of the LST. There is no additional fee taken by Troves on LST APY. We charge a 10% performance fee on the additional gain which is already accounted in the APY shown.",
|
|
42953
|
+
realizedAPYMethodology: "The realizedAPY is based on past 14 days performance by the vault",
|
|
42954
|
+
tags: lstSymbol.includes("BTC") ? ["BTC" /* BTC */, "Maxx" /* LEVERED */] : ["Maxx" /* LEVERED */],
|
|
42955
|
+
security: HYPER_LST_SECURITY,
|
|
42956
|
+
redemptionInfo: HYPER_LST_REDEMPTION_INFO,
|
|
42957
|
+
usualTimeToEarnings: "2 weeks",
|
|
42958
|
+
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 hours. This is when you realise your earnings.",
|
|
42959
|
+
points: lstSymbol === "xSTRK" ? [{
|
|
42960
|
+
multiplier: 4,
|
|
42961
|
+
logo: "https://endur.fi/favicon.ico",
|
|
42962
|
+
toolTip: "This strategy holds xSTRK. Earn 3-4x Endur points on your xSTRK due to the leverage. Points can be found on endur.fi."
|
|
42963
|
+
}] : void 0
|
|
42964
|
+
};
|
|
42965
|
+
}
|
|
42966
|
+
var HyperLSTStrategies = [
|
|
42967
|
+
getStrategySettings("xSTRK", "STRK", hyperxSTRK, false, true),
|
|
42968
|
+
getStrategySettings("xWBTC", "WBTC", hyperxWBTC, false, false),
|
|
42969
|
+
getStrategySettings("xtBTC", "tBTC", hyperxtBTC, false, false),
|
|
42970
|
+
getStrategySettings("xsBTC", "solvBTC", hyperxsBTC, false, false),
|
|
42971
|
+
getStrategySettings("xLBTC", "LBTC", hyperxLBTC, false, false),
|
|
42972
|
+
getStrategySettings("mRe7BTC", "mRe7BTC", hypermRe7BTC, false, false),
|
|
42973
|
+
getStrategySettings("mRe7YIELD", "mRe7YIELD", hypermRe7YIELD, false, false)
|
|
42974
|
+
];
|
|
42975
|
+
|
|
42976
|
+
// src/strategies/usdc-boosted-strategy.tsx
|
|
42977
|
+
import { uint256 as uint25623 } from "starknet";
|
|
42978
|
+
var USDCBoostedStrategy = class _USDCBoostedStrategy extends SVKStrategy {
|
|
42979
|
+
constructor(config, pricer, metadata) {
|
|
42980
|
+
super(config, pricer, metadata);
|
|
42981
|
+
this.metadata.additionalInfo.adapters.forEach((adapter) => {
|
|
42982
|
+
adapter.adapter.config.networkConfig = this.config;
|
|
42983
|
+
adapter.adapter.config.pricer = this.pricer;
|
|
42984
|
+
if (adapter.adapter._vesuAdapter) {
|
|
42985
|
+
adapter.adapter._vesuAdapter.networkConfig = this.config;
|
|
42986
|
+
adapter.adapter._vesuAdapter.pricer = this.pricer;
|
|
42987
|
+
}
|
|
42988
|
+
});
|
|
42989
|
+
}
|
|
42990
|
+
getTag() {
|
|
42991
|
+
return `${_USDCBoostedStrategy.name}:${this.metadata.name}`;
|
|
42992
|
+
}
|
|
42993
|
+
getAdapterById(id) {
|
|
42994
|
+
const entry = this.metadata.additionalInfo.adapters.find(
|
|
42995
|
+
(a) => a.id === id
|
|
42996
|
+
);
|
|
42997
|
+
if (!entry) {
|
|
42998
|
+
throw new Error(
|
|
42999
|
+
`${this.getTag()}::getAdapterById: adapter not found for id "${id}"`
|
|
43000
|
+
);
|
|
43001
|
+
}
|
|
43002
|
+
return entry.adapter;
|
|
43003
|
+
}
|
|
43004
|
+
async getVesuModifyPositionCall(params) {
|
|
43005
|
+
logger.verbose(
|
|
43006
|
+
`${this.getTag()}::getVesuModifyPositionCall isDeposit=${params.isDeposit}, amount=${params.leg1DepositAmount}, debtAmount=${params.debtAmount?.toNumber()}`
|
|
43007
|
+
);
|
|
43008
|
+
return this.buildManageCallFromAdapter(
|
|
43009
|
+
this.getAdapterById("vesu_usdc_strk"),
|
|
43010
|
+
params.isDeposit,
|
|
43011
|
+
params.leg1DepositAmount,
|
|
43012
|
+
params.debtAmount ? { debtAmount: params.debtAmount } : void 0
|
|
43013
|
+
);
|
|
43014
|
+
}
|
|
43015
|
+
async getVesuPositions() {
|
|
43016
|
+
const positions = await this.getAdapterById(
|
|
43017
|
+
"vesu_usdc_strk"
|
|
43018
|
+
).getPositions();
|
|
43019
|
+
return positions.map((p) => ({
|
|
43020
|
+
amount: p.amount,
|
|
43021
|
+
usdValue: p.usdValue,
|
|
43022
|
+
remarks: p.remarks ?? "",
|
|
43023
|
+
token: p.tokenInfo,
|
|
43024
|
+
protocol: p.protocol
|
|
43025
|
+
}));
|
|
43026
|
+
}
|
|
43027
|
+
async getVesuHealthFactor(blockNumber = "latest") {
|
|
43028
|
+
const vesuAdapter = this.getAdapterById("vesu_usdc_strk");
|
|
43029
|
+
return await vesuAdapter._vesuAdapter.getHealthFactor(blockNumber);
|
|
43030
|
+
}
|
|
43031
|
+
// TODO: will have to still modify for instant withdrawals as of now
|
|
43032
|
+
async getModifyHyperPositionCall(params) {
|
|
43033
|
+
logger.verbose(
|
|
43034
|
+
`${this.getTag()}::getModifyHyperPositionCall isDeposit=${params.isDeposit}, amount=${params.amount}`
|
|
43035
|
+
);
|
|
43036
|
+
return this.buildManageCallFromAdapter(
|
|
43037
|
+
this.getAdapterById("hyper_xstrk"),
|
|
43038
|
+
params.isDeposit,
|
|
43039
|
+
params.amount
|
|
43040
|
+
);
|
|
43041
|
+
}
|
|
43042
|
+
async getAvnuSwapCall(params) {
|
|
43043
|
+
logger.verbose(
|
|
43044
|
+
`${this.getTag()}::getAvnuSwapCall isDeposit=${params.isDeposit}, amount=${params.amount}`
|
|
43045
|
+
);
|
|
43046
|
+
return this.buildManageCallFromAdapter(
|
|
43047
|
+
this.getAdapterById("avnu_strk_xstrk"),
|
|
43048
|
+
params.isDeposit,
|
|
43049
|
+
params.amount
|
|
43050
|
+
);
|
|
43051
|
+
}
|
|
43052
|
+
/**
|
|
43053
|
+
* Returns the USDC balance sitting idle inside the vault contract itself.
|
|
43054
|
+
* This balance can offset the required liquidity during withdrawal processing.
|
|
43055
|
+
*/
|
|
43056
|
+
async getUnusedBalanceVault() {
|
|
43057
|
+
const collateralToken = this.metadata.additionalInfo.collateralToken;
|
|
43058
|
+
return new ERC20(this.config).balanceOf(
|
|
43059
|
+
collateralToken.address,
|
|
43060
|
+
this.metadata.additionalInfo.vaultAddress,
|
|
43061
|
+
collateralToken.decimals
|
|
43062
|
+
);
|
|
43063
|
+
}
|
|
43064
|
+
/**
|
|
43065
|
+
* Returns the current STRK balance sitting unused in the vault allocator.
|
|
43066
|
+
* This covers STRK from prior borrow cycles that hasn't been swapped yet.
|
|
43067
|
+
*/
|
|
43068
|
+
// Technically we can use this or we can even use the avnu-adapter to get the unused debt
|
|
43069
|
+
async getUnusedDebt() {
|
|
43070
|
+
const debtToken = this.metadata.additionalInfo.debtToken;
|
|
43071
|
+
return new ERC20(this.config).balanceOf(
|
|
43072
|
+
debtToken.address,
|
|
43073
|
+
this.metadata.additionalInfo.vaultAllocator,
|
|
43074
|
+
debtToken.decimals
|
|
43075
|
+
);
|
|
43076
|
+
}
|
|
43077
|
+
/**
|
|
43078
|
+
* Returns the xSTRK balance sitting in the vault allocator.
|
|
43079
|
+
* This is non-zero when the previous cycle's request_redeem on the HyperPosition
|
|
43080
|
+
* has been settled — the redeemed xSTRK lands here and is ready to be swapped.
|
|
43081
|
+
*/
|
|
43082
|
+
async getxSTRKInVault() {
|
|
43083
|
+
const xstrkToken = Global.getDefaultTokens().find(
|
|
43084
|
+
(t) => t.symbol === "xSTRK"
|
|
43085
|
+
);
|
|
43086
|
+
if (!xstrkToken) {
|
|
43087
|
+
throw new Error(`${this.getTag()}:: xSTRK token not found`);
|
|
43088
|
+
}
|
|
43089
|
+
return new ERC20(this.config).balanceOf(
|
|
43090
|
+
xstrkToken.address.address,
|
|
43091
|
+
this.metadata.additionalInfo.vaultAllocator,
|
|
43092
|
+
xstrkToken.decimals
|
|
43093
|
+
);
|
|
43094
|
+
}
|
|
43095
|
+
/**
|
|
43096
|
+
* Simulates depositing `depositAmount` USDC on Vesu and returns the
|
|
43097
|
+
* incremental STRK that would be borrowed. Needed to size the AVNU swap
|
|
43098
|
+
* call that is batched together with the Vesu call in the same transaction.
|
|
43099
|
+
*/
|
|
43100
|
+
async computeVesuDepositBorrowAmount(depositAmount) {
|
|
43101
|
+
return this.getAdapterById(
|
|
43102
|
+
"vesu_usdc_strk"
|
|
43103
|
+
).getExpectedDepositDebtDelta(depositAmount);
|
|
43104
|
+
}
|
|
43105
|
+
async computeVesuWithdrawDebtDelta(withdrawAmount) {
|
|
43106
|
+
return this.getAdapterById(
|
|
43107
|
+
"vesu_usdc_strk"
|
|
43108
|
+
).getExpectedWithdrawDebtDelta(withdrawAmount);
|
|
43109
|
+
}
|
|
43110
|
+
async getPendingHyperAssets() {
|
|
43111
|
+
const xstrkToken = Global.getDefaultTokens().find(
|
|
43112
|
+
(t) => t.symbol === "xSTRK"
|
|
43113
|
+
);
|
|
43114
|
+
const hyperXstrkRedeemNFT = ContractAddr.from(
|
|
43115
|
+
"0x51e40b839dc0c2feca923f863072673b94abfa2483345be3b30b457a90d095"
|
|
43116
|
+
);
|
|
43117
|
+
return this.getAdapterById(
|
|
43118
|
+
"hyper_xstrk"
|
|
43119
|
+
).getPendingAssetsFromOwnerNFTMethod(
|
|
43120
|
+
hyperXstrkRedeemNFT,
|
|
43121
|
+
this.metadata.additionalInfo.vaultAllocator,
|
|
43122
|
+
xstrkToken.decimals
|
|
43123
|
+
);
|
|
43124
|
+
}
|
|
43125
|
+
// TODO: rn we are just making these functions in the strategy itself but
|
|
43126
|
+
// later on we will move them to the SVKStrategy for generalization
|
|
43127
|
+
async getUserTVL(user, blockIdentifier = "latest") {
|
|
43128
|
+
const shares = await this.contract.call("balanceOf", [user.address], {
|
|
43129
|
+
blockIdentifier
|
|
43130
|
+
});
|
|
43131
|
+
const assets = await this.contract.call(
|
|
43132
|
+
"convert_to_assets",
|
|
43133
|
+
[uint25623.bnToUint256(shares)],
|
|
43134
|
+
{ blockIdentifier }
|
|
43135
|
+
);
|
|
43136
|
+
const amount = Web3Number.fromWei(
|
|
43137
|
+
assets.toString(),
|
|
43138
|
+
this.metadata.depositTokens[0].decimals
|
|
43139
|
+
);
|
|
43140
|
+
const blockNumber = typeof blockIdentifier === "number" || typeof blockIdentifier === "bigint" ? Number(blockIdentifier) : void 0;
|
|
43141
|
+
const price = await this.pricer.getPrice(
|
|
43142
|
+
this.metadata.depositTokens[0].symbol,
|
|
43143
|
+
blockNumber
|
|
43144
|
+
);
|
|
43145
|
+
const usdValue = Number(amount.toFixed(6)) * price.price;
|
|
43146
|
+
return {
|
|
43147
|
+
tokenInfo: this.asset(),
|
|
43148
|
+
amount,
|
|
43149
|
+
usdValue
|
|
43150
|
+
};
|
|
43151
|
+
}
|
|
43152
|
+
async getTVL() {
|
|
43153
|
+
const assets = await this.contract.total_assets();
|
|
43154
|
+
const amount = Web3Number.fromWei(
|
|
43155
|
+
assets.toString(),
|
|
43156
|
+
this.metadata.depositTokens[0].decimals
|
|
43157
|
+
);
|
|
43158
|
+
const price = await this.pricer.getPrice(
|
|
43159
|
+
this.metadata.depositTokens[0].symbol
|
|
43160
|
+
);
|
|
43161
|
+
const usdValue = Number(amount.toFixed(6)) * price.price;
|
|
43162
|
+
return {
|
|
43163
|
+
tokenInfo: this.asset(),
|
|
43164
|
+
amount,
|
|
43165
|
+
usdValue
|
|
43166
|
+
};
|
|
43167
|
+
}
|
|
43168
|
+
async getAUM() {
|
|
43169
|
+
const underlying = this.asset();
|
|
43170
|
+
const usdcPrice = await this.pricer.getPrice(underlying.symbol);
|
|
43171
|
+
const allPositions = [];
|
|
43172
|
+
for (const adapter of this.metadata.additionalInfo.adapters) {
|
|
43173
|
+
const positions = await adapter.adapter.getPositions();
|
|
43174
|
+
allPositions.push(...positions);
|
|
43175
|
+
}
|
|
43176
|
+
let netAUM = new Web3Number(0, underlying.decimals);
|
|
43177
|
+
for (const position of allPositions) {
|
|
43178
|
+
if (position.tokenInfo.address.eq(underlying.address)) {
|
|
43179
|
+
netAUM = netAUM.plus(position.amount);
|
|
43180
|
+
} else {
|
|
43181
|
+
const valueInUSDC = position.usdValue;
|
|
43182
|
+
netAUM = netAUM.plus(valueInUSDC);
|
|
43183
|
+
}
|
|
43184
|
+
}
|
|
43185
|
+
const unusedBalance = await this.getUnusedBalance();
|
|
43186
|
+
logger.verbose(
|
|
43187
|
+
`${this.getTag()} unused balance: ${unusedBalance.amount.toNumber()}`
|
|
43188
|
+
);
|
|
43189
|
+
netAUM = netAUM.plus(unusedBalance.amount);
|
|
43190
|
+
const prevAum = await this.getPrevAUM();
|
|
43191
|
+
logger.verbose(`${this.getTag()} AUM: ${netAUM}`);
|
|
43192
|
+
const realAUM = {
|
|
43193
|
+
tokenInfo: underlying,
|
|
43194
|
+
amount: netAUM,
|
|
43195
|
+
usdValue: netAUM.toNumber() * usdcPrice.price,
|
|
43196
|
+
apy: { apy: 0, type: "base" /* BASE */ },
|
|
43197
|
+
remarks: "finalised" /* FINALISED */,
|
|
43198
|
+
protocol: Protocols.NONE
|
|
43199
|
+
};
|
|
43200
|
+
const estimatedAUMDelta = {
|
|
43201
|
+
tokenInfo: underlying,
|
|
43202
|
+
amount: Web3Number.fromWei("0", underlying.decimals),
|
|
43203
|
+
usdValue: 0,
|
|
43204
|
+
apy: { apy: 0, type: "base" /* BASE */ },
|
|
43205
|
+
remarks: "defispring" /* DEFISPRING */,
|
|
43206
|
+
protocol: Protocols.NONE
|
|
43207
|
+
};
|
|
43208
|
+
return {
|
|
43209
|
+
net: {
|
|
43210
|
+
tokenInfo: underlying,
|
|
43211
|
+
amount: netAUM,
|
|
43212
|
+
usdValue: netAUM.toNumber() * usdcPrice.price
|
|
43213
|
+
},
|
|
43214
|
+
prevAum,
|
|
43215
|
+
splits: [realAUM, estimatedAUMDelta]
|
|
43216
|
+
};
|
|
42004
43217
|
}
|
|
42005
|
-
|
|
42006
|
-
|
|
42007
|
-
|
|
42008
|
-
|
|
42009
|
-
|
|
42010
|
-
|
|
42011
|
-
|
|
43218
|
+
// TODO: can refactor later but seems redundant since not being used ANYWHERE
|
|
43219
|
+
// Most of the fund management done through adapters only
|
|
43220
|
+
async getFundManagementCall(params) {
|
|
43221
|
+
logger.verbose(
|
|
43222
|
+
`${this.getTag()}::getFundManagementCall params: ${JSON.stringify(params)}`
|
|
43223
|
+
);
|
|
43224
|
+
const allAdapters = this.metadata.additionalInfo.adapters.map(
|
|
43225
|
+
(a) => a.adapter
|
|
43226
|
+
);
|
|
43227
|
+
if (!params.isDeposit) {
|
|
43228
|
+
const unusedBalance = await this.getUnusedBalance();
|
|
43229
|
+
logger.verbose(
|
|
43230
|
+
`${this.getTag()}::getFundManagementCall unusedBalance: ${unusedBalance.amount}, required: ${params.leg1DepositAmount}`
|
|
43231
|
+
);
|
|
43232
|
+
if (unusedBalance.amount.gte(params.leg1DepositAmount)) {
|
|
43233
|
+
return null;
|
|
43234
|
+
}
|
|
43235
|
+
const adapters2 = await AdapterOptimizer.getAdapterToUse(
|
|
43236
|
+
allAdapters,
|
|
43237
|
+
false,
|
|
43238
|
+
params.leg1DepositAmount
|
|
43239
|
+
);
|
|
43240
|
+
if (adapters2.length > 0) {
|
|
43241
|
+
const proofsInfo = adapters2.map(
|
|
43242
|
+
(adapter) => adapter.getProofs(false, this.getMerkleTree())
|
|
43243
|
+
);
|
|
43244
|
+
const calls = [];
|
|
43245
|
+
for (const info of proofsInfo) {
|
|
43246
|
+
const manageCalls = await info.callConstructor({
|
|
43247
|
+
amount: params.leg1DepositAmount
|
|
43248
|
+
});
|
|
43249
|
+
const call = this.getManageCall(
|
|
43250
|
+
this.getProofGroupsForManageCalls(manageCalls),
|
|
43251
|
+
manageCalls
|
|
43252
|
+
);
|
|
43253
|
+
calls.push(call);
|
|
43254
|
+
}
|
|
43255
|
+
return calls;
|
|
43256
|
+
}
|
|
43257
|
+
throw new Error(
|
|
43258
|
+
`${this.getTag()}::getFundManagementCall: no adapters for withdraw: ${unusedBalance.amount}`
|
|
43259
|
+
);
|
|
42012
43260
|
}
|
|
42013
|
-
|
|
42014
|
-
|
|
42015
|
-
|
|
42016
|
-
|
|
42017
|
-
|
|
42018
|
-
|
|
43261
|
+
const adapters = await AdapterOptimizer.getAdapterToUse(
|
|
43262
|
+
allAdapters,
|
|
43263
|
+
true,
|
|
43264
|
+
params.leg1DepositAmount
|
|
43265
|
+
);
|
|
43266
|
+
if (adapters.length > 0) {
|
|
43267
|
+
const proofsInfo = adapters.map(
|
|
43268
|
+
(adapter) => adapter.getProofs(true, this.getMerkleTree())
|
|
43269
|
+
);
|
|
43270
|
+
const calls = [];
|
|
43271
|
+
for (const info of proofsInfo) {
|
|
43272
|
+
const manageCalls = await info.callConstructor({
|
|
43273
|
+
amount: params.leg1DepositAmount
|
|
43274
|
+
});
|
|
43275
|
+
const call = this.getManageCall(
|
|
43276
|
+
this.getProofGroupsForManageCalls(manageCalls),
|
|
43277
|
+
manageCalls
|
|
43278
|
+
);
|
|
43279
|
+
calls.push(call);
|
|
43280
|
+
}
|
|
43281
|
+
return calls;
|
|
42019
43282
|
}
|
|
42020
|
-
|
|
43283
|
+
throw new Error(
|
|
43284
|
+
`${this.getTag()}::getFundManagementCall: no adapters for deposit: ${params.leg1DepositAmount}`
|
|
43285
|
+
);
|
|
43286
|
+
}
|
|
42021
43287
|
};
|
|
42022
|
-
function
|
|
43288
|
+
function getUSDCBoostedSettings(vaultSettings) {
|
|
43289
|
+
vaultSettings.leafAdapters = [];
|
|
43290
|
+
const xSTRKToken = Global.getDefaultTokens().find(
|
|
43291
|
+
(t) => t.symbol === "xSTRK"
|
|
43292
|
+
);
|
|
43293
|
+
const USDCToken = Global.getDefaultTokens().find((t) => t.symbol === "USDC");
|
|
43294
|
+
const STRKToken = Global.getDefaultTokens().find((t) => t.symbol === "STRK");
|
|
43295
|
+
const baseAdapterConfig = {
|
|
43296
|
+
baseToken: USDCToken,
|
|
43297
|
+
supportedPositions: [{ asset: USDCToken, isDebt: false }],
|
|
43298
|
+
networkConfig: getMainnetConfig(),
|
|
43299
|
+
pricer: new PricerFromApi(getMainnetConfig(), Global.getDefaultTokens()),
|
|
43300
|
+
vaultAllocator: vaultSettings.vaultAllocator,
|
|
43301
|
+
vaultAddress: vaultSettings.vaultAddress
|
|
43302
|
+
};
|
|
43303
|
+
const vesuModifyPositionAdapter = new VesuModifyPositionAdapter({
|
|
43304
|
+
poolId: vaultSettings.vesuPoolId,
|
|
43305
|
+
collateral: vaultSettings.collateralToken,
|
|
43306
|
+
debt: vaultSettings.debtToken,
|
|
43307
|
+
targetLtv: vaultSettings.targetLTV,
|
|
43308
|
+
maxLtv: vaultSettings.maxLTV,
|
|
43309
|
+
...baseAdapterConfig,
|
|
43310
|
+
supportedPositions: [
|
|
43311
|
+
{ asset: USDCToken, isDebt: false },
|
|
43312
|
+
{ asset: STRKToken, isDebt: true }
|
|
43313
|
+
]
|
|
43314
|
+
});
|
|
43315
|
+
const avnuAdapter = new AvnuAdapter({
|
|
43316
|
+
baseUrl: AVNU_QUOTE_URL,
|
|
43317
|
+
avnuContract: AVNU_EXCHANGE,
|
|
43318
|
+
slippage: 0.01,
|
|
43319
|
+
minimumExtendedPriceDifferenceForSwapOpen: 0,
|
|
43320
|
+
maximumExtendedPriceDifferenceForSwapClosing: 0,
|
|
43321
|
+
...baseAdapterConfig,
|
|
43322
|
+
baseToken: STRKToken,
|
|
43323
|
+
supportedPositions: [
|
|
43324
|
+
{ asset: STRKToken, isDebt: false },
|
|
43325
|
+
{ asset: xSTRKToken, isDebt: false }
|
|
43326
|
+
]
|
|
43327
|
+
});
|
|
43328
|
+
const svkTrovesAdapter = new SvkTrovesAdapter({
|
|
43329
|
+
...baseAdapterConfig,
|
|
43330
|
+
baseToken: xSTRKToken,
|
|
43331
|
+
supportedPositions: [{ asset: xSTRKToken, isDebt: false }],
|
|
43332
|
+
strategyVault: vaultSettings.hyperxSTRKVaultAddress,
|
|
43333
|
+
trovesStrategyId: "hyper_xstrk"
|
|
43334
|
+
});
|
|
43335
|
+
const usdcTransferAdapter = new TokenTransferAdapter({
|
|
43336
|
+
...baseAdapterConfig,
|
|
43337
|
+
fromAddress: vaultSettings.vaultAllocator,
|
|
43338
|
+
toAddress: vaultSettings.vaultAddress
|
|
43339
|
+
});
|
|
43340
|
+
const commonAdapter = new CommonAdapter({
|
|
43341
|
+
id: "flash_loan_init" /* FLASH_LOAN */,
|
|
43342
|
+
vaultAddress: vaultSettings.vaultAddress,
|
|
43343
|
+
vaultAllocator: vaultSettings.vaultAllocator,
|
|
43344
|
+
manager: vaultSettings.manager,
|
|
43345
|
+
asset: USDCToken.address
|
|
43346
|
+
});
|
|
43347
|
+
vaultSettings.adapters.push(
|
|
43348
|
+
// TODO: generalize the ids
|
|
43349
|
+
{ id: "vesu_usdc_strk", adapter: vesuModifyPositionAdapter },
|
|
43350
|
+
// Used to track swapped funds in vaultAllocator
|
|
43351
|
+
{ id: "avnu_strk_xstrk", adapter: avnuAdapter },
|
|
43352
|
+
{ id: "hyper_xstrk", adapter: svkTrovesAdapter },
|
|
43353
|
+
{ id: "usdc_transfer", adapter: usdcTransferAdapter }
|
|
43354
|
+
);
|
|
43355
|
+
vaultSettings.leafAdapters.push(
|
|
43356
|
+
() => vesuModifyPositionAdapter.getDepositLeaf()
|
|
43357
|
+
);
|
|
43358
|
+
vaultSettings.leafAdapters.push(
|
|
43359
|
+
() => vesuModifyPositionAdapter.getWithdrawLeaf()
|
|
43360
|
+
);
|
|
43361
|
+
vaultSettings.leafAdapters.push(() => avnuAdapter.getDepositLeaf());
|
|
43362
|
+
vaultSettings.leafAdapters.push(() => avnuAdapter.getWithdrawLeaf());
|
|
43363
|
+
vaultSettings.leafAdapters.push(() => svkTrovesAdapter.getDepositLeaf());
|
|
43364
|
+
vaultSettings.leafAdapters.push(() => svkTrovesAdapter.getWithdrawLeaf());
|
|
43365
|
+
vaultSettings.leafAdapters.push(
|
|
43366
|
+
commonAdapter.getApproveAdapter(
|
|
43367
|
+
USDCToken.address,
|
|
43368
|
+
vaultSettings.vaultAddress,
|
|
43369
|
+
"approve_bring_liquidity" /* APPROVE_BRING_LIQUIDITY */
|
|
43370
|
+
).bind(commonAdapter)
|
|
43371
|
+
);
|
|
43372
|
+
vaultSettings.leafAdapters.push(
|
|
43373
|
+
commonAdapter.getBringLiquidityAdapter("bring_liquidity" /* BRING_LIQUIDITY */).bind(commonAdapter)
|
|
43374
|
+
);
|
|
43375
|
+
return vaultSettings;
|
|
43376
|
+
}
|
|
43377
|
+
var usdcBoostedSettings = {
|
|
43378
|
+
vaultAddress: ContractAddr.from(
|
|
43379
|
+
"0xcdb0e3b2e076a2cdc4ee958b726b47c066239ef91c5ac80c94cf814147b84"
|
|
43380
|
+
),
|
|
43381
|
+
manager: ContractAddr.from(
|
|
43382
|
+
"0x72eea9bac9fa8cfffda637d3b990851446860c6fd8987d6cb50e659b01ee50f"
|
|
43383
|
+
),
|
|
43384
|
+
vaultAllocator: ContractAddr.from(
|
|
43385
|
+
"0x6d3101cff7f821412a99ebe23bb31a1950f93276285102eb4313e3601f5f927"
|
|
43386
|
+
),
|
|
43387
|
+
redeemRequestNFT: ContractAddr.from(
|
|
43388
|
+
"0x47dcc6889ca8db4e9eea8f55421e10f8ce7e356ccb45260a1c49a76f733c309"
|
|
43389
|
+
),
|
|
43390
|
+
// TODO: not applicable in our case -> remove later ( make it optional if needed)
|
|
43391
|
+
aumOracle: ContractAddr.from("0x0"),
|
|
43392
|
+
leafAdapters: [],
|
|
43393
|
+
adapters: [],
|
|
43394
|
+
// Calc using the maxLTV / targetLTV (0.5)
|
|
43395
|
+
targetHealthFactor: 1.32,
|
|
43396
|
+
// Calc using the maxLTV / maxAcceptableLTV (0.55)
|
|
43397
|
+
minHealthFactor: 1.2,
|
|
43398
|
+
vesuPoolId: VesuPools.Prime,
|
|
43399
|
+
collateralToken: Global.getDefaultTokens().find((t) => t.symbol === "USDC"),
|
|
43400
|
+
debtToken: Global.getDefaultTokens().find((t) => t.symbol === "STRK"),
|
|
43401
|
+
maxLTV: 0.66,
|
|
43402
|
+
targetLTV: 0.5,
|
|
43403
|
+
hyperxSTRKVaultAddress: ContractAddr.from(
|
|
43404
|
+
"0x46c7a54c82b1fe374353859f554a40b8bd31d3e30f742901579e7b57b1b5960"
|
|
43405
|
+
)
|
|
43406
|
+
};
|
|
43407
|
+
function getStrategySettings2(settings) {
|
|
43408
|
+
const USDCToken = Global.getDefaultTokens().find((t) => t.symbol === "USDC");
|
|
43409
|
+
const STRKToken = Global.getDefaultTokens().find((t) => t.symbol === "STRK");
|
|
42023
43410
|
return {
|
|
42024
|
-
id:
|
|
42025
|
-
name:
|
|
42026
|
-
description:
|
|
43411
|
+
id: "usdc_boosted",
|
|
43412
|
+
name: "USDC Boosted",
|
|
43413
|
+
description: "Deposits USDC as collateral on Vesu, borrows STRK, swaps to xSTRK, and deposits into Hyper-xSTRK for boosted yield",
|
|
42027
43414
|
address: settings.vaultAddress,
|
|
42028
|
-
launchBlock:
|
|
42029
|
-
type: "
|
|
43415
|
+
launchBlock: 8742931,
|
|
43416
|
+
type: "ERC4626",
|
|
42030
43417
|
vaultType: {
|
|
42031
|
-
|
|
42032
|
-
|
|
43418
|
+
// TODO: can change as per need
|
|
43419
|
+
type: "Meta Vault" /* META_VAULT */,
|
|
43420
|
+
description: "Deposits USDC as collateral on Vesu, borrows STRK, swaps to xSTRK, and deposits into Hyper-xSTRK for boosted yield"
|
|
42033
43421
|
},
|
|
42034
|
-
depositTokens: [
|
|
42035
|
-
additionalInfo:
|
|
43422
|
+
depositTokens: [USDCToken],
|
|
43423
|
+
additionalInfo: getUSDCBoostedSettings(settings),
|
|
43424
|
+
// TODO: config lateron
|
|
42036
43425
|
risk: {
|
|
42037
|
-
riskFactor:
|
|
42038
|
-
netRisk:
|
|
42039
|
-
notARisks:
|
|
43426
|
+
riskFactor: [],
|
|
43427
|
+
netRisk: 0,
|
|
43428
|
+
notARisks: []
|
|
42040
43429
|
},
|
|
42041
|
-
|
|
42042
|
-
protocols: [Protocols.ENDUR, Protocols.VESU],
|
|
43430
|
+
protocols: [Protocols.VESU, Protocols.TROVES],
|
|
42043
43431
|
curator: {
|
|
42044
43432
|
name: "Unwrap Labs",
|
|
42045
43433
|
logo: "https://assets.troves.fi/integrations/unwraplabs/white.png"
|
|
42046
43434
|
},
|
|
42047
|
-
settings:
|
|
43435
|
+
settings: {
|
|
43436
|
+
maxTVL: Web3Number.fromWei(0, USDCToken.decimals),
|
|
43437
|
+
isPaused: false,
|
|
43438
|
+
isAudited: false,
|
|
43439
|
+
isInstantWithdrawal: false,
|
|
43440
|
+
hideHarvestInfo: true,
|
|
43441
|
+
quoteToken: USDCToken,
|
|
43442
|
+
alerts: [
|
|
43443
|
+
{
|
|
43444
|
+
tab: "withdraw",
|
|
43445
|
+
text: "On withdrawal, you will receive an NFT representing your withdrawal request. The funds will be automatically sent to your wallet (NFT owner) in 1-2 hours. You can monitor the status in transactions tab.",
|
|
43446
|
+
type: "info"
|
|
43447
|
+
}
|
|
43448
|
+
]
|
|
43449
|
+
},
|
|
42048
43450
|
contractDetails: getContractDetails(settings),
|
|
42049
|
-
|
|
42050
|
-
|
|
42051
|
-
|
|
42052
|
-
|
|
42053
|
-
|
|
42054
|
-
|
|
42055
|
-
|
|
42056
|
-
|
|
42057
|
-
|
|
42058
|
-
|
|
42059
|
-
|
|
42060
|
-
|
|
42061
|
-
|
|
42062
|
-
|
|
42063
|
-
|
|
43451
|
+
// TODO: config later
|
|
43452
|
+
faqs: [],
|
|
43453
|
+
investmentSteps: [
|
|
43454
|
+
"Deposit USDC into the vault",
|
|
43455
|
+
"USDC is supplied as collateral on Vesu, STRK is borrowed",
|
|
43456
|
+
"Borrowed STRK is swapped to xSTRK via Avnu",
|
|
43457
|
+
"xSTRK is deposited into the Hyper-xSTRK vault for additional yield",
|
|
43458
|
+
"On withdrawal, the pipeline reverses to return USDC"
|
|
43459
|
+
],
|
|
43460
|
+
// TODO: config later
|
|
43461
|
+
tags: ["Meta Vaults" /* META_VAULT */],
|
|
43462
|
+
security: {
|
|
43463
|
+
auditStatus: "Audited" /* AUDITED */,
|
|
43464
|
+
sourceCode: {
|
|
43465
|
+
type: "Closed Source" /* CLOSED_SOURCE */,
|
|
43466
|
+
contractLink: "https://github.com/trovesfi/troves-contracts"
|
|
43467
|
+
},
|
|
43468
|
+
accessControl: {
|
|
43469
|
+
type: "Standard Account" /* STANDARD_ACCOUNT */,
|
|
43470
|
+
addresses: [ContractAddr.from("0x0")],
|
|
43471
|
+
timeLock: "2 Days"
|
|
43472
|
+
}
|
|
43473
|
+
},
|
|
43474
|
+
redemptionInfo: {
|
|
43475
|
+
instantWithdrawalVault: "No" /* NO */,
|
|
43476
|
+
redemptionsInfo: [
|
|
43477
|
+
{
|
|
43478
|
+
title: "Typical Duration",
|
|
43479
|
+
description: "1-2 hours"
|
|
43480
|
+
}
|
|
43481
|
+
],
|
|
43482
|
+
alerts: [
|
|
43483
|
+
{
|
|
43484
|
+
type: "info",
|
|
43485
|
+
text: "Redemption times are estimates and may vary based on network conditions and liquidity requirements.",
|
|
43486
|
+
tab: "withdraw"
|
|
43487
|
+
}
|
|
43488
|
+
]
|
|
43489
|
+
},
|
|
43490
|
+
usualTimeToEarnings: null,
|
|
43491
|
+
usualTimeToEarningsDescription: null
|
|
42064
43492
|
};
|
|
42065
43493
|
}
|
|
42066
|
-
var
|
|
42067
|
-
getStrategySettings("xSTRK", "STRK", hyperxSTRK, false, true),
|
|
42068
|
-
getStrategySettings("xWBTC", "WBTC", hyperxWBTC, false, false),
|
|
42069
|
-
getStrategySettings("xtBTC", "tBTC", hyperxtBTC, false, false),
|
|
42070
|
-
getStrategySettings("xsBTC", "solvBTC", hyperxsBTC, false, false),
|
|
42071
|
-
getStrategySettings("xLBTC", "LBTC", hyperxLBTC, false, false),
|
|
42072
|
-
getStrategySettings("mRe7BTC", "mRe7BTC", hypermRe7BTC, false, false),
|
|
42073
|
-
getStrategySettings("mRe7YIELD", "mRe7YIELD", hypermRe7YIELD, false, false)
|
|
42074
|
-
];
|
|
43494
|
+
var USDCBoostedStrategies = [getStrategySettings2(usdcBoostedSettings)];
|
|
42075
43495
|
|
|
42076
43496
|
// src/strategies/vesu-extended-strategy/services/ltv-imbalance-rebalance-math.ts
|
|
42077
43497
|
function ceilBtc(v, precision) {
|
|
@@ -43470,6 +44890,142 @@ function createSolveBudgetFromRawState(params) {
|
|
|
43470
44890
|
}
|
|
43471
44891
|
return budget;
|
|
43472
44892
|
}
|
|
44893
|
+
function assertRouteSanityAndAdjust(route, availableAmount) {
|
|
44894
|
+
if (!route.amount) {
|
|
44895
|
+
throw new Error(`Invalid route given to assertRouteSanityAndAdjust: ${JSON.stringify(route)}`);
|
|
44896
|
+
}
|
|
44897
|
+
const routeAmount = route.amount.toNumber();
|
|
44898
|
+
if (routeAmount <= availableAmount) {
|
|
44899
|
+
return route;
|
|
44900
|
+
}
|
|
44901
|
+
if (routeAmount - availableAmount <= CASE_THRESHOLD_USD) {
|
|
44902
|
+
return { ...route, amount: new Web3Number(availableAmount, route.amount.decimals) };
|
|
44903
|
+
}
|
|
44904
|
+
throw new Error(`Route amount ${routeAmount} exceeds available amount ${availableAmount}, Route name: ${route.type}`);
|
|
44905
|
+
}
|
|
44906
|
+
function assertVesuMultiplyRouteSanityAndAdjust(route, availableAmount, state, isIncrease) {
|
|
44907
|
+
const btcPrice = state.vesuPoolState.collateralPrice;
|
|
44908
|
+
const totalCollateralAmount = isIncrease ? route.marginAmount.plus(route.swappedCollateralAmount).plus(state.vesuPoolState.collateralAmount) : state.vesuPoolState.collateralAmount.minus(route.marginAmount.plus(route.swappedCollateralAmount));
|
|
44909
|
+
const totalDebtAmount = isIncrease ? route.debtAmount.plus(state.vesuPoolState.debtAmount) : state.vesuPoolState.debtAmount.minus(route.debtAmount);
|
|
44910
|
+
const newHF = HealthFactorMath.getHealthFactor(
|
|
44911
|
+
totalCollateralAmount,
|
|
44912
|
+
btcPrice,
|
|
44913
|
+
VesuConfig.maxLtv,
|
|
44914
|
+
totalDebtAmount,
|
|
44915
|
+
state.vesuPoolState.debtPrice
|
|
44916
|
+
);
|
|
44917
|
+
const idealHF = VesuConfig.maxLtv / VesuConfig.targetLtv - 0.05;
|
|
44918
|
+
assert(newHF >= idealHF, `SolveBudget::applyRoutesAndVerifyLtvState newHF=${newHF} < idealHF=${idealHF}`);
|
|
44919
|
+
}
|
|
44920
|
+
function applyRoutesAndVerifyLtvState(state, routes) {
|
|
44921
|
+
const btcPrice = state.vesuPoolState.collateralPrice;
|
|
44922
|
+
const adjustedRouters = [...routes];
|
|
44923
|
+
let index = 0;
|
|
44924
|
+
for (const r of routes) {
|
|
44925
|
+
switch (r.type) {
|
|
44926
|
+
case "WALLET_TO_VA" /* WALLET_TO_VA */: {
|
|
44927
|
+
const adjustedRoute = assertRouteSanityAndAdjust(r, state.walletUsd);
|
|
44928
|
+
const amt = adjustedRoute.amount.toNumber();
|
|
44929
|
+
state.spendWallet(amt);
|
|
44930
|
+
state.addToVA(amt);
|
|
44931
|
+
break;
|
|
44932
|
+
}
|
|
44933
|
+
case "VESU_REPAY" /* VESU_REPAY */: {
|
|
44934
|
+
const adjustedRoute = assertRouteSanityAndAdjust(r, state.vaRawUsd);
|
|
44935
|
+
const amt = Math.abs(adjustedRoute.amount.toNumber());
|
|
44936
|
+
state.repayVesuBorrowCapacity(amt);
|
|
44937
|
+
state.spendVA(amt);
|
|
44938
|
+
break;
|
|
44939
|
+
}
|
|
44940
|
+
case "EXTENDED_TO_WALLET" /* EXTENDED_TO_WALLET */: {
|
|
44941
|
+
const adjustedRoute = assertRouteSanityAndAdjust(r, state.extAvailWithdraw);
|
|
44942
|
+
const amt = adjustedRoute.amount.toNumber();
|
|
44943
|
+
state.addToWallet(amt);
|
|
44944
|
+
state.spendExtAvailTrade(amt);
|
|
44945
|
+
break;
|
|
44946
|
+
}
|
|
44947
|
+
case "REALISE_PNL" /* REALISE_PNL */: {
|
|
44948
|
+
const amt = r.amount.toNumber();
|
|
44949
|
+
state.spendExtAvailUpnl(amt);
|
|
44950
|
+
state.addToExtAvailTrade(amt);
|
|
44951
|
+
break;
|
|
44952
|
+
}
|
|
44953
|
+
case "VA_TO_EXTENDED" /* VA_TO_EXTENDED */: {
|
|
44954
|
+
const adjustedRoute = assertRouteSanityAndAdjust(r, state.vaRawUsd);
|
|
44955
|
+
const amt = adjustedRoute.amount.toNumber();
|
|
44956
|
+
state.spendVA(amt);
|
|
44957
|
+
state.addToExtAvailTrade(amt);
|
|
44958
|
+
break;
|
|
44959
|
+
}
|
|
44960
|
+
case "WALLET_TO_EXTENDED" /* WALLET_TO_EXTENDED */: {
|
|
44961
|
+
const adjustedRoute = assertRouteSanityAndAdjust(r, state.walletUsd);
|
|
44962
|
+
const amt = adjustedRoute.amount.toNumber();
|
|
44963
|
+
state.spendWallet(amt);
|
|
44964
|
+
state.addToExtAvailTrade(amt);
|
|
44965
|
+
break;
|
|
44966
|
+
}
|
|
44967
|
+
case "VESU_BORROW" /* VESU_BORROW */: {
|
|
44968
|
+
const borrowedAmount = r.amount.toNumber();
|
|
44969
|
+
const currentCollateralAmount = state.vesuPoolState.collateralAmount.toNumber();
|
|
44970
|
+
const currentDebtAmount = state.vesuPoolState.debtAmount.toNumber();
|
|
44971
|
+
const maxDebtAmount = HealthFactorMath.getMaxDebtAmount(
|
|
44972
|
+
new Web3Number(currentCollateralAmount, state.vesuPoolState.collateralToken.decimals),
|
|
44973
|
+
state.vesuPoolState.collateralPrice,
|
|
44974
|
+
VesuConfig.maxLtv,
|
|
44975
|
+
VesuConfig.maxLtv / VesuConfig.targetLtv - 0.05,
|
|
44976
|
+
// e.g. if ideal HF is 1.4, upto 1.35 is ok.
|
|
44977
|
+
state.vesuPoolState.debtPrice,
|
|
44978
|
+
state.vesuPoolState.debtToken
|
|
44979
|
+
);
|
|
44980
|
+
const availableDebtAmount = maxDebtAmount.minus(new Web3Number(currentDebtAmount, state.vesuPoolState.debtToken.decimals));
|
|
44981
|
+
if (!availableDebtAmount.plus(CASE_THRESHOLD_USD).greaterThan(borrowedAmount)) {
|
|
44982
|
+
throw new Error(`SolveBudget::applyRoutesAndVerifyLtvState availableDebtAmount=${availableDebtAmount.toNumber()} < borrowedAmount=${borrowedAmount}`);
|
|
44983
|
+
}
|
|
44984
|
+
state.spendVesuBorrowCapacity(borrowedAmount);
|
|
44985
|
+
state.addToVA(borrowedAmount);
|
|
44986
|
+
break;
|
|
44987
|
+
}
|
|
44988
|
+
case "VESU_MULTIPLY_INCREASE_LEVER" /* VESU_MULTIPLY_INCREASE_LEVER */: {
|
|
44989
|
+
const mr = r;
|
|
44990
|
+
assertVesuMultiplyRouteSanityAndAdjust(mr, state.vaRawUsd, state, true);
|
|
44991
|
+
state.applyVesuDelta(
|
|
44992
|
+
mr.poolId,
|
|
44993
|
+
mr.collateralToken,
|
|
44994
|
+
mr.debtToken,
|
|
44995
|
+
mr.marginAmount.plus(mr.swappedCollateralAmount),
|
|
44996
|
+
mr.debtAmount
|
|
44997
|
+
);
|
|
44998
|
+
state.spendVA(mr.marginAmount.toNumber() * btcPrice);
|
|
44999
|
+
break;
|
|
45000
|
+
}
|
|
45001
|
+
case "VESU_MULTIPLY_DECREASE_LEVER" /* VESU_MULTIPLY_DECREASE_LEVER */: {
|
|
45002
|
+
const mr = r;
|
|
45003
|
+
assertVesuMultiplyRouteSanityAndAdjust(mr, state.vaRawUsd, state, false);
|
|
45004
|
+
state.applyVesuDelta(
|
|
45005
|
+
mr.poolId,
|
|
45006
|
+
mr.collateralToken,
|
|
45007
|
+
mr.debtToken,
|
|
45008
|
+
new Web3Number(mr.marginAmount.negated().minus(mr.swappedCollateralAmount).toFixed(8), mr.marginAmount.decimals),
|
|
45009
|
+
mr.debtAmount
|
|
45010
|
+
);
|
|
45011
|
+
const marginBtc = mr.marginAmount.toNumber();
|
|
45012
|
+
if (marginBtc > 10 ** -COLLATERAL_PRECISION) {
|
|
45013
|
+
state.addToVA(marginBtc * btcPrice);
|
|
45014
|
+
}
|
|
45015
|
+
break;
|
|
45016
|
+
}
|
|
45017
|
+
case "EXTENDED_DECREASE_LEVER" /* EXTENDED_DECREASE_LEVER */:
|
|
45018
|
+
case "EXTENDED_INCREASE_LEVER" /* EXTENDED_INCREASE_LEVER */: {
|
|
45019
|
+
const er = r;
|
|
45020
|
+
state.applyExtendedExposureDelta(er.instrument, er.amount, btcPrice);
|
|
45021
|
+
break;
|
|
45022
|
+
}
|
|
45023
|
+
case "RETURN_TO_WAIT" /* RETURN_TO_WAIT */:
|
|
45024
|
+
break;
|
|
45025
|
+
}
|
|
45026
|
+
index++;
|
|
45027
|
+
}
|
|
45028
|
+
}
|
|
43473
45029
|
var ExtendedSVKVesuStateManager = class {
|
|
43474
45030
|
constructor(config) {
|
|
43475
45031
|
this._tag = "ExtendedSVKVesuStateManager";
|
|
@@ -43488,13 +45044,19 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
43488
45044
|
* Pass 0 (default) for normal investment / rebalancing cycles.
|
|
43489
45045
|
*/
|
|
43490
45046
|
async solve(withdrawAmount = new Web3Number(0, USDC_TOKEN_DECIMALS)) {
|
|
43491
|
-
await this._refresh();
|
|
45047
|
+
const gaurdrailBudget = await this._refresh();
|
|
43492
45048
|
if (Math.abs(this._budget.extPendingDeposit) > 0) {
|
|
43493
45049
|
logger.warn(`${this._tag}::solve extPendingDeposit=${this._budget.extPendingDeposit}`);
|
|
43494
45050
|
return null;
|
|
43495
45051
|
}
|
|
43496
45052
|
this._validateRefreshedState();
|
|
43497
45053
|
const cases = this._classifyCases(withdrawAmount);
|
|
45054
|
+
for (const c of cases) {
|
|
45055
|
+
applyRoutesAndVerifyLtvState(gaurdrailBudget, c.routes);
|
|
45056
|
+
}
|
|
45057
|
+
const extendedPositionSize = gaurdrailBudget.extendedPositionsView[0].size.toNumber();
|
|
45058
|
+
const vesuPositionSize = gaurdrailBudget.vesuPoolState.collateralAmount.toNumber();
|
|
45059
|
+
assert(Math.abs(extendedPositionSize - vesuPositionSize) <= 1e-5, "extended positions size mismatch");
|
|
43498
45060
|
const result = {
|
|
43499
45061
|
cases,
|
|
43500
45062
|
// ignore these fields for now. only cases are relevant.
|
|
@@ -43542,7 +45104,7 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
43542
45104
|
vaultUsdcBalance,
|
|
43543
45105
|
walletBalance
|
|
43544
45106
|
);
|
|
43545
|
-
|
|
45107
|
+
const data = {
|
|
43546
45108
|
assetToken: this._config.assetToken,
|
|
43547
45109
|
usdcToken: this._config.usdcToken,
|
|
43548
45110
|
unusedBalance,
|
|
@@ -43559,7 +45121,9 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
43559
45121
|
pendingDeposit: extendedBalance?.pendingDeposit || new Web3Number(0, USDC_TOKEN_DECIMALS)
|
|
43560
45122
|
},
|
|
43561
45123
|
vesuPoolStates
|
|
43562
|
-
}
|
|
45124
|
+
};
|
|
45125
|
+
this._budget = createSolveBudgetFromRawState(data);
|
|
45126
|
+
const gaurdrailBudget = createSolveBudgetFromRawState({ ...data });
|
|
43563
45127
|
this._budget.logStateSummary();
|
|
43564
45128
|
const totalUnusedUsd = unusedBalance.reduce(
|
|
43565
45129
|
(acc, b) => acc + b.usdValue,
|
|
@@ -43568,6 +45132,7 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
43568
45132
|
logger.info(
|
|
43569
45133
|
`${this._tag}::_refresh completed \u2014 unusedBalances: ${unusedBalance.length} tokens [${unusedBalance.map((b) => `${b.token.symbol}=$${b.usdValue.toFixed(2)}`).join(", ")}], totalUnusedUsd: ${totalUnusedUsd.toFixed(2)}, extendedPositions: ${extendedPositions.length} [${extendedPositions.map((p) => `${p.instrument}=${p.size.toFixed(6)} ${p.side}, ${p.valueUsd.toFixed(6)} ${p.instrument}`).join(", ")}], vesuPools: ${vesuPoolStates.length} [${vesuPoolStates.map((p) => `${p.poolId.shortString()}=${p.debtAmount.toFixed(6)} ${p.debtToken.symbol}, ${p.collateralAmount.toFixed(6)} ${p.collateralToken.symbol}`).join(", ")}], availableForTrade: ${extendedBalance?.availableForTrade.toNumber()} - availableForWithdrawal: ${extendedBalance?.availableForWithdrawal.toNumber()} - unrealisedPnl: ${extendedBalance?.unrealisedPnl.toNumber()} - extendedBalance::balance: ${extendedBalance?.balance.toNumber()} - extendedBalance::pendingDeposit: ${extendedBalance?.pendingDeposit.toNumber()} - extendedBalance::equity: ${extendedBalance?.equity.toNumber()}`
|
|
43570
45134
|
);
|
|
45135
|
+
return gaurdrailBudget;
|
|
43571
45136
|
}
|
|
43572
45137
|
// todo add communication check with python server of extended. if not working, throw error in solve function.
|
|
43573
45138
|
/** True when strategy asset and USDC share one token — VA idle balance is tracked as USDC, not as asset. */
|
|
@@ -45311,7 +46876,7 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
45311
46876
|
};
|
|
45312
46877
|
|
|
45313
46878
|
// src/strategies/vesu-extended-strategy/services/executionService.ts
|
|
45314
|
-
import { uint256 as
|
|
46879
|
+
import { uint256 as uint25624 } from "starknet";
|
|
45315
46880
|
|
|
45316
46881
|
// src/strategies/vesu-extended-strategy/types/transaction-metadata.ts
|
|
45317
46882
|
var CycleType = /* @__PURE__ */ ((CycleType2) => {
|
|
@@ -46243,7 +47808,7 @@ var _ExecutionService = class _ExecutionService {
|
|
|
46243
47808
|
const extendedContract = extendedAdapter.config.extendedContract;
|
|
46244
47809
|
const vaultId = extendedAdapter.config.vaultIdExtended;
|
|
46245
47810
|
const salt = Math.floor(Math.random() * 10 ** usdcToken.decimals);
|
|
46246
|
-
const uint256Amount =
|
|
47811
|
+
const uint256Amount = uint25624.bnToUint256(amount.toWei());
|
|
46247
47812
|
const approveCall = {
|
|
46248
47813
|
contractAddress: usdcToken.address.address,
|
|
46249
47814
|
entrypoint: "approve",
|
|
@@ -48036,6 +49601,7 @@ export {
|
|
|
48036
49601
|
SIMPLE_SANITIZER,
|
|
48037
49602
|
SIMPLE_SANITIZER_V2,
|
|
48038
49603
|
SIMPLE_SANITIZER_VESU_V1_DELEGATIONS,
|
|
49604
|
+
SVK_SIMPLE_SANITIZER,
|
|
48039
49605
|
SenseiStrategies,
|
|
48040
49606
|
SenseiVault,
|
|
48041
49607
|
SolveBudget,
|
|
@@ -48052,6 +49618,8 @@ export {
|
|
|
48052
49618
|
TokenTransferAdapter,
|
|
48053
49619
|
UNIVERSAL_ADAPTERS,
|
|
48054
49620
|
UNIVERSAL_MANAGE_IDS,
|
|
49621
|
+
USDCBoostedStrategies,
|
|
49622
|
+
USDCBoostedStrategy,
|
|
48055
49623
|
UniversalLstMultiplierStrategy,
|
|
48056
49624
|
UniversalStrategies,
|
|
48057
49625
|
UniversalStrategy,
|