@t2000/sdk 0.5.6 → 0.6.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/adapters/index.cjs +100 -39
- package/dist/adapters/index.cjs.map +1 -1
- package/dist/adapters/index.js +100 -39
- package/dist/adapters/index.js.map +1 -1
- package/dist/index.cjs +82 -20
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +82 -20
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -424,8 +424,6 @@ async function reportFee(agentAddress, operation, feeAmount, feeRate, txDigest)
|
|
|
424
424
|
} catch {
|
|
425
425
|
}
|
|
426
426
|
}
|
|
427
|
-
|
|
428
|
-
// src/protocols/navi.ts
|
|
429
427
|
var USDC_TYPE = SUPPORTED_ASSETS.USDC.type;
|
|
430
428
|
var RATE_DECIMALS = 27;
|
|
431
429
|
var LTV_DECIMALS = 27;
|
|
@@ -436,6 +434,8 @@ var SUI_SYSTEM_STATE = "0x05";
|
|
|
436
434
|
var NAVI_BALANCE_DECIMALS = 9;
|
|
437
435
|
var CONFIG_API = "https://open-api.naviprotocol.io/api/navi/config?env=prod";
|
|
438
436
|
var POOLS_API = "https://open-api.naviprotocol.io/api/navi/pools?env=prod";
|
|
437
|
+
var PACKAGE_API = "https://open-api.naviprotocol.io/api/package";
|
|
438
|
+
var packageCache = null;
|
|
439
439
|
function toBigInt(v) {
|
|
440
440
|
if (typeof v === "bigint") return v;
|
|
441
441
|
return BigInt(String(v));
|
|
@@ -460,9 +460,22 @@ async function fetchJson(url) {
|
|
|
460
460
|
const json = await res.json();
|
|
461
461
|
return json.data ?? json;
|
|
462
462
|
}
|
|
463
|
+
async function getLatestPackageId() {
|
|
464
|
+
if (packageCache && Date.now() - packageCache.ts < CACHE_TTL) return packageCache.id;
|
|
465
|
+
const res = await fetch(PACKAGE_API);
|
|
466
|
+
if (!res.ok) throw new T2000Error("PROTOCOL_UNAVAILABLE", `NAVI package API error: ${res.status}`);
|
|
467
|
+
const json = await res.json();
|
|
468
|
+
if (!json.packageId) throw new T2000Error("PROTOCOL_UNAVAILABLE", "NAVI package API returned no packageId");
|
|
469
|
+
packageCache = { id: json.packageId, ts: Date.now() };
|
|
470
|
+
return json.packageId;
|
|
471
|
+
}
|
|
463
472
|
async function getConfig(fresh = false) {
|
|
464
473
|
if (configCache && !fresh && Date.now() - configCache.ts < CACHE_TTL) return configCache.data;
|
|
465
|
-
const data = await
|
|
474
|
+
const [data, latestPkg] = await Promise.all([
|
|
475
|
+
fetchJson(CONFIG_API),
|
|
476
|
+
getLatestPackageId()
|
|
477
|
+
]);
|
|
478
|
+
data.package = latestPkg;
|
|
466
479
|
configCache = { data, ts: Date.now() };
|
|
467
480
|
return data;
|
|
468
481
|
}
|
|
@@ -480,6 +493,24 @@ async function getUsdcPool() {
|
|
|
480
493
|
if (!usdc) throw new T2000Error("PROTOCOL_UNAVAILABLE", "USDC pool not found on NAVI");
|
|
481
494
|
return usdc;
|
|
482
495
|
}
|
|
496
|
+
function addOracleUpdate(tx, config, pool) {
|
|
497
|
+
const feed = config.oracle.feeds?.find((f2) => f2.assetId === pool.id);
|
|
498
|
+
if (!feed) {
|
|
499
|
+
throw new T2000Error("PROTOCOL_UNAVAILABLE", `Oracle feed not found for asset ${pool.token?.symbol ?? pool.id}`);
|
|
500
|
+
}
|
|
501
|
+
tx.moveCall({
|
|
502
|
+
target: `${config.oracle.packageId}::oracle_pro::update_single_price_v2`,
|
|
503
|
+
arguments: [
|
|
504
|
+
tx.object(CLOCK),
|
|
505
|
+
tx.object(config.oracle.oracleConfig),
|
|
506
|
+
tx.object(config.oracle.priceOracle),
|
|
507
|
+
tx.object(config.oracle.supraOracleHolder),
|
|
508
|
+
tx.object(feed.pythPriceInfoObject),
|
|
509
|
+
tx.object(config.oracle.switchboardAggregator),
|
|
510
|
+
tx.pure.address(feed.feedId)
|
|
511
|
+
]
|
|
512
|
+
});
|
|
513
|
+
}
|
|
483
514
|
function rateToApy(rawRate) {
|
|
484
515
|
if (!rawRate || rawRate === "0") return 0;
|
|
485
516
|
return Number(BigInt(rawRate)) / 10 ** RATE_DECIMALS * 100;
|
|
@@ -502,7 +533,7 @@ function compoundBalance(rawBalance, currentIndex) {
|
|
|
502
533
|
if (!rawBalance || !currentIndex || currentIndex === "0") return 0;
|
|
503
534
|
const scale = BigInt("1" + "0".repeat(RATE_DECIMALS));
|
|
504
535
|
const half = scale / 2n;
|
|
505
|
-
const result = (rawBalance *
|
|
536
|
+
const result = (rawBalance * BigInt(currentIndex) + half) / scale;
|
|
506
537
|
return Number(result) / 10 ** NAVI_BALANCE_DECIMALS;
|
|
507
538
|
}
|
|
508
539
|
async function getUserState(client, address) {
|
|
@@ -536,23 +567,25 @@ async function fetchCoins(client, owner, coinType) {
|
|
|
536
567
|
}
|
|
537
568
|
return all;
|
|
538
569
|
}
|
|
539
|
-
function
|
|
570
|
+
function mergeCoins(tx, coins) {
|
|
540
571
|
if (coins.length === 0) throw new T2000Error("INSUFFICIENT_BALANCE", "No coins to merge");
|
|
541
572
|
const primary = tx.object(coins[0].coinObjectId);
|
|
542
573
|
if (coins.length > 1) {
|
|
543
574
|
tx.mergeCoins(primary, coins.slice(1).map((c) => tx.object(c.coinObjectId)));
|
|
544
575
|
}
|
|
545
|
-
|
|
546
|
-
return split;
|
|
576
|
+
return primary;
|
|
547
577
|
}
|
|
548
578
|
async function buildSaveTx(client, address, amount, options = {}) {
|
|
579
|
+
if (!amount || amount <= 0 || !Number.isFinite(amount)) {
|
|
580
|
+
throw new T2000Error("INVALID_AMOUNT", "Save amount must be a positive number");
|
|
581
|
+
}
|
|
549
582
|
const rawAmount = Number(usdcToRaw(amount));
|
|
550
583
|
const [config, pool] = await Promise.all([getConfig(), getUsdcPool()]);
|
|
551
584
|
const coins = await fetchCoins(client, address, USDC_TYPE);
|
|
552
585
|
if (coins.length === 0) throw new T2000Error("INSUFFICIENT_BALANCE", "No USDC coins found");
|
|
553
586
|
const tx = new Transaction();
|
|
554
587
|
tx.setSender(address);
|
|
555
|
-
const coinObj =
|
|
588
|
+
const coinObj = mergeCoins(tx, coins);
|
|
556
589
|
if (options.collectFee) {
|
|
557
590
|
addCollectFeeToTx(tx, coinObj, "save");
|
|
558
591
|
}
|
|
@@ -586,8 +619,9 @@ async function buildWithdrawTx(client, address, amount) {
|
|
|
586
619
|
const rawAmount = Number(usdcToRaw(effectiveAmount));
|
|
587
620
|
const tx = new Transaction();
|
|
588
621
|
tx.setSender(address);
|
|
589
|
-
tx
|
|
590
|
-
|
|
622
|
+
addOracleUpdate(tx, config, pool);
|
|
623
|
+
const [balance] = tx.moveCall({
|
|
624
|
+
target: `${config.package}::incentive_v3::withdraw_v2`,
|
|
591
625
|
arguments: [
|
|
592
626
|
tx.object(CLOCK),
|
|
593
627
|
tx.object(config.oracle.priceOracle),
|
|
@@ -598,17 +632,28 @@ async function buildWithdrawTx(client, address, amount) {
|
|
|
598
632
|
tx.object(config.incentiveV2),
|
|
599
633
|
tx.object(config.incentiveV3),
|
|
600
634
|
tx.object(SUI_SYSTEM_STATE)
|
|
601
|
-
]
|
|
635
|
+
],
|
|
636
|
+
typeArguments: [pool.suiCoinType]
|
|
637
|
+
});
|
|
638
|
+
const [coin] = tx.moveCall({
|
|
639
|
+
target: "0x2::coin::from_balance",
|
|
640
|
+
arguments: [balance],
|
|
641
|
+
typeArguments: [pool.suiCoinType]
|
|
602
642
|
});
|
|
643
|
+
tx.transferObjects([coin], address);
|
|
603
644
|
return { tx, effectiveAmount };
|
|
604
645
|
}
|
|
605
646
|
async function buildBorrowTx(client, address, amount, options = {}) {
|
|
647
|
+
if (!amount || amount <= 0 || !Number.isFinite(amount)) {
|
|
648
|
+
throw new T2000Error("INVALID_AMOUNT", "Borrow amount must be a positive number");
|
|
649
|
+
}
|
|
606
650
|
const rawAmount = Number(usdcToRaw(amount));
|
|
607
651
|
const [config, pool] = await Promise.all([getConfig(), getUsdcPool()]);
|
|
608
652
|
const tx = new Transaction();
|
|
609
653
|
tx.setSender(address);
|
|
610
|
-
tx
|
|
611
|
-
|
|
654
|
+
addOracleUpdate(tx, config, pool);
|
|
655
|
+
const [balance] = tx.moveCall({
|
|
656
|
+
target: `${config.package}::incentive_v3::borrow_v2`,
|
|
612
657
|
arguments: [
|
|
613
658
|
tx.object(CLOCK),
|
|
614
659
|
tx.object(config.oracle.priceOracle),
|
|
@@ -619,18 +664,32 @@ async function buildBorrowTx(client, address, amount, options = {}) {
|
|
|
619
664
|
tx.object(config.incentiveV2),
|
|
620
665
|
tx.object(config.incentiveV3),
|
|
621
666
|
tx.object(SUI_SYSTEM_STATE)
|
|
622
|
-
]
|
|
667
|
+
],
|
|
668
|
+
typeArguments: [pool.suiCoinType]
|
|
669
|
+
});
|
|
670
|
+
const [borrowedCoin] = tx.moveCall({
|
|
671
|
+
target: "0x2::coin::from_balance",
|
|
672
|
+
arguments: [balance],
|
|
673
|
+
typeArguments: [pool.suiCoinType]
|
|
623
674
|
});
|
|
675
|
+
if (options.collectFee) {
|
|
676
|
+
addCollectFeeToTx(tx, borrowedCoin, "borrow");
|
|
677
|
+
}
|
|
678
|
+
tx.transferObjects([borrowedCoin], address);
|
|
624
679
|
return tx;
|
|
625
680
|
}
|
|
626
681
|
async function buildRepayTx(client, address, amount) {
|
|
682
|
+
if (!amount || amount <= 0 || !Number.isFinite(amount)) {
|
|
683
|
+
throw new T2000Error("INVALID_AMOUNT", "Repay amount must be a positive number");
|
|
684
|
+
}
|
|
627
685
|
const rawAmount = Number(usdcToRaw(amount));
|
|
628
686
|
const [config, pool] = await Promise.all([getConfig(), getUsdcPool()]);
|
|
629
687
|
const coins = await fetchCoins(client, address, USDC_TYPE);
|
|
630
688
|
if (coins.length === 0) throw new T2000Error("INSUFFICIENT_BALANCE", "No USDC coins to repay with");
|
|
631
689
|
const tx = new Transaction();
|
|
632
690
|
tx.setSender(address);
|
|
633
|
-
|
|
691
|
+
addOracleUpdate(tx, config, pool);
|
|
692
|
+
const coinObj = mergeCoins(tx, coins);
|
|
634
693
|
tx.moveCall({
|
|
635
694
|
target: `${config.package}::incentive_v3::entry_repay`,
|
|
636
695
|
arguments: [
|
|
@@ -1000,7 +1059,7 @@ var ProtocolRegistry = class {
|
|
|
1000
1059
|
}
|
|
1001
1060
|
}
|
|
1002
1061
|
if (candidates.length === 0) {
|
|
1003
|
-
throw new
|
|
1062
|
+
throw new T2000Error("ASSET_NOT_SUPPORTED", `No lending adapter supports saving ${asset}`);
|
|
1004
1063
|
}
|
|
1005
1064
|
candidates.sort((a, b) => b.rate.saveApy - a.rate.saveApy);
|
|
1006
1065
|
return candidates[0];
|
|
@@ -1018,7 +1077,7 @@ var ProtocolRegistry = class {
|
|
|
1018
1077
|
}
|
|
1019
1078
|
}
|
|
1020
1079
|
if (candidates.length === 0) {
|
|
1021
|
-
throw new
|
|
1080
|
+
throw new T2000Error("ASSET_NOT_SUPPORTED", `No lending adapter supports borrowing ${asset}`);
|
|
1022
1081
|
}
|
|
1023
1082
|
candidates.sort((a, b) => a.rate.borrowApy - b.rate.borrowApy);
|
|
1024
1083
|
return candidates[0];
|
|
@@ -1035,7 +1094,7 @@ var ProtocolRegistry = class {
|
|
|
1035
1094
|
}
|
|
1036
1095
|
}
|
|
1037
1096
|
if (candidates.length === 0) {
|
|
1038
|
-
throw new
|
|
1097
|
+
throw new T2000Error("ASSET_NOT_SUPPORTED", `No swap adapter supports ${from} \u2192 ${to}`);
|
|
1039
1098
|
}
|
|
1040
1099
|
candidates.sort((a, b) => b.quote.expectedOutput - a.quote.expectedOutput);
|
|
1041
1100
|
return candidates[0];
|
|
@@ -1098,7 +1157,7 @@ var NaviAdapter = class {
|
|
|
1098
1157
|
const rates = await getRates(this.client);
|
|
1099
1158
|
const key = asset.toUpperCase();
|
|
1100
1159
|
const r = rates[key];
|
|
1101
|
-
if (!r) throw new
|
|
1160
|
+
if (!r) throw new T2000Error("ASSET_NOT_SUPPORTED", `NAVI does not support ${asset}`);
|
|
1102
1161
|
return { asset, saveApy: r.saveApy, borrowApy: r.borrowApy };
|
|
1103
1162
|
}
|
|
1104
1163
|
async getPositions(address) {
|
|
@@ -2301,7 +2360,10 @@ var T2000 = class _T2000 extends EventEmitter {
|
|
|
2301
2360
|
return { positions };
|
|
2302
2361
|
}
|
|
2303
2362
|
async rates() {
|
|
2304
|
-
|
|
2363
|
+
const allRatesResult = await this.registry.allRates("USDC");
|
|
2364
|
+
if (allRatesResult.length === 0) return { USDC: { saveApy: 0, borrowApy: 0 } };
|
|
2365
|
+
const best = allRatesResult.reduce((a, b) => b.rates.saveApy > a.rates.saveApy ? b : a);
|
|
2366
|
+
return { USDC: { saveApy: best.rates.saveApy, borrowApy: best.rates.borrowApy } };
|
|
2305
2367
|
}
|
|
2306
2368
|
async allRates(asset = "USDC") {
|
|
2307
2369
|
return this.registry.allRates(asset);
|