@t2000/sdk 1.4.0 → 1.6.0
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 +4 -1
- package/dist/adapters/index.cjs.map +1 -1
- package/dist/adapters/index.js +4 -1
- package/dist/adapters/index.js.map +1 -1
- package/dist/browser.cjs +2 -1
- package/dist/browser.cjs.map +1 -1
- package/dist/browser.d.cts +1 -1
- package/dist/browser.d.ts +1 -1
- package/dist/browser.js +2 -1
- package/dist/browser.js.map +1 -1
- package/dist/index.cjs +501 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +523 -4
- package/dist/index.d.ts +523 -4
- package/dist/index.js +490 -7
- package/dist/index.js.map +1 -1
- package/dist/{types-BhiUiiNs.d.ts → types-B0VlW8Ov.d.ts} +75 -1
- package/dist/{types-CMVkJNFp.d.cts → types-DrHllxZ5.d.cts} +75 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -145,6 +145,32 @@ var init_errors = __esm({
|
|
|
145
145
|
});
|
|
146
146
|
|
|
147
147
|
// src/token-registry.ts
|
|
148
|
+
var token_registry_exports = {};
|
|
149
|
+
__export(token_registry_exports, {
|
|
150
|
+
COIN_REGISTRY: () => exports.COIN_REGISTRY,
|
|
151
|
+
ETH_TYPE: () => exports.ETH_TYPE,
|
|
152
|
+
IKA_TYPE: () => exports.IKA_TYPE,
|
|
153
|
+
LOFI_TYPE: () => exports.LOFI_TYPE,
|
|
154
|
+
MANIFEST_TYPE: () => exports.MANIFEST_TYPE,
|
|
155
|
+
NAVX_TYPE: () => exports.NAVX_TYPE,
|
|
156
|
+
SUI_TYPE: () => exports.SUI_TYPE,
|
|
157
|
+
TOKEN_MAP: () => exports.TOKEN_MAP,
|
|
158
|
+
USDC_TYPE: () => exports.USDC_TYPE,
|
|
159
|
+
USDE_TYPE: () => exports.USDE_TYPE,
|
|
160
|
+
USDSUI_TYPE: () => exports.USDSUI_TYPE,
|
|
161
|
+
USDT_TYPE: () => exports.USDT_TYPE,
|
|
162
|
+
WAL_TYPE: () => exports.WAL_TYPE,
|
|
163
|
+
WBTC_TYPE: () => exports.WBTC_TYPE,
|
|
164
|
+
getCoinMeta: () => getCoinMeta,
|
|
165
|
+
getDecimalsForCoinType: () => getDecimalsForCoinType,
|
|
166
|
+
getTier: () => getTier,
|
|
167
|
+
isInRegistry: () => isInRegistry,
|
|
168
|
+
isSupported: () => isSupported,
|
|
169
|
+
isTier1: () => isTier1,
|
|
170
|
+
isTier2: () => isTier2,
|
|
171
|
+
resolveSymbol: () => resolveSymbol,
|
|
172
|
+
resolveTokenType: () => resolveTokenType
|
|
173
|
+
});
|
|
148
174
|
function getCoinMeta(coinType) {
|
|
149
175
|
return BY_TYPE.get(coinType);
|
|
150
176
|
}
|
|
@@ -628,6 +654,8 @@ __export(volo_exports, {
|
|
|
628
654
|
VOLO_PKG: () => exports.VOLO_PKG,
|
|
629
655
|
VOLO_POOL: () => exports.VOLO_POOL,
|
|
630
656
|
VSUI_TYPE: () => exports.VSUI_TYPE,
|
|
657
|
+
addStakeVSuiToTx: () => addStakeVSuiToTx,
|
|
658
|
+
addUnstakeVSuiToTx: () => addUnstakeVSuiToTx,
|
|
631
659
|
buildStakeVSuiTx: () => buildStakeVSuiTx,
|
|
632
660
|
buildUnstakeVSuiTx: () => buildUnstakeVSuiTx,
|
|
633
661
|
getVoloStats: () => getVoloStats
|
|
@@ -667,7 +695,7 @@ async function buildStakeVSuiTx(_client, address, amountMist) {
|
|
|
667
695
|
return tx;
|
|
668
696
|
}
|
|
669
697
|
async function buildUnstakeVSuiTx(client, address, amountMist) {
|
|
670
|
-
const coins = await
|
|
698
|
+
const coins = await fetchCoinsByType(client, address, exports.VSUI_TYPE);
|
|
671
699
|
if (coins.length === 0) {
|
|
672
700
|
throw new Error("No vSUI found in wallet.");
|
|
673
701
|
}
|
|
@@ -695,14 +723,81 @@ async function buildUnstakeVSuiTx(client, address, amountMist) {
|
|
|
695
723
|
tx.transferObjects([suiCoin], address);
|
|
696
724
|
return tx;
|
|
697
725
|
}
|
|
698
|
-
async function
|
|
726
|
+
async function addStakeVSuiToTx(tx, client, address, input) {
|
|
727
|
+
if (input.amountMist < MIN_STAKE_MIST) {
|
|
728
|
+
throw new Error(`Minimum stake is 1 SUI (${MIN_STAKE_MIST} MIST). Got: ${input.amountMist}`);
|
|
729
|
+
}
|
|
730
|
+
let suiCoin;
|
|
731
|
+
if (input.inputCoin) {
|
|
732
|
+
suiCoin = input.inputCoin;
|
|
733
|
+
} else {
|
|
734
|
+
const coins = await fetchCoinsByType(client, address, exports.SUI_TYPE);
|
|
735
|
+
if (coins.length === 0) {
|
|
736
|
+
throw new Error("No SUI coins found in wallet");
|
|
737
|
+
}
|
|
738
|
+
const totalBalance = coins.reduce((sum, c) => sum + BigInt(c.balance), 0n);
|
|
739
|
+
if (totalBalance < input.amountMist) {
|
|
740
|
+
throw new Error(`Insufficient SUI: need ${input.amountMist} MIST, have ${totalBalance}`);
|
|
741
|
+
}
|
|
742
|
+
const primary = tx.object(coins[0].coinObjectId);
|
|
743
|
+
if (coins.length > 1) {
|
|
744
|
+
tx.mergeCoins(primary, coins.slice(1).map((c) => tx.object(c.coinObjectId)));
|
|
745
|
+
}
|
|
746
|
+
[suiCoin] = tx.splitCoins(primary, [input.amountMist]);
|
|
747
|
+
}
|
|
748
|
+
const [vSuiCoin] = tx.moveCall({
|
|
749
|
+
target: `${exports.VOLO_PKG}::stake_pool::stake`,
|
|
750
|
+
arguments: [
|
|
751
|
+
tx.object(exports.VOLO_POOL),
|
|
752
|
+
tx.object(exports.VOLO_METADATA),
|
|
753
|
+
tx.object(SUI_SYSTEM_STATE),
|
|
754
|
+
suiCoin
|
|
755
|
+
]
|
|
756
|
+
});
|
|
757
|
+
return { coin: vSuiCoin, effectiveAmountMist: input.amountMist };
|
|
758
|
+
}
|
|
759
|
+
async function addUnstakeVSuiToTx(tx, client, address, input) {
|
|
760
|
+
let vSuiCoin;
|
|
761
|
+
if (input.inputCoin) {
|
|
762
|
+
if (input.amountMist === "all") {
|
|
763
|
+
vSuiCoin = input.inputCoin;
|
|
764
|
+
} else {
|
|
765
|
+
[vSuiCoin] = tx.splitCoins(input.inputCoin, [input.amountMist]);
|
|
766
|
+
}
|
|
767
|
+
} else {
|
|
768
|
+
const coins = await fetchCoinsByType(client, address, exports.VSUI_TYPE);
|
|
769
|
+
if (coins.length === 0) {
|
|
770
|
+
throw new Error("No vSUI found in wallet.");
|
|
771
|
+
}
|
|
772
|
+
const primary = tx.object(coins[0].coinObjectId);
|
|
773
|
+
if (coins.length > 1) {
|
|
774
|
+
tx.mergeCoins(primary, coins.slice(1).map((c) => tx.object(c.coinObjectId)));
|
|
775
|
+
}
|
|
776
|
+
if (input.amountMist === "all") {
|
|
777
|
+
vSuiCoin = primary;
|
|
778
|
+
} else {
|
|
779
|
+
[vSuiCoin] = tx.splitCoins(primary, [input.amountMist]);
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
const [suiCoin] = tx.moveCall({
|
|
783
|
+
target: `${exports.VOLO_PKG}::stake_pool::unstake`,
|
|
784
|
+
arguments: [
|
|
785
|
+
tx.object(exports.VOLO_POOL),
|
|
786
|
+
tx.object(exports.VOLO_METADATA),
|
|
787
|
+
tx.object(SUI_SYSTEM_STATE),
|
|
788
|
+
vSuiCoin
|
|
789
|
+
]
|
|
790
|
+
});
|
|
791
|
+
return { coin: suiCoin, effectiveAmountMist: input.amountMist };
|
|
792
|
+
}
|
|
793
|
+
async function fetchCoinsByType(client, owner, coinType) {
|
|
699
794
|
const all = [];
|
|
700
795
|
let cursor;
|
|
701
796
|
let hasNext = true;
|
|
702
797
|
while (hasNext) {
|
|
703
798
|
const page = await client.getCoins({
|
|
704
|
-
owner
|
|
705
|
-
coinType
|
|
799
|
+
owner,
|
|
800
|
+
coinType,
|
|
706
801
|
cursor: cursor ?? void 0
|
|
707
802
|
});
|
|
708
803
|
all.push(...page.data.map((c) => ({ coinObjectId: c.coinObjectId, balance: c.balance })));
|
|
@@ -714,6 +809,7 @@ async function fetchVSuiCoins(client, address) {
|
|
|
714
809
|
exports.VOLO_PKG = void 0; exports.VOLO_POOL = void 0; exports.VOLO_METADATA = void 0; exports.VSUI_TYPE = void 0; var SUI_SYSTEM_STATE, MIN_STAKE_MIST, VOLO_STATS_URL;
|
|
715
810
|
var init_volo = __esm({
|
|
716
811
|
"src/protocols/volo.ts"() {
|
|
812
|
+
init_token_registry();
|
|
717
813
|
exports.VOLO_PKG = "0x68d22cf8bdbcd11ecba1e094922873e4080d4d11133e2443fddda0bfd11dae20";
|
|
718
814
|
exports.VOLO_POOL = "0x2d914e23d82fedef1b5f56a32d5c64bdcc3087ccfea2b4d6ea51a71f587840e5";
|
|
719
815
|
exports.VOLO_METADATA = "0x680cd26af32b2bde8d3361e804c53ec1d1cfe24c7f039eb7f549e8dfde389a60";
|
|
@@ -729,6 +825,7 @@ var cetus_swap_exports = {};
|
|
|
729
825
|
__export(cetus_swap_exports, {
|
|
730
826
|
OVERLAY_FEE_RATE: () => exports.OVERLAY_FEE_RATE,
|
|
731
827
|
TOKEN_MAP: () => exports.TOKEN_MAP,
|
|
828
|
+
addSwapToTx: () => addSwapToTx,
|
|
732
829
|
buildSwapTx: () => buildSwapTx,
|
|
733
830
|
findSwapRoute: () => findSwapRoute,
|
|
734
831
|
resolveTokenType: () => resolveTokenType,
|
|
@@ -754,7 +851,8 @@ async function findSwapRoute(params) {
|
|
|
754
851
|
from: params.from,
|
|
755
852
|
target: params.to,
|
|
756
853
|
amount: params.amount.toString(),
|
|
757
|
-
byAmountIn: params.byAmountIn
|
|
854
|
+
byAmountIn: params.byAmountIn,
|
|
855
|
+
...params.providers ? { providers: params.providers } : {}
|
|
758
856
|
};
|
|
759
857
|
const routerData = await client.findRouters(findParams);
|
|
760
858
|
if (!routerData) return null;
|
|
@@ -796,6 +894,85 @@ async function buildSwapTx(params) {
|
|
|
796
894
|
});
|
|
797
895
|
return outputCoin;
|
|
798
896
|
}
|
|
897
|
+
async function addSwapToTx(tx, client, address, input) {
|
|
898
|
+
const { T2000Error: T2000Error2 } = await Promise.resolve().then(() => (init_errors(), errors_exports));
|
|
899
|
+
const fromType = resolveTokenType(input.from);
|
|
900
|
+
const toType = resolveTokenType(input.to);
|
|
901
|
+
if (!fromType) throw new T2000Error2("ASSET_NOT_SUPPORTED", `Unknown token: ${input.from}. Provide the symbol (USDC, SUI, ...) or full coin type.`);
|
|
902
|
+
if (!toType) throw new T2000Error2("ASSET_NOT_SUPPORTED", `Unknown token: ${input.to}. Provide the symbol (USDC, SUI, ...) or full coin type.`);
|
|
903
|
+
if (fromType === toType) throw new T2000Error2("SWAP_FAILED", "Cannot swap a token to itself");
|
|
904
|
+
if (!Number.isFinite(input.amount) || input.amount <= 0) {
|
|
905
|
+
throw new T2000Error2("INVALID_AMOUNT", "Amount must be greater than zero");
|
|
906
|
+
}
|
|
907
|
+
const fromDecimals = getDecimalsForCoinType(fromType);
|
|
908
|
+
const toDecimals = getDecimalsForCoinType(toType);
|
|
909
|
+
const requestedRaw = BigInt(Math.floor(input.amount * 10 ** fromDecimals));
|
|
910
|
+
const slippage = Math.max(1e-3, Math.min(input.slippage ?? 0.01, 0.05));
|
|
911
|
+
const byAmountIn = input.byAmountIn ?? true;
|
|
912
|
+
let inputCoin;
|
|
913
|
+
let effectiveRaw;
|
|
914
|
+
if (input.inputCoin) {
|
|
915
|
+
inputCoin = input.inputCoin;
|
|
916
|
+
effectiveRaw = requestedRaw;
|
|
917
|
+
} else {
|
|
918
|
+
const { ids, totalBalance } = await fetchAllCoinsForSwap(client, address, fromType);
|
|
919
|
+
if (ids.length === 0) {
|
|
920
|
+
throw new T2000Error2("INSUFFICIENT_BALANCE", `No ${input.from} coins found in wallet`);
|
|
921
|
+
}
|
|
922
|
+
const swapAll = requestedRaw >= totalBalance;
|
|
923
|
+
effectiveRaw = swapAll ? totalBalance : requestedRaw;
|
|
924
|
+
const primary = tx.object(ids[0]);
|
|
925
|
+
if (ids.length > 1) {
|
|
926
|
+
tx.mergeCoins(primary, ids.slice(1).map((id) => tx.object(id)));
|
|
927
|
+
}
|
|
928
|
+
inputCoin = swapAll ? primary : tx.splitCoins(primary, [effectiveRaw])[0];
|
|
929
|
+
}
|
|
930
|
+
const route = await findSwapRoute({
|
|
931
|
+
walletAddress: address,
|
|
932
|
+
from: fromType,
|
|
933
|
+
to: toType,
|
|
934
|
+
amount: effectiveRaw,
|
|
935
|
+
byAmountIn,
|
|
936
|
+
overlayFee: input.overlayFee,
|
|
937
|
+
providers: input.providers
|
|
938
|
+
});
|
|
939
|
+
if (!route) {
|
|
940
|
+
throw new T2000Error2("SWAP_NO_ROUTE", `No swap route found for ${input.from} \u2192 ${input.to}`);
|
|
941
|
+
}
|
|
942
|
+
if (route.insufficientLiquidity) {
|
|
943
|
+
throw new T2000Error2("SWAP_NO_ROUTE", `Insufficient liquidity for ${input.from} \u2192 ${input.to}`);
|
|
944
|
+
}
|
|
945
|
+
const outputCoin = await buildSwapTx({
|
|
946
|
+
walletAddress: address,
|
|
947
|
+
route,
|
|
948
|
+
tx,
|
|
949
|
+
inputCoin,
|
|
950
|
+
slippage,
|
|
951
|
+
overlayFee: input.overlayFee
|
|
952
|
+
});
|
|
953
|
+
return {
|
|
954
|
+
coin: outputCoin,
|
|
955
|
+
effectiveAmountIn: Number(effectiveRaw) / 10 ** fromDecimals,
|
|
956
|
+
expectedAmountOut: Number(route.amountOut) / 10 ** toDecimals,
|
|
957
|
+
route
|
|
958
|
+
};
|
|
959
|
+
}
|
|
960
|
+
async function fetchAllCoinsForSwap(client, owner, coinType) {
|
|
961
|
+
const ids = [];
|
|
962
|
+
let totalBalance = 0n;
|
|
963
|
+
let cursor;
|
|
964
|
+
let hasNext = true;
|
|
965
|
+
while (hasNext) {
|
|
966
|
+
const page = await client.getCoins({ owner, coinType, cursor: cursor ?? void 0 });
|
|
967
|
+
for (const c of page.data) {
|
|
968
|
+
ids.push(c.coinObjectId);
|
|
969
|
+
totalBalance += BigInt(c.balance);
|
|
970
|
+
}
|
|
971
|
+
cursor = page.nextCursor;
|
|
972
|
+
hasNext = page.hasNextPage;
|
|
973
|
+
}
|
|
974
|
+
return { ids, totalBalance };
|
|
975
|
+
}
|
|
799
976
|
async function simulateSwap(params) {
|
|
800
977
|
const client = getClient(params.walletAddress, params.overlayFee);
|
|
801
978
|
try {
|
|
@@ -808,6 +985,7 @@ async function simulateSwap(params) {
|
|
|
808
985
|
exports.OVERLAY_FEE_RATE = void 0; var clientCache;
|
|
809
986
|
var init_cetus_swap = __esm({
|
|
810
987
|
"src/protocols/cetus-swap.ts"() {
|
|
988
|
+
init_token_registry();
|
|
811
989
|
init_token_registry();
|
|
812
990
|
exports.OVERLAY_FEE_RATE = 1e-3;
|
|
813
991
|
clientCache = /* @__PURE__ */ new Map();
|
|
@@ -1173,6 +1351,10 @@ async function buildSendTx({
|
|
|
1173
1351
|
}
|
|
1174
1352
|
return tx;
|
|
1175
1353
|
}
|
|
1354
|
+
function addSendToTx(tx, coin, recipient) {
|
|
1355
|
+
const validRecipient = validateAddress(recipient);
|
|
1356
|
+
tx.transferObjects([coin], validRecipient);
|
|
1357
|
+
}
|
|
1176
1358
|
|
|
1177
1359
|
// src/wallet/balance.ts
|
|
1178
1360
|
var SUI_PRICE_FALLBACK = 1;
|
|
@@ -5315,7 +5497,10 @@ async function addSaveToTx(tx, _client, _address, coin, options = {}) {
|
|
|
5315
5497
|
async function addRepayToTx(tx, client, address, coin, options = {}) {
|
|
5316
5498
|
const asset = options.asset ?? "USDC";
|
|
5317
5499
|
const assetInfo = resolveAssetInfo(asset);
|
|
5318
|
-
await refreshOracle(tx, client, address, {
|
|
5500
|
+
await refreshOracle(tx, client, address, {
|
|
5501
|
+
skipPythUpdate: options.skipPythUpdate,
|
|
5502
|
+
skipOracle: options.skipOracle
|
|
5503
|
+
});
|
|
5319
5504
|
try {
|
|
5320
5505
|
await xe(tx, assetInfo.type, coin, { env: "prod" });
|
|
5321
5506
|
} catch (err) {
|
|
@@ -5459,6 +5644,12 @@ async function addClaimRewardsToTx(tx, client, address) {
|
|
|
5459
5644
|
return [];
|
|
5460
5645
|
}
|
|
5461
5646
|
}
|
|
5647
|
+
async function buildClaimRewardsTx(client, address) {
|
|
5648
|
+
const tx = new transactions.Transaction();
|
|
5649
|
+
tx.setSender(address);
|
|
5650
|
+
const rewards = await addClaimRewardsToTx(tx, client, address);
|
|
5651
|
+
return { tx, rewards };
|
|
5652
|
+
}
|
|
5462
5653
|
function aggregateClaimableRewards(claimable) {
|
|
5463
5654
|
const aggregated = /* @__PURE__ */ new Map();
|
|
5464
5655
|
for (const c of claimable) {
|
|
@@ -7190,6 +7381,298 @@ var T2000 = class _T2000 extends eventemitter3.EventEmitter {
|
|
|
7190
7381
|
// src/index.ts
|
|
7191
7382
|
init_errors();
|
|
7192
7383
|
|
|
7384
|
+
// src/wallet/coinSelection.ts
|
|
7385
|
+
init_errors();
|
|
7386
|
+
async function fetchAllCoins(client, owner, coinType) {
|
|
7387
|
+
const ids = [];
|
|
7388
|
+
let totalBalance = 0n;
|
|
7389
|
+
let cursor;
|
|
7390
|
+
let hasNext = true;
|
|
7391
|
+
while (hasNext) {
|
|
7392
|
+
const page = await client.getCoins({ owner, coinType, cursor: cursor ?? void 0 });
|
|
7393
|
+
for (const c of page.data) {
|
|
7394
|
+
ids.push(c.coinObjectId);
|
|
7395
|
+
totalBalance += BigInt(c.balance);
|
|
7396
|
+
}
|
|
7397
|
+
cursor = page.nextCursor;
|
|
7398
|
+
hasNext = page.hasNextPage;
|
|
7399
|
+
}
|
|
7400
|
+
return { ids, totalBalance };
|
|
7401
|
+
}
|
|
7402
|
+
async function selectAndSplitCoin(tx, client, owner, coinType, amount, options = {}) {
|
|
7403
|
+
const { ids, totalBalance } = await fetchAllCoins(client, owner, coinType);
|
|
7404
|
+
if (ids.length === 0) {
|
|
7405
|
+
throw new exports.T2000Error("INSUFFICIENT_BALANCE", `No coins found for ${coinType}`);
|
|
7406
|
+
}
|
|
7407
|
+
const allowSwapAll = options.allowSwapAll ?? true;
|
|
7408
|
+
if (amount !== "all" && amount > totalBalance && !allowSwapAll) {
|
|
7409
|
+
throw new exports.T2000Error("INSUFFICIENT_BALANCE", `Insufficient balance for ${coinType}`, {
|
|
7410
|
+
available: totalBalance.toString(),
|
|
7411
|
+
required: amount.toString()
|
|
7412
|
+
});
|
|
7413
|
+
}
|
|
7414
|
+
const requested = amount === "all" ? totalBalance : amount;
|
|
7415
|
+
const swapAll = amount === "all" || requested >= totalBalance;
|
|
7416
|
+
const effectiveAmount = swapAll ? totalBalance : requested;
|
|
7417
|
+
const primary = tx.object(ids[0]);
|
|
7418
|
+
if (ids.length > 1) {
|
|
7419
|
+
tx.mergeCoins(primary, ids.slice(1).map((id) => tx.object(id)));
|
|
7420
|
+
}
|
|
7421
|
+
const coin = swapAll ? primary : tx.splitCoins(primary, [effectiveAmount])[0];
|
|
7422
|
+
return { coin, effectiveAmount, swapAll };
|
|
7423
|
+
}
|
|
7424
|
+
async function selectSuiCoin(tx, client, owner, amountMist, sponsoredContext) {
|
|
7425
|
+
if (sponsoredContext) {
|
|
7426
|
+
const { SUI_TYPE: SUI_TYPE2 } = await Promise.resolve().then(() => (init_token_registry(), token_registry_exports));
|
|
7427
|
+
return selectAndSplitCoin(tx, client, owner, SUI_TYPE2, amountMist);
|
|
7428
|
+
}
|
|
7429
|
+
const [coin] = tx.splitCoins(tx.gas, [amountMist]);
|
|
7430
|
+
return { coin, effectiveAmount: amountMist, swapAll: false };
|
|
7431
|
+
}
|
|
7432
|
+
init_cetus_swap();
|
|
7433
|
+
init_volo();
|
|
7434
|
+
init_token_registry();
|
|
7435
|
+
init_errors();
|
|
7436
|
+
var SPONSORED_PYTH_DEPENDENT_PROVIDERS = [
|
|
7437
|
+
"HAEDALPMM",
|
|
7438
|
+
"METASTABLE",
|
|
7439
|
+
"OBRIC",
|
|
7440
|
+
"STEAMM_OMM",
|
|
7441
|
+
"STEAMM_OMM_V2",
|
|
7442
|
+
"SEVENK",
|
|
7443
|
+
"HAEDALHMMV2"
|
|
7444
|
+
];
|
|
7445
|
+
async function getSponsoredSwapProviders() {
|
|
7446
|
+
const { getProvidersExcluding } = await import('@cetusprotocol/aggregator-sdk');
|
|
7447
|
+
return getProvidersExcluding([...SPONSORED_PYTH_DEPENDENT_PROVIDERS]);
|
|
7448
|
+
}
|
|
7449
|
+
function resolveSaveableAsset(asset) {
|
|
7450
|
+
if (!asset) return "USDC";
|
|
7451
|
+
if (asset !== "USDC" && asset !== "USDsui") {
|
|
7452
|
+
throw new exports.T2000Error("ASSET_NOT_SUPPORTED", `Saveable asset must be USDC or USDsui, got ${asset}`);
|
|
7453
|
+
}
|
|
7454
|
+
return asset;
|
|
7455
|
+
}
|
|
7456
|
+
var WRITE_APPENDER_REGISTRY = {
|
|
7457
|
+
save_deposit: async (tx, input, ctx) => {
|
|
7458
|
+
const asset = resolveSaveableAsset(input.asset);
|
|
7459
|
+
const assetInfo = SUPPORTED_ASSETS[asset];
|
|
7460
|
+
if (input.amount <= 0) {
|
|
7461
|
+
throw new exports.T2000Error("INVALID_AMOUNT", "Save amount must be greater than zero");
|
|
7462
|
+
}
|
|
7463
|
+
const rawAmount = BigInt(Math.floor(input.amount * 10 ** assetInfo.decimals));
|
|
7464
|
+
const { coin, effectiveAmount } = await selectAndSplitCoin(
|
|
7465
|
+
tx,
|
|
7466
|
+
ctx.client,
|
|
7467
|
+
ctx.sender,
|
|
7468
|
+
assetInfo.type,
|
|
7469
|
+
rawAmount
|
|
7470
|
+
);
|
|
7471
|
+
await addSaveToTx(tx, ctx.client, ctx.sender, coin, { asset });
|
|
7472
|
+
return {
|
|
7473
|
+
toolName: "save_deposit",
|
|
7474
|
+
effectiveAmount: Number(effectiveAmount) / 10 ** assetInfo.decimals,
|
|
7475
|
+
asset
|
|
7476
|
+
};
|
|
7477
|
+
},
|
|
7478
|
+
withdraw: async (tx, input, ctx) => {
|
|
7479
|
+
const asset = resolveSaveableAsset(input.asset);
|
|
7480
|
+
if (input.amount <= 0) {
|
|
7481
|
+
throw new exports.T2000Error("INVALID_AMOUNT", "Withdraw amount must be greater than zero");
|
|
7482
|
+
}
|
|
7483
|
+
const { coin, effectiveAmount } = await addWithdrawToTx(
|
|
7484
|
+
tx,
|
|
7485
|
+
ctx.client,
|
|
7486
|
+
ctx.sender,
|
|
7487
|
+
input.amount,
|
|
7488
|
+
{ asset, skipPythUpdate: ctx.sponsoredContext }
|
|
7489
|
+
);
|
|
7490
|
+
tx.transferObjects([coin], ctx.sender);
|
|
7491
|
+
return { toolName: "withdraw", effectiveAmount, asset };
|
|
7492
|
+
},
|
|
7493
|
+
borrow: async (tx, input, ctx) => {
|
|
7494
|
+
const asset = resolveSaveableAsset(input.asset);
|
|
7495
|
+
if (input.amount <= 0) {
|
|
7496
|
+
throw new exports.T2000Error("INVALID_AMOUNT", "Borrow amount must be greater than zero");
|
|
7497
|
+
}
|
|
7498
|
+
const coin = await addBorrowToTx(
|
|
7499
|
+
tx,
|
|
7500
|
+
ctx.client,
|
|
7501
|
+
ctx.sender,
|
|
7502
|
+
input.amount,
|
|
7503
|
+
{ asset, skipPythUpdate: ctx.sponsoredContext }
|
|
7504
|
+
);
|
|
7505
|
+
tx.transferObjects([coin], ctx.sender);
|
|
7506
|
+
return { toolName: "borrow", effectiveAmount: input.amount, asset };
|
|
7507
|
+
},
|
|
7508
|
+
repay_debt: async (tx, input, ctx) => {
|
|
7509
|
+
const asset = resolveSaveableAsset(input.asset);
|
|
7510
|
+
const assetInfo = SUPPORTED_ASSETS[asset];
|
|
7511
|
+
if (input.amount <= 0) {
|
|
7512
|
+
throw new exports.T2000Error("INVALID_AMOUNT", "Repay amount must be greater than zero");
|
|
7513
|
+
}
|
|
7514
|
+
const rawAmount = BigInt(Math.floor(input.amount * 10 ** assetInfo.decimals));
|
|
7515
|
+
const { coin, effectiveAmount } = await selectAndSplitCoin(
|
|
7516
|
+
tx,
|
|
7517
|
+
ctx.client,
|
|
7518
|
+
ctx.sender,
|
|
7519
|
+
assetInfo.type,
|
|
7520
|
+
rawAmount
|
|
7521
|
+
);
|
|
7522
|
+
await addRepayToTx(tx, ctx.client, ctx.sender, coin, {
|
|
7523
|
+
asset,
|
|
7524
|
+
skipOracle: ctx.sponsoredContext
|
|
7525
|
+
});
|
|
7526
|
+
return {
|
|
7527
|
+
toolName: "repay_debt",
|
|
7528
|
+
effectiveAmount: Number(effectiveAmount) / 10 ** assetInfo.decimals,
|
|
7529
|
+
asset
|
|
7530
|
+
};
|
|
7531
|
+
},
|
|
7532
|
+
send_transfer: async (tx, input, ctx) => {
|
|
7533
|
+
const recipient = validateAddress(input.to);
|
|
7534
|
+
const asset = input.asset ?? "USDC";
|
|
7535
|
+
const assetInfo = SUPPORTED_ASSETS[asset];
|
|
7536
|
+
if (!assetInfo) {
|
|
7537
|
+
throw new exports.T2000Error("ASSET_NOT_SUPPORTED", `Asset ${asset} is not supported`);
|
|
7538
|
+
}
|
|
7539
|
+
if (input.amount <= 0) {
|
|
7540
|
+
throw new exports.T2000Error("INVALID_AMOUNT", "Send amount must be greater than zero");
|
|
7541
|
+
}
|
|
7542
|
+
const rawAmount = BigInt(Math.floor(input.amount * 10 ** assetInfo.decimals));
|
|
7543
|
+
let coin;
|
|
7544
|
+
let effectiveRaw;
|
|
7545
|
+
if (asset === "SUI") {
|
|
7546
|
+
const result = await selectSuiCoin(tx, ctx.client, ctx.sender, rawAmount, ctx.sponsoredContext);
|
|
7547
|
+
coin = result.coin;
|
|
7548
|
+
effectiveRaw = result.effectiveAmount;
|
|
7549
|
+
} else {
|
|
7550
|
+
const result = await selectAndSplitCoin(tx, ctx.client, ctx.sender, assetInfo.type, rawAmount);
|
|
7551
|
+
coin = result.coin;
|
|
7552
|
+
effectiveRaw = result.effectiveAmount;
|
|
7553
|
+
}
|
|
7554
|
+
addSendToTx(tx, coin, recipient);
|
|
7555
|
+
return {
|
|
7556
|
+
toolName: "send_transfer",
|
|
7557
|
+
effectiveAmount: Number(effectiveRaw) / 10 ** assetInfo.decimals,
|
|
7558
|
+
recipient,
|
|
7559
|
+
asset
|
|
7560
|
+
};
|
|
7561
|
+
},
|
|
7562
|
+
swap_execute: async (tx, input, ctx) => {
|
|
7563
|
+
const fromType = resolveTokenType(input.from);
|
|
7564
|
+
const toType = resolveTokenType(input.to);
|
|
7565
|
+
if (!fromType || !toType) {
|
|
7566
|
+
throw new exports.T2000Error(
|
|
7567
|
+
"ASSET_NOT_SUPPORTED",
|
|
7568
|
+
`Unknown token in swap: from=${input.from}, to=${input.to}`
|
|
7569
|
+
);
|
|
7570
|
+
}
|
|
7571
|
+
const providers = input.providers ?? (ctx.sponsoredContext ? await getSponsoredSwapProviders() : void 0);
|
|
7572
|
+
const result = await addSwapToTx(tx, ctx.client, ctx.sender, {
|
|
7573
|
+
from: input.from,
|
|
7574
|
+
to: input.to,
|
|
7575
|
+
amount: input.amount,
|
|
7576
|
+
slippage: input.slippage,
|
|
7577
|
+
byAmountIn: input.byAmountIn,
|
|
7578
|
+
overlayFee: ctx.overlayFee,
|
|
7579
|
+
providers
|
|
7580
|
+
});
|
|
7581
|
+
tx.transferObjects([result.coin], ctx.sender);
|
|
7582
|
+
return {
|
|
7583
|
+
toolName: "swap_execute",
|
|
7584
|
+
effectiveAmountIn: result.effectiveAmountIn,
|
|
7585
|
+
expectedAmountOut: result.expectedAmountOut,
|
|
7586
|
+
route: result.route
|
|
7587
|
+
};
|
|
7588
|
+
},
|
|
7589
|
+
claim_rewards: async (tx, _input, ctx) => {
|
|
7590
|
+
const rewards = await addClaimRewardsToTx(tx, ctx.client, ctx.sender);
|
|
7591
|
+
return { toolName: "claim_rewards", rewards };
|
|
7592
|
+
},
|
|
7593
|
+
volo_stake: async (tx, input, ctx) => {
|
|
7594
|
+
if (input.amountSui <= 0) {
|
|
7595
|
+
throw new exports.T2000Error("INVALID_AMOUNT", "Stake amount must be greater than zero");
|
|
7596
|
+
}
|
|
7597
|
+
const amountMist = BigInt(Math.floor(input.amountSui * 1e9));
|
|
7598
|
+
const result = await addStakeVSuiToTx(tx, ctx.client, ctx.sender, { amountMist });
|
|
7599
|
+
tx.transferObjects([result.coin], ctx.sender);
|
|
7600
|
+
return { toolName: "volo_stake", effectiveAmountMist: result.effectiveAmountMist };
|
|
7601
|
+
},
|
|
7602
|
+
volo_unstake: async (tx, input, ctx) => {
|
|
7603
|
+
const amountMist = input.amountVSui === "all" ? "all" : BigInt(Math.floor(input.amountVSui * 1e9));
|
|
7604
|
+
if (amountMist !== "all" && amountMist <= 0n) {
|
|
7605
|
+
throw new exports.T2000Error("INVALID_AMOUNT", "Unstake amount must be greater than zero");
|
|
7606
|
+
}
|
|
7607
|
+
const result = await addUnstakeVSuiToTx(tx, ctx.client, ctx.sender, { amountMist });
|
|
7608
|
+
tx.transferObjects([result.coin], ctx.sender);
|
|
7609
|
+
return { toolName: "volo_unstake", effectiveAmountMist: result.effectiveAmountMist };
|
|
7610
|
+
}
|
|
7611
|
+
};
|
|
7612
|
+
function deriveAllowedAddressesFromPtb(tx) {
|
|
7613
|
+
const addresses = /* @__PURE__ */ new Set();
|
|
7614
|
+
const data = tx.getData();
|
|
7615
|
+
for (const cmd of data.commands) {
|
|
7616
|
+
const transferCmd = cmd.TransferObjects;
|
|
7617
|
+
if (!transferCmd) continue;
|
|
7618
|
+
const addressArg = transferCmd.address;
|
|
7619
|
+
if (!addressArg) continue;
|
|
7620
|
+
const addressInputIndex = addressArg.Input;
|
|
7621
|
+
if (addressInputIndex === void 0) continue;
|
|
7622
|
+
const input = data.inputs[addressInputIndex];
|
|
7623
|
+
if (!input) continue;
|
|
7624
|
+
const pureBytes = input.Pure?.bytes;
|
|
7625
|
+
if (!pureBytes) continue;
|
|
7626
|
+
try {
|
|
7627
|
+
const bytes = base64ToBytes(pureBytes);
|
|
7628
|
+
if (bytes.length !== 32) continue;
|
|
7629
|
+
const hex = "0x" + Array.from(bytes).map((b2) => b2.toString(16).padStart(2, "0")).join("");
|
|
7630
|
+
addresses.add(hex);
|
|
7631
|
+
} catch {
|
|
7632
|
+
}
|
|
7633
|
+
}
|
|
7634
|
+
return Array.from(addresses);
|
|
7635
|
+
}
|
|
7636
|
+
function base64ToBytes(b64) {
|
|
7637
|
+
if (typeof Buffer !== "undefined") {
|
|
7638
|
+
return Uint8Array.from(Buffer.from(b64, "base64"));
|
|
7639
|
+
}
|
|
7640
|
+
const binary = atob(b64);
|
|
7641
|
+
const bytes = new Uint8Array(binary.length);
|
|
7642
|
+
for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
|
|
7643
|
+
return bytes;
|
|
7644
|
+
}
|
|
7645
|
+
async function composeTx(opts) {
|
|
7646
|
+
const tx = new transactions.Transaction();
|
|
7647
|
+
tx.setSender(opts.sender);
|
|
7648
|
+
const ctx = {
|
|
7649
|
+
client: opts.client,
|
|
7650
|
+
sender: opts.sender,
|
|
7651
|
+
sponsoredContext: opts.sponsoredContext ?? false,
|
|
7652
|
+
overlayFee: opts.overlayFee
|
|
7653
|
+
};
|
|
7654
|
+
const previews = [];
|
|
7655
|
+
for (const step of opts.steps) {
|
|
7656
|
+
const appender = WRITE_APPENDER_REGISTRY[step.toolName];
|
|
7657
|
+
if (!appender) {
|
|
7658
|
+
throw new exports.T2000Error(
|
|
7659
|
+
"UNKNOWN",
|
|
7660
|
+
`No fragment appender registered for tool '${step.toolName}'. Allowed: ${Object.keys(WRITE_APPENDER_REGISTRY).join(", ")}`
|
|
7661
|
+
);
|
|
7662
|
+
}
|
|
7663
|
+
const preview = await appender(tx, step.input, ctx);
|
|
7664
|
+
previews.push(preview);
|
|
7665
|
+
}
|
|
7666
|
+
const txKindBytes = await tx.build({ client: opts.client, onlyTransactionKind: true });
|
|
7667
|
+
const derivedAllowedAddresses = deriveAllowedAddressesFromPtb(tx);
|
|
7668
|
+
return {
|
|
7669
|
+
tx,
|
|
7670
|
+
txKindBytes,
|
|
7671
|
+
derivedAllowedAddresses,
|
|
7672
|
+
perStepPreviews: previews
|
|
7673
|
+
};
|
|
7674
|
+
}
|
|
7675
|
+
|
|
7193
7676
|
// src/protocols/protocolFee.ts
|
|
7194
7677
|
var FEE_RATES = {
|
|
7195
7678
|
save: SAVE_FEE_BPS,
|
|
@@ -7431,10 +7914,17 @@ exports.SafeguardError = SafeguardError;
|
|
|
7431
7914
|
exports.T2000 = T2000;
|
|
7432
7915
|
exports.T2000_OVERLAY_FEE_WALLET = T2000_OVERLAY_FEE_WALLET;
|
|
7433
7916
|
exports.USDC_DECIMALS = USDC_DECIMALS;
|
|
7917
|
+
exports.WRITE_APPENDER_REGISTRY = WRITE_APPENDER_REGISTRY;
|
|
7434
7918
|
exports.ZkLoginSigner = ZkLoginSigner;
|
|
7435
7919
|
exports.addFeeTransfer = addFeeTransfer;
|
|
7920
|
+
exports.addSendToTx = addSendToTx;
|
|
7921
|
+
exports.addStakeVSuiToTx = addStakeVSuiToTx;
|
|
7922
|
+
exports.addSwapToTx = addSwapToTx;
|
|
7923
|
+
exports.addUnstakeVSuiToTx = addUnstakeVSuiToTx;
|
|
7436
7924
|
exports.allDescriptors = allDescriptors;
|
|
7437
7925
|
exports.assertAllowedAsset = assertAllowedAsset;
|
|
7926
|
+
exports.buildClaimRewardsTx = buildClaimRewardsTx;
|
|
7927
|
+
exports.buildSendTx = buildSendTx;
|
|
7438
7928
|
exports.buildStakeVSuiTx = buildStakeVSuiTx;
|
|
7439
7929
|
exports.buildSwapTx = buildSwapTx;
|
|
7440
7930
|
exports.buildUnstakeVSuiTx = buildUnstakeVSuiTx;
|
|
@@ -7442,11 +7932,14 @@ exports.calculateFee = calculateFee;
|
|
|
7442
7932
|
exports.classifyAction = classifyAction;
|
|
7443
7933
|
exports.classifyLabel = classifyLabel;
|
|
7444
7934
|
exports.classifyTransaction = classifyTransaction;
|
|
7935
|
+
exports.composeTx = composeTx;
|
|
7936
|
+
exports.deriveAllowedAddressesFromPtb = deriveAllowedAddressesFromPtb;
|
|
7445
7937
|
exports.exportPrivateKey = exportPrivateKey;
|
|
7446
7938
|
exports.extractTransferDetails = extractTransferDetails;
|
|
7447
7939
|
exports.extractTxCommands = extractTxCommands;
|
|
7448
7940
|
exports.extractTxSender = extractTxSender;
|
|
7449
7941
|
exports.fallbackLabel = fallbackLabel;
|
|
7942
|
+
exports.fetchAllCoins = fetchAllCoins;
|
|
7450
7943
|
exports.findSwapRoute = findSwapRoute;
|
|
7451
7944
|
exports.formatAssetAmount = formatAssetAmount;
|
|
7452
7945
|
exports.formatSui = formatSui;
|
|
@@ -7483,6 +7976,8 @@ exports.refineLendingLabel = refineLendingLabel;
|
|
|
7483
7976
|
exports.resolveSymbol = resolveSymbol;
|
|
7484
7977
|
exports.resolveTokenType = resolveTokenType;
|
|
7485
7978
|
exports.saveKey = saveKey;
|
|
7979
|
+
exports.selectAndSplitCoin = selectAndSplitCoin;
|
|
7980
|
+
exports.selectSuiCoin = selectSuiCoin;
|
|
7486
7981
|
exports.simulateTransaction = simulateTransaction;
|
|
7487
7982
|
exports.stableToRaw = stableToRaw;
|
|
7488
7983
|
exports.suiToMist = suiToMist;
|