@t2000/sdk 0.8.7 → 0.9.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/README.md +22 -24
- package/dist/adapters/index.cjs +0 -18
- package/dist/adapters/index.cjs.map +1 -1
- package/dist/adapters/index.d.cts +1 -1
- package/dist/adapters/index.d.ts +1 -1
- package/dist/adapters/index.js +0 -18
- package/dist/adapters/index.js.map +1 -1
- package/dist/{index-DNjooNFy.d.cts → index-C7W686z2.d.cts} +1 -4
- package/dist/{index-DNjooNFy.d.ts → index-C7W686z2.d.ts} +1 -4
- package/dist/index.cjs +208 -97
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +10 -41
- package/dist/index.d.ts +10 -41
- package/dist/index.js +209 -95
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -155,7 +155,6 @@ interface SaveResult {
|
|
|
155
155
|
success: boolean;
|
|
156
156
|
tx: string;
|
|
157
157
|
amount: number;
|
|
158
|
-
asset: string;
|
|
159
158
|
apy: number;
|
|
160
159
|
fee: number;
|
|
161
160
|
gasCost: number;
|
|
@@ -359,8 +358,6 @@ declare class ProtocolRegistry {
|
|
|
359
358
|
getSwap(id: string): SwapAdapter | undefined;
|
|
360
359
|
listLending(): LendingAdapter[];
|
|
361
360
|
listSwap(): SwapAdapter[];
|
|
362
|
-
isSupportedAsset(asset: string, capability?: AdapterCapability): boolean;
|
|
363
|
-
getSupportedAssets(capability?: AdapterCapability): string[];
|
|
364
361
|
}
|
|
365
362
|
|
|
366
363
|
declare const descriptor$3: ProtocolDescriptor;
|
|
@@ -478,4 +475,4 @@ declare function attack(client: SuiJsonRpcClient, signer: Ed25519Keypair, sentin
|
|
|
478
475
|
/** All registered protocol descriptors — used by the indexer for event classification */
|
|
479
476
|
declare const allDescriptors: ProtocolDescriptor[];
|
|
480
477
|
|
|
481
|
-
export { type AdapterCapability as A, type BalanceResponse as B, CetusAdapter as C, type DepositInfo as D, type EarningsResult as E, type FundStatusResult as F, type GasMethod as G, type HealthFactorResult as H, listSentinels as I, descriptor$3 as J, requestAttack as K, type LendingAdapter as L, type MaxWithdrawResult as M, NaviAdapter as N, attack as O, type PositionsResult as P, descriptor as Q, type RepayResult as R, type SendResult as S, type T2000Options as T, settleAttack as U, submitPrompt as V, type WithdrawResult as W, descriptor$1 as X, type TransactionRecord as a, type SwapAdapter as b, type SaveResult as c, type BorrowResult as d, type MaxBorrowResult as e, type
|
|
478
|
+
export { type AdapterCapability as A, type BalanceResponse as B, CetusAdapter as C, type DepositInfo as D, type EarningsResult as E, type FundStatusResult as F, type GasMethod as G, type HealthFactorResult as H, listSentinels as I, descriptor$3 as J, requestAttack as K, type LendingAdapter as L, type MaxWithdrawResult as M, NaviAdapter as N, attack as O, type PositionsResult as P, descriptor as Q, type RepayResult as R, type SendResult as S, type T2000Options as T, settleAttack as U, submitPrompt as V, type WithdrawResult as W, descriptor$1 as X, type TransactionRecord as a, type SwapAdapter as b, type SaveResult as c, type BorrowResult as d, type MaxBorrowResult as e, type RatesResult as f, type LendingRates as g, type RebalanceResult as h, type SentinelAgent as i, type SentinelAttackResult as j, type AdapterPositions as k, type AdapterTxResult as l, type AssetRates as m, type GasReserve as n, type HealthInfo as o, type PositionEntry as p, type ProtocolDescriptor as q, ProtocolRegistry as r, type RebalanceStep as s, type SentinelVerdict as t, SuilendAdapter as u, type SwapQuote as v, type SwapResult as w, allDescriptors as x, descriptor$2 as y, getSentinelInfo as z };
|
|
@@ -155,7 +155,6 @@ interface SaveResult {
|
|
|
155
155
|
success: boolean;
|
|
156
156
|
tx: string;
|
|
157
157
|
amount: number;
|
|
158
|
-
asset: string;
|
|
159
158
|
apy: number;
|
|
160
159
|
fee: number;
|
|
161
160
|
gasCost: number;
|
|
@@ -359,8 +358,6 @@ declare class ProtocolRegistry {
|
|
|
359
358
|
getSwap(id: string): SwapAdapter | undefined;
|
|
360
359
|
listLending(): LendingAdapter[];
|
|
361
360
|
listSwap(): SwapAdapter[];
|
|
362
|
-
isSupportedAsset(asset: string, capability?: AdapterCapability): boolean;
|
|
363
|
-
getSupportedAssets(capability?: AdapterCapability): string[];
|
|
364
361
|
}
|
|
365
362
|
|
|
366
363
|
declare const descriptor$3: ProtocolDescriptor;
|
|
@@ -478,4 +475,4 @@ declare function attack(client: SuiJsonRpcClient, signer: Ed25519Keypair, sentin
|
|
|
478
475
|
/** All registered protocol descriptors — used by the indexer for event classification */
|
|
479
476
|
declare const allDescriptors: ProtocolDescriptor[];
|
|
480
477
|
|
|
481
|
-
export { type AdapterCapability as A, type BalanceResponse as B, CetusAdapter as C, type DepositInfo as D, type EarningsResult as E, type FundStatusResult as F, type GasMethod as G, type HealthFactorResult as H, listSentinels as I, descriptor$3 as J, requestAttack as K, type LendingAdapter as L, type MaxWithdrawResult as M, NaviAdapter as N, attack as O, type PositionsResult as P, descriptor as Q, type RepayResult as R, type SendResult as S, type T2000Options as T, settleAttack as U, submitPrompt as V, type WithdrawResult as W, descriptor$1 as X, type TransactionRecord as a, type SwapAdapter as b, type SaveResult as c, type BorrowResult as d, type MaxBorrowResult as e, type
|
|
478
|
+
export { type AdapterCapability as A, type BalanceResponse as B, CetusAdapter as C, type DepositInfo as D, type EarningsResult as E, type FundStatusResult as F, type GasMethod as G, type HealthFactorResult as H, listSentinels as I, descriptor$3 as J, requestAttack as K, type LendingAdapter as L, type MaxWithdrawResult as M, NaviAdapter as N, attack as O, type PositionsResult as P, descriptor as Q, type RepayResult as R, type SendResult as S, type T2000Options as T, settleAttack as U, submitPrompt as V, type WithdrawResult as W, descriptor$1 as X, type TransactionRecord as a, type SwapAdapter as b, type SaveResult as c, type BorrowResult as d, type MaxBorrowResult as e, type RatesResult as f, type LendingRates as g, type RebalanceResult as h, type SentinelAgent as i, type SentinelAttackResult as j, type AdapterPositions as k, type AdapterTxResult as l, type AssetRates as m, type GasReserve as n, type HealthInfo as o, type PositionEntry as p, type ProtocolDescriptor as q, ProtocolRegistry as r, type RebalanceStep as s, type SentinelVerdict as t, SuilendAdapter as u, type SwapQuote as v, type SwapResult as w, allDescriptors as x, descriptor$2 as y, getSentinelInfo as z };
|
package/dist/index.cjs
CHANGED
|
@@ -1317,24 +1317,6 @@ var ProtocolRegistry = class {
|
|
|
1317
1317
|
listSwap() {
|
|
1318
1318
|
return [...this.swap.values()];
|
|
1319
1319
|
}
|
|
1320
|
-
isSupportedAsset(asset, capability) {
|
|
1321
|
-
for (const adapter of this.lending.values()) {
|
|
1322
|
-
if (!adapter.supportedAssets.includes(asset)) continue;
|
|
1323
|
-
if (capability && !adapter.capabilities.includes(capability)) continue;
|
|
1324
|
-
return true;
|
|
1325
|
-
}
|
|
1326
|
-
return false;
|
|
1327
|
-
}
|
|
1328
|
-
getSupportedAssets(capability) {
|
|
1329
|
-
const assets = /* @__PURE__ */ new Set();
|
|
1330
|
-
for (const adapter of this.lending.values()) {
|
|
1331
|
-
if (capability && !adapter.capabilities.includes(capability)) continue;
|
|
1332
|
-
for (const a of adapter.supportedAssets) {
|
|
1333
|
-
assets.add(a);
|
|
1334
|
-
}
|
|
1335
|
-
}
|
|
1336
|
-
return [...assets];
|
|
1337
|
-
}
|
|
1338
1320
|
};
|
|
1339
1321
|
|
|
1340
1322
|
// src/adapters/navi.ts
|
|
@@ -2433,43 +2415,39 @@ var T2000 = class _T2000 extends eventemitter3.EventEmitter {
|
|
|
2433
2415
|
}
|
|
2434
2416
|
// -- Savings --
|
|
2435
2417
|
async save(params) {
|
|
2436
|
-
const asset =
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
throw new T2000Error("ASSET_NOT_SUPPORTED", `${asset} is not supported for save. Supported: ${supported}`);
|
|
2440
|
-
}
|
|
2418
|
+
const asset = "USDC";
|
|
2419
|
+
const bal = await queryBalance(this.client, this._address);
|
|
2420
|
+
const usdcBalance = bal.stables.USDC ?? 0;
|
|
2441
2421
|
let amount;
|
|
2442
2422
|
if (params.amount === "all") {
|
|
2443
|
-
|
|
2444
|
-
const
|
|
2445
|
-
|
|
2446
|
-
amount = assetBalance - reserve;
|
|
2423
|
+
await this._convertWalletStablesToUsdc(bal);
|
|
2424
|
+
const refreshedBal = await queryBalance(this.client, this._address);
|
|
2425
|
+
amount = (refreshedBal.stables.USDC ?? 0) - 1;
|
|
2447
2426
|
if (amount <= 0) {
|
|
2448
|
-
throw new T2000Error("INSUFFICIENT_BALANCE",
|
|
2449
|
-
reason:
|
|
2450
|
-
available:
|
|
2427
|
+
throw new T2000Error("INSUFFICIENT_BALANCE", "Balance too low to save after $1 gas reserve", {
|
|
2428
|
+
reason: "gas_reserve_required",
|
|
2429
|
+
available: refreshedBal.stables.USDC ?? 0
|
|
2451
2430
|
});
|
|
2452
2431
|
}
|
|
2453
2432
|
} else {
|
|
2454
2433
|
amount = params.amount;
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2434
|
+
if (amount > usdcBalance) {
|
|
2435
|
+
const totalStables = bal.available;
|
|
2436
|
+
if (amount > totalStables) {
|
|
2437
|
+
throw new T2000Error("INSUFFICIENT_BALANCE", `Insufficient balance. Available: $${totalStables.toFixed(2)}, requested: $${amount.toFixed(2)}`);
|
|
2438
|
+
}
|
|
2439
|
+
await this._convertWalletStablesToUsdc(bal, amount - usdcBalance);
|
|
2459
2440
|
}
|
|
2460
2441
|
}
|
|
2461
|
-
const
|
|
2462
|
-
const fee = shouldCollectFee ? calculateFee("save", amount) : { amount: 0, rate: 0};
|
|
2442
|
+
const fee = calculateFee("save", amount);
|
|
2463
2443
|
const saveAmount = amount;
|
|
2464
2444
|
const adapter = await this.resolveLending(params.protocol, asset, "save");
|
|
2465
2445
|
const gasResult = await executeWithGas(this.client, this.keypair, async () => {
|
|
2466
|
-
const { tx } = await adapter.buildSaveTx(this._address, saveAmount, asset, { collectFee:
|
|
2446
|
+
const { tx } = await adapter.buildSaveTx(this._address, saveAmount, asset, { collectFee: true });
|
|
2467
2447
|
return tx;
|
|
2468
2448
|
});
|
|
2469
2449
|
const rates = await adapter.getRates(asset);
|
|
2470
|
-
|
|
2471
|
-
reportFee(this._address, "save", fee.amount, fee.rate, gasResult.digest);
|
|
2472
|
-
}
|
|
2450
|
+
reportFee(this._address, "save", fee.amount, fee.rate, gasResult.digest);
|
|
2473
2451
|
this.emitBalanceChange(asset, saveAmount, "save", gasResult.digest);
|
|
2474
2452
|
let savingsBalance = saveAmount;
|
|
2475
2453
|
try {
|
|
@@ -2481,7 +2459,6 @@ var T2000 = class _T2000 extends eventemitter3.EventEmitter {
|
|
|
2481
2459
|
success: true,
|
|
2482
2460
|
tx: gasResult.digest,
|
|
2483
2461
|
amount: saveAmount,
|
|
2484
|
-
asset,
|
|
2485
2462
|
apy: rates.saveApy,
|
|
2486
2463
|
fee: fee.amount,
|
|
2487
2464
|
gasCost: gasResult.gasCostSui,
|
|
@@ -2490,14 +2467,27 @@ var T2000 = class _T2000 extends eventemitter3.EventEmitter {
|
|
|
2490
2467
|
};
|
|
2491
2468
|
}
|
|
2492
2469
|
async withdraw(params) {
|
|
2493
|
-
const asset = normalizeAsset(params.asset ?? "USDC");
|
|
2494
2470
|
if (params.amount === "all" && !params.protocol) {
|
|
2495
|
-
return this.withdrawAllProtocols(
|
|
2471
|
+
return this.withdrawAllProtocols();
|
|
2472
|
+
}
|
|
2473
|
+
const allPositions = await this.registry.allPositions(this._address);
|
|
2474
|
+
const supplies = [];
|
|
2475
|
+
for (const pos of allPositions) {
|
|
2476
|
+
if (params.protocol && pos.protocolId !== params.protocol) continue;
|
|
2477
|
+
for (const s of pos.positions.supplies) {
|
|
2478
|
+
if (s.amount > 1e-3) supplies.push({ protocolId: pos.protocolId, asset: s.asset, amount: s.amount, apy: s.apy });
|
|
2479
|
+
}
|
|
2496
2480
|
}
|
|
2497
|
-
|
|
2481
|
+
if (supplies.length === 0) {
|
|
2482
|
+
throw new T2000Error("NO_COLLATERAL", "No savings to withdraw");
|
|
2483
|
+
}
|
|
2484
|
+
supplies.sort((a, b) => a.apy - b.apy);
|
|
2485
|
+
const target = supplies[0];
|
|
2486
|
+
const adapter = this.registry.getLending(target.protocolId);
|
|
2487
|
+
if (!adapter) throw new T2000Error("PROTOCOL_UNAVAILABLE", `Protocol ${target.protocolId} not found`);
|
|
2498
2488
|
let amount;
|
|
2499
2489
|
if (params.amount === "all") {
|
|
2500
|
-
const maxResult = await adapter.maxWithdraw(this._address, asset);
|
|
2490
|
+
const maxResult = await adapter.maxWithdraw(this._address, target.asset);
|
|
2501
2491
|
amount = maxResult.maxAmount;
|
|
2502
2492
|
if (amount <= 0) {
|
|
2503
2493
|
throw new T2000Error("NO_COLLATERAL", "No savings to withdraw");
|
|
@@ -2506,7 +2496,7 @@ var T2000 = class _T2000 extends eventemitter3.EventEmitter {
|
|
|
2506
2496
|
amount = params.amount;
|
|
2507
2497
|
const hf = await adapter.getHealth(this._address);
|
|
2508
2498
|
if (hf.borrowed > 0) {
|
|
2509
|
-
const maxResult = await adapter.maxWithdraw(this._address, asset);
|
|
2499
|
+
const maxResult = await adapter.maxWithdraw(this._address, target.asset);
|
|
2510
2500
|
if (amount > maxResult.maxAmount) {
|
|
2511
2501
|
throw new T2000Error(
|
|
2512
2502
|
"WITHDRAW_WOULD_LIQUIDATE",
|
|
@@ -2523,20 +2513,37 @@ var T2000 = class _T2000 extends eventemitter3.EventEmitter {
|
|
|
2523
2513
|
const withdrawAmount = amount;
|
|
2524
2514
|
let effectiveAmount = withdrawAmount;
|
|
2525
2515
|
const gasResult = await executeWithGas(this.client, this.keypair, async () => {
|
|
2526
|
-
const built = await adapter.buildWithdrawTx(this._address, withdrawAmount, asset);
|
|
2516
|
+
const built = await adapter.buildWithdrawTx(this._address, withdrawAmount, target.asset);
|
|
2527
2517
|
effectiveAmount = built.effectiveAmount;
|
|
2528
2518
|
return built.tx;
|
|
2529
2519
|
});
|
|
2530
|
-
|
|
2520
|
+
let totalGasCost = gasResult.gasCostSui;
|
|
2521
|
+
let finalAmount = effectiveAmount;
|
|
2522
|
+
let lastDigest = gasResult.digest;
|
|
2523
|
+
if (target.asset !== "USDC") {
|
|
2524
|
+
try {
|
|
2525
|
+
const swapResult = await this._swapToUsdc(target.asset, effectiveAmount);
|
|
2526
|
+
finalAmount = swapResult.usdcReceived;
|
|
2527
|
+
lastDigest = swapResult.digest;
|
|
2528
|
+
totalGasCost += swapResult.gasCost;
|
|
2529
|
+
} catch (err) {
|
|
2530
|
+
throw new T2000Error(
|
|
2531
|
+
"SWAP_FAILED",
|
|
2532
|
+
`Withdrew $${effectiveAmount.toFixed(2)} ${target.asset} but swap to USDC failed. Your ${target.asset} is safe in your wallet.`,
|
|
2533
|
+
{ withdrawDigest: gasResult.digest, originalError: err instanceof Error ? err.message : String(err) }
|
|
2534
|
+
);
|
|
2535
|
+
}
|
|
2536
|
+
}
|
|
2537
|
+
this.emitBalanceChange("USDC", finalAmount, "withdraw", lastDigest);
|
|
2531
2538
|
return {
|
|
2532
2539
|
success: true,
|
|
2533
|
-
tx:
|
|
2534
|
-
amount:
|
|
2535
|
-
gasCost:
|
|
2540
|
+
tx: lastDigest,
|
|
2541
|
+
amount: finalAmount,
|
|
2542
|
+
gasCost: totalGasCost,
|
|
2536
2543
|
gasMethod: gasResult.gasMethod
|
|
2537
2544
|
};
|
|
2538
2545
|
}
|
|
2539
|
-
async withdrawAllProtocols(
|
|
2546
|
+
async withdrawAllProtocols() {
|
|
2540
2547
|
const allPositions = await this.registry.allPositions(this._address);
|
|
2541
2548
|
const withdrawable = [];
|
|
2542
2549
|
for (const pos of allPositions) {
|
|
@@ -2549,7 +2556,7 @@ var T2000 = class _T2000 extends eventemitter3.EventEmitter {
|
|
|
2549
2556
|
if (withdrawable.length === 0) {
|
|
2550
2557
|
throw new T2000Error("NO_COLLATERAL", "No savings to withdraw across any protocol");
|
|
2551
2558
|
}
|
|
2552
|
-
let
|
|
2559
|
+
let totalUsdcReceived = 0;
|
|
2553
2560
|
let lastDigest = "";
|
|
2554
2561
|
let totalGasCost = 0;
|
|
2555
2562
|
let lastGasMethod = "self-funded";
|
|
@@ -2564,30 +2571,88 @@ var T2000 = class _T2000 extends eventemitter3.EventEmitter {
|
|
|
2564
2571
|
effectiveAmount = built.effectiveAmount;
|
|
2565
2572
|
return built.tx;
|
|
2566
2573
|
});
|
|
2567
|
-
totalWithdrawn += effectiveAmount;
|
|
2568
2574
|
lastDigest = gasResult.digest;
|
|
2569
2575
|
totalGasCost += gasResult.gasCostSui;
|
|
2570
2576
|
lastGasMethod = gasResult.gasMethod;
|
|
2571
2577
|
this.emitBalanceChange(entry.asset, effectiveAmount, "withdraw", gasResult.digest);
|
|
2578
|
+
if (entry.asset !== "USDC") {
|
|
2579
|
+
try {
|
|
2580
|
+
const swapResult = await this._swapToUsdc(entry.asset, effectiveAmount);
|
|
2581
|
+
totalUsdcReceived += swapResult.usdcReceived;
|
|
2582
|
+
lastDigest = swapResult.digest;
|
|
2583
|
+
totalGasCost += swapResult.gasCost;
|
|
2584
|
+
} catch {
|
|
2585
|
+
totalUsdcReceived += effectiveAmount;
|
|
2586
|
+
}
|
|
2587
|
+
} else {
|
|
2588
|
+
totalUsdcReceived += effectiveAmount;
|
|
2589
|
+
}
|
|
2572
2590
|
}
|
|
2573
|
-
if (
|
|
2591
|
+
if (totalUsdcReceived <= 0) {
|
|
2574
2592
|
throw new T2000Error("NO_COLLATERAL", "No savings to withdraw across any protocol");
|
|
2575
2593
|
}
|
|
2576
2594
|
return {
|
|
2577
2595
|
success: true,
|
|
2578
2596
|
tx: lastDigest,
|
|
2579
|
-
amount:
|
|
2597
|
+
amount: totalUsdcReceived,
|
|
2580
2598
|
gasCost: totalGasCost,
|
|
2581
2599
|
gasMethod: lastGasMethod
|
|
2582
2600
|
};
|
|
2583
2601
|
}
|
|
2602
|
+
async _swapToUsdc(asset, amount) {
|
|
2603
|
+
const swapAdapter = this.registry.listSwap()[0];
|
|
2604
|
+
if (!swapAdapter) throw new T2000Error("PROTOCOL_UNAVAILABLE", "No swap adapter available");
|
|
2605
|
+
let estimatedOut = 0;
|
|
2606
|
+
let toDecimals = 6;
|
|
2607
|
+
const gasResult = await executeWithGas(this.client, this.keypair, async () => {
|
|
2608
|
+
const built = await swapAdapter.buildSwapTx(this._address, asset, "USDC", amount);
|
|
2609
|
+
estimatedOut = built.estimatedOut;
|
|
2610
|
+
toDecimals = built.toDecimals;
|
|
2611
|
+
return built.tx;
|
|
2612
|
+
});
|
|
2613
|
+
const usdcReceived = estimatedOut / 10 ** toDecimals;
|
|
2614
|
+
return { usdcReceived, digest: gasResult.digest, gasCost: gasResult.gasCostSui };
|
|
2615
|
+
}
|
|
2616
|
+
async _swapFromUsdc(toAsset, amount) {
|
|
2617
|
+
const swapAdapter = this.registry.listSwap()[0];
|
|
2618
|
+
if (!swapAdapter) throw new T2000Error("PROTOCOL_UNAVAILABLE", "No swap adapter available");
|
|
2619
|
+
let estimatedOut = 0;
|
|
2620
|
+
let toDecimals = 6;
|
|
2621
|
+
const gasResult = await executeWithGas(this.client, this.keypair, async () => {
|
|
2622
|
+
const built = await swapAdapter.buildSwapTx(this._address, "USDC", toAsset, amount);
|
|
2623
|
+
estimatedOut = built.estimatedOut;
|
|
2624
|
+
toDecimals = built.toDecimals;
|
|
2625
|
+
return built.tx;
|
|
2626
|
+
});
|
|
2627
|
+
const received = estimatedOut / 10 ** toDecimals;
|
|
2628
|
+
return { received, digest: gasResult.digest, gasCost: gasResult.gasCostSui };
|
|
2629
|
+
}
|
|
2630
|
+
async _convertWalletStablesToUsdc(bal, amountNeeded) {
|
|
2631
|
+
const nonUsdcStables = [];
|
|
2632
|
+
for (const [asset, amount] of Object.entries(bal.stables)) {
|
|
2633
|
+
if (asset !== "USDC" && amount > 0.01) {
|
|
2634
|
+
nonUsdcStables.push({ asset, amount });
|
|
2635
|
+
}
|
|
2636
|
+
}
|
|
2637
|
+
if (nonUsdcStables.length === 0) return;
|
|
2638
|
+
nonUsdcStables.sort((a, b) => b.amount - a.amount);
|
|
2639
|
+
let converted = 0;
|
|
2640
|
+
for (const entry of nonUsdcStables) {
|
|
2641
|
+
if (amountNeeded !== void 0 && converted >= amountNeeded) break;
|
|
2642
|
+
try {
|
|
2643
|
+
await this._swapToUsdc(entry.asset, entry.amount);
|
|
2644
|
+
converted += entry.amount;
|
|
2645
|
+
} catch {
|
|
2646
|
+
}
|
|
2647
|
+
}
|
|
2648
|
+
}
|
|
2584
2649
|
async maxWithdraw() {
|
|
2585
2650
|
const adapter = await this.resolveLending(void 0, "USDC", "withdraw");
|
|
2586
2651
|
return adapter.maxWithdraw(this._address, "USDC");
|
|
2587
2652
|
}
|
|
2588
2653
|
// -- Borrowing --
|
|
2589
2654
|
async borrow(params) {
|
|
2590
|
-
const asset =
|
|
2655
|
+
const asset = "USDC";
|
|
2591
2656
|
const adapter = await this.resolveLending(params.protocol, asset, "borrow");
|
|
2592
2657
|
const maxResult = await adapter.maxBorrow(this._address, asset);
|
|
2593
2658
|
if (maxResult.maxAmount <= 0) {
|
|
@@ -2599,17 +2664,14 @@ var T2000 = class _T2000 extends eventemitter3.EventEmitter {
|
|
|
2599
2664
|
currentHF: maxResult.currentHF
|
|
2600
2665
|
});
|
|
2601
2666
|
}
|
|
2602
|
-
const
|
|
2603
|
-
const fee = shouldCollectFee ? calculateFee("borrow", params.amount) : { amount: 0, rate: 0};
|
|
2667
|
+
const fee = calculateFee("borrow", params.amount);
|
|
2604
2668
|
const borrowAmount = params.amount;
|
|
2605
2669
|
const gasResult = await executeWithGas(this.client, this.keypair, async () => {
|
|
2606
|
-
const { tx } = await adapter.buildBorrowTx(this._address, borrowAmount, asset, { collectFee:
|
|
2670
|
+
const { tx } = await adapter.buildBorrowTx(this._address, borrowAmount, asset, { collectFee: true });
|
|
2607
2671
|
return tx;
|
|
2608
2672
|
});
|
|
2609
2673
|
const hf = await adapter.getHealth(this._address);
|
|
2610
|
-
|
|
2611
|
-
reportFee(this._address, "borrow", fee.amount, fee.rate, gasResult.digest);
|
|
2612
|
-
}
|
|
2674
|
+
reportFee(this._address, "borrow", fee.amount, fee.rate, gasResult.digest);
|
|
2613
2675
|
this.emitBalanceChange(asset, borrowAmount, "borrow", gasResult.digest);
|
|
2614
2676
|
return {
|
|
2615
2677
|
success: true,
|
|
@@ -2622,34 +2684,93 @@ var T2000 = class _T2000 extends eventemitter3.EventEmitter {
|
|
|
2622
2684
|
};
|
|
2623
2685
|
}
|
|
2624
2686
|
async repay(params) {
|
|
2625
|
-
const
|
|
2626
|
-
const
|
|
2627
|
-
|
|
2628
|
-
|
|
2629
|
-
const
|
|
2630
|
-
|
|
2631
|
-
if (amount <= 0) {
|
|
2632
|
-
throw new T2000Error("NO_COLLATERAL", "No outstanding borrow to repay");
|
|
2687
|
+
const allPositions = await this.registry.allPositions(this._address);
|
|
2688
|
+
const borrows = [];
|
|
2689
|
+
for (const pos of allPositions) {
|
|
2690
|
+
if (params.protocol && pos.protocolId !== params.protocol) continue;
|
|
2691
|
+
for (const b of pos.positions.borrows) {
|
|
2692
|
+
if (b.amount > 1e-3) borrows.push({ protocolId: pos.protocolId, asset: b.asset, amount: b.amount, apy: b.apy });
|
|
2633
2693
|
}
|
|
2634
|
-
} else {
|
|
2635
|
-
amount = params.amount;
|
|
2636
2694
|
}
|
|
2637
|
-
|
|
2695
|
+
if (borrows.length === 0) {
|
|
2696
|
+
throw new T2000Error("NO_COLLATERAL", "No outstanding borrow to repay");
|
|
2697
|
+
}
|
|
2698
|
+
if (params.amount === "all") {
|
|
2699
|
+
return this._repayAllBorrows(borrows);
|
|
2700
|
+
}
|
|
2701
|
+
borrows.sort((a, b) => b.apy - a.apy);
|
|
2702
|
+
const target = borrows[0];
|
|
2703
|
+
const adapter = this.registry.getLending(target.protocolId);
|
|
2704
|
+
if (!adapter) throw new T2000Error("PROTOCOL_UNAVAILABLE", `Protocol ${target.protocolId} not found`);
|
|
2705
|
+
const repayAmount = Math.min(params.amount, target.amount);
|
|
2706
|
+
let totalGasCost = 0;
|
|
2707
|
+
let lastDigest = "";
|
|
2708
|
+
if (target.asset !== "USDC") {
|
|
2709
|
+
const buffer = repayAmount * 1.005;
|
|
2710
|
+
const swapResult = await this._swapFromUsdc(target.asset, buffer);
|
|
2711
|
+
totalGasCost += swapResult.gasCost;
|
|
2712
|
+
lastDigest = swapResult.digest;
|
|
2713
|
+
}
|
|
2638
2714
|
const gasResult = await executeWithGas(this.client, this.keypair, async () => {
|
|
2639
|
-
const { tx } = await adapter.buildRepayTx(this._address, repayAmount, asset);
|
|
2715
|
+
const { tx } = await adapter.buildRepayTx(this._address, repayAmount, target.asset);
|
|
2640
2716
|
return tx;
|
|
2641
2717
|
});
|
|
2718
|
+
totalGasCost += gasResult.gasCostSui;
|
|
2719
|
+
lastDigest = gasResult.digest;
|
|
2642
2720
|
const hf = await adapter.getHealth(this._address);
|
|
2643
|
-
this.emitBalanceChange(
|
|
2721
|
+
this.emitBalanceChange("USDC", repayAmount, "repay", lastDigest);
|
|
2644
2722
|
return {
|
|
2645
2723
|
success: true,
|
|
2646
|
-
tx:
|
|
2724
|
+
tx: lastDigest,
|
|
2647
2725
|
amount: repayAmount,
|
|
2648
2726
|
remainingDebt: hf.borrowed,
|
|
2649
|
-
gasCost:
|
|
2727
|
+
gasCost: totalGasCost,
|
|
2650
2728
|
gasMethod: gasResult.gasMethod
|
|
2651
2729
|
};
|
|
2652
2730
|
}
|
|
2731
|
+
async _repayAllBorrows(borrows) {
|
|
2732
|
+
let totalRepaid = 0;
|
|
2733
|
+
let totalGasCost = 0;
|
|
2734
|
+
let lastDigest = "";
|
|
2735
|
+
let lastGasMethod = "self-funded";
|
|
2736
|
+
borrows.sort((a, b) => b.apy - a.apy);
|
|
2737
|
+
for (const borrow of borrows) {
|
|
2738
|
+
const adapter = this.registry.getLending(borrow.protocolId);
|
|
2739
|
+
if (!adapter) continue;
|
|
2740
|
+
if (borrow.asset !== "USDC") {
|
|
2741
|
+
try {
|
|
2742
|
+
const buffer = borrow.amount * 1.005;
|
|
2743
|
+
const swapResult = await this._swapFromUsdc(borrow.asset, buffer);
|
|
2744
|
+
totalGasCost += swapResult.gasCost;
|
|
2745
|
+
} catch (err) {
|
|
2746
|
+
throw new T2000Error(
|
|
2747
|
+
"SWAP_FAILED",
|
|
2748
|
+
`Could not convert USDC to ${borrow.asset} for repayment. Try again later.`,
|
|
2749
|
+
{ originalError: err instanceof Error ? err.message : String(err) }
|
|
2750
|
+
);
|
|
2751
|
+
}
|
|
2752
|
+
}
|
|
2753
|
+
const gasResult = await executeWithGas(this.client, this.keypair, async () => {
|
|
2754
|
+
const { tx } = await adapter.buildRepayTx(this._address, borrow.amount, borrow.asset);
|
|
2755
|
+
return tx;
|
|
2756
|
+
});
|
|
2757
|
+
totalRepaid += borrow.amount;
|
|
2758
|
+
totalGasCost += gasResult.gasCostSui;
|
|
2759
|
+
lastDigest = gasResult.digest;
|
|
2760
|
+
lastGasMethod = gasResult.gasMethod;
|
|
2761
|
+
}
|
|
2762
|
+
const firstAdapter = this.registry.getLending(borrows[0].protocolId);
|
|
2763
|
+
const hf = firstAdapter ? await firstAdapter.getHealth(this._address) : { borrowed: 0 };
|
|
2764
|
+
this.emitBalanceChange("USDC", totalRepaid, "repay", lastDigest);
|
|
2765
|
+
return {
|
|
2766
|
+
success: true,
|
|
2767
|
+
tx: lastDigest,
|
|
2768
|
+
amount: totalRepaid,
|
|
2769
|
+
remainingDebt: hf.borrowed,
|
|
2770
|
+
gasCost: totalGasCost,
|
|
2771
|
+
gasMethod: lastGasMethod
|
|
2772
|
+
};
|
|
2773
|
+
}
|
|
2653
2774
|
async maxBorrow() {
|
|
2654
2775
|
const adapter = await this.resolveLending(void 0, "USDC", "borrow");
|
|
2655
2776
|
return adapter.maxBorrow(this._address, "USDC");
|
|
@@ -2664,25 +2785,18 @@ var T2000 = class _T2000 extends eventemitter3.EventEmitter {
|
|
|
2664
2785
|
}
|
|
2665
2786
|
return hf;
|
|
2666
2787
|
}
|
|
2667
|
-
// -- Swap --
|
|
2668
|
-
async
|
|
2669
|
-
const fromAsset =
|
|
2670
|
-
const toAsset =
|
|
2788
|
+
// -- Swap (internal — used by rebalance and withdraw auto-swap) --
|
|
2789
|
+
async _swap(params) {
|
|
2790
|
+
const fromAsset = params.from;
|
|
2791
|
+
const toAsset = params.to;
|
|
2671
2792
|
if (!(fromAsset in SUPPORTED_ASSETS) || !(toAsset in SUPPORTED_ASSETS)) {
|
|
2672
2793
|
throw new T2000Error("ASSET_NOT_SUPPORTED", `Swap pair ${fromAsset}/${toAsset} is not supported`);
|
|
2673
2794
|
}
|
|
2674
2795
|
if (fromAsset === toAsset) {
|
|
2675
2796
|
throw new T2000Error("INVALID_AMOUNT", "Cannot swap same asset");
|
|
2676
2797
|
}
|
|
2677
|
-
|
|
2678
|
-
|
|
2679
|
-
const found = this.registry.getSwap(params.protocol);
|
|
2680
|
-
if (!found) throw new T2000Error("ASSET_NOT_SUPPORTED", `Swap adapter '${params.protocol}' not found`);
|
|
2681
|
-
adapter = found;
|
|
2682
|
-
} else {
|
|
2683
|
-
const best = await this.registry.bestSwapQuote(fromAsset, toAsset, params.amount);
|
|
2684
|
-
adapter = best.adapter;
|
|
2685
|
-
}
|
|
2798
|
+
const best = await this.registry.bestSwapQuote(fromAsset, toAsset, params.amount);
|
|
2799
|
+
const adapter = best.adapter;
|
|
2686
2800
|
const fee = calculateFee("swap", params.amount);
|
|
2687
2801
|
const swapAmount = params.amount;
|
|
2688
2802
|
const slippageBps = params.maxSlippage ? params.maxSlippage * 100 : void 0;
|
|
@@ -2725,9 +2839,9 @@ var T2000 = class _T2000 extends eventemitter3.EventEmitter {
|
|
|
2725
2839
|
gasMethod: gasResult.gasMethod
|
|
2726
2840
|
};
|
|
2727
2841
|
}
|
|
2728
|
-
async
|
|
2729
|
-
const fromAsset =
|
|
2730
|
-
const toAsset =
|
|
2842
|
+
async _swapQuote(params) {
|
|
2843
|
+
const fromAsset = params.from;
|
|
2844
|
+
const toAsset = params.to;
|
|
2731
2845
|
const best = await this.registry.bestSwapQuote(fromAsset, toAsset, params.amount);
|
|
2732
2846
|
const fee = calculateFee("swap", params.amount);
|
|
2733
2847
|
return { ...best.quote, fee: { amount: fee.amount, rate: fee.rate } };
|
|
@@ -3172,7 +3286,6 @@ exports.MIST_PER_SUI = MIST_PER_SUI;
|
|
|
3172
3286
|
exports.NaviAdapter = NaviAdapter;
|
|
3173
3287
|
exports.ProtocolRegistry = ProtocolRegistry;
|
|
3174
3288
|
exports.SENTINEL = SENTINEL;
|
|
3175
|
-
exports.STABLE_ASSETS = STABLE_ASSETS;
|
|
3176
3289
|
exports.SUI_DECIMALS = SUI_DECIMALS;
|
|
3177
3290
|
exports.SUPPORTED_ASSETS = SUPPORTED_ASSETS;
|
|
3178
3291
|
exports.SuilendAdapter = SuilendAdapter;
|
|
@@ -3195,7 +3308,6 @@ exports.getGasStatus = getGasStatus;
|
|
|
3195
3308
|
exports.getPoolPrice = getPoolPrice;
|
|
3196
3309
|
exports.getRates = getRates;
|
|
3197
3310
|
exports.getSentinelInfo = getSentinelInfo;
|
|
3198
|
-
exports.getSwapQuote = getSwapQuote;
|
|
3199
3311
|
exports.keypairFromPrivateKey = keypairFromPrivateKey;
|
|
3200
3312
|
exports.listSentinels = listSentinels;
|
|
3201
3313
|
exports.loadKey = loadKey;
|
|
@@ -3203,7 +3315,6 @@ exports.mapMoveAbortCode = mapMoveAbortCode;
|
|
|
3203
3315
|
exports.mapWalletError = mapWalletError;
|
|
3204
3316
|
exports.mistToSui = mistToSui;
|
|
3205
3317
|
exports.naviDescriptor = descriptor2;
|
|
3206
|
-
exports.normalizeAsset = normalizeAsset;
|
|
3207
3318
|
exports.rawToStable = rawToStable;
|
|
3208
3319
|
exports.rawToUsdc = rawToUsdc;
|
|
3209
3320
|
exports.requestAttack = requestAttack;
|