@t2000/sdk 0.9.0 → 0.9.2
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.cjs +121 -24
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +121 -24
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -110,6 +110,8 @@ declare class T2000 extends EventEmitter<T2000Events> {
|
|
|
110
110
|
}): Promise<WithdrawResult>;
|
|
111
111
|
private withdrawAllProtocols;
|
|
112
112
|
private _swapToUsdc;
|
|
113
|
+
private _swapFromUsdc;
|
|
114
|
+
private _convertWalletStablesToUsdc;
|
|
113
115
|
maxWithdraw(): Promise<MaxWithdrawResult>;
|
|
114
116
|
borrow(params: {
|
|
115
117
|
amount: number;
|
|
@@ -119,6 +121,7 @@ declare class T2000 extends EventEmitter<T2000Events> {
|
|
|
119
121
|
amount: number | 'all';
|
|
120
122
|
protocol?: string;
|
|
121
123
|
}): Promise<RepayResult>;
|
|
124
|
+
private _repayAllBorrows;
|
|
122
125
|
maxBorrow(): Promise<MaxBorrowResult>;
|
|
123
126
|
healthFactor(): Promise<HealthFactorResult>;
|
|
124
127
|
private _swap;
|
package/dist/index.d.ts
CHANGED
|
@@ -110,6 +110,8 @@ declare class T2000 extends EventEmitter<T2000Events> {
|
|
|
110
110
|
}): Promise<WithdrawResult>;
|
|
111
111
|
private withdrawAllProtocols;
|
|
112
112
|
private _swapToUsdc;
|
|
113
|
+
private _swapFromUsdc;
|
|
114
|
+
private _convertWalletStablesToUsdc;
|
|
113
115
|
maxWithdraw(): Promise<MaxWithdrawResult>;
|
|
114
116
|
borrow(params: {
|
|
115
117
|
amount: number;
|
|
@@ -119,6 +121,7 @@ declare class T2000 extends EventEmitter<T2000Events> {
|
|
|
119
121
|
amount: number | 'all';
|
|
120
122
|
protocol?: string;
|
|
121
123
|
}): Promise<RepayResult>;
|
|
124
|
+
private _repayAllBorrows;
|
|
122
125
|
maxBorrow(): Promise<MaxBorrowResult>;
|
|
123
126
|
healthFactor(): Promise<HealthFactorResult>;
|
|
124
127
|
private _swap;
|
package/dist/index.js
CHANGED
|
@@ -2414,22 +2414,27 @@ var T2000 = class _T2000 extends EventEmitter {
|
|
|
2414
2414
|
// -- Savings --
|
|
2415
2415
|
async save(params) {
|
|
2416
2416
|
const asset = "USDC";
|
|
2417
|
+
const bal = await queryBalance(this.client, this._address);
|
|
2418
|
+
const usdcBalance = bal.stables.USDC ?? 0;
|
|
2417
2419
|
let amount;
|
|
2418
2420
|
if (params.amount === "all") {
|
|
2419
|
-
|
|
2420
|
-
const
|
|
2421
|
-
amount =
|
|
2421
|
+
await this._convertWalletStablesToUsdc(bal);
|
|
2422
|
+
const refreshedBal = await queryBalance(this.client, this._address);
|
|
2423
|
+
amount = (refreshedBal.stables.USDC ?? 0) - 1;
|
|
2422
2424
|
if (amount <= 0) {
|
|
2423
2425
|
throw new T2000Error("INSUFFICIENT_BALANCE", "Balance too low to save after $1 gas reserve", {
|
|
2424
2426
|
reason: "gas_reserve_required",
|
|
2425
|
-
available:
|
|
2427
|
+
available: refreshedBal.stables.USDC ?? 0
|
|
2426
2428
|
});
|
|
2427
2429
|
}
|
|
2428
2430
|
} else {
|
|
2429
2431
|
amount = params.amount;
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2432
|
+
if (amount > usdcBalance) {
|
|
2433
|
+
const totalStables = bal.available;
|
|
2434
|
+
if (amount > totalStables) {
|
|
2435
|
+
throw new T2000Error("INSUFFICIENT_BALANCE", `Insufficient balance. Available: $${totalStables.toFixed(2)}, requested: $${amount.toFixed(2)}`);
|
|
2436
|
+
}
|
|
2437
|
+
await this._convertWalletStablesToUsdc(bal, amount - usdcBalance);
|
|
2433
2438
|
}
|
|
2434
2439
|
}
|
|
2435
2440
|
const fee = calculateFee("save", amount);
|
|
@@ -2606,6 +2611,39 @@ var T2000 = class _T2000 extends EventEmitter {
|
|
|
2606
2611
|
const usdcReceived = estimatedOut / 10 ** toDecimals;
|
|
2607
2612
|
return { usdcReceived, digest: gasResult.digest, gasCost: gasResult.gasCostSui };
|
|
2608
2613
|
}
|
|
2614
|
+
async _swapFromUsdc(toAsset, amount) {
|
|
2615
|
+
const swapAdapter = this.registry.listSwap()[0];
|
|
2616
|
+
if (!swapAdapter) throw new T2000Error("PROTOCOL_UNAVAILABLE", "No swap adapter available");
|
|
2617
|
+
let estimatedOut = 0;
|
|
2618
|
+
let toDecimals = 6;
|
|
2619
|
+
const gasResult = await executeWithGas(this.client, this.keypair, async () => {
|
|
2620
|
+
const built = await swapAdapter.buildSwapTx(this._address, "USDC", toAsset, amount);
|
|
2621
|
+
estimatedOut = built.estimatedOut;
|
|
2622
|
+
toDecimals = built.toDecimals;
|
|
2623
|
+
return built.tx;
|
|
2624
|
+
});
|
|
2625
|
+
const received = estimatedOut / 10 ** toDecimals;
|
|
2626
|
+
return { received, digest: gasResult.digest, gasCost: gasResult.gasCostSui };
|
|
2627
|
+
}
|
|
2628
|
+
async _convertWalletStablesToUsdc(bal, amountNeeded) {
|
|
2629
|
+
const nonUsdcStables = [];
|
|
2630
|
+
for (const [asset, amount] of Object.entries(bal.stables)) {
|
|
2631
|
+
if (asset !== "USDC" && amount > 0.01) {
|
|
2632
|
+
nonUsdcStables.push({ asset, amount });
|
|
2633
|
+
}
|
|
2634
|
+
}
|
|
2635
|
+
if (nonUsdcStables.length === 0) return;
|
|
2636
|
+
nonUsdcStables.sort((a, b) => b.amount - a.amount);
|
|
2637
|
+
let converted = 0;
|
|
2638
|
+
for (const entry of nonUsdcStables) {
|
|
2639
|
+
if (amountNeeded !== void 0 && converted >= amountNeeded) break;
|
|
2640
|
+
try {
|
|
2641
|
+
await this._swapToUsdc(entry.asset, entry.amount);
|
|
2642
|
+
converted += entry.amount;
|
|
2643
|
+
} catch {
|
|
2644
|
+
}
|
|
2645
|
+
}
|
|
2646
|
+
}
|
|
2609
2647
|
async maxWithdraw() {
|
|
2610
2648
|
const adapter = await this.resolveLending(void 0, "USDC", "withdraw");
|
|
2611
2649
|
return adapter.maxWithdraw(this._address, "USDC");
|
|
@@ -2644,34 +2682,93 @@ var T2000 = class _T2000 extends EventEmitter {
|
|
|
2644
2682
|
};
|
|
2645
2683
|
}
|
|
2646
2684
|
async repay(params) {
|
|
2647
|
-
const
|
|
2648
|
-
const
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
const
|
|
2652
|
-
|
|
2653
|
-
if (amount <= 0) {
|
|
2654
|
-
throw new T2000Error("NO_COLLATERAL", "No outstanding borrow to repay");
|
|
2685
|
+
const allPositions = await this.registry.allPositions(this._address);
|
|
2686
|
+
const borrows = [];
|
|
2687
|
+
for (const pos of allPositions) {
|
|
2688
|
+
if (params.protocol && pos.protocolId !== params.protocol) continue;
|
|
2689
|
+
for (const b of pos.positions.borrows) {
|
|
2690
|
+
if (b.amount > 1e-3) borrows.push({ protocolId: pos.protocolId, asset: b.asset, amount: b.amount, apy: b.apy });
|
|
2655
2691
|
}
|
|
2656
|
-
} else {
|
|
2657
|
-
amount = params.amount;
|
|
2658
2692
|
}
|
|
2659
|
-
|
|
2693
|
+
if (borrows.length === 0) {
|
|
2694
|
+
throw new T2000Error("NO_COLLATERAL", "No outstanding borrow to repay");
|
|
2695
|
+
}
|
|
2696
|
+
if (params.amount === "all") {
|
|
2697
|
+
return this._repayAllBorrows(borrows);
|
|
2698
|
+
}
|
|
2699
|
+
borrows.sort((a, b) => b.apy - a.apy);
|
|
2700
|
+
const target = borrows[0];
|
|
2701
|
+
const adapter = this.registry.getLending(target.protocolId);
|
|
2702
|
+
if (!adapter) throw new T2000Error("PROTOCOL_UNAVAILABLE", `Protocol ${target.protocolId} not found`);
|
|
2703
|
+
const repayAmount = Math.min(params.amount, target.amount);
|
|
2704
|
+
let totalGasCost = 0;
|
|
2705
|
+
let lastDigest = "";
|
|
2706
|
+
if (target.asset !== "USDC") {
|
|
2707
|
+
const buffer = repayAmount * 1.005;
|
|
2708
|
+
const swapResult = await this._swapFromUsdc(target.asset, buffer);
|
|
2709
|
+
totalGasCost += swapResult.gasCost;
|
|
2710
|
+
lastDigest = swapResult.digest;
|
|
2711
|
+
}
|
|
2660
2712
|
const gasResult = await executeWithGas(this.client, this.keypair, async () => {
|
|
2661
|
-
const { tx } = await adapter.buildRepayTx(this._address, repayAmount, asset);
|
|
2713
|
+
const { tx } = await adapter.buildRepayTx(this._address, repayAmount, target.asset);
|
|
2662
2714
|
return tx;
|
|
2663
2715
|
});
|
|
2716
|
+
totalGasCost += gasResult.gasCostSui;
|
|
2717
|
+
lastDigest = gasResult.digest;
|
|
2664
2718
|
const hf = await adapter.getHealth(this._address);
|
|
2665
|
-
this.emitBalanceChange(
|
|
2719
|
+
this.emitBalanceChange("USDC", repayAmount, "repay", lastDigest);
|
|
2666
2720
|
return {
|
|
2667
2721
|
success: true,
|
|
2668
|
-
tx:
|
|
2722
|
+
tx: lastDigest,
|
|
2669
2723
|
amount: repayAmount,
|
|
2670
2724
|
remainingDebt: hf.borrowed,
|
|
2671
|
-
gasCost:
|
|
2725
|
+
gasCost: totalGasCost,
|
|
2672
2726
|
gasMethod: gasResult.gasMethod
|
|
2673
2727
|
};
|
|
2674
2728
|
}
|
|
2729
|
+
async _repayAllBorrows(borrows) {
|
|
2730
|
+
let totalRepaid = 0;
|
|
2731
|
+
let totalGasCost = 0;
|
|
2732
|
+
let lastDigest = "";
|
|
2733
|
+
let lastGasMethod = "self-funded";
|
|
2734
|
+
borrows.sort((a, b) => b.apy - a.apy);
|
|
2735
|
+
for (const borrow of borrows) {
|
|
2736
|
+
const adapter = this.registry.getLending(borrow.protocolId);
|
|
2737
|
+
if (!adapter) continue;
|
|
2738
|
+
if (borrow.asset !== "USDC") {
|
|
2739
|
+
try {
|
|
2740
|
+
const buffer = borrow.amount * 1.005;
|
|
2741
|
+
const swapResult = await this._swapFromUsdc(borrow.asset, buffer);
|
|
2742
|
+
totalGasCost += swapResult.gasCost;
|
|
2743
|
+
} catch (err) {
|
|
2744
|
+
throw new T2000Error(
|
|
2745
|
+
"SWAP_FAILED",
|
|
2746
|
+
`Could not convert USDC to ${borrow.asset} for repayment. Try again later.`,
|
|
2747
|
+
{ originalError: err instanceof Error ? err.message : String(err) }
|
|
2748
|
+
);
|
|
2749
|
+
}
|
|
2750
|
+
}
|
|
2751
|
+
const gasResult = await executeWithGas(this.client, this.keypair, async () => {
|
|
2752
|
+
const { tx } = await adapter.buildRepayTx(this._address, borrow.amount, borrow.asset);
|
|
2753
|
+
return tx;
|
|
2754
|
+
});
|
|
2755
|
+
totalRepaid += borrow.amount;
|
|
2756
|
+
totalGasCost += gasResult.gasCostSui;
|
|
2757
|
+
lastDigest = gasResult.digest;
|
|
2758
|
+
lastGasMethod = gasResult.gasMethod;
|
|
2759
|
+
}
|
|
2760
|
+
const firstAdapter = this.registry.getLending(borrows[0].protocolId);
|
|
2761
|
+
const hf = firstAdapter ? await firstAdapter.getHealth(this._address) : { borrowed: 0 };
|
|
2762
|
+
this.emitBalanceChange("USDC", totalRepaid, "repay", lastDigest);
|
|
2763
|
+
return {
|
|
2764
|
+
success: true,
|
|
2765
|
+
tx: lastDigest,
|
|
2766
|
+
amount: totalRepaid,
|
|
2767
|
+
remainingDebt: hf.borrowed,
|
|
2768
|
+
gasCost: totalGasCost,
|
|
2769
|
+
gasMethod: lastGasMethod
|
|
2770
|
+
};
|
|
2771
|
+
}
|
|
2675
2772
|
async maxBorrow() {
|
|
2676
2773
|
const adapter = await this.resolveLending(void 0, "USDC", "borrow");
|
|
2677
2774
|
return adapter.maxBorrow(this._address, "USDC");
|
|
@@ -2752,14 +2849,14 @@ var T2000 = class _T2000 extends EventEmitter {
|
|
|
2752
2849
|
const allPositions = await this.registry.allPositions(this._address);
|
|
2753
2850
|
const positions = allPositions.flatMap(
|
|
2754
2851
|
(p) => [
|
|
2755
|
-
...p.positions.supplies.map((s) => ({
|
|
2852
|
+
...p.positions.supplies.filter((s) => s.amount > 5e-3).map((s) => ({
|
|
2756
2853
|
protocol: p.protocolId,
|
|
2757
2854
|
asset: s.asset,
|
|
2758
2855
|
type: "save",
|
|
2759
2856
|
amount: s.amount,
|
|
2760
2857
|
apy: s.apy
|
|
2761
2858
|
})),
|
|
2762
|
-
...p.positions.borrows.map((b) => ({
|
|
2859
|
+
...p.positions.borrows.filter((b) => b.amount > 5e-3).map((b) => ({
|
|
2763
2860
|
protocol: p.protocolId,
|
|
2764
2861
|
asset: b.asset,
|
|
2765
2862
|
type: "borrow",
|