@varla/sdk 1.11.4 → 1.14.0
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/AGENTS.md +82 -95
- package/CHANGELOG.md +367 -0
- package/LICENSE +21 -0
- package/README.md +227 -275
- package/dist/abi/full/OpinionCtfExecutionEngineAdapter.js +1 -0
- package/dist/abi/full/OpinionCtfExecutionEngineAdapter.js.map +1 -0
- package/dist/abi/full/OracleUpdaterRouter.d.ts +30 -9
- package/dist/abi/full/OracleUpdaterRouter.d.ts.map +1 -1
- package/dist/abi/full/OracleUpdaterRouter.js +37 -9
- package/dist/abi/full/OracleUpdaterRouter.js.map +1 -0
- package/dist/abi/full/PolymarketCtfAdapter.js +1 -0
- package/dist/abi/full/PolymarketCtfAdapter.js.map +1 -0
- package/dist/abi/full/VarlaAccessManager.js +1 -0
- package/dist/abi/full/VarlaAccessManager.js.map +1 -0
- package/dist/abi/full/VarlaConvertLiquidator.js +1 -0
- package/dist/abi/full/VarlaConvertLiquidator.js.map +1 -0
- package/dist/abi/full/VarlaCore.js +1 -0
- package/dist/abi/full/VarlaCore.js.map +1 -0
- package/dist/abi/full/VarlaInterestRateStrategy.js +1 -0
- package/dist/abi/full/VarlaInterestRateStrategy.js.map +1 -0
- package/dist/abi/full/VarlaLiquidator.d.ts +12 -0
- package/dist/abi/full/VarlaLiquidator.d.ts.map +1 -1
- package/dist/abi/full/VarlaLiquidator.js +17 -0
- package/dist/abi/full/VarlaLiquidator.js.map +1 -0
- package/dist/abi/full/VarlaMergeLiquidator.js +1 -0
- package/dist/abi/full/VarlaMergeLiquidator.js.map +1 -0
- package/dist/abi/full/VarlaOracle.js +1 -0
- package/dist/abi/full/VarlaOracle.js.map +1 -0
- package/dist/abi/full/VarlaPool.js +1 -0
- package/dist/abi/full/VarlaPool.js.map +1 -0
- package/dist/abi/full/VarlaProxyAdmin.js +1 -0
- package/dist/abi/full/VarlaProxyAdmin.js.map +1 -0
- package/dist/abi/index.js +1 -0
- package/dist/abi/index.js.map +1 -0
- package/dist/abi/subsets/VarlaOracle.registry.js +1 -0
- package/dist/abi/subsets/VarlaOracle.registry.js.map +1 -0
- package/dist/abi.js +1 -0
- package/dist/abi.js.map +1 -0
- package/dist/actions/admin.js +1 -0
- package/dist/actions/admin.js.map +1 -0
- package/dist/actions/core.js +1 -0
- package/dist/actions/core.js.map +1 -0
- package/dist/actions/erc1155.js +1 -0
- package/dist/actions/erc1155.js.map +1 -0
- package/dist/actions/erc20.js +1 -0
- package/dist/actions/erc20.js.map +1 -0
- package/dist/actions/index.d.ts +7 -7
- package/dist/actions/index.d.ts.map +1 -1
- package/dist/actions/index.js +8 -7
- package/dist/actions/index.js.map +1 -0
- package/dist/actions/liquidator.js +1 -0
- package/dist/actions/liquidator.js.map +1 -0
- package/dist/actions/oracle.d.ts +1 -2
- package/dist/actions/oracle.d.ts.map +1 -1
- package/dist/actions/oracle.js +1 -0
- package/dist/actions/oracle.js.map +1 -0
- package/dist/actions/oracleUpdaterRouter.d.ts +8 -1
- package/dist/actions/oracleUpdaterRouter.d.ts.map +1 -1
- package/dist/actions/oracleUpdaterRouter.js +14 -1
- package/dist/actions/oracleUpdaterRouter.js.map +1 -0
- package/dist/actions/pool.js +1 -0
- package/dist/actions/pool.js.map +1 -0
- package/dist/actions/rbac.js +1 -0
- package/dist/actions/rbac.js.map +1 -0
- package/dist/actions/tx.js +1 -0
- package/dist/actions/tx.js.map +1 -0
- package/dist/actions/utils.js +1 -0
- package/dist/actions/utils.js.map +1 -0
- package/dist/addresses/bsc.js +1 -0
- package/dist/addresses/bsc.js.map +1 -0
- package/dist/addresses/index.js +1 -0
- package/dist/addresses/index.js.map +1 -0
- package/dist/addresses/polygon.js +1 -0
- package/dist/addresses/polygon.js.map +1 -0
- package/dist/addresses.js +1 -0
- package/dist/addresses.js.map +1 -0
- package/dist/batch.js +1 -0
- package/dist/batch.js.map +1 -0
- package/dist/contracts.d.ts +1 -2
- package/dist/contracts.d.ts.map +1 -1
- package/dist/contracts.js +2 -2
- package/dist/contracts.js.map +1 -0
- package/dist/errors.d.ts +87 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +240 -0
- package/dist/errors.js.map +1 -0
- package/dist/events/decode.js +1 -0
- package/dist/events/decode.js.map +1 -0
- package/dist/events/defs.js +1 -0
- package/dist/events/defs.js.map +1 -0
- package/dist/events/index.d.ts +3 -3
- package/dist/events/index.d.ts.map +1 -1
- package/dist/events/index.js +4 -3
- package/dist/events/index.js.map +1 -0
- package/dist/events/logs.js +1 -0
- package/dist/events/logs.js.map +1 -0
- package/dist/events/oracleRegistrySync.js +1 -0
- package/dist/events/oracleRegistrySync.js.map +1 -0
- package/dist/events/recent.d.ts +1 -1
- package/dist/events/recent.d.ts.map +1 -1
- package/dist/events/recent.js +2 -1
- package/dist/events/recent.js.map +1 -0
- package/dist/format.js +1 -0
- package/dist/format.js.map +1 -0
- package/dist/generated.d.ts +42 -9
- package/dist/generated.d.ts.map +1 -1
- package/dist/generated.js +1 -0
- package/dist/generated.js.map +1 -0
- package/dist/index.d.ts +6 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -9
- package/dist/index.js.map +1 -0
- package/dist/leverage/deleverageExecute.d.ts +36 -0
- package/dist/leverage/deleverageExecute.d.ts.map +1 -0
- package/dist/leverage/deleverageExecute.js +53 -0
- package/dist/leverage/deleverageExecute.js.map +1 -0
- package/dist/leverage/execute.d.ts +62 -0
- package/dist/leverage/execute.d.ts.map +1 -0
- package/dist/leverage/execute.js +84 -0
- package/dist/leverage/execute.js.map +1 -0
- package/dist/leverage/index.d.ts +32 -0
- package/dist/leverage/index.d.ts.map +1 -0
- package/dist/leverage/index.js +12 -0
- package/dist/leverage/index.js.map +1 -0
- package/dist/leverage/math.d.ts +119 -0
- package/dist/leverage/math.d.ts.map +1 -0
- package/dist/leverage/math.js +304 -0
- package/dist/leverage/math.js.map +1 -0
- package/dist/leverage/plan.d.ts +143 -0
- package/dist/leverage/plan.d.ts.map +1 -0
- package/dist/leverage/plan.js +204 -0
- package/dist/leverage/plan.js.map +1 -0
- package/dist/leverage/preflight.d.ts +27 -0
- package/dist/leverage/preflight.d.ts.map +1 -0
- package/dist/leverage/preflight.js +34 -0
- package/dist/leverage/preflight.js.map +1 -0
- package/dist/leverage/types.d.ts +157 -0
- package/dist/leverage/types.d.ts.map +1 -0
- package/dist/leverage/types.js +43 -0
- package/dist/leverage/types.js.map +1 -0
- package/dist/meta.d.ts +42 -0
- package/dist/meta.d.ts.map +1 -0
- package/dist/meta.js +47 -0
- package/dist/meta.js.map +1 -0
- package/dist/types.js +1 -0
- package/dist/types.js.map +1 -0
- package/dist/views/accessManager.js +1 -0
- package/dist/views/accessManager.js.map +1 -0
- package/dist/views/adapters.js +1 -0
- package/dist/views/adapters.js.map +1 -0
- package/dist/views/admin.d.ts.map +1 -1
- package/dist/views/admin.js +1 -0
- package/dist/views/admin.js.map +1 -0
- package/dist/views/core.d.ts.map +1 -1
- package/dist/views/core.js +1 -0
- package/dist/views/core.js.map +1 -0
- package/dist/views/index.d.ts +5 -5
- package/dist/views/index.d.ts.map +1 -1
- package/dist/views/index.js +6 -5
- package/dist/views/index.js.map +1 -0
- package/dist/views/lenders.js +1 -0
- package/dist/views/lenders.js.map +1 -0
- package/dist/views/liquidators.d.ts +82 -1
- package/dist/views/liquidators.d.ts.map +1 -1
- package/dist/views/liquidators.js +88 -0
- package/dist/views/liquidators.js.map +1 -0
- package/dist/views/oracle.js +1 -0
- package/dist/views/oracle.js.map +1 -0
- package/dist/views/pool.js +1 -0
- package/dist/views/pool.js.map +1 -0
- package/dist/views/system.d.ts.map +1 -1
- package/dist/views/system.js +1 -0
- package/dist/views/system.js.map +1 -0
- package/package.json +18 -5
- package/src/abi/README.md +17 -0
- package/src/abi/full/OpinionCtfExecutionEngineAdapter.ts +320 -0
- package/src/abi/full/OracleUpdaterRouter.ts +528 -0
- package/src/abi/full/PolymarketCtfAdapter.ts +312 -0
- package/src/abi/full/VarlaAccessManager.ts +1171 -0
- package/src/abi/full/VarlaConvertLiquidator.ts +834 -0
- package/src/abi/full/VarlaCore.ts +2277 -0
- package/src/abi/full/VarlaInterestRateStrategy.ts +442 -0
- package/src/abi/full/VarlaLiquidator.ts +930 -0
- package/src/abi/full/VarlaMergeLiquidator.ts +797 -0
- package/src/abi/full/VarlaOracle.ts +1825 -0
- package/src/abi/full/VarlaPool.ts +1637 -0
- package/src/abi/full/VarlaProxyAdmin.ts +301 -0
- package/src/abi/index.ts +17 -0
- package/src/abi/subsets/VarlaOracle.registry.ts +784 -0
- package/src/abi.ts +2 -0
- package/src/actions/admin.ts +357 -0
- package/src/actions/core.ts +68 -0
- package/src/actions/erc1155.ts +22 -0
- package/src/actions/erc20.ts +22 -0
- package/src/actions/index.ts +13 -0
- package/src/actions/liquidator.ts +76 -0
- package/src/actions/oracle.ts +618 -0
- package/src/actions/oracleUpdaterRouter.ts +233 -0
- package/src/actions/pool.ts +76 -0
- package/src/actions/rbac.ts +72 -0
- package/src/actions/tx.ts +16 -0
- package/src/actions/utils.ts +15 -0
- package/src/addresses/README.md +17 -0
- package/src/addresses/bsc.json +16 -0
- package/src/addresses/bsc.ts +15 -0
- package/src/addresses/index.ts +6 -0
- package/src/addresses/polygon.json +16 -0
- package/src/addresses/polygon.ts +15 -0
- package/src/addresses.ts +2 -0
- package/src/batch.ts +55 -0
- package/src/contracts.ts +232 -0
- package/src/errors.ts +305 -0
- package/src/events/decode.ts +37 -0
- package/src/events/defs.ts +70 -0
- package/src/events/index.ts +7 -0
- package/src/events/logs.ts +42 -0
- package/src/events/oracleRegistrySync.ts +206 -0
- package/src/events/recent.ts +39 -0
- package/src/format.ts +121 -0
- package/src/generated.ts +27 -0
- package/src/index.ts +18 -0
- package/src/leverage/deleverageExecute.ts +111 -0
- package/src/leverage/execute.ts +172 -0
- package/src/leverage/index.ts +88 -0
- package/src/leverage/math.ts +446 -0
- package/src/leverage/plan.ts +356 -0
- package/src/leverage/preflight.ts +63 -0
- package/src/leverage/types.ts +204 -0
- package/src/meta.ts +82 -0
- package/src/types.ts +25 -0
- package/src/views/accessManager.ts +286 -0
- package/src/views/adapters.ts +27 -0
- package/src/views/admin.ts +92 -0
- package/src/views/core.ts +1370 -0
- package/src/views/index.ts +11 -0
- package/src/views/lenders.ts +65 -0
- package/src/views/liquidators.ts +377 -0
- package/src/views/oracle.ts +739 -0
- package/src/views/pool.ts +277 -0
- package/src/views/system.ts +42 -0
- package/BACKEND.md +0 -405
- package/FRONTEND.md +0 -485
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
// Note: explicit .js extension is required for Node ESM resolution.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @varla/sdk/leverage — Leverage loop planning, execution, and math helpers.
|
|
5
|
+
*
|
|
6
|
+
* This module abstracts the "recursive borrowing" pattern for leveraged
|
|
7
|
+
* long/short positions on prediction markets:
|
|
8
|
+
*
|
|
9
|
+
* ```
|
|
10
|
+
* buy tokens → deposit into VarlaCore → borrow collateral → buy more tokens → ...
|
|
11
|
+
* ```
|
|
12
|
+
*
|
|
13
|
+
* Architecture:
|
|
14
|
+
* - **math.ts**: Pure math (zero deps, zero I/O). Plan loops, compute P&L scenarios.
|
|
15
|
+
* - **plan.ts**: RPC-aware planners that read on-chain state then delegate to math.
|
|
16
|
+
* - **execute.ts**: Step executor that drives deposit/borrow txs with a callback for CLOB buys.
|
|
17
|
+
* - **types.ts**: Shared types and constants.
|
|
18
|
+
*
|
|
19
|
+
* The SDK handles all on-chain operations (deposit, borrow, approve).
|
|
20
|
+
* Off-chain CLOB trades are delegated to a consumer-provided callback.
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
export type {
|
|
24
|
+
OnDeleverageProgress,
|
|
25
|
+
RunDeleverageLoopParams,
|
|
26
|
+
RunDeleverageLoopResult,
|
|
27
|
+
} from "./deleverageExecute.js";
|
|
28
|
+
export { runDeleverageLoop } from "./deleverageExecute.js";
|
|
29
|
+
export type {
|
|
30
|
+
RunLeverageLoopParams,
|
|
31
|
+
RunLeverageLoopResult,
|
|
32
|
+
} from "./execute.js";
|
|
33
|
+
// Execution
|
|
34
|
+
export { runLeverageLoop } from "./execute.js";
|
|
35
|
+
export type {
|
|
36
|
+
LeverageScenario,
|
|
37
|
+
PlanDeleverageParams,
|
|
38
|
+
PlanLeverageLoopParams,
|
|
39
|
+
} from "./math.js";
|
|
40
|
+
// Pure math
|
|
41
|
+
export {
|
|
42
|
+
collateralForTokens,
|
|
43
|
+
estimateLiquidationPrice,
|
|
44
|
+
leverageScenario,
|
|
45
|
+
maxLeverage,
|
|
46
|
+
planDeleverage,
|
|
47
|
+
planLeverageLoop,
|
|
48
|
+
tokensForCollateral,
|
|
49
|
+
} from "./math.js";
|
|
50
|
+
export type {
|
|
51
|
+
PlanDeleverageFromChainParams,
|
|
52
|
+
PlanLeverageFromChainParams,
|
|
53
|
+
PlanLeverageFromChainPreciseParams,
|
|
54
|
+
} from "./plan.js";
|
|
55
|
+
// RPC-aware planners
|
|
56
|
+
export {
|
|
57
|
+
planDeleverageFromChain,
|
|
58
|
+
planLeverageFromChain,
|
|
59
|
+
planLeverageFromChainPrecise,
|
|
60
|
+
resolveLeveragePositionId,
|
|
61
|
+
} from "./plan.js";
|
|
62
|
+
export type { ReadErc1155IsApprovedForAllParams } from "./preflight.js";
|
|
63
|
+
// Preflight
|
|
64
|
+
export {
|
|
65
|
+
prepareApprovePositionsTokenIfNeeded,
|
|
66
|
+
readErc1155IsApprovedForAll,
|
|
67
|
+
} from "./preflight.js";
|
|
68
|
+
// Types + constants
|
|
69
|
+
export type {
|
|
70
|
+
BuyResult,
|
|
71
|
+
DeleveragePlan,
|
|
72
|
+
DeleverageStep,
|
|
73
|
+
LeverageDirection,
|
|
74
|
+
LeveragePlan,
|
|
75
|
+
LeverageStep,
|
|
76
|
+
LeverageStepResult,
|
|
77
|
+
LeverageSummary,
|
|
78
|
+
OnLeverageProgress,
|
|
79
|
+
SellResult,
|
|
80
|
+
} from "./types.js";
|
|
81
|
+
export {
|
|
82
|
+
collateralForDollars,
|
|
83
|
+
DEFAULT_MAX_ITERATIONS,
|
|
84
|
+
DEFAULT_MIN_STEP_COLLATERAL,
|
|
85
|
+
PRICE_E8,
|
|
86
|
+
pow10,
|
|
87
|
+
WAD,
|
|
88
|
+
} from "./types.js";
|
|
@@ -0,0 +1,446 @@
|
|
|
1
|
+
// Note: explicit .js extension is required for Node ESM resolution.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Pure math helpers for leverage planning.
|
|
5
|
+
*
|
|
6
|
+
* All functions are deterministic and have zero side-effects (no RPC, no I/O).
|
|
7
|
+
* They operate on bigint with WAD (1e18) and PRICE_E8 (1e8) precision.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type {
|
|
11
|
+
DeleveragePlan,
|
|
12
|
+
DeleverageStep,
|
|
13
|
+
LeveragePlan,
|
|
14
|
+
LeverageStep,
|
|
15
|
+
LeverageSummary,
|
|
16
|
+
} from "./types.js";
|
|
17
|
+
import { DEFAULT_MAX_ITERATIONS, DEFAULT_MIN_STEP_COLLATERAL, PRICE_E8, WAD } from "./types.js";
|
|
18
|
+
|
|
19
|
+
// ---------------------------------------------------------------------------
|
|
20
|
+
// Helpers
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
|
|
23
|
+
/** max(a, 0n) */
|
|
24
|
+
function clampPositive(a: bigint): bigint {
|
|
25
|
+
return a > 0n ? a : 0n;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Floor division: a * b / c (bigint, no overflow risk in JS BigInt).
|
|
30
|
+
*/
|
|
31
|
+
function mulDiv(a: bigint, b: bigint, c: bigint): bigint {
|
|
32
|
+
if (c === 0n) throw new Error("mulDiv: division by zero");
|
|
33
|
+
return (a * b) / c;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Ceil division: (a * b + c - 1) / c.
|
|
38
|
+
*/
|
|
39
|
+
function mulDivUp(a: bigint, b: bigint, c: bigint): bigint {
|
|
40
|
+
if (c === 0n) throw new Error("mulDivUp: division by zero");
|
|
41
|
+
return (a * b + c - 1n) / c;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// ---------------------------------------------------------------------------
|
|
45
|
+
// Public helpers
|
|
46
|
+
// ---------------------------------------------------------------------------
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Maximum theoretical leverage for a given LTV.
|
|
50
|
+
*
|
|
51
|
+
* Formula: 1 / (1 - LTV)
|
|
52
|
+
*/
|
|
53
|
+
export function maxLeverage(ltvWad: bigint): bigint {
|
|
54
|
+
if (ltvWad <= 0n) return WAD; // 0% LTV → 1×
|
|
55
|
+
if (ltvWad >= WAD) throw new Error("LTV must be < 100%");
|
|
56
|
+
return mulDiv(WAD, WAD, WAD - ltvWad);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Estimated liquidation price for a leveraged position.
|
|
61
|
+
*
|
|
62
|
+
* HF = (tokens * price * LTV) / debt = 1.0
|
|
63
|
+
* → price = debt / (tokens * LTV)
|
|
64
|
+
*/
|
|
65
|
+
export function estimateLiquidationPrice(
|
|
66
|
+
totalTokens: bigint,
|
|
67
|
+
totalDebt: bigint,
|
|
68
|
+
ltvWad: bigint,
|
|
69
|
+
): bigint {
|
|
70
|
+
if (totalTokens <= 0n) return 0n;
|
|
71
|
+
if (totalDebt <= 0n) return 0n;
|
|
72
|
+
if (ltvWad <= 0n) return 0n;
|
|
73
|
+
|
|
74
|
+
const numerator = totalDebt * PRICE_E8 * WAD;
|
|
75
|
+
const denominator = totalTokens * ltvWad;
|
|
76
|
+
if (denominator === 0n) return 0n;
|
|
77
|
+
// Round UP (conservative: liquidation happens sooner than estimated).
|
|
78
|
+
return (numerator + denominator - 1n) / denominator;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Compute how many outcome tokens you get for a given collateral amount at a given price.
|
|
83
|
+
*
|
|
84
|
+
* tokens = collateral * PRICE_E8 / price
|
|
85
|
+
*/
|
|
86
|
+
export function tokensForCollateral(collateralAmount: bigint, tokenPriceE8: bigint): bigint {
|
|
87
|
+
if (tokenPriceE8 <= 0n) throw new Error("Token price must be > 0");
|
|
88
|
+
return mulDiv(collateralAmount, PRICE_E8, tokenPriceE8);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Compute collateral value of a token amount at a given price.
|
|
93
|
+
*
|
|
94
|
+
* collateral = tokens * price / PRICE_E8
|
|
95
|
+
*/
|
|
96
|
+
export function collateralForTokens(tokenAmount: bigint, tokenPriceE8: bigint): bigint {
|
|
97
|
+
return mulDiv(tokenAmount, tokenPriceE8, PRICE_E8);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// ---------------------------------------------------------------------------
|
|
101
|
+
// Leverage loop planner
|
|
102
|
+
// ---------------------------------------------------------------------------
|
|
103
|
+
|
|
104
|
+
export type PlanLeverageLoopParams = {
|
|
105
|
+
/** User's initial collateral capital (collateral base units). */
|
|
106
|
+
initialCapital: bigint;
|
|
107
|
+
/** Current token price (8 decimals). */
|
|
108
|
+
tokenPriceE8: bigint;
|
|
109
|
+
/** Effective LTV for this position (WAD). */
|
|
110
|
+
ltvWad: bigint;
|
|
111
|
+
/**
|
|
112
|
+
* Target leverage as WAD (e.g. 3e18 = 3.0×).
|
|
113
|
+
*
|
|
114
|
+
* NOTE: This planner targets leverage precisely under the assumption that:
|
|
115
|
+
* - all borrows are immediately spent at a constant price,
|
|
116
|
+
* - and there are no fees.
|
|
117
|
+
*/
|
|
118
|
+
targetLeverageWad?: bigint;
|
|
119
|
+
/** Max iterations (default: 10). */
|
|
120
|
+
maxIterations?: number;
|
|
121
|
+
/** Minimum borrow per step to continue looping (default: DEFAULT_MIN_STEP_COLLATERAL). */
|
|
122
|
+
minStepBorrow?: bigint;
|
|
123
|
+
/** Starting deposited token amount already in Core (optional). */
|
|
124
|
+
startingTokens?: bigint;
|
|
125
|
+
/** Starting debt already owed to Core/Pool (optional). */
|
|
126
|
+
startingDebt?: bigint;
|
|
127
|
+
/** Optional absolute cap on total debt (collateral base units). */
|
|
128
|
+
maxTotalDebt?: bigint;
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Plan a leverage loop (pure math, zero RPC).
|
|
133
|
+
*
|
|
134
|
+
* Output steps:
|
|
135
|
+
* - buy (off-chain)
|
|
136
|
+
* - deposit (on-chain)
|
|
137
|
+
* - borrow (on-chain)
|
|
138
|
+
* - repeat
|
|
139
|
+
*
|
|
140
|
+
* Important: the loop is designed so it **does not end with an unused borrow**.
|
|
141
|
+
* If `maxIterations` is hit, the final iteration ends at `deposit`.
|
|
142
|
+
*/
|
|
143
|
+
export function planLeverageLoop(params: PlanLeverageLoopParams): LeveragePlan {
|
|
144
|
+
const {
|
|
145
|
+
initialCapital,
|
|
146
|
+
tokenPriceE8,
|
|
147
|
+
ltvWad,
|
|
148
|
+
targetLeverageWad,
|
|
149
|
+
maxIterations = DEFAULT_MAX_ITERATIONS,
|
|
150
|
+
minStepBorrow = DEFAULT_MIN_STEP_COLLATERAL,
|
|
151
|
+
startingTokens = 0n,
|
|
152
|
+
startingDebt = 0n,
|
|
153
|
+
maxTotalDebt,
|
|
154
|
+
} = params;
|
|
155
|
+
|
|
156
|
+
if (initialCapital <= 0n) throw new Error("initialCapital must be > 0");
|
|
157
|
+
if (tokenPriceE8 <= 0n) throw new Error("tokenPriceE8 must be > 0");
|
|
158
|
+
if (ltvWad <= 0n || ltvWad >= WAD) throw new Error("ltvWad must be in (0, 1e18)");
|
|
159
|
+
if (maxIterations < 1) throw new Error("maxIterations must be >= 1");
|
|
160
|
+
if (startingTokens < 0n) throw new Error("startingTokens must be >= 0");
|
|
161
|
+
if (startingDebt < 0n) throw new Error("startingDebt must be >= 0");
|
|
162
|
+
|
|
163
|
+
const maxLev = maxLeverage(ltvWad);
|
|
164
|
+
|
|
165
|
+
// Target leverage semantics:
|
|
166
|
+
// - undefined => run to max (bounded by maxIterations / minStepBorrow / caps)
|
|
167
|
+
// - <= 1× => treat as 1× (no borrowing)
|
|
168
|
+
// - > maxLev => clamp to maxLev
|
|
169
|
+
const effectiveTargetLev =
|
|
170
|
+
targetLeverageWad !== undefined
|
|
171
|
+
? targetLeverageWad <= WAD
|
|
172
|
+
? WAD
|
|
173
|
+
: targetLeverageWad > maxLev
|
|
174
|
+
? maxLev
|
|
175
|
+
: targetLeverageWad
|
|
176
|
+
: undefined;
|
|
177
|
+
|
|
178
|
+
const steps: LeverageStep[] = [];
|
|
179
|
+
let totalTokens = startingTokens;
|
|
180
|
+
let totalDebt = startingDebt;
|
|
181
|
+
let collateralAvailable = initialCapital;
|
|
182
|
+
|
|
183
|
+
// Equity is invariant under constant price assumption.
|
|
184
|
+
const startingExposure = collateralForTokens(startingTokens, tokenPriceE8);
|
|
185
|
+
const baseEquity = clampPositive(startingExposure - startingDebt) + initialCapital;
|
|
186
|
+
|
|
187
|
+
// L = exposure / equity = 1 + debt / equity => debtTarget = equity*(L-1)
|
|
188
|
+
const targetTotalDebt =
|
|
189
|
+
effectiveTargetLev !== undefined
|
|
190
|
+
? effectiveTargetLev > WAD
|
|
191
|
+
? mulDiv(baseEquity, effectiveTargetLev - WAD, WAD)
|
|
192
|
+
: 0n
|
|
193
|
+
: undefined;
|
|
194
|
+
|
|
195
|
+
for (let i = 0; i < maxIterations; i++) {
|
|
196
|
+
if (collateralAvailable <= 0n) break;
|
|
197
|
+
|
|
198
|
+
// buy
|
|
199
|
+
const spendCollateral = collateralAvailable;
|
|
200
|
+
|
|
201
|
+
const tokensBought = tokensForCollateral(spendCollateral, tokenPriceE8);
|
|
202
|
+
if (tokensBought <= 0n) break;
|
|
203
|
+
|
|
204
|
+
// Spend the available collateral for this iteration.
|
|
205
|
+
// The next iteration is funded *only* via the subsequent borrow.
|
|
206
|
+
collateralAvailable = 0n;
|
|
207
|
+
|
|
208
|
+
steps.push({
|
|
209
|
+
kind: "buy",
|
|
210
|
+
collateralAmount: spendCollateral,
|
|
211
|
+
expectedTokens: tokensBought,
|
|
212
|
+
iteration: i,
|
|
213
|
+
});
|
|
214
|
+
totalTokens += tokensBought;
|
|
215
|
+
|
|
216
|
+
// deposit
|
|
217
|
+
steps.push({ kind: "deposit", amount: tokensBought, iteration: i });
|
|
218
|
+
|
|
219
|
+
// If this is the last allowed iteration, do not borrow (would be unused).
|
|
220
|
+
if (i === maxIterations - 1) break;
|
|
221
|
+
|
|
222
|
+
// borrow
|
|
223
|
+
const exposure = collateralForTokens(totalTokens, tokenPriceE8);
|
|
224
|
+
const maxAdditionalBorrow = clampPositive(mulDiv(exposure, ltvWad, WAD) - totalDebt);
|
|
225
|
+
if (maxAdditionalBorrow <= 0n) break;
|
|
226
|
+
|
|
227
|
+
let borrowAmount = maxAdditionalBorrow;
|
|
228
|
+
|
|
229
|
+
// Targeting cap.
|
|
230
|
+
if (targetTotalDebt !== undefined) {
|
|
231
|
+
const remaining = clampPositive(targetTotalDebt - totalDebt);
|
|
232
|
+
borrowAmount = remaining < borrowAmount ? remaining : borrowAmount;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// Absolute cap on total debt (e.g., pool liquidity headroom).
|
|
236
|
+
if (maxTotalDebt !== undefined) {
|
|
237
|
+
const remaining = clampPositive(maxTotalDebt - totalDebt);
|
|
238
|
+
borrowAmount = remaining < borrowAmount ? remaining : borrowAmount;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
if (borrowAmount <= 0n) break;
|
|
242
|
+
if (borrowAmount < minStepBorrow) break;
|
|
243
|
+
|
|
244
|
+
steps.push({ kind: "borrow", collateralAmount: borrowAmount, iteration: i });
|
|
245
|
+
totalDebt += borrowAmount;
|
|
246
|
+
collateralAvailable = borrowAmount;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// Compute summary.
|
|
250
|
+
const totalExposure = collateralForTokens(totalTokens, tokenPriceE8);
|
|
251
|
+
const netEquity = clampPositive(totalExposure - totalDebt);
|
|
252
|
+
const effectiveLeverageWad = netEquity > 0n ? mulDiv(totalExposure, WAD, netEquity) : 0n;
|
|
253
|
+
const estimatedLiquidationPriceE8 = estimateLiquidationPrice(totalTokens, totalDebt, ltvWad);
|
|
254
|
+
|
|
255
|
+
const iterations = steps.length > 0 ? steps[steps.length - 1]!.iteration + 1 : 0;
|
|
256
|
+
|
|
257
|
+
const summary: LeverageSummary = {
|
|
258
|
+
totalTokens,
|
|
259
|
+
totalDebt,
|
|
260
|
+
netEquity,
|
|
261
|
+
effectiveLeverageWad,
|
|
262
|
+
estimatedLiquidationPriceE8,
|
|
263
|
+
iterations,
|
|
264
|
+
maxLeverageWad: maxLev,
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
return {
|
|
268
|
+
steps,
|
|
269
|
+
summary,
|
|
270
|
+
params: {
|
|
271
|
+
initialCapital,
|
|
272
|
+
tokenPriceE8,
|
|
273
|
+
ltvWad,
|
|
274
|
+
targetLeverageWad,
|
|
275
|
+
maxIterations,
|
|
276
|
+
minStepBorrow,
|
|
277
|
+
},
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// ---------------------------------------------------------------------------
|
|
282
|
+
// Deleverage planner
|
|
283
|
+
// ---------------------------------------------------------------------------
|
|
284
|
+
|
|
285
|
+
export type PlanDeleverageParams = {
|
|
286
|
+
/** Current deposited token balance in VarlaCore. */
|
|
287
|
+
depositedTokens: bigint;
|
|
288
|
+
/** Current collateral debt (collateral base units). */
|
|
289
|
+
currentDebt: bigint;
|
|
290
|
+
/** Current token price (8 decimals). */
|
|
291
|
+
tokenPriceE8: bigint;
|
|
292
|
+
/** Effective LTV for this position (WAD). */
|
|
293
|
+
ltvWad: bigint;
|
|
294
|
+
/**
|
|
295
|
+
* How much debt to reduce.
|
|
296
|
+
* Use "full" for complete unwind, or a bigint for partial deleverage.
|
|
297
|
+
*/
|
|
298
|
+
targetDebtReduction: "full" | bigint;
|
|
299
|
+
/** Max iterations (default: 10). */
|
|
300
|
+
maxIterations?: number;
|
|
301
|
+
/** Minimum sell size (in collateral base units) to continue looping. */
|
|
302
|
+
minStepSell?: bigint;
|
|
303
|
+
};
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Plan a deleverage (unwind) loop (pure math, zero RPC).
|
|
307
|
+
*
|
|
308
|
+
* Steps: withdraw → sell → repay → ...
|
|
309
|
+
*/
|
|
310
|
+
export function planDeleverage(params: PlanDeleverageParams): DeleveragePlan {
|
|
311
|
+
const {
|
|
312
|
+
depositedTokens,
|
|
313
|
+
currentDebt,
|
|
314
|
+
tokenPriceE8,
|
|
315
|
+
ltvWad,
|
|
316
|
+
targetDebtReduction,
|
|
317
|
+
maxIterations = DEFAULT_MAX_ITERATIONS,
|
|
318
|
+
minStepSell = DEFAULT_MIN_STEP_COLLATERAL,
|
|
319
|
+
} = params;
|
|
320
|
+
|
|
321
|
+
if (tokenPriceE8 <= 0n) throw new Error("tokenPriceE8 must be > 0");
|
|
322
|
+
if (ltvWad <= 0n || ltvWad >= WAD) throw new Error("ltvWad must be in (0, 1e18)");
|
|
323
|
+
if (depositedTokens < 0n) throw new Error("depositedTokens must be >= 0");
|
|
324
|
+
if (currentDebt < 0n) throw new Error("currentDebt must be >= 0");
|
|
325
|
+
|
|
326
|
+
const targetRepay = targetDebtReduction === "full" ? currentDebt : targetDebtReduction;
|
|
327
|
+
if (targetRepay <= 0n) {
|
|
328
|
+
return {
|
|
329
|
+
steps: [],
|
|
330
|
+
summary: {
|
|
331
|
+
tokensToSell: 0n,
|
|
332
|
+
totalRepayment: 0n,
|
|
333
|
+
tokensRemaining: depositedTokens,
|
|
334
|
+
collateralRemaining: 0n,
|
|
335
|
+
iterations: 0,
|
|
336
|
+
},
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
const steps: DeleverageStep[] = [];
|
|
341
|
+
let remainingTokens = depositedTokens;
|
|
342
|
+
let remainingDebt = currentDebt;
|
|
343
|
+
let totalSold = 0n;
|
|
344
|
+
let totalRepaid = 0n;
|
|
345
|
+
|
|
346
|
+
for (let i = 0; i < maxIterations; i++) {
|
|
347
|
+
if (remainingDebt <= 0n) break;
|
|
348
|
+
if (totalRepaid >= targetRepay) break;
|
|
349
|
+
if (remainingTokens <= 0n) break;
|
|
350
|
+
|
|
351
|
+
// How many tokens must remain to keep HF >= 1?
|
|
352
|
+
// HF = (tokens * price * ltv) / debt >= 1
|
|
353
|
+
// → tokens >= ceil(debt * PRICE_E8 * WAD / (price * ltv))
|
|
354
|
+
const minTokensForHealth =
|
|
355
|
+
remainingDebt > 0n ? mulDivUp(remainingDebt, PRICE_E8 * WAD, tokenPriceE8 * ltvWad) : 0n;
|
|
356
|
+
|
|
357
|
+
const withdrawable = clampPositive(remainingTokens - minTokensForHealth);
|
|
358
|
+
if (withdrawable <= 0n) break;
|
|
359
|
+
|
|
360
|
+
// Cap to remaining target repayment.
|
|
361
|
+
const remainingTarget = clampPositive(targetRepay - totalRepaid);
|
|
362
|
+
const tokensNeededForTarget = mulDivUp(remainingTarget, PRICE_E8, tokenPriceE8);
|
|
363
|
+
const tokensToWithdraw =
|
|
364
|
+
withdrawable < tokensNeededForTarget ? withdrawable : tokensNeededForTarget;
|
|
365
|
+
if (tokensToWithdraw <= 0n) break;
|
|
366
|
+
|
|
367
|
+
const collateralProceeds = collateralForTokens(tokensToWithdraw, tokenPriceE8);
|
|
368
|
+
if (collateralProceeds < minStepSell) break;
|
|
369
|
+
|
|
370
|
+
// withdraw
|
|
371
|
+
steps.push({ kind: "withdraw", amount: tokensToWithdraw, iteration: i });
|
|
372
|
+
remainingTokens -= tokensToWithdraw;
|
|
373
|
+
|
|
374
|
+
// sell
|
|
375
|
+
steps.push({
|
|
376
|
+
kind: "sell",
|
|
377
|
+
tokenAmount: tokensToWithdraw,
|
|
378
|
+
expectedCollateral: collateralProceeds,
|
|
379
|
+
iteration: i,
|
|
380
|
+
});
|
|
381
|
+
totalSold += tokensToWithdraw;
|
|
382
|
+
|
|
383
|
+
// repay
|
|
384
|
+
const repayAmount = collateralProceeds > remainingDebt ? remainingDebt : collateralProceeds;
|
|
385
|
+
steps.push({ kind: "repay", collateralAmount: repayAmount, iteration: i });
|
|
386
|
+
remainingDebt -= repayAmount;
|
|
387
|
+
totalRepaid += repayAmount;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
const collateralRemaining = clampPositive(
|
|
391
|
+
collateralForTokens(remainingTokens, tokenPriceE8) - remainingDebt,
|
|
392
|
+
);
|
|
393
|
+
const iterations = steps.length > 0 ? steps[steps.length - 1]!.iteration + 1 : 0;
|
|
394
|
+
|
|
395
|
+
return {
|
|
396
|
+
steps,
|
|
397
|
+
summary: {
|
|
398
|
+
tokensToSell: totalSold,
|
|
399
|
+
totalRepayment: totalRepaid,
|
|
400
|
+
tokensRemaining: remainingTokens,
|
|
401
|
+
collateralRemaining,
|
|
402
|
+
iterations,
|
|
403
|
+
},
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
// ---------------------------------------------------------------------------
|
|
408
|
+
// P&L scenario helper
|
|
409
|
+
// ---------------------------------------------------------------------------
|
|
410
|
+
|
|
411
|
+
export type LeverageScenario = {
|
|
412
|
+
/** Exit price (8 decimals). */
|
|
413
|
+
exitPriceE8: bigint;
|
|
414
|
+
/** Gross position value at exit. */
|
|
415
|
+
grossValue: bigint;
|
|
416
|
+
/** Profit/loss vs initial capital (can be negative). */
|
|
417
|
+
pnl: bigint;
|
|
418
|
+
/** Return as WAD (e.g. 2.5e18 = +250%). Negative for losses. */
|
|
419
|
+
returnWad: bigint;
|
|
420
|
+
/** Whether position would be liquidated at this price. */
|
|
421
|
+
isLiquidated: boolean;
|
|
422
|
+
};
|
|
423
|
+
|
|
424
|
+
/**
|
|
425
|
+
* Compute P&L for a leveraged position at a hypothetical exit price.
|
|
426
|
+
*/
|
|
427
|
+
export function leverageScenario(params: {
|
|
428
|
+
totalTokens: bigint;
|
|
429
|
+
totalDebt: bigint;
|
|
430
|
+
initialCapital: bigint;
|
|
431
|
+
exitPriceE8: bigint;
|
|
432
|
+
ltvWad: bigint;
|
|
433
|
+
}): LeverageScenario {
|
|
434
|
+
const { totalTokens, totalDebt, initialCapital, exitPriceE8, ltvWad } = params;
|
|
435
|
+
|
|
436
|
+
const grossValue = collateralForTokens(totalTokens, exitPriceE8);
|
|
437
|
+
const pnl = grossValue - totalDebt - initialCapital;
|
|
438
|
+
|
|
439
|
+
const returnWad = initialCapital > 0n ? mulDiv(pnl, WAD, initialCapital) : 0n;
|
|
440
|
+
|
|
441
|
+
// HF = (tokens * price * ltv) / debt
|
|
442
|
+
const collateralValue = mulDiv(grossValue, ltvWad, WAD);
|
|
443
|
+
const isLiquidated = totalDebt > 0n && collateralValue < totalDebt;
|
|
444
|
+
|
|
445
|
+
return { exitPriceE8, grossValue, pnl, returnWad, isLiquidated };
|
|
446
|
+
}
|