@msafe/sui3-sdk 1.0.21 → 1.0.22

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/index.cjs CHANGED
@@ -61,6 +61,8 @@ __export(src_exports, {
61
61
  TESTNET_RPC_URL: () => TESTNET_RPC_URL,
62
62
  Uint8ArrayToHex: () => Uint8ArrayToHex,
63
63
  addPrefix: () => addPrefix,
64
+ collectPayloadObjectIds: () => collectPayloadObjectIds,
65
+ collectQueueExcludeObjectIds: () => collectQueueExcludeObjectIds,
64
66
  computeGasBudget: () => computeGasBudget,
65
67
  createCoinReservationRef: () => createCoinReservationRef,
66
68
  estimateGasBudget: () => estimateGasBudget,
@@ -71,6 +73,7 @@ __export(src_exports, {
71
73
  httpUrlToGrpcBaseUrl: () => httpUrlToGrpcBaseUrl,
72
74
  isCoinReservationDigest: () => isCoinReservationDigest,
73
75
  msafeChainToSuiNetwork: () => msafeChainToSuiNetwork,
76
+ parkedPayloadHex: () => parkedPayloadHex,
74
77
  preferClassicGasPayment: () => preferClassicGasPayment,
75
78
  prepareGasFunding: () => prepareGasFunding,
76
79
  selectGasFunding: () => selectGasFunding,
@@ -503,18 +506,66 @@ function computeGasBudget(gasUsed, gasPrice) {
503
506
  return BigInt(computationCost) + BigInt(storageCost) + safeOverhead;
504
507
  }
505
508
  function collectUsedObjectIds(tx) {
506
- return tx.getData().inputs.reduce((used, input) => {
509
+ const used = tx.getData().inputs.reduce((acc, input) => {
507
510
  const immOrOwned = input.Object?.ImmOrOwnedObject?.objectId;
508
511
  if (immOrOwned) {
509
- used.add((0, import_utils4.normalizeSuiObjectId)(immOrOwned));
510
- return used;
512
+ acc.add((0, import_utils4.normalizeSuiObjectId)(immOrOwned));
513
+ return acc;
511
514
  }
512
515
  const unresolved = input.UnresolvedObject?.objectId;
513
516
  if (unresolved) {
514
- used.add((0, import_utils4.normalizeSuiObjectId)(unresolved));
517
+ acc.add((0, import_utils4.normalizeSuiObjectId)(unresolved));
515
518
  }
516
- return used;
519
+ return acc;
517
520
  }, /* @__PURE__ */ new Set());
521
+ (tx.getData().gasData.payment ?? []).forEach((payment) => {
522
+ if (payment.objectId) {
523
+ used.add((0, import_utils4.normalizeSuiObjectId)(payment.objectId));
524
+ }
525
+ });
526
+ return used;
527
+ }
528
+ function addExcludeObjectIds(used, excludeObjectIds) {
529
+ Array.from(excludeObjectIds ?? [], (id) => used.add((0, import_utils4.normalizeSuiObjectId)(id)));
530
+ return used;
531
+ }
532
+ function payloadToTransaction(payload) {
533
+ if (typeof payload !== "string") {
534
+ return import_transactions.Transaction.from(payload);
535
+ }
536
+ if (/^[0-9a-fA-F]+$/.test(payload) && payload.length % 2 === 0) {
537
+ return import_transactions.Transaction.from((0, import_utils4.fromHex)(payload));
538
+ }
539
+ return import_transactions.Transaction.from(payload);
540
+ }
541
+ function collectPayloadObjectIds(payload) {
542
+ return [...collectUsedObjectIds(payloadToTransaction(payload))];
543
+ }
544
+ function parkedPayloadHex(intention) {
545
+ if (!intention || typeof intention !== "object") {
546
+ return void 0;
547
+ }
548
+ const { content, digest } = intention;
549
+ if (typeof content !== "string" || typeof digest !== "string" || !digest) {
550
+ return void 0;
551
+ }
552
+ if (!/^[0-9a-fA-F]+$/.test(content) || content.length < 64) {
553
+ return void 0;
554
+ }
555
+ return content;
556
+ }
557
+ function collectQueueExcludeObjectIds(input) {
558
+ const ids = /* @__PURE__ */ new Set();
559
+ if (input.pendingPayload) {
560
+ collectPayloadObjectIds(input.pendingPayload).forEach((id) => ids.add(id));
561
+ }
562
+ (input.parkedPayloads ?? []).forEach((payload) => {
563
+ if (!payload) {
564
+ return;
565
+ }
566
+ collectPayloadObjectIds(payload).forEach((id) => ids.add(id));
567
+ });
568
+ return [...ids];
518
569
  }
519
570
  function txConsumesOwnedSuiCoins(tx) {
520
571
  return tx.getData().commands.some((cmd) => {
@@ -532,8 +583,8 @@ function txConsumesOwnedSuiCoins(tx) {
532
583
  }
533
584
  });
534
585
  }
535
- async function loadSuiGasFunding(suiClient, owner, tx) {
536
- const usedObjectIds = collectUsedObjectIds(tx);
586
+ async function loadSuiGasFunding(suiClient, owner, tx, excludeObjectIds) {
587
+ const usedObjectIds = addExcludeObjectIds(collectUsedObjectIds(tx), excludeObjectIds);
537
588
  const [coins, balanceRes] = await Promise.all([
538
589
  getAllCoins({ suiClient, owner, coinType: SUI_COIN }),
539
590
  suiClient.getBalance({ owner, coinType: SUI_COIN })
@@ -584,7 +635,7 @@ async function selectGasFunding(input) {
584
635
  const { tx, suiClient, owner, gasBudget } = input;
585
636
  const { payment } = tx.getData().gasData;
586
637
  if (payment != null && payment.length > 0) {
587
- const funding2 = await loadSuiGasFunding(suiClient, owner, tx);
638
+ const funding2 = await loadSuiGasFunding(suiClient, owner, tx, input.excludeObjectIds);
588
639
  return {
589
640
  mode: "classic",
590
641
  gasBudget,
@@ -592,7 +643,7 @@ async function selectGasFunding(input) {
592
643
  addressBalance: funding2.addressBalance
593
644
  };
594
645
  }
595
- const funding = await loadSuiGasFunding(suiClient, owner, tx);
646
+ const funding = await loadSuiGasFunding(suiClient, owner, tx, input.excludeObjectIds);
596
647
  const { paymentCoins, coinBalance, addressBalance, total } = funding;
597
648
  if (total < gasBudget) {
598
649
  throw new InsufficientGasFundsError(gasBudget, coinBalance, addressBalance);
@@ -638,8 +689,13 @@ function isPositiveBudget(budget) {
638
689
  }
639
690
  async function estimateGasBudget(input) {
640
691
  const { tx, suiClient, owner, gasPrice } = input;
641
- const funding = await loadSuiGasFunding(suiClient, owner, tx);
642
- if (funding.total <= 0n) {
692
+ const funding = input.preferAddressBalance ? {
693
+ ...await loadSuiGasFunding(suiClient, owner, tx, input.excludeObjectIds),
694
+ paymentCoins: [],
695
+ coinBalance: 0n
696
+ } : await loadSuiGasFunding(suiClient, owner, tx, input.excludeObjectIds);
697
+ const fundingTotal = input.preferAddressBalance ? funding.addressBalance : funding.total;
698
+ if (fundingTotal <= 0n) {
643
699
  throw new InsufficientGasFundsError(0n, funding.coinBalance, funding.addressBalance);
644
700
  }
645
701
  const { budget, payment } = tx.getData().gasData;
@@ -672,7 +728,7 @@ async function estimateGasBudget(input) {
672
728
  return computeGasBudget(effects.gasUsed, gasPrice);
673
729
  }
674
730
  async function prepareGasFunding(input) {
675
- const { tx, suiClient, owner, gasPrice } = input;
731
+ const { tx, suiClient, owner, gasPrice, excludeObjectIds } = input;
676
732
  const { payment, budget: existingBudget } = tx.getData().gasData;
677
733
  const bakedAddressBalanceGas = payment != null && payment.length === 0;
678
734
  let { gasBudget } = input;
@@ -682,7 +738,14 @@ async function prepareGasFunding(input) {
682
738
  const existingPositive = isPositiveBudget(existingBudget) ? BigInt(existingBudget) : null;
683
739
  if (gasBudget == null) {
684
740
  if (bakedAddressBalanceGas || existingPositive == null) {
685
- gasBudget = await estimateGasBudget({ tx, suiClient, owner, gasPrice });
741
+ gasBudget = await estimateGasBudget({
742
+ tx,
743
+ suiClient,
744
+ owner,
745
+ gasPrice,
746
+ excludeObjectIds,
747
+ preferAddressBalance: input.preferAddressBalance
748
+ });
686
749
  } else {
687
750
  gasBudget = existingPositive;
688
751
  }
@@ -691,7 +754,20 @@ async function prepareGasFunding(input) {
691
754
  if (bakedAddressBalanceGas) {
692
755
  tx.setExpiration(null);
693
756
  }
694
- return selectGasFunding({ tx, suiClient, owner, gasBudget });
757
+ if (input.preferAddressBalance) {
758
+ const funding = await loadSuiGasFunding(suiClient, owner, tx, excludeObjectIds);
759
+ if (funding.addressBalance < gasBudget) {
760
+ throw new InsufficientGasFundsError(gasBudget, funding.coinBalance, funding.addressBalance);
761
+ }
762
+ tx.setGasPayment([]);
763
+ return {
764
+ mode: "addressBalance",
765
+ gasBudget,
766
+ coinBalance: funding.coinBalance,
767
+ addressBalance: funding.addressBalance
768
+ };
769
+ }
770
+ return selectGasFunding({ tx, suiClient, owner, gasBudget, excludeObjectIds });
695
771
  }
696
772
  async function preferClassicGasPayment(input) {
697
773
  const { tx, suiClient, owner } = input;
@@ -734,7 +810,9 @@ var Simulator = class {
734
810
  tx,
735
811
  suiClient,
736
812
  owner: input.sender,
737
- gasPrice
813
+ gasPrice,
814
+ preferAddressBalance: input.preferAddressBalance,
815
+ excludeObjectIds: input.excludeObjectIds
738
816
  });
739
817
  } catch (e) {
740
818
  const message = e instanceof Error ? e.message : String(e);
@@ -755,9 +833,17 @@ var Simulator = class {
755
833
  simulationError: message
756
834
  };
757
835
  }
836
+ return this.inspectBuilt(built, gasPrice);
837
+ }
838
+ /** Dry-run a frozen payload without re-selecting gas. */
839
+ async simulateBuilt(built) {
840
+ const gasPrice = await this.getGasPrice();
841
+ return this.inspectBuilt(built, gasPrice);
842
+ }
843
+ async inspectBuilt(built, gasPrice) {
758
844
  let inspectResult;
759
845
  try {
760
- inspectResult = await suiClient.simulateTransaction({
846
+ inspectResult = await this.globals.suiClient.simulateTransaction({
761
847
  transaction: built,
762
848
  include: {
763
849
  effects: true,
@@ -1130,7 +1216,12 @@ var MSafeAccount = class _MSafeAccount {
1130
1216
  async simulateIntention(request) {
1131
1217
  const txb = await this.buildTxFromIntention(request);
1132
1218
  txb.setSender(this.address);
1133
- return this.simulator.simulate({ txb, sender: this.address });
1219
+ return this.simulator.simulate({
1220
+ txb,
1221
+ sender: this.address,
1222
+ preferAddressBalance: request.preferAddressBalance,
1223
+ excludeObjectIds: request.excludeObjectIds
1224
+ });
1134
1225
  }
1135
1226
  async proposeIntention(input) {
1136
1227
  const message = import_sui3_utils4.SigningMessageHelper.proposeIntentionMessage({
@@ -1156,13 +1247,19 @@ var MSafeAccount = class _MSafeAccount {
1156
1247
  suiClient: this.globals.suiClient,
1157
1248
  owner: this.address,
1158
1249
  gasPrice: input.gasPrice,
1159
- gasBudget: input.gasBudget
1250
+ gasBudget: input.gasBudget,
1251
+ preferAddressBalance: input.preferAddressBalance,
1252
+ excludeObjectIds: input.excludeObjectIds
1160
1253
  });
1161
1254
  const payload = await txb.build({ client: this.globals.suiClient });
1162
1255
  const digest = await txb.getDigest({ client: this.globals.suiClient });
1163
1256
  const signature = await this.wallet.signTransactionBlock({ transactionBlock: payload });
1257
+ const apiInput = { ...input };
1258
+ delete apiInput.txb;
1259
+ delete apiInput.preferAddressBalance;
1260
+ delete apiInput.excludeObjectIds;
1164
1261
  return this.backend.proposeIntentionAndBuildVote({
1165
- ...input,
1262
+ ...apiInput,
1166
1263
  payload: (0, import_utils6.toHex)(payload),
1167
1264
  digest,
1168
1265
  msafeAddress: this.address,
@@ -1270,6 +1367,10 @@ var MSafeAccount = class _MSafeAccount {
1270
1367
  }
1271
1368
  async simulateBuildTransaction() {
1272
1369
  const intention = await this.backend.getNextIntention({ msafeAddress: this.address });
1370
+ const parked = parkedPayloadHex(intention.intention);
1371
+ if (parked) {
1372
+ return this.simulator.simulateBuilt((0, import_utils6.fromHex)(parked));
1373
+ }
1273
1374
  const txb = await this.buildTxFromIntention({
1274
1375
  application: intention.application,
1275
1376
  intention: intention.intention,