@t2000/sdk 5.5.1 → 5.6.1
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/browser.cjs +197 -24
- 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 +191 -27
- package/dist/browser.js.map +1 -1
- package/dist/index.cjs +145 -32
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +17 -70
- package/dist/index.d.ts +17 -70
- package/dist/index.js +139 -33
- package/dist/index.js.map +1 -1
- package/dist/{simulate-KETPmlDo.d.cts → send-D2nKpwJN.d.cts} +162 -21
- package/dist/{simulate-KETPmlDo.d.ts → send-D2nKpwJN.d.ts} +162 -21
- package/package.json +1 -1
package/dist/browser.cjs
CHANGED
|
@@ -231,6 +231,7 @@ var init_token_registry = __esm({
|
|
|
231
231
|
// src/wallet/coinSelection.ts
|
|
232
232
|
var coinSelection_exports = {};
|
|
233
233
|
__export(coinSelection_exports, {
|
|
234
|
+
buildCoinToAddressBalanceMigration: () => buildCoinToAddressBalanceMigration,
|
|
234
235
|
fetchAllCoins: () => fetchAllCoins,
|
|
235
236
|
selectAndSplitCoin: () => selectAndSplitCoin,
|
|
236
237
|
selectSuiCoin: () => selectSuiCoin
|
|
@@ -344,6 +345,32 @@ async function selectCoinObjectsOnly(tx, client, owner, coinType, amount, allowS
|
|
|
344
345
|
});
|
|
345
346
|
return { coin, effectiveAmount, swapAll };
|
|
346
347
|
}
|
|
348
|
+
function buildCoinToAddressBalanceMigration(args) {
|
|
349
|
+
const { coins, coinType, owner, minAmount } = args;
|
|
350
|
+
const sorted = [...coins].filter((c) => c.balance > 0n).sort((a, b) => b.balance > a.balance ? 1 : b.balance < a.balance ? -1 : 0);
|
|
351
|
+
const selected = [];
|
|
352
|
+
let migratedRaw = 0n;
|
|
353
|
+
for (const c of sorted) {
|
|
354
|
+
if (migratedRaw >= minAmount) break;
|
|
355
|
+
selected.push(c);
|
|
356
|
+
migratedRaw += c.balance;
|
|
357
|
+
}
|
|
358
|
+
if (migratedRaw < minAmount) {
|
|
359
|
+
throw new exports.T2000Error("INSUFFICIENT_BALANCE", `Insufficient ${coinType} coin objects to migrate`, {
|
|
360
|
+
available: migratedRaw.toString(),
|
|
361
|
+
required: minAmount.toString()
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
const tx = new transactions.Transaction();
|
|
365
|
+
for (const c of selected) {
|
|
366
|
+
tx.moveCall({
|
|
367
|
+
target: "0x2::coin::send_funds",
|
|
368
|
+
typeArguments: [coinType],
|
|
369
|
+
arguments: [tx.object(c.objectId), tx.pure.address(owner)]
|
|
370
|
+
});
|
|
371
|
+
}
|
|
372
|
+
return { tx, migratedRaw };
|
|
373
|
+
}
|
|
347
374
|
async function selectSuiCoin(tx, client, owner, amountMist, sponsoredContext, mergeCache) {
|
|
348
375
|
if (sponsoredContext) {
|
|
349
376
|
const { SUI_TYPE: SUI_TYPE2 } = await Promise.resolve().then(() => (init_token_registry(), token_registry_exports));
|
|
@@ -442,10 +469,60 @@ async function executeTx(client, signer, buildTx, options = {}) {
|
|
|
442
469
|
}
|
|
443
470
|
return { digest: txn.digest, gasCostSui, effects };
|
|
444
471
|
}
|
|
472
|
+
var PREFLIGHT_MAX_AMOUNT = 1e6;
|
|
473
|
+
var PREFLIGHT_OK = { valid: true };
|
|
474
|
+
function preflightFail(code, error) {
|
|
475
|
+
return { valid: false, code, error };
|
|
476
|
+
}
|
|
477
|
+
function checkPositiveAmount(amount, label = "Amount", max = PREFLIGHT_MAX_AMOUNT) {
|
|
478
|
+
if (typeof amount !== "number" || !Number.isFinite(amount)) {
|
|
479
|
+
return preflightFail("INVALID_AMOUNT", `${label} must be a finite number`);
|
|
480
|
+
}
|
|
481
|
+
if (amount <= 0) {
|
|
482
|
+
return preflightFail("INVALID_AMOUNT", `${label} must be greater than zero`);
|
|
483
|
+
}
|
|
484
|
+
if (amount > max) {
|
|
485
|
+
return preflightFail("INVALID_AMOUNT", `${label} ${amount} exceeds the sane maximum (${max})`);
|
|
486
|
+
}
|
|
487
|
+
return PREFLIGHT_OK;
|
|
488
|
+
}
|
|
489
|
+
function checkSuiAddress(address, label = "recipient") {
|
|
490
|
+
try {
|
|
491
|
+
if (typeof address === "string" && address.trim() !== "" && utils.isValidSuiAddress(utils.normalizeSuiAddress(address))) {
|
|
492
|
+
return PREFLIGHT_OK;
|
|
493
|
+
}
|
|
494
|
+
} catch {
|
|
495
|
+
}
|
|
496
|
+
return preflightFail("INVALID_ADDRESS", `Invalid ${label} address: ${address}`);
|
|
497
|
+
}
|
|
445
498
|
|
|
446
499
|
// src/wallet/pay.ts
|
|
500
|
+
function preflightPay(input) {
|
|
501
|
+
if (typeof input.url !== "string" || input.url.trim() === "") {
|
|
502
|
+
return preflightFail("FACILITATOR_REJECTION", "A target URL is required to pay");
|
|
503
|
+
}
|
|
504
|
+
let parsed;
|
|
505
|
+
try {
|
|
506
|
+
parsed = new URL(input.url);
|
|
507
|
+
} catch {
|
|
508
|
+
return preflightFail("FACILITATOR_REJECTION", `Invalid URL: ${input.url}`);
|
|
509
|
+
}
|
|
510
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
511
|
+
return preflightFail(
|
|
512
|
+
"FACILITATOR_REJECTION",
|
|
513
|
+
`URL must be http(s): got ${parsed.protocol}//`
|
|
514
|
+
);
|
|
515
|
+
}
|
|
516
|
+
if (input.maxPrice !== void 0) {
|
|
517
|
+
const priceCheck = checkPositiveAmount(input.maxPrice, "maxPrice");
|
|
518
|
+
if (!priceCheck.valid) return priceCheck;
|
|
519
|
+
}
|
|
520
|
+
return PREFLIGHT_OK;
|
|
521
|
+
}
|
|
447
522
|
async function payWithMpp(args) {
|
|
448
523
|
const { signer, client, options } = args;
|
|
524
|
+
const pf = preflightPay({ url: options.url, maxPrice: options.maxPrice });
|
|
525
|
+
if (!pf.valid) throw new exports.T2000Error(pf.code, pf.error);
|
|
449
526
|
const method = (options.method ?? "GET").toUpperCase();
|
|
450
527
|
const canHaveBody = method !== "GET" && method !== "HEAD";
|
|
451
528
|
const reqInit = {
|
|
@@ -525,40 +602,26 @@ async function ensureAddressBalanceCovers(args) {
|
|
|
525
602
|
required: amountRaw.toString()
|
|
526
603
|
});
|
|
527
604
|
}
|
|
605
|
+
const coins = [];
|
|
528
606
|
let coinSum = 0n;
|
|
529
607
|
let cursor;
|
|
530
608
|
let hasNext = true;
|
|
531
609
|
while (hasNext) {
|
|
532
610
|
const page = await client.core.listCoins({ owner, coinType: asset, cursor: cursor ?? void 0 });
|
|
533
|
-
for (const c of page.objects)
|
|
611
|
+
for (const c of page.objects) {
|
|
612
|
+
coins.push({ objectId: c.objectId, balance: BigInt(c.balance) });
|
|
613
|
+
coinSum += BigInt(c.balance);
|
|
614
|
+
}
|
|
534
615
|
cursor = page.cursor;
|
|
535
616
|
hasNext = page.hasNextPage;
|
|
536
617
|
}
|
|
537
618
|
const addressBalance = total - coinSum;
|
|
538
619
|
if (addressBalance >= amountRaw) return 0;
|
|
539
620
|
const shortfall = amountRaw - addressBalance;
|
|
540
|
-
const {
|
|
541
|
-
const { selectAndSplitCoin: selectAndSplitCoin2 } = await Promise.resolve().then(() => (init_coinSelection(), coinSelection_exports));
|
|
621
|
+
const { buildCoinToAddressBalanceMigration: buildCoinToAddressBalanceMigration2 } = await Promise.resolve().then(() => (init_coinSelection(), coinSelection_exports));
|
|
542
622
|
const grpcClient = await makeGrpcBuildClient(client);
|
|
543
|
-
const
|
|
544
|
-
|
|
545
|
-
signer,
|
|
546
|
-
async () => {
|
|
547
|
-
const tx = new Transaction2();
|
|
548
|
-
const { coin } = await selectAndSplitCoin2(tx, client, owner, asset, shortfall, {
|
|
549
|
-
sponsoredContext: true,
|
|
550
|
-
// coin-objects-only — never the address balance
|
|
551
|
-
allowSwapAll: false
|
|
552
|
-
});
|
|
553
|
-
tx.moveCall({
|
|
554
|
-
target: "0x2::coin::send_funds",
|
|
555
|
-
typeArguments: [asset],
|
|
556
|
-
arguments: [coin, tx.pure.address(owner)]
|
|
557
|
-
});
|
|
558
|
-
return tx;
|
|
559
|
-
},
|
|
560
|
-
{ buildClient: grpcClient }
|
|
561
|
-
);
|
|
623
|
+
const { tx } = buildCoinToAddressBalanceMigration2({ coins, coinType: asset, owner, minAmount: shortfall });
|
|
624
|
+
const migration = await executeTx(client, signer, () => tx, { buildClient: grpcClient });
|
|
562
625
|
return migration.gasCostSui;
|
|
563
626
|
}
|
|
564
627
|
async function finalize(response, opts) {
|
|
@@ -656,12 +719,35 @@ var SUPPORTED_ASSETS = {
|
|
|
656
719
|
}
|
|
657
720
|
};
|
|
658
721
|
var STABLE_ASSETS = ["USDC", "USDsui"];
|
|
659
|
-
|
|
722
|
+
var OPERATION_ASSETS = {
|
|
723
|
+
send: ["USDC", "USDsui", "SUI"],
|
|
724
|
+
swap: "*"
|
|
725
|
+
};
|
|
726
|
+
function isAllowedAsset(op, asset) {
|
|
727
|
+
const allowed = OPERATION_ASSETS[op];
|
|
728
|
+
if (allowed === "*") return true;
|
|
729
|
+
const target = asset.toLowerCase();
|
|
730
|
+
return allowed.some((a) => a.toLowerCase() === target);
|
|
731
|
+
}
|
|
732
|
+
function assertAllowedAsset(op, asset) {
|
|
733
|
+
if (!asset) return;
|
|
734
|
+
if (!isAllowedAsset(op, asset)) {
|
|
735
|
+
const allowed = OPERATION_ASSETS[op];
|
|
736
|
+
const list = Array.isArray(allowed) ? allowed.join(", ") : "any";
|
|
737
|
+
const swapHint = " Swap to USDC or USDsui first, or send SUI." ;
|
|
738
|
+
throw new exports.T2000Error(
|
|
739
|
+
"INVALID_ASSET",
|
|
740
|
+
`${op} only supports ${list}. Cannot use ${asset}.${swapHint}`
|
|
741
|
+
);
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
var GASLESS_STABLE_TYPES = {
|
|
660
745
|
USDC: SUPPORTED_ASSETS.USDC.type,
|
|
661
746
|
USDsui: SUPPORTED_ASSETS.USDsui.type
|
|
662
|
-
}
|
|
747
|
+
};
|
|
663
748
|
var T2000_OVERLAY_FEE_WALLET = process.env.T2000_OVERLAY_FEE_WALLET ?? "0x5366efbf2b4fe5767fe2e78eb197aa5f5d138d88ac3333fbf3f80a1927da473a";
|
|
664
749
|
var DEFAULT_NETWORK = "mainnet";
|
|
750
|
+
var GASLESS_MIN_STABLE_AMOUNT = 0.01;
|
|
665
751
|
var GAS_RESERVE_MIN = 0.05;
|
|
666
752
|
init_errors();
|
|
667
753
|
function validateAddress(address) {
|
|
@@ -902,6 +988,9 @@ function rawToStable(raw, decimals) {
|
|
|
902
988
|
function getDecimals(asset) {
|
|
903
989
|
return SUPPORTED_ASSETS[asset].decimals;
|
|
904
990
|
}
|
|
991
|
+
function displayToRaw(amount, decimals) {
|
|
992
|
+
return BigInt(Math.round(amount * 10 ** decimals));
|
|
993
|
+
}
|
|
905
994
|
function formatUsd(amount) {
|
|
906
995
|
return `$${amount.toFixed(2)}`;
|
|
907
996
|
}
|
|
@@ -939,6 +1028,23 @@ function fromBase642(b64) {
|
|
|
939
1028
|
// src/protocols/cetus-swap.ts
|
|
940
1029
|
init_token_registry();
|
|
941
1030
|
init_token_registry();
|
|
1031
|
+
function preflightSwap(input) {
|
|
1032
|
+
if (typeof input.from !== "string" || input.from.trim() === "") {
|
|
1033
|
+
return preflightFail("INVALID_ASSET", "A `from` token is required to swap");
|
|
1034
|
+
}
|
|
1035
|
+
if (typeof input.to !== "string" || input.to.trim() === "") {
|
|
1036
|
+
return preflightFail("INVALID_ASSET", "A `to` token is required to swap");
|
|
1037
|
+
}
|
|
1038
|
+
const amountCheck = checkPositiveAmount(input.amount, "Amount", Number.POSITIVE_INFINITY);
|
|
1039
|
+
if (!amountCheck.valid) return amountCheck;
|
|
1040
|
+
const resolvedFrom = resolveTokenType(input.from);
|
|
1041
|
+
const resolvedTo = resolveTokenType(input.to);
|
|
1042
|
+
const sameToken = input.from.trim() === input.to.trim() || resolvedFrom !== null && resolvedFrom === resolvedTo;
|
|
1043
|
+
if (sameToken) {
|
|
1044
|
+
return preflightFail("INVALID_ASSET", `Cannot swap ${input.from} to itself`);
|
|
1045
|
+
}
|
|
1046
|
+
return PREFLIGHT_OK;
|
|
1047
|
+
}
|
|
942
1048
|
var OVERLAY_FEE_RATE = 1e-3;
|
|
943
1049
|
var clientCache = /* @__PURE__ */ new Map();
|
|
944
1050
|
function getClient(walletAddress, overlayFee) {
|
|
@@ -1004,6 +1110,64 @@ async function buildSwapTx(params) {
|
|
|
1004
1110
|
});
|
|
1005
1111
|
return outputCoin;
|
|
1006
1112
|
}
|
|
1113
|
+
init_errors();
|
|
1114
|
+
function preflightSend(input) {
|
|
1115
|
+
try {
|
|
1116
|
+
assertAllowedAsset("send", input.asset);
|
|
1117
|
+
} catch (e) {
|
|
1118
|
+
return preflightFail("INVALID_ASSET", e.message);
|
|
1119
|
+
}
|
|
1120
|
+
const amountCheck = checkPositiveAmount(input.amount);
|
|
1121
|
+
if (!amountCheck.valid) return amountCheck;
|
|
1122
|
+
if ((input.asset === "USDC" || input.asset === "USDsui") && input.amount < GASLESS_MIN_STABLE_AMOUNT) {
|
|
1123
|
+
return preflightFail(
|
|
1124
|
+
"INVALID_AMOUNT",
|
|
1125
|
+
`Minimum gasless transfer is ${GASLESS_MIN_STABLE_AMOUNT} ${input.asset}. Got ${input.amount}.`
|
|
1126
|
+
);
|
|
1127
|
+
}
|
|
1128
|
+
const addressCheck = checkSuiAddress(input.to);
|
|
1129
|
+
if (!addressCheck.valid) return addressCheck;
|
|
1130
|
+
return PREFLIGHT_OK;
|
|
1131
|
+
}
|
|
1132
|
+
async function buildSendTx({
|
|
1133
|
+
client,
|
|
1134
|
+
address,
|
|
1135
|
+
to,
|
|
1136
|
+
amount,
|
|
1137
|
+
asset
|
|
1138
|
+
}) {
|
|
1139
|
+
const pf = preflightSend({ to, amount, asset });
|
|
1140
|
+
if (!pf.valid) throw new exports.T2000Error(pf.code, pf.error);
|
|
1141
|
+
const recipient = validateAddress(to);
|
|
1142
|
+
const assetInfo = SUPPORTED_ASSETS[asset];
|
|
1143
|
+
if (!assetInfo) throw new exports.T2000Error("ASSET_NOT_SUPPORTED", `Asset ${asset} is not supported`);
|
|
1144
|
+
const rawAmount = displayToRaw(amount, assetInfo.decimals);
|
|
1145
|
+
const tx = new transactions.Transaction();
|
|
1146
|
+
tx.setSender(address);
|
|
1147
|
+
const balanceResp = await client.core.getBalance({ owner: address, coinType: assetInfo.type });
|
|
1148
|
+
const totalBalance = BigInt(balanceResp.balance.balance);
|
|
1149
|
+
if (totalBalance < rawAmount) {
|
|
1150
|
+
throw new exports.T2000Error("INSUFFICIENT_BALANCE", `Insufficient ${asset} balance`, {
|
|
1151
|
+
available: Number(totalBalance) / 10 ** assetInfo.decimals,
|
|
1152
|
+
required: amount
|
|
1153
|
+
});
|
|
1154
|
+
}
|
|
1155
|
+
if (asset === "SUI") {
|
|
1156
|
+
const [sendCoin] = tx.splitCoins(tx.gas, [rawAmount]);
|
|
1157
|
+
tx.transferObjects([sendCoin], recipient);
|
|
1158
|
+
return tx;
|
|
1159
|
+
}
|
|
1160
|
+
const coinType = GASLESS_STABLE_TYPES[asset];
|
|
1161
|
+
tx.moveCall({
|
|
1162
|
+
target: "0x2::balance::send_funds",
|
|
1163
|
+
typeArguments: [coinType],
|
|
1164
|
+
arguments: [
|
|
1165
|
+
tx.balance({ type: coinType, balance: rawAmount }),
|
|
1166
|
+
tx.pure.address(recipient)
|
|
1167
|
+
]
|
|
1168
|
+
});
|
|
1169
|
+
return tx;
|
|
1170
|
+
}
|
|
1007
1171
|
|
|
1008
1172
|
// src/browser.ts
|
|
1009
1173
|
init_token_registry();
|
|
@@ -1016,13 +1180,18 @@ exports.KeypairSigner = KeypairSigner;
|
|
|
1016
1180
|
exports.LABEL_PATTERNS = LABEL_PATTERNS;
|
|
1017
1181
|
exports.MIST_PER_SUI = MIST_PER_SUI;
|
|
1018
1182
|
exports.OVERLAY_FEE_RATE = OVERLAY_FEE_RATE;
|
|
1183
|
+
exports.PREFLIGHT_MAX_AMOUNT = PREFLIGHT_MAX_AMOUNT;
|
|
1184
|
+
exports.PREFLIGHT_OK = PREFLIGHT_OK;
|
|
1019
1185
|
exports.STABLE_ASSETS = STABLE_ASSETS;
|
|
1020
1186
|
exports.SUI_DECIMALS = SUI_DECIMALS;
|
|
1021
1187
|
exports.SUPPORTED_ASSETS = SUPPORTED_ASSETS;
|
|
1022
1188
|
exports.T2000_OVERLAY_FEE_WALLET = T2000_OVERLAY_FEE_WALLET;
|
|
1023
1189
|
exports.USDC_DECIMALS = USDC_DECIMALS;
|
|
1024
1190
|
exports.ZkLoginSigner = ZkLoginSigner;
|
|
1191
|
+
exports.buildSendTx = buildSendTx;
|
|
1025
1192
|
exports.buildSwapTx = buildSwapTx;
|
|
1193
|
+
exports.checkPositiveAmount = checkPositiveAmount;
|
|
1194
|
+
exports.checkSuiAddress = checkSuiAddress;
|
|
1026
1195
|
exports.classifyAction = classifyAction;
|
|
1027
1196
|
exports.classifyLabel = classifyLabel;
|
|
1028
1197
|
exports.classifyTransaction = classifyTransaction;
|
|
@@ -1044,6 +1213,10 @@ exports.mapWalletError = mapWalletError;
|
|
|
1044
1213
|
exports.mistToSui = mistToSui;
|
|
1045
1214
|
exports.parseSuiRpcTx = parseSuiRpcTx;
|
|
1046
1215
|
exports.payWithMpp = payWithMpp;
|
|
1216
|
+
exports.preflightFail = preflightFail;
|
|
1217
|
+
exports.preflightPay = preflightPay;
|
|
1218
|
+
exports.preflightSend = preflightSend;
|
|
1219
|
+
exports.preflightSwap = preflightSwap;
|
|
1047
1220
|
exports.rawToStable = rawToStable;
|
|
1048
1221
|
exports.rawToUsdc = rawToUsdc;
|
|
1049
1222
|
exports.refineLendingLabel = refineLendingLabel;
|