@mysten/sui 2.14.1 → 2.16.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/CHANGELOG.md +29 -0
- package/dist/bcs/bcs.d.mts +6 -6
- package/dist/bcs/index.d.mts +20 -20
- package/dist/client/mvr.d.mts.map +1 -1
- package/dist/client/mvr.mjs +3 -0
- package/dist/client/mvr.mjs.map +1 -1
- package/dist/grpc/index.d.mts +3 -1
- package/dist/grpc/index.mjs +2 -1
- package/dist/grpc/proto/sui/rpc/v2/state_service.client.d.mts +4 -4
- package/dist/grpc/proto/sui/rpc/v2/subscription_service.client.d.mts +4 -4
- package/dist/transactions/Transaction.d.mts +9 -9
- package/dist/transactions/Transaction.d.mts.map +1 -1
- package/dist/transactions/data/v1.d.mts +220 -220
- package/dist/transactions/data/v1.d.mts.map +1 -1
- package/dist/transactions/data/v2.d.mts +16 -16
- package/dist/transactions/data/v2.d.mts.map +1 -1
- package/dist/transactions/intents/CoinWithBalance.mjs +35 -5
- package/dist/transactions/intents/CoinWithBalance.mjs.map +1 -1
- package/dist/utils/format.d.mts +5 -1
- package/dist/utils/format.d.mts.map +1 -1
- package/dist/utils/format.mjs +19 -1
- package/dist/utils/format.mjs.map +1 -1
- package/dist/utils/index.d.mts +2 -2
- package/dist/utils/index.mjs +2 -2
- package/dist/version.mjs +2 -2
- package/dist/version.mjs.map +1 -1
- package/dist/zklogin/bcs.d.mts +14 -14
- package/dist/zklogin/bcs.d.mts.map +1 -1
- package/docs/clients/grpc.md +55 -2
- package/docs/llms-index.md +5 -5
- package/docs/utils/index.md +7 -0
- package/package.json +4 -2
- package/src/client/mvr.ts +12 -0
- package/src/grpc/index.ts +6 -0
- package/src/transactions/intents/CoinWithBalance.ts +41 -6
- package/src/utils/format.ts +36 -0
- package/src/utils/index.ts +1 -1
- package/src/version.ts +2 -2
|
@@ -140,6 +140,12 @@ export async function resolveCoinBalance(
|
|
|
140
140
|
intentsByType.get(type)!.push({ balance, outputKind: outputKind ?? 'coin' });
|
|
141
141
|
}
|
|
142
142
|
|
|
143
|
+
if (totalByType.has('gas') && totalByType.has(SUI_TYPE)) {
|
|
144
|
+
throw new Error(
|
|
145
|
+
'Cannot mix SUI CoinWithBalance intents that use the gas coin with ones that do not (useGasCoin: false). Use one or the other.',
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
|
|
143
149
|
const usedIds = new Set<string>();
|
|
144
150
|
|
|
145
151
|
for (const input of transactionData.inputs) {
|
|
@@ -188,6 +194,7 @@ export async function resolveCoinBalance(
|
|
|
188
194
|
|
|
189
195
|
const mergedCoins = new Map<string, Argument>();
|
|
190
196
|
const exactBalanceByType = new Map<string, boolean>();
|
|
197
|
+
const usedAddressBalance = new Set<string>();
|
|
191
198
|
|
|
192
199
|
// Per-type state for Path 2 combined splits
|
|
193
200
|
type TypeState = { results: Argument[]; nextIntent: number };
|
|
@@ -251,7 +258,31 @@ export async function resolveCoinBalance(
|
|
|
251
258
|
// Step 1: Build sources and merge
|
|
252
259
|
const sources: Argument[] = [];
|
|
253
260
|
|
|
254
|
-
if (
|
|
261
|
+
if (addressBalance >= totalRequired) {
|
|
262
|
+
// AB sufficient — source entirely from address balance, no coins needed.
|
|
263
|
+
usedAddressBalance.add(type);
|
|
264
|
+
|
|
265
|
+
commands.push(
|
|
266
|
+
TransactionCommands.MoveCall({
|
|
267
|
+
target: '0x2::coin::redeem_funds',
|
|
268
|
+
typeArguments: [coinType],
|
|
269
|
+
arguments: [
|
|
270
|
+
transactionData.addInput(
|
|
271
|
+
'withdrawal',
|
|
272
|
+
Inputs.FundsWithdrawal({
|
|
273
|
+
reservation: {
|
|
274
|
+
$kind: 'MaxAmountU64',
|
|
275
|
+
MaxAmountU64: String(totalRequired),
|
|
276
|
+
},
|
|
277
|
+
typeArg: { $kind: 'Balance', Balance: coinType },
|
|
278
|
+
withdrawFrom: { $kind: 'Sender', Sender: true },
|
|
279
|
+
}),
|
|
280
|
+
),
|
|
281
|
+
],
|
|
282
|
+
}),
|
|
283
|
+
);
|
|
284
|
+
sources.push({ $kind: 'Result', Result: index + commands.length - 1 });
|
|
285
|
+
} else if (type === 'gas') {
|
|
255
286
|
sources.push({ $kind: 'GasCoin', GasCoin: true });
|
|
256
287
|
} else {
|
|
257
288
|
const coins = coinsByType.get(type)!;
|
|
@@ -275,6 +306,7 @@ export async function resolveCoinBalance(
|
|
|
275
306
|
}
|
|
276
307
|
|
|
277
308
|
if (abNeeded > 0n) {
|
|
309
|
+
usedAddressBalance.add(type);
|
|
278
310
|
commands.push(
|
|
279
311
|
TransactionCommands.MoveCall({
|
|
280
312
|
target: '0x2::coin::redeem_funds',
|
|
@@ -363,17 +395,20 @@ export async function resolveCoinBalance(
|
|
|
363
395
|
|
|
364
396
|
// Step 3: Remainder handling
|
|
365
397
|
for (const [type, mergedCoin] of mergedCoins) {
|
|
366
|
-
|
|
398
|
+
// When gas type used GasCoin (not AB), leftover stays in the gas coin — no remainder needed.
|
|
399
|
+
if (type === 'gas' && !usedAddressBalance.has(type)) continue;
|
|
367
400
|
|
|
401
|
+
const coinType = type === 'gas' ? SUI_TYPE : type;
|
|
368
402
|
const hasBalanceIntent = intentsByType.get(type)?.some((i) => i.outputKind === 'balance');
|
|
403
|
+
const sourcedFromAB = usedAddressBalance.has(type);
|
|
369
404
|
|
|
370
|
-
if (hasBalanceIntent) {
|
|
371
|
-
//
|
|
405
|
+
if (hasBalanceIntent || sourcedFromAB) {
|
|
406
|
+
// Sourced from AB or balance intents exist: send remainder back to sender's address balance.
|
|
372
407
|
// coin::send_funds is gasless-eligible and handles zero amounts.
|
|
373
408
|
transactionData.commands.push(
|
|
374
409
|
TransactionCommands.MoveCall({
|
|
375
410
|
target: '0x2::coin::send_funds',
|
|
376
|
-
typeArguments: [
|
|
411
|
+
typeArguments: [coinType],
|
|
377
412
|
arguments: [
|
|
378
413
|
mergedCoin,
|
|
379
414
|
transactionData.addInput(
|
|
@@ -388,7 +423,7 @@ export async function resolveCoinBalance(
|
|
|
388
423
|
transactionData.commands.push(
|
|
389
424
|
TransactionCommands.MoveCall({
|
|
390
425
|
target: '0x2::coin::destroy_zero',
|
|
391
|
-
typeArguments: [
|
|
426
|
+
typeArguments: [coinType],
|
|
392
427
|
arguments: [mergedCoin],
|
|
393
428
|
}),
|
|
394
429
|
);
|
package/src/utils/format.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
// Copyright (c) Mysten Labs, Inc.
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
3
|
|
|
4
|
+
import { SUI_DECIMALS } from './constants.js';
|
|
5
|
+
|
|
4
6
|
const ELLIPSIS = '\u{2026}';
|
|
5
7
|
|
|
6
8
|
export function formatAddress(address: string) {
|
|
@@ -17,3 +19,37 @@ export function formatDigest(digest: string) {
|
|
|
17
19
|
// Use 10 first characters
|
|
18
20
|
return `${digest.slice(0, 10)}${ELLIPSIS}`;
|
|
19
21
|
}
|
|
22
|
+
|
|
23
|
+
const AMOUNT_REGEX = /^-?(?:[0-9]+(?:\.[0-9]+)?|\.[0-9]+)$/;
|
|
24
|
+
|
|
25
|
+
/** Parse a decimal string into its smallest-unit bigint representation. No floating point. */
|
|
26
|
+
export function parseToUnits(amount: string, decimals: number): bigint {
|
|
27
|
+
if (decimals < 0 || !Number.isInteger(decimals)) {
|
|
28
|
+
throw new Error(`Invalid decimals: ${decimals}`);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (!AMOUNT_REGEX.test(amount)) {
|
|
32
|
+
throw new Error(`Invalid amount: "${amount}"`);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const negative = amount.startsWith('-');
|
|
36
|
+
const stripped = negative ? amount.slice(1) : amount;
|
|
37
|
+
|
|
38
|
+
const [whole, fraction = ''] = stripped.split('.');
|
|
39
|
+
|
|
40
|
+
if (fraction.length > decimals) {
|
|
41
|
+
throw new Error(
|
|
42
|
+
`Too many decimal places: "${amount}" has ${fraction.length} but max is ${decimals}`,
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const paddedFraction = fraction.padEnd(decimals, '0') || '0';
|
|
47
|
+
const result = BigInt(whole || '0') * 10n ** BigInt(decimals) + BigInt(paddedFraction);
|
|
48
|
+
|
|
49
|
+
return negative ? -result : result;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** Parse a SUI decimal string into MIST. */
|
|
53
|
+
export function parseToMist(amount: string): bigint {
|
|
54
|
+
return parseToUnits(amount, SUI_DECIMALS);
|
|
55
|
+
}
|
package/src/utils/index.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Copyright (c) Mysten Labs, Inc.
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
3
|
|
|
4
|
-
export { formatAddress, formatDigest } from './format.js';
|
|
4
|
+
export { formatAddress, formatDigest, parseToUnits, parseToMist } from './format.js';
|
|
5
5
|
export {
|
|
6
6
|
isValidStructTag,
|
|
7
7
|
isValidSuiAddress,
|
package/src/version.ts
CHANGED