@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.cjs
CHANGED
|
@@ -2416,22 +2416,27 @@ var T2000 = class _T2000 extends eventemitter3.EventEmitter {
|
|
|
2416
2416
|
// -- Savings --
|
|
2417
2417
|
async save(params) {
|
|
2418
2418
|
const asset = "USDC";
|
|
2419
|
+
const bal = await queryBalance(this.client, this._address);
|
|
2420
|
+
const usdcBalance = bal.stables.USDC ?? 0;
|
|
2419
2421
|
let amount;
|
|
2420
2422
|
if (params.amount === "all") {
|
|
2421
|
-
|
|
2422
|
-
const
|
|
2423
|
-
amount =
|
|
2423
|
+
await this._convertWalletStablesToUsdc(bal);
|
|
2424
|
+
const refreshedBal = await queryBalance(this.client, this._address);
|
|
2425
|
+
amount = (refreshedBal.stables.USDC ?? 0) - 1;
|
|
2424
2426
|
if (amount <= 0) {
|
|
2425
2427
|
throw new T2000Error("INSUFFICIENT_BALANCE", "Balance too low to save after $1 gas reserve", {
|
|
2426
2428
|
reason: "gas_reserve_required",
|
|
2427
|
-
available:
|
|
2429
|
+
available: refreshedBal.stables.USDC ?? 0
|
|
2428
2430
|
});
|
|
2429
2431
|
}
|
|
2430
2432
|
} else {
|
|
2431
2433
|
amount = params.amount;
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
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);
|
|
2435
2440
|
}
|
|
2436
2441
|
}
|
|
2437
2442
|
const fee = calculateFee("save", amount);
|
|
@@ -2608,6 +2613,39 @@ var T2000 = class _T2000 extends eventemitter3.EventEmitter {
|
|
|
2608
2613
|
const usdcReceived = estimatedOut / 10 ** toDecimals;
|
|
2609
2614
|
return { usdcReceived, digest: gasResult.digest, gasCost: gasResult.gasCostSui };
|
|
2610
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
|
+
}
|
|
2611
2649
|
async maxWithdraw() {
|
|
2612
2650
|
const adapter = await this.resolveLending(void 0, "USDC", "withdraw");
|
|
2613
2651
|
return adapter.maxWithdraw(this._address, "USDC");
|
|
@@ -2646,34 +2684,93 @@ var T2000 = class _T2000 extends eventemitter3.EventEmitter {
|
|
|
2646
2684
|
};
|
|
2647
2685
|
}
|
|
2648
2686
|
async repay(params) {
|
|
2649
|
-
const
|
|
2650
|
-
const
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
const
|
|
2654
|
-
|
|
2655
|
-
if (amount <= 0) {
|
|
2656
|
-
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 });
|
|
2657
2693
|
}
|
|
2658
|
-
} else {
|
|
2659
|
-
amount = params.amount;
|
|
2660
2694
|
}
|
|
2661
|
-
|
|
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
|
+
}
|
|
2662
2714
|
const gasResult = await executeWithGas(this.client, this.keypair, async () => {
|
|
2663
|
-
const { tx } = await adapter.buildRepayTx(this._address, repayAmount, asset);
|
|
2715
|
+
const { tx } = await adapter.buildRepayTx(this._address, repayAmount, target.asset);
|
|
2664
2716
|
return tx;
|
|
2665
2717
|
});
|
|
2718
|
+
totalGasCost += gasResult.gasCostSui;
|
|
2719
|
+
lastDigest = gasResult.digest;
|
|
2666
2720
|
const hf = await adapter.getHealth(this._address);
|
|
2667
|
-
this.emitBalanceChange(
|
|
2721
|
+
this.emitBalanceChange("USDC", repayAmount, "repay", lastDigest);
|
|
2668
2722
|
return {
|
|
2669
2723
|
success: true,
|
|
2670
|
-
tx:
|
|
2724
|
+
tx: lastDigest,
|
|
2671
2725
|
amount: repayAmount,
|
|
2672
2726
|
remainingDebt: hf.borrowed,
|
|
2673
|
-
gasCost:
|
|
2727
|
+
gasCost: totalGasCost,
|
|
2674
2728
|
gasMethod: gasResult.gasMethod
|
|
2675
2729
|
};
|
|
2676
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
|
+
}
|
|
2677
2774
|
async maxBorrow() {
|
|
2678
2775
|
const adapter = await this.resolveLending(void 0, "USDC", "borrow");
|
|
2679
2776
|
return adapter.maxBorrow(this._address, "USDC");
|
|
@@ -2754,14 +2851,14 @@ var T2000 = class _T2000 extends eventemitter3.EventEmitter {
|
|
|
2754
2851
|
const allPositions = await this.registry.allPositions(this._address);
|
|
2755
2852
|
const positions = allPositions.flatMap(
|
|
2756
2853
|
(p) => [
|
|
2757
|
-
...p.positions.supplies.map((s) => ({
|
|
2854
|
+
...p.positions.supplies.filter((s) => s.amount > 5e-3).map((s) => ({
|
|
2758
2855
|
protocol: p.protocolId,
|
|
2759
2856
|
asset: s.asset,
|
|
2760
2857
|
type: "save",
|
|
2761
2858
|
amount: s.amount,
|
|
2762
2859
|
apy: s.apy
|
|
2763
2860
|
})),
|
|
2764
|
-
...p.positions.borrows.map((b) => ({
|
|
2861
|
+
...p.positions.borrows.filter((b) => b.amount > 5e-3).map((b) => ({
|
|
2765
2862
|
protocol: p.protocolId,
|
|
2766
2863
|
asset: b.asset,
|
|
2767
2864
|
type: "borrow",
|