@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.mjs
CHANGED
|
@@ -21734,6 +21734,7 @@ import { CairoCustomEnum as CairoCustomEnum2, Contract as Contract10, hash as ha
|
|
|
21734
21734
|
|
|
21735
21735
|
// src/strategies/universal-adapters/adapter-utils.ts
|
|
21736
21736
|
var SIMPLE_SANITIZER = ContractAddr.from("0x5a2e3ceb3da368b983a8717898427ab7b6daf04014b70f321e777f9aad940b4");
|
|
21737
|
+
var SVK_SIMPLE_SANITIZER = ContractAddr.from("0x03dcde04343257c3ce14574676cb9c5b2eda16e332c1b8caf5dc4c95ac568d2f");
|
|
21737
21738
|
var EXTENDED_SANITIZER = ContractAddr.from("0x65891708362b24dcf4c40c8e218cce6e82d1d6b3a3404c9ab00a48f08e2c110");
|
|
21738
21739
|
var AVNU_LEGACY_SANITIZER = ContractAddr.from("0x0656fBE853f116DD53956176a553eDe8fE65632252f8aceB50C1B9B6c8237309");
|
|
21739
21740
|
var SIMPLE_SANITIZER_V2 = ContractAddr.from("0x7b6f98311af8aa425278570e62abf523e6462eaa01a38c1feab9b2f416492e2");
|
|
@@ -35597,7 +35598,14 @@ var VesuModifyPositionAdapter = class _VesuModifyPositionAdapter extends BaseAda
|
|
|
35597
35598
|
}
|
|
35598
35599
|
const normalizedDebtAmount = this._normalizeDebtAmountFromHelper(
|
|
35599
35600
|
helperOutput
|
|
35600
|
-
);
|
|
35601
|
+
).minus(state.currentDebt);
|
|
35602
|
+
if (normalizedDebtAmount.lessThan(0)) {
|
|
35603
|
+
logger.warn(`VesuModifyPositionAdapter: deposit debt delta is negative (${normalizedDebtAmount.toNumber()}), clamping to zero`);
|
|
35604
|
+
return {
|
|
35605
|
+
collateral: this._toSigned(collateralToAdd, false),
|
|
35606
|
+
debt: this._toSigned(Web3Number.fromWei(0, this.config.debt.decimals), false)
|
|
35607
|
+
};
|
|
35608
|
+
}
|
|
35601
35609
|
return {
|
|
35602
35610
|
collateral: this._toSigned(collateralToAdd, false),
|
|
35603
35611
|
debt: this._toSigned(normalizedDebtAmount, false)
|
|
@@ -35615,8 +35623,8 @@ var VesuModifyPositionAdapter = class _VesuModifyPositionAdapter extends BaseAda
|
|
|
35615
35623
|
state.debtPrice,
|
|
35616
35624
|
this.config.debt
|
|
35617
35625
|
);
|
|
35618
|
-
if (!helperOutput || helperOutput.
|
|
35619
|
-
throw new Error(`Failed to calculate
|
|
35626
|
+
if (!helperOutput || helperOutput.lessThan(0)) {
|
|
35627
|
+
throw new Error(`Failed to calculate max debt amount for withdraw: ${helperOutput?.toNumber()}`);
|
|
35620
35628
|
}
|
|
35621
35629
|
const normalizedDebtAmount = this._normalizeDebtAmountFromHelper(
|
|
35622
35630
|
helperOutput
|
|
@@ -35813,6 +35821,24 @@ var VesuModifyPositionAdapter = class _VesuModifyPositionAdapter extends BaseAda
|
|
|
35813
35821
|
this._prepareVesuAdapter();
|
|
35814
35822
|
return this._vesuAdapter.getHealthFactor();
|
|
35815
35823
|
}
|
|
35824
|
+
/**
|
|
35825
|
+
* Simulates a deposit of `depositAmount` collateral and returns how much
|
|
35826
|
+
* debt (STRK) would be incrementally borrowed to reach the target LTV.
|
|
35827
|
+
* Used upstream to size the AVNU swap call in the same transaction batch.
|
|
35828
|
+
*/
|
|
35829
|
+
async getExpectedDepositDebtDelta(depositAmount) {
|
|
35830
|
+
const defaults = await this._buildDefaultDepositDeltas({ amount: depositAmount });
|
|
35831
|
+
return defaults.debt.amount;
|
|
35832
|
+
}
|
|
35833
|
+
/**
|
|
35834
|
+
* Simulates a withdrawal of `withdrawAmount` collateral and returns the
|
|
35835
|
+
* incremental debt delta needed to keep the target health factor.
|
|
35836
|
+
* Positive means borrow, negative means repay.
|
|
35837
|
+
*/
|
|
35838
|
+
async getExpectedWithdrawDebtDelta(withdrawAmount) {
|
|
35839
|
+
const defaults = await this._buildDefaultWithdrawDeltas({ amount: withdrawAmount });
|
|
35840
|
+
return defaults.debt.amount;
|
|
35841
|
+
}
|
|
35816
35842
|
};
|
|
35817
35843
|
|
|
35818
35844
|
// src/strategies/universal-adapters/extended-adapter.ts
|
|
@@ -36370,6 +36396,25 @@ var ExtendedAdapter = class _ExtendedAdapter extends BaseAdapter {
|
|
|
36370
36396
|
return { success: false, data: [] };
|
|
36371
36397
|
}
|
|
36372
36398
|
}
|
|
36399
|
+
/** Account funding payment history via `GET /api/v1/account/funding-payments` (USDC amounts). */
|
|
36400
|
+
async getFundingPayments(side, startTime, limit) {
|
|
36401
|
+
try {
|
|
36402
|
+
const response = await this.client.getUserFundingPayments(
|
|
36403
|
+
this.config.extendedMarketName,
|
|
36404
|
+
side,
|
|
36405
|
+
startTime ?? Date.now() - 30 * 24 * 60 * 60 * 1e3,
|
|
36406
|
+
limit ?? 200
|
|
36407
|
+
);
|
|
36408
|
+
if (response.status !== "OK") {
|
|
36409
|
+
logger.error("error getting funding payments", response.data);
|
|
36410
|
+
return { success: false, data: [] };
|
|
36411
|
+
}
|
|
36412
|
+
return { success: true, data: response.data ?? [] };
|
|
36413
|
+
} catch (err) {
|
|
36414
|
+
logger.error("error getting funding payments", err);
|
|
36415
|
+
return { success: false, data: [] };
|
|
36416
|
+
}
|
|
36417
|
+
}
|
|
36373
36418
|
async getPosition(supportedPosition) {
|
|
36374
36419
|
const holdings = await this.getExtendedDepositAmount();
|
|
36375
36420
|
if (!holdings) {
|
|
@@ -39009,228 +39054,1076 @@ var universal_vault_abi_default = [
|
|
|
39009
39054
|
}
|
|
39010
39055
|
];
|
|
39011
39056
|
|
|
39012
|
-
// src/
|
|
39013
|
-
var
|
|
39014
|
-
|
|
39015
|
-
|
|
39016
|
-
|
|
39017
|
-
|
|
39018
|
-
|
|
39019
|
-
|
|
39020
|
-
|
|
39021
|
-
|
|
39022
|
-
|
|
39023
|
-
}
|
|
39024
|
-
return 0;
|
|
39025
|
-
}
|
|
39026
|
-
var SvkTrovesAdapter = class _SvkTrovesAdapter extends BaseAdapter {
|
|
39027
|
-
constructor(config) {
|
|
39028
|
-
super(config, _SvkTrovesAdapter.name, Protocols.TROVES);
|
|
39029
|
-
this.config = config;
|
|
39030
|
-
}
|
|
39031
|
-
/** Owner used for share balance + `due_assets_from_owner`. */
|
|
39032
|
-
_positionOwner() {
|
|
39033
|
-
return this.config.positionOwner ?? this.config.vaultAllocator;
|
|
39034
|
-
}
|
|
39035
|
-
/**
|
|
39036
|
-
* Proof readable IDs must stay ≤ 31 chars (Cairo short string). We derive a short ASCII suffix from
|
|
39037
|
-
* `strategyVault` address so multiple SVK adapters in one tree stay distinct.
|
|
39038
|
-
*/
|
|
39039
|
-
_proofSuffix() {
|
|
39040
|
-
return this.config.strategyVault.address.replace(/^0x/, "").slice(-6);
|
|
39041
|
-
}
|
|
39042
|
-
_depositApproveProofReadableId() {
|
|
39043
|
-
return `appr_dep_svk_${this._proofSuffix()}`;
|
|
39044
|
-
}
|
|
39045
|
-
_depositCallProofReadableId() {
|
|
39046
|
-
return `dep_svk_${this._proofSuffix()}`;
|
|
39047
|
-
}
|
|
39048
|
-
_withdrawCallProofReadableId() {
|
|
39049
|
-
return `wtdrw_svk_${this._proofSuffix()}`;
|
|
39050
|
-
}
|
|
39051
|
-
async getAPY(supportedPosition) {
|
|
39052
|
-
const CACHE_KEY = `svk_apy_${this.config.trovesStrategyId}`;
|
|
39053
|
-
const cached = this.getCache(CACHE_KEY);
|
|
39054
|
-
if (cached) {
|
|
39055
|
-
return cached;
|
|
39056
|
-
}
|
|
39057
|
-
const url = this.config.trovesStrategiesApiUrl ?? DEFAULT_TROVES_STRATEGIES_API;
|
|
39058
|
-
try {
|
|
39059
|
-
const res = await fetch(url);
|
|
39060
|
-
if (!res.ok) {
|
|
39061
|
-
logger.warn(`${_SvkTrovesAdapter.name}::getAPY: HTTP ${res.status} from ${url}`);
|
|
39062
|
-
const fallback = { apy: 0, type: "base" /* BASE */ };
|
|
39063
|
-
this.setCache(CACHE_KEY, fallback, 3e5);
|
|
39064
|
-
return fallback;
|
|
39065
|
-
}
|
|
39066
|
-
const body = await res.json();
|
|
39067
|
-
const row = body.strategies?.find((s) => s.id === this.config.trovesStrategyId);
|
|
39068
|
-
if (!row) {
|
|
39069
|
-
logger.warn(
|
|
39070
|
-
`${_SvkTrovesAdapter.name}::getAPY: strategy id not found: ${this.config.trovesStrategyId}`
|
|
39071
|
-
);
|
|
39072
|
-
const fallback = { apy: 0, type: "base" /* BASE */ };
|
|
39073
|
-
this.setCache(CACHE_KEY, fallback, 3e5);
|
|
39074
|
-
return fallback;
|
|
39075
|
-
}
|
|
39076
|
-
const apy = parseTrovesApyField(row.apy);
|
|
39077
|
-
const result = { apy, type: "base" /* BASE */ };
|
|
39078
|
-
this.setCache(CACHE_KEY, result, 3e5);
|
|
39079
|
-
return result;
|
|
39080
|
-
} catch (error) {
|
|
39081
|
-
logger.error(`${_SvkTrovesAdapter.name}::getAPY:`, error);
|
|
39082
|
-
throw error;
|
|
39083
|
-
}
|
|
39084
|
-
}
|
|
39085
|
-
async getPosition(supportedPosition) {
|
|
39086
|
-
const CACHE_KEY = `svk_pos_${this.config.strategyVault.address}_${this._positionOwner().address}`;
|
|
39087
|
-
const cached = this.getCache(CACHE_KEY);
|
|
39088
|
-
if (cached) {
|
|
39089
|
-
return cached;
|
|
39090
|
-
}
|
|
39091
|
-
try {
|
|
39092
|
-
const vault = new Contract14({
|
|
39093
|
-
abi: universal_vault_abi_default,
|
|
39094
|
-
address: this.config.strategyVault.address,
|
|
39095
|
-
providerOrAccount: this.config.networkConfig.provider
|
|
39096
|
-
});
|
|
39097
|
-
const owner = this._positionOwner();
|
|
39098
|
-
const decimals = supportedPosition.asset.decimals;
|
|
39099
|
-
const shares = await vault.balance_of(owner.address);
|
|
39100
|
-
const shareU256 = uint25619.bnToUint256(shares);
|
|
39101
|
-
const liquidAssetsRaw = await vault.convert_to_assets(shareU256);
|
|
39102
|
-
const liquid = Web3Number.fromWei(liquidAssetsRaw.toString(), decimals);
|
|
39103
|
-
let pending = Web3Number.fromWei("0", decimals);
|
|
39104
|
-
try {
|
|
39105
|
-
const dueRaw = await vault.call("due_assets_from_owner", [owner.address]);
|
|
39106
|
-
pending = Web3Number.fromWei(dueRaw.toString(), decimals);
|
|
39107
|
-
} catch (e) {
|
|
39108
|
-
logger.warn(
|
|
39109
|
-
`${_SvkTrovesAdapter.name}::getPosition: due_assets_from_owner failed (treating as 0): ${e.message}`
|
|
39110
|
-
);
|
|
39111
|
-
}
|
|
39112
|
-
const total = liquid.plus(pending);
|
|
39113
|
-
const remarks = `Troves ${this.config.trovesStrategyId} holdings`;
|
|
39114
|
-
const result = {
|
|
39115
|
-
amount: total,
|
|
39116
|
-
remarks
|
|
39117
|
-
};
|
|
39118
|
-
this.setCache(CACHE_KEY, result, 6e4);
|
|
39119
|
-
return result;
|
|
39120
|
-
} catch (error) {
|
|
39121
|
-
logger.error(`${_SvkTrovesAdapter.name}::getPosition:`, error);
|
|
39122
|
-
throw error;
|
|
39123
|
-
}
|
|
39124
|
-
}
|
|
39125
|
-
async maxDeposit(amount) {
|
|
39126
|
-
const baseToken = this.config.baseToken;
|
|
39127
|
-
if (!amount) {
|
|
39128
|
-
return {
|
|
39129
|
-
tokenInfo: baseToken,
|
|
39130
|
-
amount: new Web3Number("999999999999999999999999999", baseToken.decimals),
|
|
39131
|
-
usdValue: 1e27,
|
|
39132
|
-
remarks: "Max deposit (unbounded placeholder)",
|
|
39133
|
-
apy: await this.getAPY({ asset: baseToken, isDebt: false }),
|
|
39134
|
-
protocol: this.protocol
|
|
39135
|
-
};
|
|
39136
|
-
}
|
|
39137
|
-
const usdValue = await this.getUSDValue(baseToken, amount);
|
|
39138
|
-
return {
|
|
39139
|
-
tokenInfo: baseToken,
|
|
39140
|
-
amount,
|
|
39141
|
-
usdValue,
|
|
39142
|
-
remarks: "Deposit amount",
|
|
39143
|
-
apy: await this.getAPY({ asset: baseToken, isDebt: false }),
|
|
39144
|
-
protocol: this.protocol
|
|
39145
|
-
};
|
|
39146
|
-
}
|
|
39147
|
-
async maxWithdraw() {
|
|
39148
|
-
const baseToken = this.config.baseToken;
|
|
39149
|
-
const current = await this.getPosition({ asset: baseToken, isDebt: false });
|
|
39150
|
-
const pos = current ?? { amount: new Web3Number("0", baseToken.decimals), remarks: "" };
|
|
39151
|
-
const usdValue = await this.getUSDValue(baseToken, pos.amount);
|
|
39152
|
-
return {
|
|
39153
|
-
tokenInfo: baseToken,
|
|
39154
|
-
amount: pos.amount,
|
|
39155
|
-
usdValue,
|
|
39156
|
-
remarks: "Max withdraw (liquid + pending redemption, underlying units)",
|
|
39157
|
-
apy: await this.getAPY({ asset: baseToken, isDebt: false }),
|
|
39158
|
-
protocol: this.protocol
|
|
39159
|
-
};
|
|
39160
|
-
}
|
|
39161
|
-
_getDepositLeaf() {
|
|
39162
|
-
const baseToken = this.config.baseToken;
|
|
39163
|
-
const strategyVault = this.config.strategyVault;
|
|
39164
|
-
const receiver = this.config.vaultAllocator;
|
|
39165
|
-
return [
|
|
39057
|
+
// src/data/redeem-request-nft.abi.json
|
|
39058
|
+
var redeem_request_nft_abi_default = [
|
|
39059
|
+
{
|
|
39060
|
+
type: "impl",
|
|
39061
|
+
name: "RedeemRequestImpl",
|
|
39062
|
+
interface_name: "vault::redeem_request::interface::IRedeemRequest"
|
|
39063
|
+
},
|
|
39064
|
+
{
|
|
39065
|
+
type: "struct",
|
|
39066
|
+
name: "core::integer::u256",
|
|
39067
|
+
members: [
|
|
39166
39068
|
{
|
|
39167
|
-
|
|
39168
|
-
|
|
39169
|
-
packedArguments: [strategyVault.toBigInt()],
|
|
39170
|
-
sanitizer: SIMPLE_SANITIZER,
|
|
39171
|
-
id: this._depositApproveProofReadableId()
|
|
39069
|
+
name: "low",
|
|
39070
|
+
type: "core::integer::u128"
|
|
39172
39071
|
},
|
|
39173
39072
|
{
|
|
39174
|
-
|
|
39175
|
-
|
|
39176
|
-
packedArguments: [receiver.toBigInt()],
|
|
39177
|
-
sanitizer: SIMPLE_SANITIZER,
|
|
39178
|
-
id: this._depositCallProofReadableId()
|
|
39179
|
-
}
|
|
39180
|
-
];
|
|
39181
|
-
}
|
|
39182
|
-
_getWithdrawLeaf() {
|
|
39183
|
-
const strategyVault = this.config.strategyVault;
|
|
39184
|
-
const recv = this.config.vaultAllocator;
|
|
39185
|
-
const owner = this.config.vaultAllocator;
|
|
39186
|
-
return [
|
|
39187
|
-
{
|
|
39188
|
-
target: strategyVault,
|
|
39189
|
-
method: "withdraw",
|
|
39190
|
-
packedArguments: [recv.toBigInt(), owner.toBigInt()],
|
|
39191
|
-
sanitizer: SIMPLE_SANITIZER,
|
|
39192
|
-
id: this._withdrawCallProofReadableId()
|
|
39073
|
+
name: "high",
|
|
39074
|
+
type: "core::integer::u128"
|
|
39193
39075
|
}
|
|
39194
|
-
]
|
|
39195
|
-
}
|
|
39196
|
-
|
|
39197
|
-
|
|
39198
|
-
|
|
39199
|
-
|
|
39200
|
-
return this.constructSimpleLeafData({ id, target, method, packedArguments }, sanitizer);
|
|
39201
|
-
});
|
|
39202
|
-
return { leaves, callConstructor: this.getDepositCall.bind(this) };
|
|
39203
|
-
}
|
|
39204
|
-
getWithdrawAdapter() {
|
|
39205
|
-
const leafConfigs = this._getWithdrawLeaf();
|
|
39206
|
-
const leaves = leafConfigs.map((config) => {
|
|
39207
|
-
const { target, method, packedArguments, sanitizer, id } = config;
|
|
39208
|
-
return this.constructSimpleLeafData({ id, target, method, packedArguments }, sanitizer);
|
|
39209
|
-
});
|
|
39210
|
-
return { leaves, callConstructor: this.getWithdrawCall.bind(this) };
|
|
39211
|
-
}
|
|
39212
|
-
async getDepositCall(params) {
|
|
39213
|
-
const baseToken = this.config.baseToken;
|
|
39214
|
-
const strategyVault = this.config.strategyVault;
|
|
39215
|
-
const amount = params.amount;
|
|
39216
|
-
const uint256Amount = uint25619.bnToUint256(amount.toWei());
|
|
39217
|
-
const receiver = this.config.vaultAllocator;
|
|
39218
|
-
return [
|
|
39076
|
+
]
|
|
39077
|
+
},
|
|
39078
|
+
{
|
|
39079
|
+
type: "struct",
|
|
39080
|
+
name: "vault::redeem_request::interface::RedeemRequestInfo",
|
|
39081
|
+
members: [
|
|
39219
39082
|
{
|
|
39220
|
-
|
|
39221
|
-
|
|
39222
|
-
call: {
|
|
39223
|
-
contractAddress: baseToken.address,
|
|
39224
|
-
selector: hash11.getSelectorFromName("approve"),
|
|
39225
|
-
calldata: [
|
|
39226
|
-
strategyVault.toBigInt(),
|
|
39227
|
-
toBigInt(uint256Amount.low.toString()),
|
|
39228
|
-
toBigInt(uint256Amount.high.toString())
|
|
39229
|
-
]
|
|
39230
|
-
}
|
|
39083
|
+
name: "epoch",
|
|
39084
|
+
type: "core::integer::u256"
|
|
39231
39085
|
},
|
|
39232
39086
|
{
|
|
39233
|
-
|
|
39087
|
+
name: "nominal",
|
|
39088
|
+
type: "core::integer::u256"
|
|
39089
|
+
}
|
|
39090
|
+
]
|
|
39091
|
+
},
|
|
39092
|
+
{
|
|
39093
|
+
type: "interface",
|
|
39094
|
+
name: "vault::redeem_request::interface::IRedeemRequest",
|
|
39095
|
+
items: [
|
|
39096
|
+
{
|
|
39097
|
+
type: "function",
|
|
39098
|
+
name: "vault",
|
|
39099
|
+
inputs: [],
|
|
39100
|
+
outputs: [
|
|
39101
|
+
{
|
|
39102
|
+
type: "core::starknet::contract_address::ContractAddress"
|
|
39103
|
+
}
|
|
39104
|
+
],
|
|
39105
|
+
state_mutability: "view"
|
|
39106
|
+
},
|
|
39107
|
+
{
|
|
39108
|
+
type: "function",
|
|
39109
|
+
name: "id_to_info",
|
|
39110
|
+
inputs: [
|
|
39111
|
+
{
|
|
39112
|
+
name: "id",
|
|
39113
|
+
type: "core::integer::u256"
|
|
39114
|
+
}
|
|
39115
|
+
],
|
|
39116
|
+
outputs: [
|
|
39117
|
+
{
|
|
39118
|
+
type: "vault::redeem_request::interface::RedeemRequestInfo"
|
|
39119
|
+
}
|
|
39120
|
+
],
|
|
39121
|
+
state_mutability: "view"
|
|
39122
|
+
},
|
|
39123
|
+
{
|
|
39124
|
+
type: "function",
|
|
39125
|
+
name: "id_len",
|
|
39126
|
+
inputs: [],
|
|
39127
|
+
outputs: [
|
|
39128
|
+
{
|
|
39129
|
+
type: "core::integer::u256"
|
|
39130
|
+
}
|
|
39131
|
+
],
|
|
39132
|
+
state_mutability: "view"
|
|
39133
|
+
},
|
|
39134
|
+
{
|
|
39135
|
+
type: "function",
|
|
39136
|
+
name: "mint",
|
|
39137
|
+
inputs: [
|
|
39138
|
+
{
|
|
39139
|
+
name: "to",
|
|
39140
|
+
type: "core::starknet::contract_address::ContractAddress"
|
|
39141
|
+
},
|
|
39142
|
+
{
|
|
39143
|
+
name: "redeem_request_info",
|
|
39144
|
+
type: "vault::redeem_request::interface::RedeemRequestInfo"
|
|
39145
|
+
}
|
|
39146
|
+
],
|
|
39147
|
+
outputs: [
|
|
39148
|
+
{
|
|
39149
|
+
type: "core::integer::u256"
|
|
39150
|
+
}
|
|
39151
|
+
],
|
|
39152
|
+
state_mutability: "external"
|
|
39153
|
+
},
|
|
39154
|
+
{
|
|
39155
|
+
type: "function",
|
|
39156
|
+
name: "burn",
|
|
39157
|
+
inputs: [
|
|
39158
|
+
{
|
|
39159
|
+
name: "id",
|
|
39160
|
+
type: "core::integer::u256"
|
|
39161
|
+
}
|
|
39162
|
+
],
|
|
39163
|
+
outputs: [],
|
|
39164
|
+
state_mutability: "external"
|
|
39165
|
+
}
|
|
39166
|
+
]
|
|
39167
|
+
},
|
|
39168
|
+
{
|
|
39169
|
+
type: "impl",
|
|
39170
|
+
name: "UpgradeableImpl",
|
|
39171
|
+
interface_name: "openzeppelin_interfaces::upgrades::IUpgradeable"
|
|
39172
|
+
},
|
|
39173
|
+
{
|
|
39174
|
+
type: "interface",
|
|
39175
|
+
name: "openzeppelin_interfaces::upgrades::IUpgradeable",
|
|
39176
|
+
items: [
|
|
39177
|
+
{
|
|
39178
|
+
type: "function",
|
|
39179
|
+
name: "upgrade",
|
|
39180
|
+
inputs: [
|
|
39181
|
+
{
|
|
39182
|
+
name: "new_class_hash",
|
|
39183
|
+
type: "core::starknet::class_hash::ClassHash"
|
|
39184
|
+
}
|
|
39185
|
+
],
|
|
39186
|
+
outputs: [],
|
|
39187
|
+
state_mutability: "external"
|
|
39188
|
+
}
|
|
39189
|
+
]
|
|
39190
|
+
},
|
|
39191
|
+
{
|
|
39192
|
+
type: "impl",
|
|
39193
|
+
name: "ERC721MixinImpl",
|
|
39194
|
+
interface_name: "openzeppelin_interfaces::token::erc721::ERC721ABI"
|
|
39195
|
+
},
|
|
39196
|
+
{
|
|
39197
|
+
type: "struct",
|
|
39198
|
+
name: "core::array::Span::<core::felt252>",
|
|
39199
|
+
members: [
|
|
39200
|
+
{
|
|
39201
|
+
name: "snapshot",
|
|
39202
|
+
type: "@core::array::Array::<core::felt252>"
|
|
39203
|
+
}
|
|
39204
|
+
]
|
|
39205
|
+
},
|
|
39206
|
+
{
|
|
39207
|
+
type: "enum",
|
|
39208
|
+
name: "core::bool",
|
|
39209
|
+
variants: [
|
|
39210
|
+
{
|
|
39211
|
+
name: "False",
|
|
39212
|
+
type: "()"
|
|
39213
|
+
},
|
|
39214
|
+
{
|
|
39215
|
+
name: "True",
|
|
39216
|
+
type: "()"
|
|
39217
|
+
}
|
|
39218
|
+
]
|
|
39219
|
+
},
|
|
39220
|
+
{
|
|
39221
|
+
type: "struct",
|
|
39222
|
+
name: "core::byte_array::ByteArray",
|
|
39223
|
+
members: [
|
|
39224
|
+
{
|
|
39225
|
+
name: "data",
|
|
39226
|
+
type: "core::array::Array::<core::bytes_31::bytes31>"
|
|
39227
|
+
},
|
|
39228
|
+
{
|
|
39229
|
+
name: "pending_word",
|
|
39230
|
+
type: "core::felt252"
|
|
39231
|
+
},
|
|
39232
|
+
{
|
|
39233
|
+
name: "pending_word_len",
|
|
39234
|
+
type: "core::integer::u32"
|
|
39235
|
+
}
|
|
39236
|
+
]
|
|
39237
|
+
},
|
|
39238
|
+
{
|
|
39239
|
+
type: "interface",
|
|
39240
|
+
name: "openzeppelin_interfaces::token::erc721::ERC721ABI",
|
|
39241
|
+
items: [
|
|
39242
|
+
{
|
|
39243
|
+
type: "function",
|
|
39244
|
+
name: "balance_of",
|
|
39245
|
+
inputs: [
|
|
39246
|
+
{
|
|
39247
|
+
name: "account",
|
|
39248
|
+
type: "core::starknet::contract_address::ContractAddress"
|
|
39249
|
+
}
|
|
39250
|
+
],
|
|
39251
|
+
outputs: [
|
|
39252
|
+
{
|
|
39253
|
+
type: "core::integer::u256"
|
|
39254
|
+
}
|
|
39255
|
+
],
|
|
39256
|
+
state_mutability: "view"
|
|
39257
|
+
},
|
|
39258
|
+
{
|
|
39259
|
+
type: "function",
|
|
39260
|
+
name: "owner_of",
|
|
39261
|
+
inputs: [
|
|
39262
|
+
{
|
|
39263
|
+
name: "token_id",
|
|
39264
|
+
type: "core::integer::u256"
|
|
39265
|
+
}
|
|
39266
|
+
],
|
|
39267
|
+
outputs: [
|
|
39268
|
+
{
|
|
39269
|
+
type: "core::starknet::contract_address::ContractAddress"
|
|
39270
|
+
}
|
|
39271
|
+
],
|
|
39272
|
+
state_mutability: "view"
|
|
39273
|
+
},
|
|
39274
|
+
{
|
|
39275
|
+
type: "function",
|
|
39276
|
+
name: "safe_transfer_from",
|
|
39277
|
+
inputs: [
|
|
39278
|
+
{
|
|
39279
|
+
name: "from",
|
|
39280
|
+
type: "core::starknet::contract_address::ContractAddress"
|
|
39281
|
+
},
|
|
39282
|
+
{
|
|
39283
|
+
name: "to",
|
|
39284
|
+
type: "core::starknet::contract_address::ContractAddress"
|
|
39285
|
+
},
|
|
39286
|
+
{
|
|
39287
|
+
name: "token_id",
|
|
39288
|
+
type: "core::integer::u256"
|
|
39289
|
+
},
|
|
39290
|
+
{
|
|
39291
|
+
name: "data",
|
|
39292
|
+
type: "core::array::Span::<core::felt252>"
|
|
39293
|
+
}
|
|
39294
|
+
],
|
|
39295
|
+
outputs: [],
|
|
39296
|
+
state_mutability: "external"
|
|
39297
|
+
},
|
|
39298
|
+
{
|
|
39299
|
+
type: "function",
|
|
39300
|
+
name: "transfer_from",
|
|
39301
|
+
inputs: [
|
|
39302
|
+
{
|
|
39303
|
+
name: "from",
|
|
39304
|
+
type: "core::starknet::contract_address::ContractAddress"
|
|
39305
|
+
},
|
|
39306
|
+
{
|
|
39307
|
+
name: "to",
|
|
39308
|
+
type: "core::starknet::contract_address::ContractAddress"
|
|
39309
|
+
},
|
|
39310
|
+
{
|
|
39311
|
+
name: "token_id",
|
|
39312
|
+
type: "core::integer::u256"
|
|
39313
|
+
}
|
|
39314
|
+
],
|
|
39315
|
+
outputs: [],
|
|
39316
|
+
state_mutability: "external"
|
|
39317
|
+
},
|
|
39318
|
+
{
|
|
39319
|
+
type: "function",
|
|
39320
|
+
name: "approve",
|
|
39321
|
+
inputs: [
|
|
39322
|
+
{
|
|
39323
|
+
name: "to",
|
|
39324
|
+
type: "core::starknet::contract_address::ContractAddress"
|
|
39325
|
+
},
|
|
39326
|
+
{
|
|
39327
|
+
name: "token_id",
|
|
39328
|
+
type: "core::integer::u256"
|
|
39329
|
+
}
|
|
39330
|
+
],
|
|
39331
|
+
outputs: [],
|
|
39332
|
+
state_mutability: "external"
|
|
39333
|
+
},
|
|
39334
|
+
{
|
|
39335
|
+
type: "function",
|
|
39336
|
+
name: "set_approval_for_all",
|
|
39337
|
+
inputs: [
|
|
39338
|
+
{
|
|
39339
|
+
name: "operator",
|
|
39340
|
+
type: "core::starknet::contract_address::ContractAddress"
|
|
39341
|
+
},
|
|
39342
|
+
{
|
|
39343
|
+
name: "approved",
|
|
39344
|
+
type: "core::bool"
|
|
39345
|
+
}
|
|
39346
|
+
],
|
|
39347
|
+
outputs: [],
|
|
39348
|
+
state_mutability: "external"
|
|
39349
|
+
},
|
|
39350
|
+
{
|
|
39351
|
+
type: "function",
|
|
39352
|
+
name: "get_approved",
|
|
39353
|
+
inputs: [
|
|
39354
|
+
{
|
|
39355
|
+
name: "token_id",
|
|
39356
|
+
type: "core::integer::u256"
|
|
39357
|
+
}
|
|
39358
|
+
],
|
|
39359
|
+
outputs: [
|
|
39360
|
+
{
|
|
39361
|
+
type: "core::starknet::contract_address::ContractAddress"
|
|
39362
|
+
}
|
|
39363
|
+
],
|
|
39364
|
+
state_mutability: "view"
|
|
39365
|
+
},
|
|
39366
|
+
{
|
|
39367
|
+
type: "function",
|
|
39368
|
+
name: "is_approved_for_all",
|
|
39369
|
+
inputs: [
|
|
39370
|
+
{
|
|
39371
|
+
name: "owner",
|
|
39372
|
+
type: "core::starknet::contract_address::ContractAddress"
|
|
39373
|
+
},
|
|
39374
|
+
{
|
|
39375
|
+
name: "operator",
|
|
39376
|
+
type: "core::starknet::contract_address::ContractAddress"
|
|
39377
|
+
}
|
|
39378
|
+
],
|
|
39379
|
+
outputs: [
|
|
39380
|
+
{
|
|
39381
|
+
type: "core::bool"
|
|
39382
|
+
}
|
|
39383
|
+
],
|
|
39384
|
+
state_mutability: "view"
|
|
39385
|
+
},
|
|
39386
|
+
{
|
|
39387
|
+
type: "function",
|
|
39388
|
+
name: "supports_interface",
|
|
39389
|
+
inputs: [
|
|
39390
|
+
{
|
|
39391
|
+
name: "interface_id",
|
|
39392
|
+
type: "core::felt252"
|
|
39393
|
+
}
|
|
39394
|
+
],
|
|
39395
|
+
outputs: [
|
|
39396
|
+
{
|
|
39397
|
+
type: "core::bool"
|
|
39398
|
+
}
|
|
39399
|
+
],
|
|
39400
|
+
state_mutability: "view"
|
|
39401
|
+
},
|
|
39402
|
+
{
|
|
39403
|
+
type: "function",
|
|
39404
|
+
name: "name",
|
|
39405
|
+
inputs: [],
|
|
39406
|
+
outputs: [
|
|
39407
|
+
{
|
|
39408
|
+
type: "core::byte_array::ByteArray"
|
|
39409
|
+
}
|
|
39410
|
+
],
|
|
39411
|
+
state_mutability: "view"
|
|
39412
|
+
},
|
|
39413
|
+
{
|
|
39414
|
+
type: "function",
|
|
39415
|
+
name: "symbol",
|
|
39416
|
+
inputs: [],
|
|
39417
|
+
outputs: [
|
|
39418
|
+
{
|
|
39419
|
+
type: "core::byte_array::ByteArray"
|
|
39420
|
+
}
|
|
39421
|
+
],
|
|
39422
|
+
state_mutability: "view"
|
|
39423
|
+
},
|
|
39424
|
+
{
|
|
39425
|
+
type: "function",
|
|
39426
|
+
name: "token_uri",
|
|
39427
|
+
inputs: [
|
|
39428
|
+
{
|
|
39429
|
+
name: "token_id",
|
|
39430
|
+
type: "core::integer::u256"
|
|
39431
|
+
}
|
|
39432
|
+
],
|
|
39433
|
+
outputs: [
|
|
39434
|
+
{
|
|
39435
|
+
type: "core::byte_array::ByteArray"
|
|
39436
|
+
}
|
|
39437
|
+
],
|
|
39438
|
+
state_mutability: "view"
|
|
39439
|
+
},
|
|
39440
|
+
{
|
|
39441
|
+
type: "function",
|
|
39442
|
+
name: "balanceOf",
|
|
39443
|
+
inputs: [
|
|
39444
|
+
{
|
|
39445
|
+
name: "account",
|
|
39446
|
+
type: "core::starknet::contract_address::ContractAddress"
|
|
39447
|
+
}
|
|
39448
|
+
],
|
|
39449
|
+
outputs: [
|
|
39450
|
+
{
|
|
39451
|
+
type: "core::integer::u256"
|
|
39452
|
+
}
|
|
39453
|
+
],
|
|
39454
|
+
state_mutability: "view"
|
|
39455
|
+
},
|
|
39456
|
+
{
|
|
39457
|
+
type: "function",
|
|
39458
|
+
name: "ownerOf",
|
|
39459
|
+
inputs: [
|
|
39460
|
+
{
|
|
39461
|
+
name: "tokenId",
|
|
39462
|
+
type: "core::integer::u256"
|
|
39463
|
+
}
|
|
39464
|
+
],
|
|
39465
|
+
outputs: [
|
|
39466
|
+
{
|
|
39467
|
+
type: "core::starknet::contract_address::ContractAddress"
|
|
39468
|
+
}
|
|
39469
|
+
],
|
|
39470
|
+
state_mutability: "view"
|
|
39471
|
+
},
|
|
39472
|
+
{
|
|
39473
|
+
type: "function",
|
|
39474
|
+
name: "safeTransferFrom",
|
|
39475
|
+
inputs: [
|
|
39476
|
+
{
|
|
39477
|
+
name: "from",
|
|
39478
|
+
type: "core::starknet::contract_address::ContractAddress"
|
|
39479
|
+
},
|
|
39480
|
+
{
|
|
39481
|
+
name: "to",
|
|
39482
|
+
type: "core::starknet::contract_address::ContractAddress"
|
|
39483
|
+
},
|
|
39484
|
+
{
|
|
39485
|
+
name: "tokenId",
|
|
39486
|
+
type: "core::integer::u256"
|
|
39487
|
+
},
|
|
39488
|
+
{
|
|
39489
|
+
name: "data",
|
|
39490
|
+
type: "core::array::Span::<core::felt252>"
|
|
39491
|
+
}
|
|
39492
|
+
],
|
|
39493
|
+
outputs: [],
|
|
39494
|
+
state_mutability: "external"
|
|
39495
|
+
},
|
|
39496
|
+
{
|
|
39497
|
+
type: "function",
|
|
39498
|
+
name: "transferFrom",
|
|
39499
|
+
inputs: [
|
|
39500
|
+
{
|
|
39501
|
+
name: "from",
|
|
39502
|
+
type: "core::starknet::contract_address::ContractAddress"
|
|
39503
|
+
},
|
|
39504
|
+
{
|
|
39505
|
+
name: "to",
|
|
39506
|
+
type: "core::starknet::contract_address::ContractAddress"
|
|
39507
|
+
},
|
|
39508
|
+
{
|
|
39509
|
+
name: "tokenId",
|
|
39510
|
+
type: "core::integer::u256"
|
|
39511
|
+
}
|
|
39512
|
+
],
|
|
39513
|
+
outputs: [],
|
|
39514
|
+
state_mutability: "external"
|
|
39515
|
+
},
|
|
39516
|
+
{
|
|
39517
|
+
type: "function",
|
|
39518
|
+
name: "setApprovalForAll",
|
|
39519
|
+
inputs: [
|
|
39520
|
+
{
|
|
39521
|
+
name: "operator",
|
|
39522
|
+
type: "core::starknet::contract_address::ContractAddress"
|
|
39523
|
+
},
|
|
39524
|
+
{
|
|
39525
|
+
name: "approved",
|
|
39526
|
+
type: "core::bool"
|
|
39527
|
+
}
|
|
39528
|
+
],
|
|
39529
|
+
outputs: [],
|
|
39530
|
+
state_mutability: "external"
|
|
39531
|
+
},
|
|
39532
|
+
{
|
|
39533
|
+
type: "function",
|
|
39534
|
+
name: "getApproved",
|
|
39535
|
+
inputs: [
|
|
39536
|
+
{
|
|
39537
|
+
name: "tokenId",
|
|
39538
|
+
type: "core::integer::u256"
|
|
39539
|
+
}
|
|
39540
|
+
],
|
|
39541
|
+
outputs: [
|
|
39542
|
+
{
|
|
39543
|
+
type: "core::starknet::contract_address::ContractAddress"
|
|
39544
|
+
}
|
|
39545
|
+
],
|
|
39546
|
+
state_mutability: "view"
|
|
39547
|
+
},
|
|
39548
|
+
{
|
|
39549
|
+
type: "function",
|
|
39550
|
+
name: "isApprovedForAll",
|
|
39551
|
+
inputs: [
|
|
39552
|
+
{
|
|
39553
|
+
name: "owner",
|
|
39554
|
+
type: "core::starknet::contract_address::ContractAddress"
|
|
39555
|
+
},
|
|
39556
|
+
{
|
|
39557
|
+
name: "operator",
|
|
39558
|
+
type: "core::starknet::contract_address::ContractAddress"
|
|
39559
|
+
}
|
|
39560
|
+
],
|
|
39561
|
+
outputs: [
|
|
39562
|
+
{
|
|
39563
|
+
type: "core::bool"
|
|
39564
|
+
}
|
|
39565
|
+
],
|
|
39566
|
+
state_mutability: "view"
|
|
39567
|
+
},
|
|
39568
|
+
{
|
|
39569
|
+
type: "function",
|
|
39570
|
+
name: "tokenURI",
|
|
39571
|
+
inputs: [
|
|
39572
|
+
{
|
|
39573
|
+
name: "tokenId",
|
|
39574
|
+
type: "core::integer::u256"
|
|
39575
|
+
}
|
|
39576
|
+
],
|
|
39577
|
+
outputs: [
|
|
39578
|
+
{
|
|
39579
|
+
type: "core::byte_array::ByteArray"
|
|
39580
|
+
}
|
|
39581
|
+
],
|
|
39582
|
+
state_mutability: "view"
|
|
39583
|
+
}
|
|
39584
|
+
]
|
|
39585
|
+
},
|
|
39586
|
+
{
|
|
39587
|
+
type: "impl",
|
|
39588
|
+
name: "ERC721EnumerableImpl",
|
|
39589
|
+
interface_name: "openzeppelin_interfaces::token::erc721::IERC721Enumerable"
|
|
39590
|
+
},
|
|
39591
|
+
{
|
|
39592
|
+
type: "interface",
|
|
39593
|
+
name: "openzeppelin_interfaces::token::erc721::IERC721Enumerable",
|
|
39594
|
+
items: [
|
|
39595
|
+
{
|
|
39596
|
+
type: "function",
|
|
39597
|
+
name: "total_supply",
|
|
39598
|
+
inputs: [],
|
|
39599
|
+
outputs: [
|
|
39600
|
+
{
|
|
39601
|
+
type: "core::integer::u256"
|
|
39602
|
+
}
|
|
39603
|
+
],
|
|
39604
|
+
state_mutability: "view"
|
|
39605
|
+
},
|
|
39606
|
+
{
|
|
39607
|
+
type: "function",
|
|
39608
|
+
name: "token_by_index",
|
|
39609
|
+
inputs: [
|
|
39610
|
+
{
|
|
39611
|
+
name: "index",
|
|
39612
|
+
type: "core::integer::u256"
|
|
39613
|
+
}
|
|
39614
|
+
],
|
|
39615
|
+
outputs: [
|
|
39616
|
+
{
|
|
39617
|
+
type: "core::integer::u256"
|
|
39618
|
+
}
|
|
39619
|
+
],
|
|
39620
|
+
state_mutability: "view"
|
|
39621
|
+
},
|
|
39622
|
+
{
|
|
39623
|
+
type: "function",
|
|
39624
|
+
name: "token_of_owner_by_index",
|
|
39625
|
+
inputs: [
|
|
39626
|
+
{
|
|
39627
|
+
name: "owner",
|
|
39628
|
+
type: "core::starknet::contract_address::ContractAddress"
|
|
39629
|
+
},
|
|
39630
|
+
{
|
|
39631
|
+
name: "index",
|
|
39632
|
+
type: "core::integer::u256"
|
|
39633
|
+
}
|
|
39634
|
+
],
|
|
39635
|
+
outputs: [
|
|
39636
|
+
{
|
|
39637
|
+
type: "core::integer::u256"
|
|
39638
|
+
}
|
|
39639
|
+
],
|
|
39640
|
+
state_mutability: "view"
|
|
39641
|
+
}
|
|
39642
|
+
]
|
|
39643
|
+
},
|
|
39644
|
+
{
|
|
39645
|
+
type: "constructor",
|
|
39646
|
+
name: "constructor",
|
|
39647
|
+
inputs: [
|
|
39648
|
+
{
|
|
39649
|
+
name: "owner",
|
|
39650
|
+
type: "core::starknet::contract_address::ContractAddress"
|
|
39651
|
+
},
|
|
39652
|
+
{
|
|
39653
|
+
name: "vault",
|
|
39654
|
+
type: "core::starknet::contract_address::ContractAddress"
|
|
39655
|
+
}
|
|
39656
|
+
]
|
|
39657
|
+
},
|
|
39658
|
+
{
|
|
39659
|
+
type: "event",
|
|
39660
|
+
name: "openzeppelin_token::erc721::erc721::ERC721Component::Transfer",
|
|
39661
|
+
kind: "struct",
|
|
39662
|
+
members: [
|
|
39663
|
+
{
|
|
39664
|
+
name: "from",
|
|
39665
|
+
type: "core::starknet::contract_address::ContractAddress",
|
|
39666
|
+
kind: "key"
|
|
39667
|
+
},
|
|
39668
|
+
{
|
|
39669
|
+
name: "to",
|
|
39670
|
+
type: "core::starknet::contract_address::ContractAddress",
|
|
39671
|
+
kind: "key"
|
|
39672
|
+
},
|
|
39673
|
+
{
|
|
39674
|
+
name: "token_id",
|
|
39675
|
+
type: "core::integer::u256",
|
|
39676
|
+
kind: "key"
|
|
39677
|
+
}
|
|
39678
|
+
]
|
|
39679
|
+
},
|
|
39680
|
+
{
|
|
39681
|
+
type: "event",
|
|
39682
|
+
name: "openzeppelin_token::erc721::erc721::ERC721Component::Approval",
|
|
39683
|
+
kind: "struct",
|
|
39684
|
+
members: [
|
|
39685
|
+
{
|
|
39686
|
+
name: "owner",
|
|
39687
|
+
type: "core::starknet::contract_address::ContractAddress",
|
|
39688
|
+
kind: "key"
|
|
39689
|
+
},
|
|
39690
|
+
{
|
|
39691
|
+
name: "approved",
|
|
39692
|
+
type: "core::starknet::contract_address::ContractAddress",
|
|
39693
|
+
kind: "key"
|
|
39694
|
+
},
|
|
39695
|
+
{
|
|
39696
|
+
name: "token_id",
|
|
39697
|
+
type: "core::integer::u256",
|
|
39698
|
+
kind: "key"
|
|
39699
|
+
}
|
|
39700
|
+
]
|
|
39701
|
+
},
|
|
39702
|
+
{
|
|
39703
|
+
type: "event",
|
|
39704
|
+
name: "openzeppelin_token::erc721::erc721::ERC721Component::ApprovalForAll",
|
|
39705
|
+
kind: "struct",
|
|
39706
|
+
members: [
|
|
39707
|
+
{
|
|
39708
|
+
name: "owner",
|
|
39709
|
+
type: "core::starknet::contract_address::ContractAddress",
|
|
39710
|
+
kind: "key"
|
|
39711
|
+
},
|
|
39712
|
+
{
|
|
39713
|
+
name: "operator",
|
|
39714
|
+
type: "core::starknet::contract_address::ContractAddress",
|
|
39715
|
+
kind: "key"
|
|
39716
|
+
},
|
|
39717
|
+
{
|
|
39718
|
+
name: "approved",
|
|
39719
|
+
type: "core::bool",
|
|
39720
|
+
kind: "data"
|
|
39721
|
+
}
|
|
39722
|
+
]
|
|
39723
|
+
},
|
|
39724
|
+
{
|
|
39725
|
+
type: "event",
|
|
39726
|
+
name: "openzeppelin_token::erc721::erc721::ERC721Component::Event",
|
|
39727
|
+
kind: "enum",
|
|
39728
|
+
variants: [
|
|
39729
|
+
{
|
|
39730
|
+
name: "Transfer",
|
|
39731
|
+
type: "openzeppelin_token::erc721::erc721::ERC721Component::Transfer",
|
|
39732
|
+
kind: "nested"
|
|
39733
|
+
},
|
|
39734
|
+
{
|
|
39735
|
+
name: "Approval",
|
|
39736
|
+
type: "openzeppelin_token::erc721::erc721::ERC721Component::Approval",
|
|
39737
|
+
kind: "nested"
|
|
39738
|
+
},
|
|
39739
|
+
{
|
|
39740
|
+
name: "ApprovalForAll",
|
|
39741
|
+
type: "openzeppelin_token::erc721::erc721::ERC721Component::ApprovalForAll",
|
|
39742
|
+
kind: "nested"
|
|
39743
|
+
}
|
|
39744
|
+
]
|
|
39745
|
+
},
|
|
39746
|
+
{
|
|
39747
|
+
type: "event",
|
|
39748
|
+
name: "openzeppelin_token::erc721::extensions::erc721_enumerable::erc721_enumerable::ERC721EnumerableComponent::Event",
|
|
39749
|
+
kind: "enum",
|
|
39750
|
+
variants: []
|
|
39751
|
+
},
|
|
39752
|
+
{
|
|
39753
|
+
type: "event",
|
|
39754
|
+
name: "openzeppelin_introspection::src5::SRC5Component::Event",
|
|
39755
|
+
kind: "enum",
|
|
39756
|
+
variants: []
|
|
39757
|
+
},
|
|
39758
|
+
{
|
|
39759
|
+
type: "event",
|
|
39760
|
+
name: "openzeppelin_upgrades::upgradeable::UpgradeableComponent::Upgraded",
|
|
39761
|
+
kind: "struct",
|
|
39762
|
+
members: [
|
|
39763
|
+
{
|
|
39764
|
+
name: "class_hash",
|
|
39765
|
+
type: "core::starknet::class_hash::ClassHash",
|
|
39766
|
+
kind: "data"
|
|
39767
|
+
}
|
|
39768
|
+
]
|
|
39769
|
+
},
|
|
39770
|
+
{
|
|
39771
|
+
type: "event",
|
|
39772
|
+
name: "openzeppelin_upgrades::upgradeable::UpgradeableComponent::Event",
|
|
39773
|
+
kind: "enum",
|
|
39774
|
+
variants: [
|
|
39775
|
+
{
|
|
39776
|
+
name: "Upgraded",
|
|
39777
|
+
type: "openzeppelin_upgrades::upgradeable::UpgradeableComponent::Upgraded",
|
|
39778
|
+
kind: "nested"
|
|
39779
|
+
}
|
|
39780
|
+
]
|
|
39781
|
+
},
|
|
39782
|
+
{
|
|
39783
|
+
type: "event",
|
|
39784
|
+
name: "vault::redeem_request::redeem_request::RedeemRequest::Event",
|
|
39785
|
+
kind: "enum",
|
|
39786
|
+
variants: [
|
|
39787
|
+
{
|
|
39788
|
+
name: "ERC721Event",
|
|
39789
|
+
type: "openzeppelin_token::erc721::erc721::ERC721Component::Event",
|
|
39790
|
+
kind: "flat"
|
|
39791
|
+
},
|
|
39792
|
+
{
|
|
39793
|
+
name: "ERC721EnumerableEvent",
|
|
39794
|
+
type: "openzeppelin_token::erc721::extensions::erc721_enumerable::erc721_enumerable::ERC721EnumerableComponent::Event",
|
|
39795
|
+
kind: "flat"
|
|
39796
|
+
},
|
|
39797
|
+
{
|
|
39798
|
+
name: "SRC5Event",
|
|
39799
|
+
type: "openzeppelin_introspection::src5::SRC5Component::Event",
|
|
39800
|
+
kind: "flat"
|
|
39801
|
+
},
|
|
39802
|
+
{
|
|
39803
|
+
name: "UpgradeableEvent",
|
|
39804
|
+
type: "openzeppelin_upgrades::upgradeable::UpgradeableComponent::Event",
|
|
39805
|
+
kind: "flat"
|
|
39806
|
+
}
|
|
39807
|
+
]
|
|
39808
|
+
}
|
|
39809
|
+
];
|
|
39810
|
+
|
|
39811
|
+
// src/strategies/universal-adapters/svk-troves-adapter.ts
|
|
39812
|
+
var DEFAULT_TROVES_STRATEGIES_API = "https://app.troves.fi/api/strategies";
|
|
39813
|
+
function parseTrovesApyField(raw) {
|
|
39814
|
+
if (typeof raw === "number" && Number.isFinite(raw)) {
|
|
39815
|
+
return raw;
|
|
39816
|
+
}
|
|
39817
|
+
if (typeof raw === "string") {
|
|
39818
|
+
const n = Number.parseFloat(raw);
|
|
39819
|
+
if (Number.isFinite(n)) {
|
|
39820
|
+
return n;
|
|
39821
|
+
}
|
|
39822
|
+
}
|
|
39823
|
+
return 0;
|
|
39824
|
+
}
|
|
39825
|
+
var SvkTrovesAdapter = class _SvkTrovesAdapter extends BaseAdapter {
|
|
39826
|
+
constructor(config) {
|
|
39827
|
+
super(config, _SvkTrovesAdapter.name, Protocols.TROVES);
|
|
39828
|
+
this.config = config;
|
|
39829
|
+
}
|
|
39830
|
+
/** Owner used for share balance + `due_assets_from_owner`. */
|
|
39831
|
+
_positionOwner() {
|
|
39832
|
+
return this.config.positionOwner ?? this.config.vaultAllocator;
|
|
39833
|
+
}
|
|
39834
|
+
/**
|
|
39835
|
+
* Proof readable IDs must stay ≤ 31 chars (Cairo short string). We derive a short ASCII suffix from
|
|
39836
|
+
* `strategyVault` address so multiple SVK adapters in one tree stay distinct.
|
|
39837
|
+
*/
|
|
39838
|
+
_proofSuffix() {
|
|
39839
|
+
return this.config.strategyVault.address.replace(/^0x/, "").slice(-6);
|
|
39840
|
+
}
|
|
39841
|
+
_depositApproveProofReadableId() {
|
|
39842
|
+
return `appr_dep_svk_${this._proofSuffix()}`;
|
|
39843
|
+
}
|
|
39844
|
+
_depositCallProofReadableId() {
|
|
39845
|
+
return `dep_svk_${this._proofSuffix()}`;
|
|
39846
|
+
}
|
|
39847
|
+
_withdrawCallProofReadableId() {
|
|
39848
|
+
return `wtdrw_svk_${this._proofSuffix()}`;
|
|
39849
|
+
}
|
|
39850
|
+
async getAPY(supportedPosition) {
|
|
39851
|
+
const CACHE_KEY = `svk_apy_${this.config.trovesStrategyId}`;
|
|
39852
|
+
const cached = this.getCache(CACHE_KEY);
|
|
39853
|
+
if (cached) {
|
|
39854
|
+
return cached;
|
|
39855
|
+
}
|
|
39856
|
+
const url = this.config.trovesStrategiesApiUrl ?? DEFAULT_TROVES_STRATEGIES_API;
|
|
39857
|
+
try {
|
|
39858
|
+
const res = await fetch(url);
|
|
39859
|
+
if (!res.ok) {
|
|
39860
|
+
logger.warn(`${_SvkTrovesAdapter.name}::getAPY: HTTP ${res.status} from ${url}`);
|
|
39861
|
+
const fallback = { apy: 0, type: "base" /* BASE */ };
|
|
39862
|
+
this.setCache(CACHE_KEY, fallback, 3e5);
|
|
39863
|
+
return fallback;
|
|
39864
|
+
}
|
|
39865
|
+
const body = await res.json();
|
|
39866
|
+
const row = body.strategies?.find((s) => s.id === this.config.trovesStrategyId);
|
|
39867
|
+
if (!row) {
|
|
39868
|
+
logger.warn(
|
|
39869
|
+
`${_SvkTrovesAdapter.name}::getAPY: strategy id not found: ${this.config.trovesStrategyId}`
|
|
39870
|
+
);
|
|
39871
|
+
const fallback = { apy: 0, type: "base" /* BASE */ };
|
|
39872
|
+
this.setCache(CACHE_KEY, fallback, 3e5);
|
|
39873
|
+
return fallback;
|
|
39874
|
+
}
|
|
39875
|
+
const apy = parseTrovesApyField(row.apy);
|
|
39876
|
+
const result = { apy, type: "base" /* BASE */ };
|
|
39877
|
+
this.setCache(CACHE_KEY, result, 3e5);
|
|
39878
|
+
return result;
|
|
39879
|
+
} catch (error) {
|
|
39880
|
+
logger.error(`${_SvkTrovesAdapter.name}::getAPY:`, error);
|
|
39881
|
+
throw error;
|
|
39882
|
+
}
|
|
39883
|
+
}
|
|
39884
|
+
async getPosition(supportedPosition) {
|
|
39885
|
+
const CACHE_KEY = `svk_pos_${this.config.strategyVault.address}_${this._positionOwner().address}`;
|
|
39886
|
+
const cached = this.getCache(CACHE_KEY);
|
|
39887
|
+
if (cached) {
|
|
39888
|
+
return cached;
|
|
39889
|
+
}
|
|
39890
|
+
try {
|
|
39891
|
+
const vault = new Contract14({
|
|
39892
|
+
abi: universal_vault_abi_default,
|
|
39893
|
+
address: this.config.strategyVault.address,
|
|
39894
|
+
providerOrAccount: this.config.networkConfig.provider
|
|
39895
|
+
});
|
|
39896
|
+
const owner = this._positionOwner();
|
|
39897
|
+
const decimals = supportedPosition.asset.decimals;
|
|
39898
|
+
const shares = await vault.balance_of(owner.address);
|
|
39899
|
+
const shareU256 = uint25619.bnToUint256(shares);
|
|
39900
|
+
const liquidAssetsRaw = await vault.convert_to_assets(shareU256);
|
|
39901
|
+
const liquid = Web3Number.fromWei(liquidAssetsRaw.toString(), decimals);
|
|
39902
|
+
let pending = Web3Number.fromWei("0", decimals);
|
|
39903
|
+
try {
|
|
39904
|
+
const dueRaw = await vault.call("due_assets_from_owner", [owner.address]);
|
|
39905
|
+
pending = Web3Number.fromWei(dueRaw.toString(), decimals);
|
|
39906
|
+
} catch (e) {
|
|
39907
|
+
logger.warn(
|
|
39908
|
+
`${_SvkTrovesAdapter.name}::getPosition: due_assets_from_owner failed (treating as 0): ${e.message}`
|
|
39909
|
+
);
|
|
39910
|
+
}
|
|
39911
|
+
const total = liquid.plus(pending);
|
|
39912
|
+
const remarks = `Troves ${this.config.trovesStrategyId} holdings`;
|
|
39913
|
+
const result = {
|
|
39914
|
+
amount: total,
|
|
39915
|
+
remarks
|
|
39916
|
+
};
|
|
39917
|
+
this.setCache(CACHE_KEY, result, 6e4);
|
|
39918
|
+
return result;
|
|
39919
|
+
} catch (error) {
|
|
39920
|
+
logger.error(`${_SvkTrovesAdapter.name}::getPosition:`, error);
|
|
39921
|
+
throw error;
|
|
39922
|
+
}
|
|
39923
|
+
}
|
|
39924
|
+
async getPendingAssetsFromOwner(owner = this._positionOwner(), decimals = this.config.baseToken.decimals) {
|
|
39925
|
+
const vault = new Contract14({
|
|
39926
|
+
abi: universal_vault_abi_default,
|
|
39927
|
+
address: this.config.strategyVault.address,
|
|
39928
|
+
providerOrAccount: this.config.networkConfig.provider
|
|
39929
|
+
});
|
|
39930
|
+
try {
|
|
39931
|
+
const dueRaw = await vault.call("due_assets_from_owner", [owner.address]);
|
|
39932
|
+
return Web3Number.fromWei(dueRaw.toString(), decimals);
|
|
39933
|
+
} catch (e) {
|
|
39934
|
+
logger.warn(
|
|
39935
|
+
`${_SvkTrovesAdapter.name}::getPendingAssetsFromOwner: due_assets_from_owner failed (treating as 0): ${e.message}`
|
|
39936
|
+
);
|
|
39937
|
+
return Web3Number.fromWei("0", decimals);
|
|
39938
|
+
}
|
|
39939
|
+
}
|
|
39940
|
+
/**
|
|
39941
|
+
* Get pending assets from owner by scanning redeem request NFTs.
|
|
39942
|
+
* This method iterates backwards through NFT IDs to find all pending redemptions for a specific owner.
|
|
39943
|
+
*
|
|
39944
|
+
* @param redeemRequestNFT - The redeem request NFT contract address
|
|
39945
|
+
* @param owner - The owner address to check for pending redemptions (defaults to positionOwner)
|
|
39946
|
+
* @param decimals - Token decimals for conversion (defaults to baseToken decimals)
|
|
39947
|
+
* @returns Total pending assets from all NFTs owned by the specified address
|
|
39948
|
+
*/
|
|
39949
|
+
async getPendingAssetsFromOwnerNFTMethod(redeemRequestNFT, owner = this._positionOwner(), decimals = this.config.baseToken.decimals) {
|
|
39950
|
+
try {
|
|
39951
|
+
const nftContract = new Contract14({
|
|
39952
|
+
abi: redeem_request_nft_abi_default,
|
|
39953
|
+
address: redeemRequestNFT.address,
|
|
39954
|
+
providerOrAccount: this.config.networkConfig.provider
|
|
39955
|
+
});
|
|
39956
|
+
const idLenRaw = await nftContract.id_len();
|
|
39957
|
+
const latestId = BigInt(idLenRaw.toString());
|
|
39958
|
+
if (latestId === 0n) {
|
|
39959
|
+
logger.info(
|
|
39960
|
+
`${_SvkTrovesAdapter.name}::getPendingAssetsFromOwnerNFTMethod: No NFTs minted yet`
|
|
39961
|
+
);
|
|
39962
|
+
return Web3Number.fromWei("0", decimals);
|
|
39963
|
+
}
|
|
39964
|
+
const matchingIds = [];
|
|
39965
|
+
let currentId = latestId - 1n;
|
|
39966
|
+
while (currentId >= 0n) {
|
|
39967
|
+
try {
|
|
39968
|
+
const idU256 = uint25619.bnToUint256(currentId);
|
|
39969
|
+
const ownerRaw = await nftContract.owner_of(idU256);
|
|
39970
|
+
const nftOwnerAddr = ContractAddr.from(ownerRaw.toString());
|
|
39971
|
+
if (nftOwnerAddr.eq(owner)) {
|
|
39972
|
+
matchingIds.push(currentId);
|
|
39973
|
+
logger.debug(
|
|
39974
|
+
`${_SvkTrovesAdapter.name}::getPendingAssetsFromOwnerNFTMethod: Found matching NFT ID ${currentId} for owner ${owner.address}`
|
|
39975
|
+
);
|
|
39976
|
+
}
|
|
39977
|
+
currentId--;
|
|
39978
|
+
} catch (e) {
|
|
39979
|
+
logger.info(
|
|
39980
|
+
`${_SvkTrovesAdapter.name}::getPendingAssetsFromOwnerNFTMethod: Reached last pending NFT at id ${currentId}`
|
|
39981
|
+
);
|
|
39982
|
+
break;
|
|
39983
|
+
}
|
|
39984
|
+
}
|
|
39985
|
+
if (matchingIds.length === 0) {
|
|
39986
|
+
logger.info(
|
|
39987
|
+
`${_SvkTrovesAdapter.name}::getPendingAssetsFromOwnerNFTMethod: No matching NFTs found for owner ${owner.address}`
|
|
39988
|
+
);
|
|
39989
|
+
return Web3Number.fromWei("0", decimals);
|
|
39990
|
+
}
|
|
39991
|
+
let totalNominal = 0n;
|
|
39992
|
+
for (const nftId of matchingIds) {
|
|
39993
|
+
try {
|
|
39994
|
+
const idU256 = uint25619.bnToUint256(nftId);
|
|
39995
|
+
const infoRaw = await nftContract.id_to_info(idU256);
|
|
39996
|
+
const nominal = BigInt(infoRaw.nominal.toString());
|
|
39997
|
+
totalNominal += nominal;
|
|
39998
|
+
logger.debug(
|
|
39999
|
+
`${_SvkTrovesAdapter.name}::getPendingAssetsFromOwnerNFTMethod: NFT ID ${nftId} has nominal ${nominal}`
|
|
40000
|
+
);
|
|
40001
|
+
} catch (e) {
|
|
40002
|
+
logger.warn(
|
|
40003
|
+
`${_SvkTrovesAdapter.name}::getPendingAssetsFromOwnerNFTMethod: Failed to get info for NFT ID ${nftId}: ${e.message}`
|
|
40004
|
+
);
|
|
40005
|
+
}
|
|
40006
|
+
}
|
|
40007
|
+
logger.info(
|
|
40008
|
+
`${_SvkTrovesAdapter.name}::getPendingAssetsFromOwnerNFTMethod: Found ${matchingIds.length} NFTs with total nominal ${totalNominal}`
|
|
40009
|
+
);
|
|
40010
|
+
return Web3Number.fromWei(totalNominal.toString(), decimals);
|
|
40011
|
+
} catch (error) {
|
|
40012
|
+
logger.error(
|
|
40013
|
+
`${_SvkTrovesAdapter.name}::getPendingAssetsFromOwnerNFTMethod: ${error.message}`
|
|
40014
|
+
);
|
|
40015
|
+
return Web3Number.fromWei("0", decimals);
|
|
40016
|
+
}
|
|
40017
|
+
}
|
|
40018
|
+
async maxDeposit(amount) {
|
|
40019
|
+
const baseToken = this.config.baseToken;
|
|
40020
|
+
if (!amount) {
|
|
40021
|
+
return {
|
|
40022
|
+
tokenInfo: baseToken,
|
|
40023
|
+
amount: new Web3Number("999999999999999999999999999", baseToken.decimals),
|
|
40024
|
+
usdValue: 1e27,
|
|
40025
|
+
remarks: "Max deposit (unbounded placeholder)",
|
|
40026
|
+
apy: await this.getAPY({ asset: baseToken, isDebt: false }),
|
|
40027
|
+
protocol: this.protocol
|
|
40028
|
+
};
|
|
40029
|
+
}
|
|
40030
|
+
const usdValue = await this.getUSDValue(baseToken, amount);
|
|
40031
|
+
return {
|
|
40032
|
+
tokenInfo: baseToken,
|
|
40033
|
+
amount,
|
|
40034
|
+
usdValue,
|
|
40035
|
+
remarks: "Deposit amount",
|
|
40036
|
+
apy: await this.getAPY({ asset: baseToken, isDebt: false }),
|
|
40037
|
+
protocol: this.protocol
|
|
40038
|
+
};
|
|
40039
|
+
}
|
|
40040
|
+
async maxWithdraw() {
|
|
40041
|
+
const baseToken = this.config.baseToken;
|
|
40042
|
+
const current = await this.getPosition({ asset: baseToken, isDebt: false });
|
|
40043
|
+
const pos = current ?? { amount: new Web3Number("0", baseToken.decimals), remarks: "" };
|
|
40044
|
+
const usdValue = await this.getUSDValue(baseToken, pos.amount);
|
|
40045
|
+
return {
|
|
40046
|
+
tokenInfo: baseToken,
|
|
40047
|
+
amount: pos.amount,
|
|
40048
|
+
usdValue,
|
|
40049
|
+
remarks: "Max withdraw (liquid + pending redemption, underlying units)",
|
|
40050
|
+
apy: await this.getAPY({ asset: baseToken, isDebt: false }),
|
|
40051
|
+
protocol: this.protocol
|
|
40052
|
+
};
|
|
40053
|
+
}
|
|
40054
|
+
_getDepositLeaf() {
|
|
40055
|
+
const baseToken = this.config.baseToken;
|
|
40056
|
+
const strategyVault = this.config.strategyVault;
|
|
40057
|
+
const receiver = this.config.vaultAllocator;
|
|
40058
|
+
return [
|
|
40059
|
+
{
|
|
40060
|
+
target: baseToken.address,
|
|
40061
|
+
method: "approve",
|
|
40062
|
+
packedArguments: [strategyVault.toBigInt()],
|
|
40063
|
+
sanitizer: SIMPLE_SANITIZER,
|
|
40064
|
+
id: this._depositApproveProofReadableId()
|
|
40065
|
+
},
|
|
40066
|
+
{
|
|
40067
|
+
target: strategyVault,
|
|
40068
|
+
method: "deposit",
|
|
40069
|
+
packedArguments: [receiver.toBigInt()],
|
|
40070
|
+
sanitizer: SIMPLE_SANITIZER,
|
|
40071
|
+
id: this._depositCallProofReadableId()
|
|
40072
|
+
}
|
|
40073
|
+
];
|
|
40074
|
+
}
|
|
40075
|
+
_getWithdrawLeaf() {
|
|
40076
|
+
const strategyVault = this.config.strategyVault;
|
|
40077
|
+
const recv = this.config.vaultAllocator;
|
|
40078
|
+
const owner = this.config.vaultAllocator;
|
|
40079
|
+
return [
|
|
40080
|
+
{
|
|
40081
|
+
target: strategyVault,
|
|
40082
|
+
method: "request_redeem",
|
|
40083
|
+
packedArguments: [recv.toBigInt(), owner.toBigInt()],
|
|
40084
|
+
sanitizer: SVK_SIMPLE_SANITIZER,
|
|
40085
|
+
id: this._withdrawCallProofReadableId()
|
|
40086
|
+
}
|
|
40087
|
+
];
|
|
40088
|
+
}
|
|
40089
|
+
getDepositAdapter() {
|
|
40090
|
+
const leafConfigs = this._getDepositLeaf();
|
|
40091
|
+
const leaves = leafConfigs.map((config) => {
|
|
40092
|
+
const { target, method, packedArguments, sanitizer, id } = config;
|
|
40093
|
+
return this.constructSimpleLeafData({ id, target, method, packedArguments }, sanitizer);
|
|
40094
|
+
});
|
|
40095
|
+
return { leaves, callConstructor: this.getDepositCall.bind(this) };
|
|
40096
|
+
}
|
|
40097
|
+
getWithdrawAdapter() {
|
|
40098
|
+
const leafConfigs = this._getWithdrawLeaf();
|
|
40099
|
+
const leaves = leafConfigs.map((config) => {
|
|
40100
|
+
const { target, method, packedArguments, sanitizer, id } = config;
|
|
40101
|
+
return this.constructSimpleLeafData({ id, target, method, packedArguments }, sanitizer);
|
|
40102
|
+
});
|
|
40103
|
+
return { leaves, callConstructor: this.getWithdrawCall.bind(this) };
|
|
40104
|
+
}
|
|
40105
|
+
async getDepositCall(params) {
|
|
40106
|
+
const baseToken = this.config.baseToken;
|
|
40107
|
+
const strategyVault = this.config.strategyVault;
|
|
40108
|
+
const amount = params.amount;
|
|
40109
|
+
const uint256Amount = uint25619.bnToUint256(amount.toWei());
|
|
40110
|
+
const receiver = this.config.vaultAllocator;
|
|
40111
|
+
return [
|
|
40112
|
+
{
|
|
40113
|
+
proofReadableId: this._depositApproveProofReadableId(),
|
|
40114
|
+
sanitizer: SIMPLE_SANITIZER,
|
|
40115
|
+
call: {
|
|
40116
|
+
contractAddress: baseToken.address,
|
|
40117
|
+
selector: hash11.getSelectorFromName("approve"),
|
|
40118
|
+
calldata: [
|
|
40119
|
+
strategyVault.toBigInt(),
|
|
40120
|
+
toBigInt(uint256Amount.low.toString()),
|
|
40121
|
+
toBigInt(uint256Amount.high.toString())
|
|
40122
|
+
]
|
|
40123
|
+
}
|
|
40124
|
+
},
|
|
40125
|
+
{
|
|
40126
|
+
proofReadableId: this._depositCallProofReadableId(),
|
|
39234
40127
|
sanitizer: SIMPLE_SANITIZER,
|
|
39235
40128
|
call: {
|
|
39236
40129
|
contractAddress: strategyVault,
|
|
@@ -39250,16 +40143,23 @@ var SvkTrovesAdapter = class _SvkTrovesAdapter extends BaseAdapter {
|
|
|
39250
40143
|
const uint256Amount = uint25619.bnToUint256(amount.toWei());
|
|
39251
40144
|
const recv = this.config.vaultAllocator;
|
|
39252
40145
|
const owner = this.config.vaultAllocator;
|
|
40146
|
+
const vault = new Contract14({
|
|
40147
|
+
abi: universal_vault_abi_default,
|
|
40148
|
+
address: strategyVault.address,
|
|
40149
|
+
providerOrAccount: this.config.networkConfig.provider
|
|
40150
|
+
});
|
|
40151
|
+
const sharesRaw = await vault.convert_to_shares(uint256Amount);
|
|
40152
|
+
const sharesU256 = uint25619.bnToUint256(sharesRaw.toString());
|
|
39253
40153
|
return [
|
|
39254
40154
|
{
|
|
39255
40155
|
proofReadableId: this._withdrawCallProofReadableId(),
|
|
39256
|
-
sanitizer:
|
|
40156
|
+
sanitizer: SVK_SIMPLE_SANITIZER,
|
|
39257
40157
|
call: {
|
|
39258
40158
|
contractAddress: strategyVault,
|
|
39259
|
-
selector: hash11.getSelectorFromName("
|
|
40159
|
+
selector: hash11.getSelectorFromName("request_redeem"),
|
|
39260
40160
|
calldata: [
|
|
39261
|
-
toBigInt(
|
|
39262
|
-
toBigInt(
|
|
40161
|
+
toBigInt(sharesU256.low.toString()),
|
|
40162
|
+
toBigInt(sharesU256.high.toString()),
|
|
39263
40163
|
recv.toBigInt(),
|
|
39264
40164
|
owner.toBigInt()
|
|
39265
40165
|
]
|
|
@@ -41044,9 +41944,9 @@ var SVKStrategy = class extends BaseStrategy {
|
|
|
41044
41944
|
* Builds a manage call from an adapter's proof tree.
|
|
41045
41945
|
* DRY helper for the repeated getProofs → getManageCall pattern.
|
|
41046
41946
|
*/
|
|
41047
|
-
async buildManageCallFromAdapter(adapter, isDeposit, amount) {
|
|
41947
|
+
async buildManageCallFromAdapter(adapter, isDeposit, amount, additionalParams) {
|
|
41048
41948
|
const proofsInfo = adapter.getProofs(isDeposit, this.getMerkleTree());
|
|
41049
|
-
const manageCalls = await proofsInfo.callConstructor({ amount });
|
|
41949
|
+
const manageCalls = await proofsInfo.callConstructor({ amount, ...additionalParams });
|
|
41050
41950
|
return this.getManageCall(
|
|
41051
41951
|
this.getProofGroupsForManageCalls(manageCalls),
|
|
41052
41952
|
manageCalls
|
|
@@ -42148,95 +43048,615 @@ function createHyperLSTSettings(lstSymbol, underlyingSymbol) {
|
|
|
42148
43048
|
] }),
|
|
42149
43049
|
type: "info"
|
|
42150
43050
|
},
|
|
42151
|
-
{
|
|
42152
|
-
tab: "deposit",
|
|
42153
|
-
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.",
|
|
42154
|
-
type: "info"
|
|
42155
|
-
}
|
|
42156
|
-
]
|
|
42157
|
-
};
|
|
42158
|
-
}
|
|
42159
|
-
var HYPER_LST_SECURITY = {
|
|
42160
|
-
auditStatus: "Audited" /* AUDITED */,
|
|
42161
|
-
sourceCode: {
|
|
42162
|
-
type: "Closed Source" /* CLOSED_SOURCE */,
|
|
42163
|
-
contractLink: "https://github.com/trovesfi/troves-contracts"
|
|
42164
|
-
},
|
|
42165
|
-
accessControl: {
|
|
42166
|
-
type: "Standard Account" /* STANDARD_ACCOUNT */,
|
|
42167
|
-
addresses: [ContractAddr.from("0x0")],
|
|
42168
|
-
timeLock: "2 Days"
|
|
43051
|
+
{
|
|
43052
|
+
tab: "deposit",
|
|
43053
|
+
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.",
|
|
43054
|
+
type: "info"
|
|
43055
|
+
}
|
|
43056
|
+
]
|
|
43057
|
+
};
|
|
43058
|
+
}
|
|
43059
|
+
var HYPER_LST_SECURITY = {
|
|
43060
|
+
auditStatus: "Audited" /* AUDITED */,
|
|
43061
|
+
sourceCode: {
|
|
43062
|
+
type: "Closed Source" /* CLOSED_SOURCE */,
|
|
43063
|
+
contractLink: "https://github.com/trovesfi/troves-contracts"
|
|
43064
|
+
},
|
|
43065
|
+
accessControl: {
|
|
43066
|
+
type: "Standard Account" /* STANDARD_ACCOUNT */,
|
|
43067
|
+
addresses: [ContractAddr.from("0x0")],
|
|
43068
|
+
timeLock: "2 Days"
|
|
43069
|
+
}
|
|
43070
|
+
};
|
|
43071
|
+
var HYPER_LST_REDEMPTION_INFO = {
|
|
43072
|
+
instantWithdrawalVault: "No" /* NO */,
|
|
43073
|
+
redemptionsInfo: [
|
|
43074
|
+
{
|
|
43075
|
+
title: "Typical Duration",
|
|
43076
|
+
description: "1-2 hours"
|
|
43077
|
+
}
|
|
43078
|
+
],
|
|
43079
|
+
alerts: [
|
|
43080
|
+
{
|
|
43081
|
+
type: "info",
|
|
43082
|
+
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.",
|
|
43083
|
+
tab: "withdraw"
|
|
43084
|
+
}
|
|
43085
|
+
]
|
|
43086
|
+
};
|
|
43087
|
+
function getStrategySettings(lstSymbol, underlyingSymbol, settings, isPreview = false, isLST) {
|
|
43088
|
+
return {
|
|
43089
|
+
id: `hyper_${lstSymbol.toLowerCase()}`,
|
|
43090
|
+
name: `Hyper ${lstSymbol}`,
|
|
43091
|
+
description: getDescription2(lstSymbol, underlyingSymbol),
|
|
43092
|
+
address: settings.vaultAddress,
|
|
43093
|
+
launchBlock: 0,
|
|
43094
|
+
type: "Other",
|
|
43095
|
+
vaultType: {
|
|
43096
|
+
type: "Looping" /* LOOPING */,
|
|
43097
|
+
description: `Creates leveraged looping position on ${lstSymbol} by borrowing ${underlyingSymbol} to increase yield`
|
|
43098
|
+
},
|
|
43099
|
+
depositTokens: [Global.getDefaultTokens().find((token) => token.symbol === lstSymbol)],
|
|
43100
|
+
additionalInfo: getLooperSettings2(lstSymbol, underlyingSymbol, settings, lstSymbol === "xSTRK" ? VesuPools.Re7xSTRK : VesuPools.Re7xBTC),
|
|
43101
|
+
risk: {
|
|
43102
|
+
riskFactor: _riskFactor4,
|
|
43103
|
+
netRisk: _riskFactor4.reduce((acc, curr) => acc + curr.value * curr.weight, 0) / _riskFactor4.reduce((acc, curr) => acc + curr.weight, 0),
|
|
43104
|
+
notARisks: getNoRiskTags(_riskFactor4)
|
|
43105
|
+
},
|
|
43106
|
+
auditUrl: AUDIT_URL4,
|
|
43107
|
+
protocols: [Protocols.ENDUR, Protocols.VESU],
|
|
43108
|
+
curator: {
|
|
43109
|
+
name: "Unwrap Labs",
|
|
43110
|
+
logo: "https://assets.troves.fi/integrations/unwraplabs/white.png"
|
|
43111
|
+
},
|
|
43112
|
+
settings: createHyperLSTSettings(lstSymbol, underlyingSymbol),
|
|
43113
|
+
contractDetails: getContractDetails(settings),
|
|
43114
|
+
faqs: getFAQs2(lstSymbol, underlyingSymbol, isLST),
|
|
43115
|
+
investmentSteps: getInvestmentSteps(lstSymbol, underlyingSymbol),
|
|
43116
|
+
isPreview,
|
|
43117
|
+
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.",
|
|
43118
|
+
realizedAPYMethodology: "The realizedAPY is based on past 14 days performance by the vault",
|
|
43119
|
+
tags: lstSymbol.includes("BTC") ? ["BTC" /* BTC */, "Maxx" /* LEVERED */] : ["Maxx" /* LEVERED */],
|
|
43120
|
+
security: HYPER_LST_SECURITY,
|
|
43121
|
+
redemptionInfo: HYPER_LST_REDEMPTION_INFO,
|
|
43122
|
+
usualTimeToEarnings: "2 weeks",
|
|
43123
|
+
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.",
|
|
43124
|
+
points: lstSymbol === "xSTRK" ? [{
|
|
43125
|
+
multiplier: 4,
|
|
43126
|
+
logo: "https://endur.fi/favicon.ico",
|
|
43127
|
+
toolTip: "This strategy holds xSTRK. Earn 3-4x Endur points on your xSTRK due to the leverage. Points can be found on endur.fi."
|
|
43128
|
+
}] : void 0
|
|
43129
|
+
};
|
|
43130
|
+
}
|
|
43131
|
+
var HyperLSTStrategies = [
|
|
43132
|
+
getStrategySettings("xSTRK", "STRK", hyperxSTRK, false, true),
|
|
43133
|
+
getStrategySettings("xWBTC", "WBTC", hyperxWBTC, false, false),
|
|
43134
|
+
getStrategySettings("xtBTC", "tBTC", hyperxtBTC, false, false),
|
|
43135
|
+
getStrategySettings("xsBTC", "solvBTC", hyperxsBTC, false, false),
|
|
43136
|
+
getStrategySettings("xLBTC", "LBTC", hyperxLBTC, false, false),
|
|
43137
|
+
getStrategySettings("mRe7BTC", "mRe7BTC", hypermRe7BTC, false, false),
|
|
43138
|
+
getStrategySettings("mRe7YIELD", "mRe7YIELD", hypermRe7YIELD, false, false)
|
|
43139
|
+
];
|
|
43140
|
+
|
|
43141
|
+
// src/strategies/usdc-boosted-strategy.tsx
|
|
43142
|
+
import { uint256 as uint25623 } from "starknet";
|
|
43143
|
+
var USDCBoostedStrategy = class _USDCBoostedStrategy extends SVKStrategy {
|
|
43144
|
+
constructor(config, pricer, metadata) {
|
|
43145
|
+
super(config, pricer, metadata);
|
|
43146
|
+
this.metadata.additionalInfo.adapters.forEach((adapter) => {
|
|
43147
|
+
adapter.adapter.config.networkConfig = this.config;
|
|
43148
|
+
adapter.adapter.config.pricer = this.pricer;
|
|
43149
|
+
if (adapter.adapter._vesuAdapter) {
|
|
43150
|
+
adapter.adapter._vesuAdapter.networkConfig = this.config;
|
|
43151
|
+
adapter.adapter._vesuAdapter.pricer = this.pricer;
|
|
43152
|
+
}
|
|
43153
|
+
});
|
|
43154
|
+
}
|
|
43155
|
+
getTag() {
|
|
43156
|
+
return `${_USDCBoostedStrategy.name}:${this.metadata.name}`;
|
|
43157
|
+
}
|
|
43158
|
+
getAdapterById(id) {
|
|
43159
|
+
const entry = this.metadata.additionalInfo.adapters.find(
|
|
43160
|
+
(a) => a.id === id
|
|
43161
|
+
);
|
|
43162
|
+
if (!entry) {
|
|
43163
|
+
throw new Error(
|
|
43164
|
+
`${this.getTag()}::getAdapterById: adapter not found for id "${id}"`
|
|
43165
|
+
);
|
|
43166
|
+
}
|
|
43167
|
+
return entry.adapter;
|
|
43168
|
+
}
|
|
43169
|
+
async getVesuModifyPositionCall(params) {
|
|
43170
|
+
logger.verbose(
|
|
43171
|
+
`${this.getTag()}::getVesuModifyPositionCall isDeposit=${params.isDeposit}, amount=${params.leg1DepositAmount}, debtAmount=${params.debtAmount?.toNumber()}`
|
|
43172
|
+
);
|
|
43173
|
+
return this.buildManageCallFromAdapter(
|
|
43174
|
+
this.getAdapterById("vesu_usdc_strk"),
|
|
43175
|
+
params.isDeposit,
|
|
43176
|
+
params.leg1DepositAmount,
|
|
43177
|
+
params.debtAmount ? { debtAmount: params.debtAmount } : void 0
|
|
43178
|
+
);
|
|
43179
|
+
}
|
|
43180
|
+
async getVesuPositions() {
|
|
43181
|
+
const positions = await this.getAdapterById(
|
|
43182
|
+
"vesu_usdc_strk"
|
|
43183
|
+
).getPositions();
|
|
43184
|
+
return positions.map((p) => ({
|
|
43185
|
+
amount: p.amount,
|
|
43186
|
+
usdValue: p.usdValue,
|
|
43187
|
+
remarks: p.remarks ?? "",
|
|
43188
|
+
token: p.tokenInfo,
|
|
43189
|
+
protocol: p.protocol
|
|
43190
|
+
}));
|
|
43191
|
+
}
|
|
43192
|
+
async getVesuHealthFactor(blockNumber = "latest") {
|
|
43193
|
+
const vesuAdapter = this.getAdapterById("vesu_usdc_strk");
|
|
43194
|
+
return await vesuAdapter._vesuAdapter.getHealthFactor(blockNumber);
|
|
43195
|
+
}
|
|
43196
|
+
// TODO: will have to still modify for instant withdrawals as of now
|
|
43197
|
+
async getModifyHyperPositionCall(params) {
|
|
43198
|
+
logger.verbose(
|
|
43199
|
+
`${this.getTag()}::getModifyHyperPositionCall isDeposit=${params.isDeposit}, amount=${params.amount}`
|
|
43200
|
+
);
|
|
43201
|
+
return this.buildManageCallFromAdapter(
|
|
43202
|
+
this.getAdapterById("hyper_xstrk"),
|
|
43203
|
+
params.isDeposit,
|
|
43204
|
+
params.amount
|
|
43205
|
+
);
|
|
43206
|
+
}
|
|
43207
|
+
async getAvnuSwapCall(params) {
|
|
43208
|
+
logger.verbose(
|
|
43209
|
+
`${this.getTag()}::getAvnuSwapCall isDeposit=${params.isDeposit}, amount=${params.amount}`
|
|
43210
|
+
);
|
|
43211
|
+
return this.buildManageCallFromAdapter(
|
|
43212
|
+
this.getAdapterById("avnu_strk_xstrk"),
|
|
43213
|
+
params.isDeposit,
|
|
43214
|
+
params.amount
|
|
43215
|
+
);
|
|
43216
|
+
}
|
|
43217
|
+
/**
|
|
43218
|
+
* Returns the USDC balance sitting idle inside the vault contract itself.
|
|
43219
|
+
* This balance can offset the required liquidity during withdrawal processing.
|
|
43220
|
+
*/
|
|
43221
|
+
async getUnusedBalanceVault() {
|
|
43222
|
+
const collateralToken = this.metadata.additionalInfo.collateralToken;
|
|
43223
|
+
return new ERC20(this.config).balanceOf(
|
|
43224
|
+
collateralToken.address,
|
|
43225
|
+
this.metadata.additionalInfo.vaultAddress,
|
|
43226
|
+
collateralToken.decimals
|
|
43227
|
+
);
|
|
43228
|
+
}
|
|
43229
|
+
/**
|
|
43230
|
+
* Returns the current STRK balance sitting unused in the vault allocator.
|
|
43231
|
+
* This covers STRK from prior borrow cycles that hasn't been swapped yet.
|
|
43232
|
+
*/
|
|
43233
|
+
// Technically we can use this or we can even use the avnu-adapter to get the unused debt
|
|
43234
|
+
async getUnusedDebt() {
|
|
43235
|
+
const debtToken = this.metadata.additionalInfo.debtToken;
|
|
43236
|
+
return new ERC20(this.config).balanceOf(
|
|
43237
|
+
debtToken.address,
|
|
43238
|
+
this.metadata.additionalInfo.vaultAllocator,
|
|
43239
|
+
debtToken.decimals
|
|
43240
|
+
);
|
|
43241
|
+
}
|
|
43242
|
+
/**
|
|
43243
|
+
* Returns the xSTRK balance sitting in the vault allocator.
|
|
43244
|
+
* This is non-zero when the previous cycle's request_redeem on the HyperPosition
|
|
43245
|
+
* has been settled — the redeemed xSTRK lands here and is ready to be swapped.
|
|
43246
|
+
*/
|
|
43247
|
+
async getxSTRKInVault() {
|
|
43248
|
+
const xstrkToken = Global.getDefaultTokens().find(
|
|
43249
|
+
(t) => t.symbol === "xSTRK"
|
|
43250
|
+
);
|
|
43251
|
+
if (!xstrkToken) {
|
|
43252
|
+
throw new Error(`${this.getTag()}:: xSTRK token not found`);
|
|
43253
|
+
}
|
|
43254
|
+
return new ERC20(this.config).balanceOf(
|
|
43255
|
+
xstrkToken.address.address,
|
|
43256
|
+
this.metadata.additionalInfo.vaultAllocator,
|
|
43257
|
+
xstrkToken.decimals
|
|
43258
|
+
);
|
|
43259
|
+
}
|
|
43260
|
+
/**
|
|
43261
|
+
* Simulates depositing `depositAmount` USDC on Vesu and returns the
|
|
43262
|
+
* incremental STRK that would be borrowed. Needed to size the AVNU swap
|
|
43263
|
+
* call that is batched together with the Vesu call in the same transaction.
|
|
43264
|
+
*/
|
|
43265
|
+
async computeVesuDepositBorrowAmount(depositAmount) {
|
|
43266
|
+
return this.getAdapterById(
|
|
43267
|
+
"vesu_usdc_strk"
|
|
43268
|
+
).getExpectedDepositDebtDelta(depositAmount);
|
|
43269
|
+
}
|
|
43270
|
+
async computeVesuWithdrawDebtDelta(withdrawAmount) {
|
|
43271
|
+
return this.getAdapterById(
|
|
43272
|
+
"vesu_usdc_strk"
|
|
43273
|
+
).getExpectedWithdrawDebtDelta(withdrawAmount);
|
|
43274
|
+
}
|
|
43275
|
+
async getPendingHyperAssets() {
|
|
43276
|
+
const xstrkToken = Global.getDefaultTokens().find(
|
|
43277
|
+
(t) => t.symbol === "xSTRK"
|
|
43278
|
+
);
|
|
43279
|
+
const hyperXstrkRedeemNFT = ContractAddr.from(
|
|
43280
|
+
"0x51e40b839dc0c2feca923f863072673b94abfa2483345be3b30b457a90d095"
|
|
43281
|
+
);
|
|
43282
|
+
return this.getAdapterById(
|
|
43283
|
+
"hyper_xstrk"
|
|
43284
|
+
).getPendingAssetsFromOwnerNFTMethod(
|
|
43285
|
+
hyperXstrkRedeemNFT,
|
|
43286
|
+
this.metadata.additionalInfo.vaultAllocator,
|
|
43287
|
+
xstrkToken.decimals
|
|
43288
|
+
);
|
|
43289
|
+
}
|
|
43290
|
+
// TODO: rn we are just making these functions in the strategy itself but
|
|
43291
|
+
// later on we will move them to the SVKStrategy for generalization
|
|
43292
|
+
async getUserTVL(user, blockIdentifier = "latest") {
|
|
43293
|
+
const shares = await this.contract.call("balanceOf", [user.address], {
|
|
43294
|
+
blockIdentifier
|
|
43295
|
+
});
|
|
43296
|
+
const assets = await this.contract.call(
|
|
43297
|
+
"convert_to_assets",
|
|
43298
|
+
[uint25623.bnToUint256(shares)],
|
|
43299
|
+
{ blockIdentifier }
|
|
43300
|
+
);
|
|
43301
|
+
const amount = Web3Number.fromWei(
|
|
43302
|
+
assets.toString(),
|
|
43303
|
+
this.metadata.depositTokens[0].decimals
|
|
43304
|
+
);
|
|
43305
|
+
const blockNumber = typeof blockIdentifier === "number" || typeof blockIdentifier === "bigint" ? Number(blockIdentifier) : void 0;
|
|
43306
|
+
const price = await this.pricer.getPrice(
|
|
43307
|
+
this.metadata.depositTokens[0].symbol,
|
|
43308
|
+
blockNumber
|
|
43309
|
+
);
|
|
43310
|
+
const usdValue = Number(amount.toFixed(6)) * price.price;
|
|
43311
|
+
return {
|
|
43312
|
+
tokenInfo: this.asset(),
|
|
43313
|
+
amount,
|
|
43314
|
+
usdValue
|
|
43315
|
+
};
|
|
43316
|
+
}
|
|
43317
|
+
async getTVL() {
|
|
43318
|
+
const assets = await this.contract.total_assets();
|
|
43319
|
+
const amount = Web3Number.fromWei(
|
|
43320
|
+
assets.toString(),
|
|
43321
|
+
this.metadata.depositTokens[0].decimals
|
|
43322
|
+
);
|
|
43323
|
+
const price = await this.pricer.getPrice(
|
|
43324
|
+
this.metadata.depositTokens[0].symbol
|
|
43325
|
+
);
|
|
43326
|
+
const usdValue = Number(amount.toFixed(6)) * price.price;
|
|
43327
|
+
return {
|
|
43328
|
+
tokenInfo: this.asset(),
|
|
43329
|
+
amount,
|
|
43330
|
+
usdValue
|
|
43331
|
+
};
|
|
43332
|
+
}
|
|
43333
|
+
async getAUM() {
|
|
43334
|
+
const underlying = this.asset();
|
|
43335
|
+
const usdcPrice = await this.pricer.getPrice(underlying.symbol);
|
|
43336
|
+
const allPositions = [];
|
|
43337
|
+
for (const adapter of this.metadata.additionalInfo.adapters) {
|
|
43338
|
+
const positions = await adapter.adapter.getPositions();
|
|
43339
|
+
allPositions.push(...positions);
|
|
43340
|
+
}
|
|
43341
|
+
let netAUM = new Web3Number(0, underlying.decimals);
|
|
43342
|
+
for (const position of allPositions) {
|
|
43343
|
+
if (position.tokenInfo.address.eq(underlying.address)) {
|
|
43344
|
+
netAUM = netAUM.plus(position.amount);
|
|
43345
|
+
} else {
|
|
43346
|
+
const valueInUSDC = position.usdValue;
|
|
43347
|
+
netAUM = netAUM.plus(valueInUSDC);
|
|
43348
|
+
}
|
|
43349
|
+
}
|
|
43350
|
+
const unusedBalance = await this.getUnusedBalance();
|
|
43351
|
+
logger.verbose(
|
|
43352
|
+
`${this.getTag()} unused balance: ${unusedBalance.amount.toNumber()}`
|
|
43353
|
+
);
|
|
43354
|
+
netAUM = netAUM.plus(unusedBalance.amount);
|
|
43355
|
+
const prevAum = await this.getPrevAUM();
|
|
43356
|
+
logger.verbose(`${this.getTag()} AUM: ${netAUM}`);
|
|
43357
|
+
const realAUM = {
|
|
43358
|
+
tokenInfo: underlying,
|
|
43359
|
+
amount: netAUM,
|
|
43360
|
+
usdValue: netAUM.toNumber() * usdcPrice.price,
|
|
43361
|
+
apy: { apy: 0, type: "base" /* BASE */ },
|
|
43362
|
+
remarks: "finalised" /* FINALISED */,
|
|
43363
|
+
protocol: Protocols.NONE
|
|
43364
|
+
};
|
|
43365
|
+
const estimatedAUMDelta = {
|
|
43366
|
+
tokenInfo: underlying,
|
|
43367
|
+
amount: Web3Number.fromWei("0", underlying.decimals),
|
|
43368
|
+
usdValue: 0,
|
|
43369
|
+
apy: { apy: 0, type: "base" /* BASE */ },
|
|
43370
|
+
remarks: "defispring" /* DEFISPRING */,
|
|
43371
|
+
protocol: Protocols.NONE
|
|
43372
|
+
};
|
|
43373
|
+
return {
|
|
43374
|
+
net: {
|
|
43375
|
+
tokenInfo: underlying,
|
|
43376
|
+
amount: netAUM,
|
|
43377
|
+
usdValue: netAUM.toNumber() * usdcPrice.price
|
|
43378
|
+
},
|
|
43379
|
+
prevAum,
|
|
43380
|
+
splits: [realAUM, estimatedAUMDelta]
|
|
43381
|
+
};
|
|
42169
43382
|
}
|
|
42170
|
-
|
|
42171
|
-
|
|
42172
|
-
|
|
42173
|
-
|
|
42174
|
-
|
|
42175
|
-
|
|
42176
|
-
|
|
43383
|
+
// TODO: can refactor later but seems redundant since not being used ANYWHERE
|
|
43384
|
+
// Most of the fund management done through adapters only
|
|
43385
|
+
async getFundManagementCall(params) {
|
|
43386
|
+
logger.verbose(
|
|
43387
|
+
`${this.getTag()}::getFundManagementCall params: ${JSON.stringify(params)}`
|
|
43388
|
+
);
|
|
43389
|
+
const allAdapters = this.metadata.additionalInfo.adapters.map(
|
|
43390
|
+
(a) => a.adapter
|
|
43391
|
+
);
|
|
43392
|
+
if (!params.isDeposit) {
|
|
43393
|
+
const unusedBalance = await this.getUnusedBalance();
|
|
43394
|
+
logger.verbose(
|
|
43395
|
+
`${this.getTag()}::getFundManagementCall unusedBalance: ${unusedBalance.amount}, required: ${params.leg1DepositAmount}`
|
|
43396
|
+
);
|
|
43397
|
+
if (unusedBalance.amount.gte(params.leg1DepositAmount)) {
|
|
43398
|
+
return null;
|
|
43399
|
+
}
|
|
43400
|
+
const adapters2 = await AdapterOptimizer.getAdapterToUse(
|
|
43401
|
+
allAdapters,
|
|
43402
|
+
false,
|
|
43403
|
+
params.leg1DepositAmount
|
|
43404
|
+
);
|
|
43405
|
+
if (adapters2.length > 0) {
|
|
43406
|
+
const proofsInfo = adapters2.map(
|
|
43407
|
+
(adapter) => adapter.getProofs(false, this.getMerkleTree())
|
|
43408
|
+
);
|
|
43409
|
+
const calls = [];
|
|
43410
|
+
for (const info of proofsInfo) {
|
|
43411
|
+
const manageCalls = await info.callConstructor({
|
|
43412
|
+
amount: params.leg1DepositAmount
|
|
43413
|
+
});
|
|
43414
|
+
const call = this.getManageCall(
|
|
43415
|
+
this.getProofGroupsForManageCalls(manageCalls),
|
|
43416
|
+
manageCalls
|
|
43417
|
+
);
|
|
43418
|
+
calls.push(call);
|
|
43419
|
+
}
|
|
43420
|
+
return calls;
|
|
43421
|
+
}
|
|
43422
|
+
throw new Error(
|
|
43423
|
+
`${this.getTag()}::getFundManagementCall: no adapters for withdraw: ${unusedBalance.amount}`
|
|
43424
|
+
);
|
|
42177
43425
|
}
|
|
42178
|
-
|
|
42179
|
-
|
|
42180
|
-
|
|
42181
|
-
|
|
42182
|
-
|
|
42183
|
-
|
|
43426
|
+
const adapters = await AdapterOptimizer.getAdapterToUse(
|
|
43427
|
+
allAdapters,
|
|
43428
|
+
true,
|
|
43429
|
+
params.leg1DepositAmount
|
|
43430
|
+
);
|
|
43431
|
+
if (adapters.length > 0) {
|
|
43432
|
+
const proofsInfo = adapters.map(
|
|
43433
|
+
(adapter) => adapter.getProofs(true, this.getMerkleTree())
|
|
43434
|
+
);
|
|
43435
|
+
const calls = [];
|
|
43436
|
+
for (const info of proofsInfo) {
|
|
43437
|
+
const manageCalls = await info.callConstructor({
|
|
43438
|
+
amount: params.leg1DepositAmount
|
|
43439
|
+
});
|
|
43440
|
+
const call = this.getManageCall(
|
|
43441
|
+
this.getProofGroupsForManageCalls(manageCalls),
|
|
43442
|
+
manageCalls
|
|
43443
|
+
);
|
|
43444
|
+
calls.push(call);
|
|
43445
|
+
}
|
|
43446
|
+
return calls;
|
|
42184
43447
|
}
|
|
42185
|
-
|
|
43448
|
+
throw new Error(
|
|
43449
|
+
`${this.getTag()}::getFundManagementCall: no adapters for deposit: ${params.leg1DepositAmount}`
|
|
43450
|
+
);
|
|
43451
|
+
}
|
|
42186
43452
|
};
|
|
42187
|
-
function
|
|
43453
|
+
function getUSDCBoostedSettings(vaultSettings) {
|
|
43454
|
+
vaultSettings.leafAdapters = [];
|
|
43455
|
+
const xSTRKToken = Global.getDefaultTokens().find(
|
|
43456
|
+
(t) => t.symbol === "xSTRK"
|
|
43457
|
+
);
|
|
43458
|
+
const USDCToken = Global.getDefaultTokens().find((t) => t.symbol === "USDC");
|
|
43459
|
+
const STRKToken = Global.getDefaultTokens().find((t) => t.symbol === "STRK");
|
|
43460
|
+
const baseAdapterConfig = {
|
|
43461
|
+
baseToken: USDCToken,
|
|
43462
|
+
supportedPositions: [{ asset: USDCToken, isDebt: false }],
|
|
43463
|
+
networkConfig: getMainnetConfig(),
|
|
43464
|
+
pricer: new PricerFromApi(getMainnetConfig(), Global.getDefaultTokens()),
|
|
43465
|
+
vaultAllocator: vaultSettings.vaultAllocator,
|
|
43466
|
+
vaultAddress: vaultSettings.vaultAddress
|
|
43467
|
+
};
|
|
43468
|
+
const vesuModifyPositionAdapter = new VesuModifyPositionAdapter({
|
|
43469
|
+
poolId: vaultSettings.vesuPoolId,
|
|
43470
|
+
collateral: vaultSettings.collateralToken,
|
|
43471
|
+
debt: vaultSettings.debtToken,
|
|
43472
|
+
targetLtv: vaultSettings.targetLTV,
|
|
43473
|
+
maxLtv: vaultSettings.maxLTV,
|
|
43474
|
+
...baseAdapterConfig,
|
|
43475
|
+
supportedPositions: [
|
|
43476
|
+
{ asset: USDCToken, isDebt: false },
|
|
43477
|
+
{ asset: STRKToken, isDebt: true }
|
|
43478
|
+
]
|
|
43479
|
+
});
|
|
43480
|
+
const avnuAdapter = new AvnuAdapter({
|
|
43481
|
+
baseUrl: AVNU_QUOTE_URL,
|
|
43482
|
+
avnuContract: AVNU_EXCHANGE,
|
|
43483
|
+
slippage: 0.01,
|
|
43484
|
+
minimumExtendedPriceDifferenceForSwapOpen: 0,
|
|
43485
|
+
maximumExtendedPriceDifferenceForSwapClosing: 0,
|
|
43486
|
+
...baseAdapterConfig,
|
|
43487
|
+
baseToken: STRKToken,
|
|
43488
|
+
supportedPositions: [
|
|
43489
|
+
{ asset: STRKToken, isDebt: false },
|
|
43490
|
+
{ asset: xSTRKToken, isDebt: false }
|
|
43491
|
+
]
|
|
43492
|
+
});
|
|
43493
|
+
const svkTrovesAdapter = new SvkTrovesAdapter({
|
|
43494
|
+
...baseAdapterConfig,
|
|
43495
|
+
baseToken: xSTRKToken,
|
|
43496
|
+
supportedPositions: [{ asset: xSTRKToken, isDebt: false }],
|
|
43497
|
+
strategyVault: vaultSettings.hyperxSTRKVaultAddress,
|
|
43498
|
+
trovesStrategyId: "hyper_xstrk"
|
|
43499
|
+
});
|
|
43500
|
+
const usdcTransferAdapter = new TokenTransferAdapter({
|
|
43501
|
+
...baseAdapterConfig,
|
|
43502
|
+
fromAddress: vaultSettings.vaultAllocator,
|
|
43503
|
+
toAddress: vaultSettings.vaultAddress
|
|
43504
|
+
});
|
|
43505
|
+
const commonAdapter = new CommonAdapter({
|
|
43506
|
+
id: "flash_loan_init" /* FLASH_LOAN */,
|
|
43507
|
+
vaultAddress: vaultSettings.vaultAddress,
|
|
43508
|
+
vaultAllocator: vaultSettings.vaultAllocator,
|
|
43509
|
+
manager: vaultSettings.manager,
|
|
43510
|
+
asset: USDCToken.address
|
|
43511
|
+
});
|
|
43512
|
+
vaultSettings.adapters.push(
|
|
43513
|
+
// TODO: generalize the ids
|
|
43514
|
+
{ id: "vesu_usdc_strk", adapter: vesuModifyPositionAdapter },
|
|
43515
|
+
// Used to track swapped funds in vaultAllocator
|
|
43516
|
+
{ id: "avnu_strk_xstrk", adapter: avnuAdapter },
|
|
43517
|
+
{ id: "hyper_xstrk", adapter: svkTrovesAdapter },
|
|
43518
|
+
{ id: "usdc_transfer", adapter: usdcTransferAdapter }
|
|
43519
|
+
);
|
|
43520
|
+
vaultSettings.leafAdapters.push(
|
|
43521
|
+
() => vesuModifyPositionAdapter.getDepositLeaf()
|
|
43522
|
+
);
|
|
43523
|
+
vaultSettings.leafAdapters.push(
|
|
43524
|
+
() => vesuModifyPositionAdapter.getWithdrawLeaf()
|
|
43525
|
+
);
|
|
43526
|
+
vaultSettings.leafAdapters.push(() => avnuAdapter.getDepositLeaf());
|
|
43527
|
+
vaultSettings.leafAdapters.push(() => avnuAdapter.getWithdrawLeaf());
|
|
43528
|
+
vaultSettings.leafAdapters.push(() => svkTrovesAdapter.getDepositLeaf());
|
|
43529
|
+
vaultSettings.leafAdapters.push(() => svkTrovesAdapter.getWithdrawLeaf());
|
|
43530
|
+
vaultSettings.leafAdapters.push(
|
|
43531
|
+
commonAdapter.getApproveAdapter(
|
|
43532
|
+
USDCToken.address,
|
|
43533
|
+
vaultSettings.vaultAddress,
|
|
43534
|
+
"approve_bring_liquidity" /* APPROVE_BRING_LIQUIDITY */
|
|
43535
|
+
).bind(commonAdapter)
|
|
43536
|
+
);
|
|
43537
|
+
vaultSettings.leafAdapters.push(
|
|
43538
|
+
commonAdapter.getBringLiquidityAdapter("bring_liquidity" /* BRING_LIQUIDITY */).bind(commonAdapter)
|
|
43539
|
+
);
|
|
43540
|
+
return vaultSettings;
|
|
43541
|
+
}
|
|
43542
|
+
var usdcBoostedSettings = {
|
|
43543
|
+
vaultAddress: ContractAddr.from(
|
|
43544
|
+
"0xcdb0e3b2e076a2cdc4ee958b726b47c066239ef91c5ac80c94cf814147b84"
|
|
43545
|
+
),
|
|
43546
|
+
manager: ContractAddr.from(
|
|
43547
|
+
"0x72eea9bac9fa8cfffda637d3b990851446860c6fd8987d6cb50e659b01ee50f"
|
|
43548
|
+
),
|
|
43549
|
+
vaultAllocator: ContractAddr.from(
|
|
43550
|
+
"0x6d3101cff7f821412a99ebe23bb31a1950f93276285102eb4313e3601f5f927"
|
|
43551
|
+
),
|
|
43552
|
+
redeemRequestNFT: ContractAddr.from(
|
|
43553
|
+
"0x47dcc6889ca8db4e9eea8f55421e10f8ce7e356ccb45260a1c49a76f733c309"
|
|
43554
|
+
),
|
|
43555
|
+
// TODO: not applicable in our case -> remove later ( make it optional if needed)
|
|
43556
|
+
aumOracle: ContractAddr.from("0x0"),
|
|
43557
|
+
leafAdapters: [],
|
|
43558
|
+
adapters: [],
|
|
43559
|
+
// Calc using the maxLTV / targetLTV (0.5)
|
|
43560
|
+
targetHealthFactor: 1.32,
|
|
43561
|
+
// Calc using the maxLTV / maxAcceptableLTV (0.55)
|
|
43562
|
+
minHealthFactor: 1.2,
|
|
43563
|
+
vesuPoolId: VesuPools.Prime,
|
|
43564
|
+
collateralToken: Global.getDefaultTokens().find((t) => t.symbol === "USDC"),
|
|
43565
|
+
debtToken: Global.getDefaultTokens().find((t) => t.symbol === "STRK"),
|
|
43566
|
+
maxLTV: 0.66,
|
|
43567
|
+
targetLTV: 0.5,
|
|
43568
|
+
hyperxSTRKVaultAddress: ContractAddr.from(
|
|
43569
|
+
"0x46c7a54c82b1fe374353859f554a40b8bd31d3e30f742901579e7b57b1b5960"
|
|
43570
|
+
)
|
|
43571
|
+
};
|
|
43572
|
+
function getStrategySettings2(settings) {
|
|
43573
|
+
const USDCToken = Global.getDefaultTokens().find((t) => t.symbol === "USDC");
|
|
43574
|
+
const STRKToken = Global.getDefaultTokens().find((t) => t.symbol === "STRK");
|
|
42188
43575
|
return {
|
|
42189
|
-
id:
|
|
42190
|
-
name:
|
|
42191
|
-
description:
|
|
43576
|
+
id: "usdc_boosted",
|
|
43577
|
+
name: "USDC Boosted",
|
|
43578
|
+
description: "Deposits USDC as collateral on Vesu, borrows STRK, swaps to xSTRK, and deposits into Hyper-xSTRK for boosted yield",
|
|
42192
43579
|
address: settings.vaultAddress,
|
|
42193
|
-
launchBlock:
|
|
42194
|
-
type: "
|
|
43580
|
+
launchBlock: 8742931,
|
|
43581
|
+
type: "ERC4626",
|
|
42195
43582
|
vaultType: {
|
|
42196
|
-
|
|
42197
|
-
|
|
43583
|
+
// TODO: can change as per need
|
|
43584
|
+
type: "Meta Vault" /* META_VAULT */,
|
|
43585
|
+
description: "Deposits USDC as collateral on Vesu, borrows STRK, swaps to xSTRK, and deposits into Hyper-xSTRK for boosted yield"
|
|
42198
43586
|
},
|
|
42199
|
-
depositTokens: [
|
|
42200
|
-
additionalInfo:
|
|
43587
|
+
depositTokens: [USDCToken],
|
|
43588
|
+
additionalInfo: getUSDCBoostedSettings(settings),
|
|
43589
|
+
// TODO: config lateron
|
|
42201
43590
|
risk: {
|
|
42202
|
-
riskFactor:
|
|
42203
|
-
netRisk:
|
|
42204
|
-
notARisks:
|
|
43591
|
+
riskFactor: [],
|
|
43592
|
+
netRisk: 0,
|
|
43593
|
+
notARisks: []
|
|
42205
43594
|
},
|
|
42206
|
-
|
|
42207
|
-
protocols: [Protocols.ENDUR, Protocols.VESU],
|
|
43595
|
+
protocols: [Protocols.VESU, Protocols.TROVES],
|
|
42208
43596
|
curator: {
|
|
42209
43597
|
name: "Unwrap Labs",
|
|
42210
43598
|
logo: "https://assets.troves.fi/integrations/unwraplabs/white.png"
|
|
42211
43599
|
},
|
|
42212
|
-
settings:
|
|
43600
|
+
settings: {
|
|
43601
|
+
maxTVL: Web3Number.fromWei(0, USDCToken.decimals),
|
|
43602
|
+
isPaused: false,
|
|
43603
|
+
isAudited: false,
|
|
43604
|
+
isInstantWithdrawal: false,
|
|
43605
|
+
hideHarvestInfo: true,
|
|
43606
|
+
quoteToken: USDCToken,
|
|
43607
|
+
alerts: [
|
|
43608
|
+
{
|
|
43609
|
+
tab: "withdraw",
|
|
43610
|
+
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.",
|
|
43611
|
+
type: "info"
|
|
43612
|
+
}
|
|
43613
|
+
]
|
|
43614
|
+
},
|
|
42213
43615
|
contractDetails: getContractDetails(settings),
|
|
42214
|
-
|
|
42215
|
-
|
|
42216
|
-
|
|
42217
|
-
|
|
42218
|
-
|
|
42219
|
-
|
|
42220
|
-
|
|
42221
|
-
|
|
42222
|
-
|
|
42223
|
-
|
|
42224
|
-
|
|
42225
|
-
|
|
42226
|
-
|
|
42227
|
-
|
|
42228
|
-
|
|
43616
|
+
// TODO: config later
|
|
43617
|
+
faqs: [],
|
|
43618
|
+
investmentSteps: [
|
|
43619
|
+
"Deposit USDC into the vault",
|
|
43620
|
+
"USDC is supplied as collateral on Vesu, STRK is borrowed",
|
|
43621
|
+
"Borrowed STRK is swapped to xSTRK via Avnu",
|
|
43622
|
+
"xSTRK is deposited into the Hyper-xSTRK vault for additional yield",
|
|
43623
|
+
"On withdrawal, the pipeline reverses to return USDC"
|
|
43624
|
+
],
|
|
43625
|
+
// TODO: config later
|
|
43626
|
+
tags: ["Meta Vaults" /* META_VAULT */],
|
|
43627
|
+
security: {
|
|
43628
|
+
auditStatus: "Audited" /* AUDITED */,
|
|
43629
|
+
sourceCode: {
|
|
43630
|
+
type: "Closed Source" /* CLOSED_SOURCE */,
|
|
43631
|
+
contractLink: "https://github.com/trovesfi/troves-contracts"
|
|
43632
|
+
},
|
|
43633
|
+
accessControl: {
|
|
43634
|
+
type: "Standard Account" /* STANDARD_ACCOUNT */,
|
|
43635
|
+
addresses: [ContractAddr.from("0x0")],
|
|
43636
|
+
timeLock: "2 Days"
|
|
43637
|
+
}
|
|
43638
|
+
},
|
|
43639
|
+
redemptionInfo: {
|
|
43640
|
+
instantWithdrawalVault: "No" /* NO */,
|
|
43641
|
+
redemptionsInfo: [
|
|
43642
|
+
{
|
|
43643
|
+
title: "Typical Duration",
|
|
43644
|
+
description: "1-2 hours"
|
|
43645
|
+
}
|
|
43646
|
+
],
|
|
43647
|
+
alerts: [
|
|
43648
|
+
{
|
|
43649
|
+
type: "info",
|
|
43650
|
+
text: "Redemption times are estimates and may vary based on network conditions and liquidity requirements.",
|
|
43651
|
+
tab: "withdraw"
|
|
43652
|
+
}
|
|
43653
|
+
]
|
|
43654
|
+
},
|
|
43655
|
+
usualTimeToEarnings: null,
|
|
43656
|
+
usualTimeToEarningsDescription: null
|
|
42229
43657
|
};
|
|
42230
43658
|
}
|
|
42231
|
-
var
|
|
42232
|
-
getStrategySettings("xSTRK", "STRK", hyperxSTRK, false, true),
|
|
42233
|
-
getStrategySettings("xWBTC", "WBTC", hyperxWBTC, false, false),
|
|
42234
|
-
getStrategySettings("xtBTC", "tBTC", hyperxtBTC, false, false),
|
|
42235
|
-
getStrategySettings("xsBTC", "solvBTC", hyperxsBTC, false, false),
|
|
42236
|
-
getStrategySettings("xLBTC", "LBTC", hyperxLBTC, false, false),
|
|
42237
|
-
getStrategySettings("mRe7BTC", "mRe7BTC", hypermRe7BTC, false, false),
|
|
42238
|
-
getStrategySettings("mRe7YIELD", "mRe7YIELD", hypermRe7YIELD, false, false)
|
|
42239
|
-
];
|
|
43659
|
+
var USDCBoostedStrategies = [getStrategySettings2(usdcBoostedSettings)];
|
|
42240
43660
|
|
|
42241
43661
|
// src/strategies/vesu-extended-strategy/services/ltv-imbalance-rebalance-math.ts
|
|
42242
43662
|
function ceilBtc(v, precision) {
|
|
@@ -43635,6 +45055,142 @@ function createSolveBudgetFromRawState(params) {
|
|
|
43635
45055
|
}
|
|
43636
45056
|
return budget;
|
|
43637
45057
|
}
|
|
45058
|
+
function assertRouteSanityAndAdjust(route, availableAmount) {
|
|
45059
|
+
if (!route.amount) {
|
|
45060
|
+
throw new Error(`Invalid route given to assertRouteSanityAndAdjust: ${JSON.stringify(route)}`);
|
|
45061
|
+
}
|
|
45062
|
+
const routeAmount = route.amount.toNumber();
|
|
45063
|
+
if (routeAmount <= availableAmount) {
|
|
45064
|
+
return route;
|
|
45065
|
+
}
|
|
45066
|
+
if (routeAmount - availableAmount <= CASE_THRESHOLD_USD) {
|
|
45067
|
+
return { ...route, amount: new Web3Number(availableAmount, route.amount.decimals) };
|
|
45068
|
+
}
|
|
45069
|
+
throw new Error(`Route amount ${routeAmount} exceeds available amount ${availableAmount}, Route name: ${route.type}`);
|
|
45070
|
+
}
|
|
45071
|
+
function assertVesuMultiplyRouteSanityAndAdjust(route, availableAmount, state, isIncrease) {
|
|
45072
|
+
const btcPrice = state.vesuPoolState.collateralPrice;
|
|
45073
|
+
const totalCollateralAmount = isIncrease ? route.marginAmount.plus(route.swappedCollateralAmount).plus(state.vesuPoolState.collateralAmount) : state.vesuPoolState.collateralAmount.minus(route.marginAmount.plus(route.swappedCollateralAmount));
|
|
45074
|
+
const totalDebtAmount = isIncrease ? route.debtAmount.plus(state.vesuPoolState.debtAmount) : state.vesuPoolState.debtAmount.minus(route.debtAmount);
|
|
45075
|
+
const newHF = HealthFactorMath.getHealthFactor(
|
|
45076
|
+
totalCollateralAmount,
|
|
45077
|
+
btcPrice,
|
|
45078
|
+
VesuConfig.maxLtv,
|
|
45079
|
+
totalDebtAmount,
|
|
45080
|
+
state.vesuPoolState.debtPrice
|
|
45081
|
+
);
|
|
45082
|
+
const idealHF = VesuConfig.maxLtv / VesuConfig.targetLtv - 0.05;
|
|
45083
|
+
assert(newHF >= idealHF, `SolveBudget::applyRoutesAndVerifyLtvState newHF=${newHF} < idealHF=${idealHF}`);
|
|
45084
|
+
}
|
|
45085
|
+
function applyRoutesAndVerifyLtvState(state, routes) {
|
|
45086
|
+
const btcPrice = state.vesuPoolState.collateralPrice;
|
|
45087
|
+
const adjustedRouters = [...routes];
|
|
45088
|
+
let index = 0;
|
|
45089
|
+
for (const r of routes) {
|
|
45090
|
+
switch (r.type) {
|
|
45091
|
+
case "WALLET_TO_VA" /* WALLET_TO_VA */: {
|
|
45092
|
+
const adjustedRoute = assertRouteSanityAndAdjust(r, state.walletUsd);
|
|
45093
|
+
const amt = adjustedRoute.amount.toNumber();
|
|
45094
|
+
state.spendWallet(amt);
|
|
45095
|
+
state.addToVA(amt);
|
|
45096
|
+
break;
|
|
45097
|
+
}
|
|
45098
|
+
case "VESU_REPAY" /* VESU_REPAY */: {
|
|
45099
|
+
const adjustedRoute = assertRouteSanityAndAdjust(r, state.vaRawUsd);
|
|
45100
|
+
const amt = Math.abs(adjustedRoute.amount.toNumber());
|
|
45101
|
+
state.repayVesuBorrowCapacity(amt);
|
|
45102
|
+
state.spendVA(amt);
|
|
45103
|
+
break;
|
|
45104
|
+
}
|
|
45105
|
+
case "EXTENDED_TO_WALLET" /* EXTENDED_TO_WALLET */: {
|
|
45106
|
+
const adjustedRoute = assertRouteSanityAndAdjust(r, state.extAvailWithdraw);
|
|
45107
|
+
const amt = adjustedRoute.amount.toNumber();
|
|
45108
|
+
state.addToWallet(amt);
|
|
45109
|
+
state.spendExtAvailTrade(amt);
|
|
45110
|
+
break;
|
|
45111
|
+
}
|
|
45112
|
+
case "REALISE_PNL" /* REALISE_PNL */: {
|
|
45113
|
+
const amt = r.amount.toNumber();
|
|
45114
|
+
state.spendExtAvailUpnl(amt);
|
|
45115
|
+
state.addToExtAvailTrade(amt);
|
|
45116
|
+
break;
|
|
45117
|
+
}
|
|
45118
|
+
case "VA_TO_EXTENDED" /* VA_TO_EXTENDED */: {
|
|
45119
|
+
const adjustedRoute = assertRouteSanityAndAdjust(r, state.vaRawUsd);
|
|
45120
|
+
const amt = adjustedRoute.amount.toNumber();
|
|
45121
|
+
state.spendVA(amt);
|
|
45122
|
+
state.addToExtAvailTrade(amt);
|
|
45123
|
+
break;
|
|
45124
|
+
}
|
|
45125
|
+
case "WALLET_TO_EXTENDED" /* WALLET_TO_EXTENDED */: {
|
|
45126
|
+
const adjustedRoute = assertRouteSanityAndAdjust(r, state.walletUsd);
|
|
45127
|
+
const amt = adjustedRoute.amount.toNumber();
|
|
45128
|
+
state.spendWallet(amt);
|
|
45129
|
+
state.addToExtAvailTrade(amt);
|
|
45130
|
+
break;
|
|
45131
|
+
}
|
|
45132
|
+
case "VESU_BORROW" /* VESU_BORROW */: {
|
|
45133
|
+
const borrowedAmount = r.amount.toNumber();
|
|
45134
|
+
const currentCollateralAmount = state.vesuPoolState.collateralAmount.toNumber();
|
|
45135
|
+
const currentDebtAmount = state.vesuPoolState.debtAmount.toNumber();
|
|
45136
|
+
const maxDebtAmount = HealthFactorMath.getMaxDebtAmount(
|
|
45137
|
+
new Web3Number(currentCollateralAmount, state.vesuPoolState.collateralToken.decimals),
|
|
45138
|
+
state.vesuPoolState.collateralPrice,
|
|
45139
|
+
VesuConfig.maxLtv,
|
|
45140
|
+
VesuConfig.maxLtv / VesuConfig.targetLtv - 0.05,
|
|
45141
|
+
// e.g. if ideal HF is 1.4, upto 1.35 is ok.
|
|
45142
|
+
state.vesuPoolState.debtPrice,
|
|
45143
|
+
state.vesuPoolState.debtToken
|
|
45144
|
+
);
|
|
45145
|
+
const availableDebtAmount = maxDebtAmount.minus(new Web3Number(currentDebtAmount, state.vesuPoolState.debtToken.decimals));
|
|
45146
|
+
if (!availableDebtAmount.plus(CASE_THRESHOLD_USD).greaterThan(borrowedAmount)) {
|
|
45147
|
+
throw new Error(`SolveBudget::applyRoutesAndVerifyLtvState availableDebtAmount=${availableDebtAmount.toNumber()} < borrowedAmount=${borrowedAmount}`);
|
|
45148
|
+
}
|
|
45149
|
+
state.spendVesuBorrowCapacity(borrowedAmount);
|
|
45150
|
+
state.addToVA(borrowedAmount);
|
|
45151
|
+
break;
|
|
45152
|
+
}
|
|
45153
|
+
case "VESU_MULTIPLY_INCREASE_LEVER" /* VESU_MULTIPLY_INCREASE_LEVER */: {
|
|
45154
|
+
const mr = r;
|
|
45155
|
+
assertVesuMultiplyRouteSanityAndAdjust(mr, state.vaRawUsd, state, true);
|
|
45156
|
+
state.applyVesuDelta(
|
|
45157
|
+
mr.poolId,
|
|
45158
|
+
mr.collateralToken,
|
|
45159
|
+
mr.debtToken,
|
|
45160
|
+
mr.marginAmount.plus(mr.swappedCollateralAmount),
|
|
45161
|
+
mr.debtAmount
|
|
45162
|
+
);
|
|
45163
|
+
state.spendVA(mr.marginAmount.toNumber() * btcPrice);
|
|
45164
|
+
break;
|
|
45165
|
+
}
|
|
45166
|
+
case "VESU_MULTIPLY_DECREASE_LEVER" /* VESU_MULTIPLY_DECREASE_LEVER */: {
|
|
45167
|
+
const mr = r;
|
|
45168
|
+
assertVesuMultiplyRouteSanityAndAdjust(mr, state.vaRawUsd, state, false);
|
|
45169
|
+
state.applyVesuDelta(
|
|
45170
|
+
mr.poolId,
|
|
45171
|
+
mr.collateralToken,
|
|
45172
|
+
mr.debtToken,
|
|
45173
|
+
new Web3Number(mr.marginAmount.negated().minus(mr.swappedCollateralAmount).toFixed(8), mr.marginAmount.decimals),
|
|
45174
|
+
mr.debtAmount
|
|
45175
|
+
);
|
|
45176
|
+
const marginBtc = mr.marginAmount.toNumber();
|
|
45177
|
+
if (marginBtc > 10 ** -COLLATERAL_PRECISION) {
|
|
45178
|
+
state.addToVA(marginBtc * btcPrice);
|
|
45179
|
+
}
|
|
45180
|
+
break;
|
|
45181
|
+
}
|
|
45182
|
+
case "EXTENDED_DECREASE_LEVER" /* EXTENDED_DECREASE_LEVER */:
|
|
45183
|
+
case "EXTENDED_INCREASE_LEVER" /* EXTENDED_INCREASE_LEVER */: {
|
|
45184
|
+
const er = r;
|
|
45185
|
+
state.applyExtendedExposureDelta(er.instrument, er.amount, btcPrice);
|
|
45186
|
+
break;
|
|
45187
|
+
}
|
|
45188
|
+
case "RETURN_TO_WAIT" /* RETURN_TO_WAIT */:
|
|
45189
|
+
break;
|
|
45190
|
+
}
|
|
45191
|
+
index++;
|
|
45192
|
+
}
|
|
45193
|
+
}
|
|
43638
45194
|
var ExtendedSVKVesuStateManager = class {
|
|
43639
45195
|
constructor(config) {
|
|
43640
45196
|
this._tag = "ExtendedSVKVesuStateManager";
|
|
@@ -43653,13 +45209,19 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
43653
45209
|
* Pass 0 (default) for normal investment / rebalancing cycles.
|
|
43654
45210
|
*/
|
|
43655
45211
|
async solve(withdrawAmount = new Web3Number(0, USDC_TOKEN_DECIMALS)) {
|
|
43656
|
-
await this._refresh();
|
|
45212
|
+
const gaurdrailBudget = await this._refresh();
|
|
43657
45213
|
if (Math.abs(this._budget.extPendingDeposit) > 0) {
|
|
43658
45214
|
logger.warn(`${this._tag}::solve extPendingDeposit=${this._budget.extPendingDeposit}`);
|
|
43659
45215
|
return null;
|
|
43660
45216
|
}
|
|
43661
45217
|
this._validateRefreshedState();
|
|
43662
45218
|
const cases = this._classifyCases(withdrawAmount);
|
|
45219
|
+
for (const c of cases) {
|
|
45220
|
+
applyRoutesAndVerifyLtvState(gaurdrailBudget, c.routes);
|
|
45221
|
+
}
|
|
45222
|
+
const extendedPositionSize = gaurdrailBudget.extendedPositionsView[0].size.toNumber();
|
|
45223
|
+
const vesuPositionSize = gaurdrailBudget.vesuPoolState.collateralAmount.toNumber();
|
|
45224
|
+
assert(Math.abs(extendedPositionSize - vesuPositionSize) <= 1e-5, "extended positions size mismatch");
|
|
43663
45225
|
const result = {
|
|
43664
45226
|
cases,
|
|
43665
45227
|
// ignore these fields for now. only cases are relevant.
|
|
@@ -43707,7 +45269,7 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
43707
45269
|
vaultUsdcBalance,
|
|
43708
45270
|
walletBalance
|
|
43709
45271
|
);
|
|
43710
|
-
|
|
45272
|
+
const data = {
|
|
43711
45273
|
assetToken: this._config.assetToken,
|
|
43712
45274
|
usdcToken: this._config.usdcToken,
|
|
43713
45275
|
unusedBalance,
|
|
@@ -43724,7 +45286,9 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
43724
45286
|
pendingDeposit: extendedBalance?.pendingDeposit || new Web3Number(0, USDC_TOKEN_DECIMALS)
|
|
43725
45287
|
},
|
|
43726
45288
|
vesuPoolStates
|
|
43727
|
-
}
|
|
45289
|
+
};
|
|
45290
|
+
this._budget = createSolveBudgetFromRawState(data);
|
|
45291
|
+
const gaurdrailBudget = createSolveBudgetFromRawState({ ...data });
|
|
43728
45292
|
this._budget.logStateSummary();
|
|
43729
45293
|
const totalUnusedUsd = unusedBalance.reduce(
|
|
43730
45294
|
(acc, b) => acc + b.usdValue,
|
|
@@ -43733,6 +45297,7 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
43733
45297
|
logger.info(
|
|
43734
45298
|
`${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()}`
|
|
43735
45299
|
);
|
|
45300
|
+
return gaurdrailBudget;
|
|
43736
45301
|
}
|
|
43737
45302
|
// todo add communication check with python server of extended. if not working, throw error in solve function.
|
|
43738
45303
|
/** True when strategy asset and USDC share one token — VA idle balance is tracked as USDC, not as asset. */
|
|
@@ -45476,7 +47041,7 @@ var ExtendedSVKVesuStateManager = class {
|
|
|
45476
47041
|
};
|
|
45477
47042
|
|
|
45478
47043
|
// src/strategies/vesu-extended-strategy/services/executionService.ts
|
|
45479
|
-
import { uint256 as
|
|
47044
|
+
import { uint256 as uint25624 } from "starknet";
|
|
45480
47045
|
|
|
45481
47046
|
// src/strategies/vesu-extended-strategy/types/transaction-metadata.ts
|
|
45482
47047
|
var CycleType = /* @__PURE__ */ ((CycleType2) => {
|
|
@@ -46408,7 +47973,7 @@ var _ExecutionService = class _ExecutionService {
|
|
|
46408
47973
|
const extendedContract = extendedAdapter.config.extendedContract;
|
|
46409
47974
|
const vaultId = extendedAdapter.config.vaultIdExtended;
|
|
46410
47975
|
const salt = Math.floor(Math.random() * 10 ** usdcToken.decimals);
|
|
46411
|
-
const uint256Amount =
|
|
47976
|
+
const uint256Amount = uint25624.bnToUint256(amount.toWei());
|
|
46412
47977
|
const approveCall = {
|
|
46413
47978
|
contractAddress: usdcToken.address.address,
|
|
46414
47979
|
entrypoint: "approve",
|
|
@@ -48364,7 +49929,7 @@ var PricerRedis = class extends Pricer {
|
|
|
48364
49929
|
};
|
|
48365
49930
|
|
|
48366
49931
|
// src/node/deployer.ts
|
|
48367
|
-
import
|
|
49932
|
+
import assert3 from "assert";
|
|
48368
49933
|
import { Deployer as SnDeployer, TransactionExecutionStatus, constants as constants3, extractContractHashes, json, num as num14 } from "starknet";
|
|
48369
49934
|
import { readFileSync as readFileSync2, existsSync, writeFileSync as writeFileSync2 } from "fs";
|
|
48370
49935
|
|
|
@@ -48633,8 +50198,8 @@ async function prepareMultiDeployContracts(contracts, config, acc) {
|
|
|
48633
50198
|
classHash,
|
|
48634
50199
|
constructorCalldata: constructorData
|
|
48635
50200
|
}, acc.address);
|
|
48636
|
-
|
|
48637
|
-
|
|
50201
|
+
assert3(calls.length == 1, `Expected exactly one call, got ${calls.length}`);
|
|
50202
|
+
assert3(addresses.length == 1, `Expected exactly one address, got ${addresses.length}`);
|
|
48638
50203
|
result.push({
|
|
48639
50204
|
contract_name,
|
|
48640
50205
|
package_name,
|
|
@@ -48647,7 +50212,7 @@ async function prepareMultiDeployContracts(contracts, config, acc) {
|
|
|
48647
50212
|
}
|
|
48648
50213
|
async function executeDeployCalls(contractsInfo, acc, provider2) {
|
|
48649
50214
|
for (let contractInfo of contractsInfo) {
|
|
48650
|
-
|
|
50215
|
+
assert3(num14.toHexString(contractInfo.call.contractAddress) == num14.toHexString(constants3.UDC.ADDRESS), "Must be pointed at UDC address");
|
|
48651
50216
|
}
|
|
48652
50217
|
const allCalls = contractsInfo.map((info) => info.call);
|
|
48653
50218
|
await executeTransactions(allCalls, acc, provider2, `Deploying contracts: ${contractsInfo.map((info) => info.contract_name).join(", ")}`);
|
|
@@ -48791,6 +50356,7 @@ export {
|
|
|
48791
50356
|
SIMPLE_SANITIZER,
|
|
48792
50357
|
SIMPLE_SANITIZER_V2,
|
|
48793
50358
|
SIMPLE_SANITIZER_VESU_V1_DELEGATIONS,
|
|
50359
|
+
SVK_SIMPLE_SANITIZER,
|
|
48794
50360
|
SenseiStrategies,
|
|
48795
50361
|
SenseiVault,
|
|
48796
50362
|
SolveBudget,
|
|
@@ -48810,6 +50376,8 @@ export {
|
|
|
48810
50376
|
TokenTransferAdapter,
|
|
48811
50377
|
UNIVERSAL_ADAPTERS,
|
|
48812
50378
|
UNIVERSAL_MANAGE_IDS,
|
|
50379
|
+
USDCBoostedStrategies,
|
|
50380
|
+
USDCBoostedStrategy,
|
|
48813
50381
|
UniversalLstMultiplierStrategy,
|
|
48814
50382
|
UniversalStrategies,
|
|
48815
50383
|
UniversalStrategy,
|