@msafe/sui3-sdk 0.0.35 → 0.0.36

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
@@ -43,7 +43,6 @@ __export(src_exports, {
43
43
  LOCAL_API_URL: () => LOCAL_API_URL,
44
44
  LOCAL_SYNCING_URL: () => LOCAL_SYNCING_URL,
45
45
  MAINNET_RPC_URL: () => MAINNET_RPC_URL,
46
- MSAFE_APPLICATION: () => MSAFE_APPLICATION,
47
46
  MSafeAccount: () => MSafeAccount,
48
47
  MSafeClient: () => MSafeClient,
49
48
  MSafeEnv: () => MSafeEnv,
@@ -176,10 +175,83 @@ var InvitationSDK = class {
176
175
  };
177
176
 
178
177
  // src/core/MSafeAccount.ts
178
+ var import_sui_app_store = require("@msafe/sui-app-store");
179
179
  var import_sui3_utils4 = require("@msafe/sui3-utils");
180
- var import_transactions = require("@mysten/sui.js/transactions");
180
+ var import_transactions2 = require("@mysten/sui.js/transactions");
181
181
  var import_utils3 = require("@mysten/sui.js/utils");
182
182
 
183
+ // src/simulate/simulator.ts
184
+ var import_transactions = require("@mysten/sui.js/transactions");
185
+ var GAS_SAFE_OVERHEAD = 1000n;
186
+ var DEF_GAS_PRICE_NUM = 120n;
187
+ var DEF_GAS_PRICE_DEN = 100n;
188
+ var DEF_GAS_PRICE_OPTION = {
189
+ multiplier: {
190
+ numerator: DEF_GAS_PRICE_NUM,
191
+ denominator: DEF_GAS_PRICE_DEN
192
+ }
193
+ };
194
+ var Simulator = class {
195
+ constructor(globals) {
196
+ this.globals = globals;
197
+ }
198
+ async simulate(input, options = DEF_GAS_PRICE_OPTION) {
199
+ const tx = this.copyTransactionBlock(input.txb);
200
+ const { suiClient } = this.globals;
201
+ const gasPrice = await this.getGasPrice(options);
202
+ tx.setGasPrice(gasPrice);
203
+ const inspectResult = await suiClient.devInspectTransactionBlock({ transactionBlock: tx, sender: input.sender });
204
+ const { gasUsed } = inspectResult.effects;
205
+ const gasBudget = this.toGasBudget(gasUsed, gasPrice);
206
+ const success = inspectResult.effects.status.status === "success";
207
+ let error;
208
+ if (!success) {
209
+ error = inspectResult.effects.status.error;
210
+ }
211
+ return {
212
+ success,
213
+ gasPrice,
214
+ gasObject: inspectResult.effects.gasObject.reference,
215
+ gasUsed,
216
+ gasBudget,
217
+ simulationError: error
218
+ };
219
+ }
220
+ async getGasPrice(option) {
221
+ if (this.isFixedValue(option)) {
222
+ return option.fixedVal;
223
+ }
224
+ const refGasPrice = await this.globals.suiClient.getReferenceGasPrice();
225
+ return this.applyGasOption(refGasPrice, option);
226
+ }
227
+ toGasBudget(gasUsed, gasPrice) {
228
+ const { computationCost, storageCost } = gasUsed;
229
+ const safeOverhead = GAS_SAFE_OVERHEAD * gasPrice;
230
+ const baseComputationCostWithOverhead = BigInt(computationCost) + safeOverhead;
231
+ const gasBudget = baseComputationCostWithOverhead + BigInt(storageCost);
232
+ return gasBudget > baseComputationCostWithOverhead ? gasBudget : baseComputationCostWithOverhead;
233
+ }
234
+ isFixedValue(option) {
235
+ return "fixedVal" in option;
236
+ }
237
+ isMultiplier(option) {
238
+ return "multiplier" in option;
239
+ }
240
+ applyGasOption(val, option) {
241
+ if (this.isFixedValue(option)) {
242
+ return option.fixedVal;
243
+ }
244
+ if (this.isMultiplier(option)) {
245
+ const { multiplier } = option;
246
+ return val * multiplier.numerator / multiplier.denominator;
247
+ }
248
+ throw new Error("Sanity: Unknown gas price option");
249
+ }
250
+ copyTransactionBlock(tx) {
251
+ return import_transactions.TransactionBlock.from(tx.serialize());
252
+ }
253
+ };
254
+
183
255
  // src/utils/buffer.ts
184
256
  function stringToBuffer(s) {
185
257
  return Buffer.from(s, "utf-8");
@@ -529,9 +601,11 @@ var MSafeAccount = class _MSafeAccount {
529
601
  creationNonce: info.creationNonce
530
602
  });
531
603
  this.coinHelper = new CoinHelper(this.suiClient);
604
+ this.simulator = new Simulator(globals);
532
605
  }
533
606
  multiSig;
534
607
  coinHelper;
608
+ simulator;
535
609
  static async New(globals, address) {
536
610
  const info = await globals.backend.getMSafeAccountInfo(address);
537
611
  const ms = new _MSafeAccount(globals, info);
@@ -560,7 +634,6 @@ var MSafeAccount = class _MSafeAccount {
560
634
  };
561
635
  return getAllOwnedObjects(this.suiClient, this.address, filterCoinObjectOptions);
562
636
  }
563
- // TODO: Calculate the votes
564
637
  async pendingTransaction() {
565
638
  const res = await this.backend.getPendingTransactions({ msafeAddress: this.address });
566
639
  if (!res.pending) {
@@ -586,7 +659,6 @@ var MSafeAccount = class _MSafeAccount {
586
659
  rejectWeight: this.calculateWeightFromVotes(rejectPending?.votes ?? [])
587
660
  };
588
661
  }
589
- // TODO: Calculate the votes.
590
662
  async historyTransaction(pagination) {
591
663
  return this.backend.getHistoryTransactions({
592
664
  msafeAddress: this.address,
@@ -602,6 +674,22 @@ var MSafeAccount = class _MSafeAccount {
602
674
  async nextSequenceNumber() {
603
675
  return this.backend.getNextSequenceNumber(this.address);
604
676
  }
677
+ async simulateIntention(request) {
678
+ const appHelper = import_sui_app_store.appHelpers.getAppHelper(request.application);
679
+ if (!appHelper) {
680
+ throw new Error(`Can't find app helper for application ${request.application}`);
681
+ }
682
+ const txb = await appHelper.build({
683
+ intentionData: request.intention,
684
+ txType: request.txType,
685
+ txSubType: request.txSubType,
686
+ suiClient: this.globals.suiClient,
687
+ account: {
688
+ address: this.address
689
+ }
690
+ });
691
+ return this.simulator.simulate({ txb, sender: this.address });
692
+ }
605
693
  async proposeIntention(input) {
606
694
  const message = import_sui3_utils4.SigningMessageHelper.proposeIntentionMessage({
607
695
  msafeAddress: this.address,
@@ -611,12 +699,22 @@ var MSafeAccount = class _MSafeAccount {
611
699
  const signature = await this.wallet.signPersonalMessage({
612
700
  messageStr: message
613
701
  });
614
- await this.backend.proposeIntention({
702
+ return this.backend.proposeIntention({
615
703
  ...input,
616
704
  msafeAddress: this.address,
617
705
  signature: signature.signature
618
706
  });
619
707
  }
708
+ async simulateCoinTransferIntention(intention) {
709
+ const sn = await this.nextSequenceNumber();
710
+ return this.simulateIntention({
711
+ application: import_sui3_utils4.TransactionDefaultApplication,
712
+ txType: import_sui3_utils4.TransactionType.Assets,
713
+ txSubType: import_sui3_utils4.TransactionSubTypes.assets.coin.send,
714
+ sequenceNumber: sn,
715
+ intention
716
+ });
717
+ }
620
718
  async proposeCoinTransferIntention(intention) {
621
719
  const sn = await this.nextSequenceNumber();
622
720
  return this.proposeIntention({
@@ -640,7 +738,7 @@ var MSafeAccount = class _MSafeAccount {
640
738
  }
641
739
  async proposePlainPayloadIntention(intention) {
642
740
  const sn = await this.nextSequenceNumber();
643
- const tb = import_transactions.TransactionBlock.from(intention.payload);
741
+ const tb = import_transactions2.TransactionBlock.from(intention.payload);
644
742
  if (!tb.blockData.sender || !(0, import_sui3_utils4.isSameAddress)(tb.blockData.sender, this.address)) {
645
743
  throw new Error("Transaction sender is not same as the multisig address");
646
744
  }
@@ -664,7 +762,7 @@ var MSafeAccount = class _MSafeAccount {
664
762
  // Shortcut for proposing a transaction to be a pending transaction, and add user vote to it.
665
763
  // Requires the multi-sig to be empty in pending transaction.
666
764
  async proposePendingTransaction(intention) {
667
- const txb = new import_transactions.TransactionBlock();
765
+ const txb = new import_transactions2.TransactionBlock();
668
766
  const payload = await txb.build({ client: this.suiClient });
669
767
  const digest = await txb.getDigest({ client: this.suiClient });
670
768
  const signature = await this.wallet.signTransactionBlock({ transactionBlock: payload });
@@ -692,33 +790,34 @@ var MSafeAccount = class _MSafeAccount {
692
790
  signature: signature.signature
693
791
  });
694
792
  }
695
- async buildNextIntentionAndAddToPending() {
696
- return this.backend.buildNextIntentionAndAddToPending({ msafeAddress: this.address });
793
+ async simulateBuildTransaction() {
794
+ const intention = await this.backend.getNextIntention({ msafeAddress: this.address });
795
+ const appHelper = import_sui_app_store.appHelpers.getAppHelper(intention.application);
796
+ if (!appHelper) {
797
+ throw new Error(`Can't find app helper for application ${intention.application}`);
798
+ }
799
+ const txb = await appHelper.build({
800
+ intentionData: intention.intention,
801
+ txType: intention.txType,
802
+ txSubType: intention.txSubType,
803
+ suiClient: this.globals.suiClient,
804
+ account: {
805
+ address: this.address
806
+ }
807
+ });
808
+ return this.simulator.simulate({ txb, sender: this.address });
809
+ }
810
+ async buildNextIntentionAndAddToPending(gasOption) {
811
+ return this.backend.buildNextIntentionAndAddToPending({
812
+ msafeAddress: this.address,
813
+ forceBuild: gasOption.forceBuild,
814
+ gasPrice: gasOption.gasPrice,
815
+ gasBudget: gasOption.gasBudget
816
+ });
697
817
  }
698
818
  async skipNextFailedIntention() {
699
819
  return this.backend.skipNextFailedIntention({ msafeAddress: this.address });
700
820
  }
701
- async simulateIntention() {
702
- const txb = new import_transactions.TransactionBlock();
703
- txb.setSender(this.address);
704
- if (!txb.blockData.gasConfig.price) {
705
- const refGas = await this.suiClient.getReferenceGasPrice();
706
- txb.setGasPrice(refGas);
707
- }
708
- const payload = await txb.build({ client: this.suiClient });
709
- const dryRunResult = await this.suiClient.dryRunTransactionBlock({ transactionBlock: payload });
710
- const success = dryRunResult.effects.status.status === "success";
711
- const errorMsg = dryRunResult.effects.status.error;
712
- const gasPrice = BigInt(txb.blockData.gasConfig.price);
713
- const { gasUsed } = dryRunResult.effects;
714
- return {
715
- success,
716
- errorMsg,
717
- gasPrice,
718
- gasUsed,
719
- dryRunResult
720
- };
721
- }
722
821
  async executePendingTx(pending, isRejectTx = false) {
723
822
  const votes = isRejectTx ? pending.rejectVotes : pending.votes;
724
823
  const payload = isRejectTx ? pending.rejectPayload : pending.payload;
@@ -958,6 +1057,13 @@ var BackendImpl = class _BackendImpl {
958
1057
  });
959
1058
  return res.data;
960
1059
  }
1060
+ async getNextIntention(input) {
1061
+ const res = await this.get(`/transaction/intention/next`, {
1062
+ params: input,
1063
+ headers: this.headers()
1064
+ });
1065
+ return res.data;
1066
+ }
961
1067
  async getCurrentSequenceNumber(address) {
962
1068
  const res = await this.get(`/transaction/sn/current`, {
963
1069
  params: {
@@ -984,7 +1090,6 @@ var BackendImpl = class _BackendImpl {
984
1090
  async proposeIntention(input) {
985
1091
  await this.post(`/transaction/intention`, input, { headers: this.headers() });
986
1092
  }
987
- // TODO later
988
1093
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
989
1094
  async proposePendingTransaction(_input) {
990
1095
  return void 0;
@@ -1000,7 +1105,11 @@ var BackendImpl = class _BackendImpl {
1000
1105
  });
1001
1106
  }
1002
1107
  async buildNextIntentionAndAddToPending(input) {
1003
- await this.post(`/transaction/pending/build`, input, { headers: this.headers() });
1108
+ await this.post(
1109
+ `/transaction/pending/build`,
1110
+ { ...input, gasPrice: input.gasPrice.toString(), gasBudget: input.gasBudget.toString() },
1111
+ { headers: this.headers() }
1112
+ );
1004
1113
  }
1005
1114
  async skipNextFailedIntention(input) {
1006
1115
  await this.post(`/transaction/pending/skip`, input, { headers: this.headers() });
@@ -1103,7 +1212,6 @@ var MSafeEnv = /* @__PURE__ */ ((MSafeEnv3) => {
1103
1212
  MSafeEnv3["prod"] = "prod";
1104
1213
  return MSafeEnv3;
1105
1214
  })(MSafeEnv || {});
1106
- var MSAFE_APPLICATION = "msafe";
1107
1215
  var TESTNET_RPC_URL = "https://sui-testnet.blockvision.org/v1/2Sgk89ivT64MnKdcGzjmyjY2ndD";
1108
1216
  var MAINNET_RPC_URL = "https://sui-mainnet.blockvision.org/v1/2Sgk7NPvqkd7mESYkxF01yX15l7";
1109
1217
  var LOCAL_API_URL = "http://127.0.0.1:3000";
@@ -1301,7 +1409,6 @@ var MSafeClient = class _MSafeClient {
1301
1409
  LOCAL_API_URL,
1302
1410
  LOCAL_SYNCING_URL,
1303
1411
  MAINNET_RPC_URL,
1304
- MSAFE_APPLICATION,
1305
1412
  MSafeAccount,
1306
1413
  MSafeClient,
1307
1414
  MSafeEnv,