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