@msafe/sui3-sdk 1.0.23 → 1.0.24

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@msafe/sui3-sdk",
3
- "version": "1.0.23",
3
+ "version": "1.0.24",
4
4
  "description": "SDK for MSafe SUI V3",
5
5
  "type": "module",
6
6
  "module": "./dist/index.js",
@@ -8,6 +8,12 @@ import { getAllCoins, SUI_COIN } from '@/utils/sui';
8
8
 
9
9
  const GAS_SAFE_OVERHEAD = 1000n;
10
10
 
11
+ /** Protocol cap: a transaction may smash at most this many gas payment objects. */
12
+ export const MAX_GAS_PAYMENT_OBJECTS = 256;
13
+
14
+ /** Cover target for estimate probes (1 SUI is enough for a normal dry-run). */
15
+ const ESTIMATE_GAS_COVER = 1_000_000_000n;
16
+
11
17
  export type GasFundingMode = 'classic' | 'addressBalance' | 'mixedTopUp';
12
18
 
13
19
  export interface GasFundingResult {
@@ -49,7 +55,37 @@ export function computeGasBudget(
49
55
  return BigInt(computationCost) + BigInt(storageCost) + safeOverhead;
50
56
  }
51
57
 
52
- type PaymentCoinRef = { objectId: string; version: string; digest: string; balance: bigint };
58
+ export type PaymentCoinRef = { objectId: string; version: string; digest: string; balance: bigint };
59
+
60
+ /**
61
+ * Pick the fewest large SUI coins that cover `cover`, capped at 256.
62
+ * Never attach every owned coin — accounts with hundreds of SUI objects
63
+ * exceed max_gas_payment_objects and trip gasless estimate
64
+ * ("gas_budget must be 0 for gasless transactions").
65
+ */
66
+ export function pickGasPaymentCoins(coins: PaymentCoinRef[], cover: bigint): PaymentCoinRef[] {
67
+ if (cover <= 0n) {
68
+ return [];
69
+ }
70
+
71
+ const sorted = [...coins]
72
+ .filter((coin) => coin.balance > 0n)
73
+ .sort((a, b) => (a.balance === b.balance ? 0 : a.balance < b.balance ? 1 : -1));
74
+
75
+ const selected: PaymentCoinRef[] = [];
76
+ let sum = 0n;
77
+ for (const coin of sorted) {
78
+ if (selected.length >= MAX_GAS_PAYMENT_OBJECTS) {
79
+ break;
80
+ }
81
+ selected.push(coin);
82
+ sum += coin.balance;
83
+ if (sum >= cover) {
84
+ break;
85
+ }
86
+ }
87
+ return selected;
88
+ }
53
89
 
54
90
  interface SuiGasFunding {
55
91
  paymentCoins: PaymentCoinRef[];
@@ -285,17 +321,18 @@ export async function selectGasFunding(input: {
285
321
  // gas (payment: []) is stricter on budget and is what Mysten auto-picks when
286
322
  // addressBalance > 0 — avoid it unless there is no usable gas coin.
287
323
  if (paymentCoins.length > 0 && coinBalance >= gasBudget) {
288
- tx.setGasPayment(toObjectRefs(paymentCoins));
324
+ tx.setGasPayment(toObjectRefs(pickGasPaymentCoins(paymentCoins, gasBudget)));
289
325
  return { mode: 'classic', gasBudget, coinBalance, addressBalance };
290
326
  }
291
327
 
292
328
  if (paymentCoins.length > 0 && total >= gasBudget) {
293
329
  const topUpAmount = gasBudget - coinBalance; // > 0 and <= addressBalance
330
+ // One real coin is enough — reservation smashes into it.
294
331
  await applyMixedTopUp({
295
332
  tx,
296
333
  suiClient,
297
334
  owner,
298
- paymentCoins,
335
+ paymentCoins: pickGasPaymentCoins(paymentCoins, 1n),
299
336
  topUpAmount,
300
337
  });
301
338
  return { mode: 'mixedTopUp', gasBudget, coinBalance, addressBalance };
@@ -381,9 +418,9 @@ export async function estimateGasBudget(input: {
381
418
  probe.setSender(owner);
382
419
  probe.setGasPrice(gasPrice);
383
420
 
384
- // Prefer classic coins for the probe when available (cheaper than address-balance gas).
421
+ // Prefer a few large classic coins for the probe (never attach every owned coin).
385
422
  if (funding.paymentCoins.length > 0) {
386
- probe.setGasPayment(toObjectRefs(funding.paymentCoins));
423
+ probe.setGasPayment(toObjectRefs(pickGasPaymentCoins(funding.paymentCoins, ESTIMATE_GAS_COVER)));
387
424
  }
388
425
 
389
426
  let built: Uint8Array;
@@ -500,6 +537,6 @@ export async function preferClassicGasPayment(input: {
500
537
  if (funding.paymentCoins.length === 0) {
501
538
  return false;
502
539
  }
503
- tx.setGasPayment(toObjectRefs(funding.paymentCoins));
540
+ tx.setGasPayment(toObjectRefs(pickGasPaymentCoins(funding.paymentCoins, ESTIMATE_GAS_COVER)));
504
541
  return true;
505
542
  }