@strkfarm/sdk 1.1.70 → 2.0.0-dev.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +2 -2
- package/dist/cli.mjs +2 -2
- package/dist/index.browser.global.js +66861 -59746
- package/dist/index.browser.mjs +24970 -18579
- package/dist/index.d.ts +1969 -776
- package/dist/index.js +25264 -18850
- package/dist/index.mjs +25463 -19089
- package/package.json +80 -76
- package/src/data/extended-deposit.abi.json +3613 -0
- package/src/data/universal-vault.abi.json +135 -20
- package/src/dataTypes/address.ts +8 -1
- package/src/global.ts +240 -193
- package/src/interfaces/common.tsx +26 -2
- package/src/modules/ExtendedWrapperSDk/index.ts +62 -0
- package/src/modules/ExtendedWrapperSDk/types.ts +311 -0
- package/src/modules/ExtendedWrapperSDk/wrapper.ts +395 -0
- package/src/modules/avnu.ts +17 -4
- package/src/modules/ekubo-quoter.ts +98 -10
- package/src/modules/erc20.ts +67 -21
- package/src/modules/harvests.ts +16 -29
- package/src/modules/index.ts +5 -1
- package/src/modules/lst-apr.ts +36 -0
- package/src/modules/midas.ts +159 -0
- package/src/modules/pricer-from-api.ts +2 -2
- package/src/modules/pricer-lst.ts +1 -1
- package/src/modules/pricer.ts +3 -38
- package/src/modules/token-market-data.ts +202 -0
- package/src/node/deployer.ts +1 -36
- package/src/strategies/autoCompounderStrk.ts +1 -1
- package/src/strategies/base-strategy.ts +20 -3
- package/src/strategies/ekubo-cl-vault.tsx +123 -306
- package/src/strategies/index.ts +4 -1
- package/src/strategies/svk-strategy.ts +247 -0
- package/src/strategies/universal-adapters/adapter-optimizer.ts +65 -0
- package/src/strategies/universal-adapters/adapter-utils.ts +5 -1
- package/src/strategies/universal-adapters/avnu-adapter.ts +418 -0
- package/src/strategies/universal-adapters/baseAdapter.ts +181 -153
- package/src/strategies/universal-adapters/common-adapter.ts +98 -77
- package/src/strategies/universal-adapters/extended-adapter.ts +544 -0
- package/src/strategies/universal-adapters/index.ts +5 -1
- package/src/strategies/universal-adapters/unused-balance-adapter.ts +109 -0
- package/src/strategies/universal-adapters/vesu-adapter.ts +220 -218
- package/src/strategies/universal-adapters/vesu-multiply-adapter.ts +924 -0
- package/src/strategies/universal-adapters/vesu-supply-only-adapter.ts +58 -51
- package/src/strategies/universal-lst-muliplier-strategy.tsx +707 -774
- package/src/strategies/universal-strategy.tsx +1098 -1180
- package/src/strategies/vesu-extended-strategy/services/operationService.ts +28 -0
- package/src/strategies/vesu-extended-strategy/utils/config.runtime.ts +77 -0
- package/src/strategies/vesu-extended-strategy/utils/constants.ts +48 -0
- package/src/strategies/vesu-extended-strategy/utils/helper.ts +374 -0
- package/src/strategies/vesu-extended-strategy/vesu-extended-strategy.tsx +992 -0
- package/src/strategies/vesu-rebalance.tsx +16 -19
- package/src/utils/health-factor-math.ts +11 -5
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Web3Number } from "@/dataTypes";
|
|
2
|
+
import { TokenInfo } from "@/interfaces";
|
|
3
|
+
import { ExtendedAdapter } from "@/strategies/universal-adapters/extended-adapter";
|
|
4
|
+
import { VesuMultiplyAdapter } from "../../universal-adapters/vesu-multiply-adapter";
|
|
5
|
+
import { Call } from "starknet";
|
|
6
|
+
export abstract class Operations {
|
|
7
|
+
abstract shouldMoveAssets(
|
|
8
|
+
extendedAmount: Web3Number,
|
|
9
|
+
vesuAmount: Web3Number
|
|
10
|
+
): Promise<Call[]>;
|
|
11
|
+
abstract shouldInvest(): Promise<{
|
|
12
|
+
shouldInvest: boolean;
|
|
13
|
+
vesuAmount: Web3Number;
|
|
14
|
+
extendedAmount: Web3Number;
|
|
15
|
+
extendedLeverage: number;
|
|
16
|
+
vesuLeverage: number;
|
|
17
|
+
}>;
|
|
18
|
+
abstract moveAssets(
|
|
19
|
+
params: { from: string; to: string; amount: Web3Number },
|
|
20
|
+
extendedAdapter: ExtendedAdapter,
|
|
21
|
+
vesuAdapter: VesuMultiplyAdapter
|
|
22
|
+
): Promise<Call[]>;
|
|
23
|
+
abstract handleDeposit(): Promise<{
|
|
24
|
+
extendedAmountInBTC: Web3Number;
|
|
25
|
+
calls: Call[];
|
|
26
|
+
}>;
|
|
27
|
+
abstract handleWithdraw(amount: Web3Number): Promise<Call[]>;
|
|
28
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AVNU_API,
|
|
3
|
+
USDC_TOKEN_ADDRESS,
|
|
4
|
+
USDC_TOKEN_DECIMALS,
|
|
5
|
+
WBTC_TOKEN_ADDRESS,
|
|
6
|
+
WBTC_TOKEN_DECIMALS,
|
|
7
|
+
WALLET_ADDRESS,
|
|
8
|
+
EXTEND_CONTRACT_ADDRESS,
|
|
9
|
+
MULTIPLY_CONTRACT_ADDRESS,
|
|
10
|
+
EXTENDED_BASE_URL,
|
|
11
|
+
EXTEND_MARKET_NAME,
|
|
12
|
+
EXTENDED_QTY_PRECISION,
|
|
13
|
+
EXTENDED_FEES,
|
|
14
|
+
MAINTENANCE_MARGIN,
|
|
15
|
+
VESU_POOL_ID,
|
|
16
|
+
MAX_LTV_BTC_USDC,
|
|
17
|
+
MAX_LIQUIDATION_RATIO,
|
|
18
|
+
TARGET_HF,
|
|
19
|
+
EKUBO_ENDPOINT,
|
|
20
|
+
PRICE_MAX_SLIPPAGE_EKUBO,
|
|
21
|
+
MINIMUM_DEBT_AMOUNT_VESU_FOR_REBALANCING,
|
|
22
|
+
MINIMUM_EXTENDED_POSITION_SIZE
|
|
23
|
+
} from "./constants"
|
|
24
|
+
import VesuPoolV2Abi from '@/data/vesu-pool-v2.abi.json';
|
|
25
|
+
import ExtendedDepositAbi from '@/data/extended-deposit.abi.json';
|
|
26
|
+
import VesuMultiplyAbi from '@/data/vesu-multiple.abi.json';
|
|
27
|
+
|
|
28
|
+
// Grouped, readable configuration (no behavior change). Consumers can migrate gradually.
|
|
29
|
+
|
|
30
|
+
export const AddressesConfig = {
|
|
31
|
+
tokens: {
|
|
32
|
+
USDC: { address: USDC_TOKEN_ADDRESS, decimals: USDC_TOKEN_DECIMALS },
|
|
33
|
+
WBTC: { address: WBTC_TOKEN_ADDRESS, decimals: WBTC_TOKEN_DECIMALS },
|
|
34
|
+
},
|
|
35
|
+
contracts: {
|
|
36
|
+
EXTENDED: EXTEND_CONTRACT_ADDRESS,
|
|
37
|
+
MULTIPLY: MULTIPLY_CONTRACT_ADDRESS,
|
|
38
|
+
},
|
|
39
|
+
wallet: {
|
|
40
|
+
address: WALLET_ADDRESS,
|
|
41
|
+
},
|
|
42
|
+
} as const;
|
|
43
|
+
|
|
44
|
+
export const ExtendedConfig = {
|
|
45
|
+
baseUrl: EXTENDED_BASE_URL,
|
|
46
|
+
marketName: EXTEND_MARKET_NAME,
|
|
47
|
+
maintenanceMargin: MAINTENANCE_MARGIN,
|
|
48
|
+
precision: EXTENDED_QTY_PRECISION,
|
|
49
|
+
fees: EXTENDED_FEES,
|
|
50
|
+
minPositionSize: MINIMUM_EXTENDED_POSITION_SIZE,
|
|
51
|
+
} as const;
|
|
52
|
+
|
|
53
|
+
export const VesuConfig = {
|
|
54
|
+
poolId: VESU_POOL_ID,
|
|
55
|
+
maxLtv: MAX_LTV_BTC_USDC,
|
|
56
|
+
maxLiquidationRatio: MAX_LIQUIDATION_RATIO,
|
|
57
|
+
targetHealthFactor: TARGET_HF,
|
|
58
|
+
ekubo: {
|
|
59
|
+
endpoint: EKUBO_ENDPOINT,
|
|
60
|
+
priceMaxSlippage: PRICE_MAX_SLIPPAGE_EKUBO,
|
|
61
|
+
},
|
|
62
|
+
avnu: {
|
|
63
|
+
api: AVNU_API,
|
|
64
|
+
},
|
|
65
|
+
minDebtForVesuRebalacing:MINIMUM_DEBT_AMOUNT_VESU_FOR_REBALANCING
|
|
66
|
+
} as const;
|
|
67
|
+
|
|
68
|
+
export const AbisConfig = {
|
|
69
|
+
vesu: {
|
|
70
|
+
multiply: VesuMultiplyAbi,
|
|
71
|
+
pool: VesuPoolV2Abi,
|
|
72
|
+
},
|
|
73
|
+
extended: {
|
|
74
|
+
contract: ExtendedDepositAbi,
|
|
75
|
+
},
|
|
76
|
+
} as const;
|
|
77
|
+
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
export const AVNU_API = "https://starknet.api.avnu.fi/swap/v2/quotes";
|
|
2
|
+
export const SLIPPAGE = 0.01;
|
|
3
|
+
export const USDC_TOKEN_DECIMALS = 6;
|
|
4
|
+
export const USDC_TOKEN_ADDRESS =
|
|
5
|
+
"0x053C91253BC9682c04929cA02ED00b3E423f6710D2ee7e0D5EBB06F3eCF368A8";
|
|
6
|
+
export const WBTC_TOKEN_ADDRESS = "0x3fe2b97c1fd336e750087d68b9b867997fd64a2661ff3ca5a7c771641e8e7ac";
|
|
7
|
+
export const WBTC_TOKEN_DECIMALS = 8;
|
|
8
|
+
export const MAINTENANCE_MARGIN = 0.01;
|
|
9
|
+
export const MAX_PRICE_DROP_PERCENTAGE = Number(process.env.MAX_PRICE_DROP_PERCENTAGE ?? 0.25);
|
|
10
|
+
export const MAX_LTV_BTC_USDC = 0.8428;
|
|
11
|
+
export const MAX_LIQUIDATION_RATIO = 0.86;
|
|
12
|
+
export const VAULT_ID_EXTENDED= process.env.VAULT_ID_EXTENDED ?? 220774;
|
|
13
|
+
export const WALLET_ADDRESS =
|
|
14
|
+
process.env.WALLET_ADDRESS ?? "0x07b84bb6E87588BdAde0bfe6173A615b3C220F9C3803456aE183C50EA1d15Ba1";
|
|
15
|
+
export const TESTNET_WALLET_ADDRESS =
|
|
16
|
+
process.env.TESTNET_WALLET_ADDRESS ?? "0x07b84bb6E87588BdAde0bfe6173A615b3C220F9C3803456aE183C50EA1d15Ba1";
|
|
17
|
+
export const TEST_WALLET_2 =
|
|
18
|
+
process.env.TEST_WALLET_2 ?? "0x004C1bdC61DAc7947F3C93d0163d660012E2aB0521567f7155fcf502848791A7";
|
|
19
|
+
export const STRK_API_TEST_RPC = process.env.STRK_API_TEST_RPC ?? "https://sepolia.starknet.a5a.ch";
|
|
20
|
+
export const STRK_API_RPC = process.env.STRK_API_RPC ?? "https://mainnet.starknet.a5a.ch";
|
|
21
|
+
export const MAX_RETRIES = Number(process.env.MAX_RETRIES ?? 3);
|
|
22
|
+
export const MAX_DELAY = Number(process.env.MAX_DELAY ?? 100);
|
|
23
|
+
export const EXTEND_MARKET_NAME = "BTC-USD";
|
|
24
|
+
export const LIMIT_BALANCE = Number(process.env.LIMIT_BALANCE ?? 10);
|
|
25
|
+
export const REBALANCER_INTERVAL = Number(process.env.REBALANCER_INTERVAL ?? 180000); //3 mins
|
|
26
|
+
export const WITHDRAWAL_INTERVAL = Number(process.env.WITHDRAWAL_INTERVAL ?? 18000000); //5 hours
|
|
27
|
+
export const INVESTING_INTERVAL = Number(process.env.INVESTING_INTERVAL ?? 180000); //3 mins
|
|
28
|
+
export const MAXIMUM_DELTA = Number(process.env.MAXIMUM_DELTA ?? 5);
|
|
29
|
+
export const EXTENDED_BASE_URL = process.env.EXTENDED_BASE_URL ?? "https://api.starknet.extended.exchange";
|
|
30
|
+
export const VESU_POOL_ID = "0x02eef0c13b10b487ea5916b54c0a7f98ec43fb3048f60fdeedaf5b08f6f88aaf";
|
|
31
|
+
export const EKUBO_ENDPOINT = "https://quoter-mainnet-api.ekubo.org/{{AMOUNT}}/{{TOKEN_FROM_ADDRESS}}/{{TOKEN_TO_ADDRESS}}"; // e.g. ETH/USDC'
|
|
32
|
+
export const TARGET_HF = Number(process.env.TARGET_HF ?? 1.4);
|
|
33
|
+
export const MULTIPLY_CONTRACT_ADDRESS = "0x07964760e90baa28841ec94714151e03fbc13321797e68a874e88f27c9d58513";
|
|
34
|
+
export const EXTEND_CONTRACT_ADDRESS = "0x062da0780fae50d68cecaa5a051606dc21217ba290969b302db4dd99d2e9b470";
|
|
35
|
+
export const EXTENDED_QTY_PRECISION = 5;
|
|
36
|
+
export const EXTENDED_FEES= Number(process.env.EXTENDED_FEES ?? 0.006);
|
|
37
|
+
export const REBALANCE_PRICE_DROP_PERCENTAGE = Number(process.env.REBALANCE_PRICE_DROP_PERCENTAGE ?? 3);
|
|
38
|
+
export const PRICE_MAX_SLIPPAGE_EKUBO = Number(process.env.PRICE_MAX_SLIPPAGE_EKUBO ?? 0.005);
|
|
39
|
+
export const MINIMUM_DEBT_AMOUNT_VESU_FOR_REBALANCING = Number(process.env.MINIMUM_DEBT_AMOUNT_VESU_FOR_REBALANCING ?? 1);
|
|
40
|
+
export const MINIMUM_EXTENDED_POSITION_SIZE = 0.0001;
|
|
41
|
+
export const MINIMUM_WBTC_DIFFERENCE_FOR_AVNU_SWAP = 0.00001;
|
|
42
|
+
export const MAX_PRICE_DIFFERENCE_BETWEEN_AVNU_AND_EXTENDED = 700;
|
|
43
|
+
export const MIN_PRICE_DIFFERENCE_BETWEEN_AVNU_AND_EXTENDED = -100;
|
|
44
|
+
|
|
45
|
+
//STATUS CODES
|
|
46
|
+
export const SUCCESS_STATUS_CODE = 200;
|
|
47
|
+
export const ERROR_STATUS_CODE = 500;
|
|
48
|
+
export const BAD_REQUEST_STATUS_CODE = 400;
|
|
@@ -0,0 +1,374 @@
|
|
|
1
|
+
import {
|
|
2
|
+
MAINTENANCE_MARGIN,
|
|
3
|
+
MAX_LTV_BTC_USDC,
|
|
4
|
+
MAX_PRICE_DROP_PERCENTAGE,
|
|
5
|
+
TARGET_HF,
|
|
6
|
+
WBTC_TOKEN_ADDRESS,
|
|
7
|
+
USDC_TOKEN_ADDRESS,
|
|
8
|
+
WBTC_TOKEN_DECIMALS,
|
|
9
|
+
USDC_TOKEN_DECIMALS,
|
|
10
|
+
MAX_LIQUIDATION_RATIO,
|
|
11
|
+
} from "./constants";
|
|
12
|
+
import { Web3Number } from "@/dataTypes";
|
|
13
|
+
import { Position } from "@/modules/ExtendedWrapperSDk";
|
|
14
|
+
// import { getAllOpenPositionsExtended } from "../services/extendedService";
|
|
15
|
+
import ExtendedWrapper from "@/modules/ExtendedWrapperSDk";
|
|
16
|
+
import { logger } from "@/utils";
|
|
17
|
+
// import {
|
|
18
|
+
// calculatePositionOnVesu,
|
|
19
|
+
// getAssetPrice,
|
|
20
|
+
// } from "../services/vesuService";
|
|
21
|
+
/**
|
|
22
|
+
* Function to return formatted amount to BigInt
|
|
23
|
+
* Converts a decimal amount to the proper format for blockchain transactions
|
|
24
|
+
* @param {number} amount - The decimal amount to convert
|
|
25
|
+
* @param {number} fromTokenDecimals - The decimal precision of the token
|
|
26
|
+
* @returns {string} The formatted amount as a hexadecimal string
|
|
27
|
+
*/
|
|
28
|
+
export const returnFormattedAmount = (
|
|
29
|
+
amount: number,
|
|
30
|
+
toTokenDecimals: number
|
|
31
|
+
) => {
|
|
32
|
+
const formattedAmount =
|
|
33
|
+
"0x" + BigInt(Math.floor(amount * 10 ** toTokenDecimals)).toString(16);
|
|
34
|
+
return formattedAmount;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* calculates the amount to distribute to Extend and Vesu
|
|
39
|
+
* Determines how much to allocate to each platform based on leverage calculations
|
|
40
|
+
* @param {number} amount - The total amount to distribute
|
|
41
|
+
* @returns {object} Object containing avnu_amount, extended_amount, and extended_leverage
|
|
42
|
+
*/
|
|
43
|
+
export const calculateAmountDistribution = async (
|
|
44
|
+
amount: number,
|
|
45
|
+
client: ExtendedWrapper,
|
|
46
|
+
marketName: string,
|
|
47
|
+
collateralPrice: number,
|
|
48
|
+
debtPrice: number,
|
|
49
|
+
collateralUnits: Web3Number,
|
|
50
|
+
extendedPosition: Position[] | null
|
|
51
|
+
): Promise<{
|
|
52
|
+
vesu_amount: Web3Number;
|
|
53
|
+
extended_amount: Web3Number;
|
|
54
|
+
extended_leverage: number;
|
|
55
|
+
vesu_leverage: number;
|
|
56
|
+
}> => {
|
|
57
|
+
try {
|
|
58
|
+
const extended_leverage = calculateExtendedLevergae();
|
|
59
|
+
const vesu_leverage = calculateVesuLeverage();
|
|
60
|
+
if (extendedPosition === null) {
|
|
61
|
+
logger.error("error getting extended positions");
|
|
62
|
+
return {
|
|
63
|
+
vesu_amount: new Web3Number(0, 0),
|
|
64
|
+
extended_amount: new Web3Number(0, 0),
|
|
65
|
+
extended_leverage: 0,
|
|
66
|
+
vesu_leverage: 0,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
const extendedBTCExposure =
|
|
70
|
+
extendedPosition.length > 0
|
|
71
|
+
? new Web3Number(extendedPosition[0].size, WBTC_TOKEN_DECIMALS)
|
|
72
|
+
: new Web3Number(0, WBTC_TOKEN_DECIMALS);
|
|
73
|
+
const extendedExposureUSD =
|
|
74
|
+
extendedBTCExposure.multipliedBy(collateralPrice);
|
|
75
|
+
const vesuBTCExposureUSD = collateralUnits.multipliedBy(collateralPrice);
|
|
76
|
+
const numerator1 = vesu_leverage * amount + vesuBTCExposureUSD.toNumber();
|
|
77
|
+
const numerator2 = extendedExposureUSD.toNumber();
|
|
78
|
+
const denominator = vesu_leverage + extended_leverage;
|
|
79
|
+
const ExtendedAmount = new Web3Number(
|
|
80
|
+
((numerator1 - numerator2) / denominator).toFixed(2),
|
|
81
|
+
USDC_TOKEN_DECIMALS
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
const VesuAmount = new Web3Number(
|
|
85
|
+
amount.toFixed(2),
|
|
86
|
+
USDC_TOKEN_DECIMALS
|
|
87
|
+
).minus(ExtendedAmount);
|
|
88
|
+
|
|
89
|
+
return {
|
|
90
|
+
vesu_amount: VesuAmount,
|
|
91
|
+
extended_amount: ExtendedAmount,
|
|
92
|
+
extended_leverage,
|
|
93
|
+
vesu_leverage,
|
|
94
|
+
};
|
|
95
|
+
} catch (err) {
|
|
96
|
+
return {
|
|
97
|
+
vesu_amount: new Web3Number(0, 0),
|
|
98
|
+
extended_amount: new Web3Number(0, 0),
|
|
99
|
+
extended_leverage: 0,
|
|
100
|
+
vesu_leverage: 0,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* calculate the amount distribution for withdrawal
|
|
107
|
+
* @param amount - The amount to withdraw
|
|
108
|
+
* @param client - The client
|
|
109
|
+
* @param marketName - The market name
|
|
110
|
+
* @returns {object} Object containing avnu_amount and extended_amount
|
|
111
|
+
*/
|
|
112
|
+
export const calculateAmountDistributionForWithdrawal = async (
|
|
113
|
+
amountInUsdc: Web3Number,
|
|
114
|
+
collateralPrice: number,
|
|
115
|
+
collateralUnits: Web3Number,
|
|
116
|
+
extendedPosition: Position[] | null
|
|
117
|
+
): Promise<{
|
|
118
|
+
vesu_amount: Web3Number;
|
|
119
|
+
extended_amount: Web3Number;
|
|
120
|
+
extended_leverage: number;
|
|
121
|
+
vesu_leverage: number;
|
|
122
|
+
} | null> => {
|
|
123
|
+
try {
|
|
124
|
+
const extended_leverage = calculateExtendedLevergae();
|
|
125
|
+
const vesu_leverage = calculateVesuLeverage();
|
|
126
|
+
if (extendedPosition === null) {
|
|
127
|
+
logger.error("error getting extended positions");
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
const extendedBTCExposure =
|
|
131
|
+
extendedPosition.length > 0
|
|
132
|
+
? new Web3Number(extendedPosition[0].size, WBTC_TOKEN_DECIMALS)
|
|
133
|
+
: new Web3Number(0, WBTC_TOKEN_DECIMALS);
|
|
134
|
+
const extendedExposureUSD =
|
|
135
|
+
extendedBTCExposure.multipliedBy(collateralPrice);
|
|
136
|
+
// console.log("the extended exposure usd is", extendedExposureUSD.toNumber());
|
|
137
|
+
//console.log("the collateral units are", collateralUnits.toNumber());\
|
|
138
|
+
const vesuExposureUSD = collateralUnits.multipliedBy(collateralPrice);
|
|
139
|
+
if (vesuExposureUSD.lessThan(0)) {
|
|
140
|
+
return {
|
|
141
|
+
vesu_amount: new Web3Number(0, USDC_TOKEN_DECIMALS),
|
|
142
|
+
extended_amount: amountInUsdc,
|
|
143
|
+
extended_leverage,
|
|
144
|
+
vesu_leverage,
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
if (extendedExposureUSD.lessThan(0)) {
|
|
148
|
+
return {
|
|
149
|
+
vesu_amount: amountInUsdc,
|
|
150
|
+
extended_amount: new Web3Number(0, USDC_TOKEN_DECIMALS),
|
|
151
|
+
extended_leverage,
|
|
152
|
+
vesu_leverage,
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
//console.log("the vesu exposure usd is", vesuExposureUSD.toNumber());
|
|
156
|
+
const numerator1 = amountInUsdc.multipliedBy(extended_leverage);
|
|
157
|
+
const numerator2 = vesuExposureUSD.multipliedBy(vesu_leverage);
|
|
158
|
+
const numerator3 = extendedExposureUSD
|
|
159
|
+
.multipliedBy(extended_leverage)
|
|
160
|
+
.multipliedBy(-1);
|
|
161
|
+
const finalNumerator = numerator1.plus(numerator2).plus(numerator3);
|
|
162
|
+
const denominator = extended_leverage + vesu_leverage;
|
|
163
|
+
const vesuAmountInUSDC = finalNumerator.dividedBy(denominator);
|
|
164
|
+
console.log("the vesu amount in usdc is", vesuAmountInUSDC.toNumber());
|
|
165
|
+
const extendedAmountInUSDC = amountInUsdc.minus(vesuAmountInUSDC);
|
|
166
|
+
console.log(
|
|
167
|
+
"the extended amount in usdc is",
|
|
168
|
+
extendedAmountInUSDC.toNumber()
|
|
169
|
+
);
|
|
170
|
+
//console.log("the vesu amount in usdc is", vesuAmountInUSDC.toNumber());
|
|
171
|
+
//console.log("the extended amount in usdc is", extendedAmountInUSDC.toNumber());
|
|
172
|
+
|
|
173
|
+
return {
|
|
174
|
+
vesu_amount: vesuAmountInUSDC,
|
|
175
|
+
extended_amount: extendedAmountInUSDC,
|
|
176
|
+
extended_leverage,
|
|
177
|
+
vesu_leverage,
|
|
178
|
+
};
|
|
179
|
+
} catch (err) {
|
|
180
|
+
logger.error(`error calculating amount distribution for withdrawal: ${err}`);
|
|
181
|
+
return null;
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
/**
|
|
185
|
+
* calculate the leverage required for Avnu
|
|
186
|
+
* calculates the optimal leverage for Avnu based on LTV ratios and price drop protection
|
|
187
|
+
* @returns {number} The calculated leverage value
|
|
188
|
+
*/
|
|
189
|
+
export const calculateVesuLeverage = () => {
|
|
190
|
+
const max_ltv_ratio = (1 - MAX_PRICE_DROP_PERCENTAGE) * MAX_LIQUIDATION_RATIO; //0.75
|
|
191
|
+
const our_ltv_ratio = Math.floor(max_ltv_ratio * 100) - 5; //buffer of 5% to prevent liquidation
|
|
192
|
+
const leverage = 1 / (1 - our_ltv_ratio / 100);
|
|
193
|
+
return Math.ceil(leverage * 10) / 10;
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* calculate leverage for extended
|
|
198
|
+
* calculates the maximum safe leverage for Extended based on maintenance margin and price drop protection
|
|
199
|
+
* @returns {number} The calculated leverage value
|
|
200
|
+
*/
|
|
201
|
+
export const calculateExtendedLevergae = () => {
|
|
202
|
+
const extended_leverage_max =
|
|
203
|
+
1 / (MAINTENANCE_MARGIN + MAX_PRICE_DROP_PERCENTAGE);
|
|
204
|
+
return Math.floor(extended_leverage_max);
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* calculates the debt amount for leverage operations
|
|
209
|
+
* Determines how much debt to add or remove based on collateral changes and target health factor
|
|
210
|
+
* @param {Web3Number} collateralAmount - Current collateral amount
|
|
211
|
+
* @param {Web3Number} debtAmount - Current debt amount
|
|
212
|
+
* @param {number} debtPrice - Current price of the debt token
|
|
213
|
+
* @param {number} maxLtv - Maximum loan-to-value ratio (default: MAX_LTV_BTC_USDC)
|
|
214
|
+
* @param {number} addedAmount - Amount being added to collateral
|
|
215
|
+
* @param {number} collateralPrice - Current price of the collateral token
|
|
216
|
+
* @param {boolean} isDeposit - Whether this is a deposit (true) or withdrawal (false)
|
|
217
|
+
* @returns {object} Object containing deltadebtAmountUnits and isIncrease flag
|
|
218
|
+
*/
|
|
219
|
+
// In case BTC_PRICE DROPS the added amount will be zero, and use this formula to calculated the debt that needs to be paid to maintain the ltv
|
|
220
|
+
export const calculateDebtAmount = (
|
|
221
|
+
collateralAmount: Web3Number,
|
|
222
|
+
debtAmount: Web3Number,
|
|
223
|
+
debtPrice: number,
|
|
224
|
+
maxLtv: number = MAX_LTV_BTC_USDC,
|
|
225
|
+
addedAmount: Web3Number, // this is in btc
|
|
226
|
+
collateralPrice: number,
|
|
227
|
+
isDeposit: boolean
|
|
228
|
+
) => {
|
|
229
|
+
try {
|
|
230
|
+
// => X = (((collateral + legDepositAmount) * collateralPrice * ltv) - (debt * debtPrice * target hf)) / (target hf - ltv)
|
|
231
|
+
const marginAmount = addedAmount.multipliedBy(isDeposit ? 1 : -1);
|
|
232
|
+
const numerator1 = collateralAmount
|
|
233
|
+
.plus(addedAmount)
|
|
234
|
+
.multipliedBy(collateralPrice)
|
|
235
|
+
.multipliedBy(maxLtv);
|
|
236
|
+
const numerator2 = debtAmount
|
|
237
|
+
.multipliedBy(debtPrice)
|
|
238
|
+
.multipliedBy(TARGET_HF);
|
|
239
|
+
const denominator = TARGET_HF - maxLtv;
|
|
240
|
+
const x_debt_usd = numerator1.minus(numerator2).dividedBy(denominator);
|
|
241
|
+
let deltadebtAmountUnits = new Web3Number(
|
|
242
|
+
x_debt_usd.dividedBy(debtPrice).toFixed(2),
|
|
243
|
+
2
|
|
244
|
+
);
|
|
245
|
+
let isIncrease = x_debt_usd.greaterThan(0);
|
|
246
|
+
return { deltadebtAmountUnits, isIncrease };
|
|
247
|
+
} catch (err) {
|
|
248
|
+
return { deltadebtAmountUnits: null, isIncrease: null };
|
|
249
|
+
}
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* calculate the debt amount to be repaid for withdrawal
|
|
254
|
+
* @param debtAmount in debt units
|
|
255
|
+
* @param collateralAmount in collateral units
|
|
256
|
+
* @param maxLtv in percentage
|
|
257
|
+
* @param withdrawalAmount in collateral units
|
|
258
|
+
* @param collateralPrice in usd
|
|
259
|
+
* @param debtPrice in usd
|
|
260
|
+
* @returns deltadebtAmountUnits in debt units
|
|
261
|
+
* isIncrease: true if the debt amount is increasing, false if it is decreasing
|
|
262
|
+
*/
|
|
263
|
+
export const calculateDebtReductionAmountForWithdrawal = (
|
|
264
|
+
debtAmount: Web3Number,
|
|
265
|
+
collateralAmount: Web3Number,
|
|
266
|
+
maxLtv: number = MAX_LTV_BTC_USDC,
|
|
267
|
+
withdrawalAmount: Web3Number,
|
|
268
|
+
collateralPrice: number,
|
|
269
|
+
debtPrice: number,
|
|
270
|
+
usdcDecimals: number
|
|
271
|
+
) => {
|
|
272
|
+
try {
|
|
273
|
+
const vesuLeverage = calculateVesuLeverage();
|
|
274
|
+
const numerator1 = collateralAmount
|
|
275
|
+
.multipliedBy(collateralPrice)
|
|
276
|
+
.multipliedBy(maxLtv)
|
|
277
|
+
.multipliedBy(-1);
|
|
278
|
+
withdrawalAmount = withdrawalAmount.multipliedBy(vesuLeverage);
|
|
279
|
+
const numerator2 = debtAmount
|
|
280
|
+
.multipliedBy(debtPrice)
|
|
281
|
+
.multipliedBy(TARGET_HF);
|
|
282
|
+
const numerator3 = withdrawalAmount
|
|
283
|
+
.multipliedBy(collateralPrice)
|
|
284
|
+
.multipliedBy(maxLtv);
|
|
285
|
+
const numeratorTotal = numerator1.plus(numerator2).plus(numerator3);
|
|
286
|
+
const denominator = debtPrice * TARGET_HF;
|
|
287
|
+
const x_debt_usdc = numeratorTotal.dividedBy(denominator);
|
|
288
|
+
let deltadebtAmountUnits = x_debt_usdc
|
|
289
|
+
.multipliedBy(-1)
|
|
290
|
+
.toFixed(usdcDecimals); // means we are paying debt
|
|
291
|
+
return { deltadebtAmountUnits };
|
|
292
|
+
} catch (err) {
|
|
293
|
+
return { deltadebtAmountUnits: null };
|
|
294
|
+
}
|
|
295
|
+
};
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* calculate the amount to deposit on extended when incurring losses
|
|
299
|
+
* @param client - The client
|
|
300
|
+
* @returns The amount to deposit on extended when incurring losses
|
|
301
|
+
*/
|
|
302
|
+
export const calculateAmountDepositOnExtendedWhenIncurringLosses = async (
|
|
303
|
+
client: ExtendedWrapper
|
|
304
|
+
) => {
|
|
305
|
+
try {
|
|
306
|
+
const extendedHoldings = await client.getHoldings();
|
|
307
|
+
const extended_leverage = calculateExtendedLevergae();
|
|
308
|
+
const latestPosition = (await client.getPositions()).data.pop();
|
|
309
|
+
console.log("the latest position is", latestPosition, extendedHoldings);
|
|
310
|
+
if (!extendedHoldings || !latestPosition) {
|
|
311
|
+
logger.error(`error getting extended position: extendedHoldings=${extendedHoldings}, latestPosition=${latestPosition}`);
|
|
312
|
+
return null;
|
|
313
|
+
}
|
|
314
|
+
const positionValueInUSD = latestPosition.value;
|
|
315
|
+
const equity = extendedHoldings.data.equity;
|
|
316
|
+
const deposit =
|
|
317
|
+
Number(positionValueInUSD) / extended_leverage - Number(equity);
|
|
318
|
+
return new Web3Number(Math.floor(deposit / 0.2) * 0.2, USDC_TOKEN_DECIMALS);
|
|
319
|
+
} catch (err) {
|
|
320
|
+
return null;
|
|
321
|
+
}
|
|
322
|
+
};
|
|
323
|
+
|
|
324
|
+
export const calculateExposureDelta = (
|
|
325
|
+
exposure_extended: number,
|
|
326
|
+
exposure_vesu: number
|
|
327
|
+
) => {
|
|
328
|
+
const exposure_delta = new Web3Number(exposure_extended - exposure_vesu, 2);
|
|
329
|
+
return exposure_delta.absoluteValue().toNumber();
|
|
330
|
+
};
|
|
331
|
+
|
|
332
|
+
/// In case BTC PRICE DROPS
|
|
333
|
+
// 1. calculate the ltv on vesu
|
|
334
|
+
// 2. Find the debt that needs to be paid to maintain the ltv
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* calculate the delta percentage between the current btc price and the last btc price
|
|
338
|
+
* @param {number} btcPrice - The current btc price
|
|
339
|
+
* @param {number} lastBtcPrice - The last btc price
|
|
340
|
+
* @returns {number} The delta percentage
|
|
341
|
+
*/
|
|
342
|
+
export const calculateBTCPriceDelta = (
|
|
343
|
+
btcPrice: number,
|
|
344
|
+
lastBtcPrice: number
|
|
345
|
+
) => {
|
|
346
|
+
return ((btcPrice - lastBtcPrice) / lastBtcPrice) * 100;
|
|
347
|
+
};
|
|
348
|
+
|
|
349
|
+
export const calculateVesUPositionSizeGivenExtended = (
|
|
350
|
+
extendedPositonValue: number,
|
|
351
|
+
extendedHoldingAmount: Web3Number,
|
|
352
|
+
collateralAmount: Web3Number,
|
|
353
|
+
collateralPrice: number
|
|
354
|
+
) => {
|
|
355
|
+
const extendedLeverage = calculateExtendedLevergae();
|
|
356
|
+
const vesuLeverage = calculateVesuLeverage();
|
|
357
|
+
const extendedAmount = extendedHoldingAmount;
|
|
358
|
+
const extendedAmountInBTC = extendedAmount
|
|
359
|
+
.dividedBy(collateralPrice)
|
|
360
|
+
const numerator1 = extendedAmount.multipliedBy(extendedLeverage)
|
|
361
|
+
.plus(extendedPositonValue)
|
|
362
|
+
const numerator2 = collateralAmount
|
|
363
|
+
.multipliedBy(collateralPrice)
|
|
364
|
+
.multipliedBy(-1);
|
|
365
|
+
const vesuAmountInUsd = numerator1.plus(numerator2).dividedBy(vesuLeverage);
|
|
366
|
+
const vesuAmountInBTC = vesuAmountInUsd
|
|
367
|
+
.dividedBy(collateralPrice)
|
|
368
|
+
.toFixed(WBTC_TOKEN_DECIMALS);
|
|
369
|
+
return {
|
|
370
|
+
vesuAmountInUsd: vesuAmountInUsd.toFixed(2),
|
|
371
|
+
vesuAmountInBTC: new Web3Number(vesuAmountInBTC, WBTC_TOKEN_DECIMALS),
|
|
372
|
+
extendedAmountInBTC: extendedAmountInBTC,
|
|
373
|
+
};
|
|
374
|
+
};
|