@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 +120 -19
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +35 -1
- package/dist/index.d.ts +35 -1
- package/dist/index.js +125 -24
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/core/MSafeAccount.ts +22 -3
- package/src/simulate/simulator.ts +19 -2
- package/src/utils/gasFunding.ts +125 -16
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
|
-
|
|
509
|
+
const used = tx.getData().inputs.reduce((acc, input) => {
|
|
507
510
|
const immOrOwned = input.Object?.ImmOrOwnedObject?.objectId;
|
|
508
511
|
if (immOrOwned) {
|
|
509
|
-
|
|
510
|
-
return
|
|
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
|
-
|
|
517
|
+
acc.add((0, import_utils4.normalizeSuiObjectId)(unresolved));
|
|
515
518
|
}
|
|
516
|
-
return
|
|
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 =
|
|
642
|
-
|
|
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({
|
|
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
|
-
|
|
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({
|
|
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
|
-
...
|
|
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,
|