@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.js CHANGED
@@ -122,6 +122,7 @@ var InvitationSDK = class {
122
122
  };
123
123
 
124
124
  // src/core/MSafeAccount.ts
125
+ import { appHelpers } from "@msafe/sui-app-store";
125
126
  import {
126
127
  MultiSigAccount as MultiSigAccount2,
127
128
  SigningMessageHelper as SigningMessageHelper3,
@@ -132,9 +133,81 @@ import {
132
133
  buildRejectTxb,
133
134
  isSameAddress as isSameAddress2
134
135
  } from "@msafe/sui3-utils";
135
- import { TransactionBlock } from "@mysten/sui.js/transactions";
136
+ import { TransactionBlock as TransactionBlock2 } from "@mysten/sui.js/transactions";
136
137
  import { normalizeStructTag as normalizeStructTag3 } from "@mysten/sui.js/utils";
137
138
 
139
+ // src/simulate/simulator.ts
140
+ import { TransactionBlock } from "@mysten/sui.js/transactions";
141
+ var GAS_SAFE_OVERHEAD = 1000n;
142
+ var DEF_GAS_PRICE_NUM = 120n;
143
+ var DEF_GAS_PRICE_DEN = 100n;
144
+ var DEF_GAS_PRICE_OPTION = {
145
+ multiplier: {
146
+ numerator: DEF_GAS_PRICE_NUM,
147
+ denominator: DEF_GAS_PRICE_DEN
148
+ }
149
+ };
150
+ var Simulator = class {
151
+ constructor(globals) {
152
+ this.globals = globals;
153
+ }
154
+ async simulate(input, options = DEF_GAS_PRICE_OPTION) {
155
+ const tx = this.copyTransactionBlock(input.txb);
156
+ const { suiClient } = this.globals;
157
+ const gasPrice = await this.getGasPrice(options);
158
+ tx.setGasPrice(gasPrice);
159
+ const inspectResult = await suiClient.devInspectTransactionBlock({ transactionBlock: tx, sender: input.sender });
160
+ const { gasUsed } = inspectResult.effects;
161
+ const gasBudget = this.toGasBudget(gasUsed, gasPrice);
162
+ const success = inspectResult.effects.status.status === "success";
163
+ let error;
164
+ if (!success) {
165
+ error = inspectResult.effects.status.error;
166
+ }
167
+ return {
168
+ success,
169
+ gasPrice,
170
+ gasObject: inspectResult.effects.gasObject.reference,
171
+ gasUsed,
172
+ gasBudget,
173
+ simulationError: error
174
+ };
175
+ }
176
+ async getGasPrice(option) {
177
+ if (this.isFixedValue(option)) {
178
+ return option.fixedVal;
179
+ }
180
+ const refGasPrice = await this.globals.suiClient.getReferenceGasPrice();
181
+ return this.applyGasOption(refGasPrice, option);
182
+ }
183
+ toGasBudget(gasUsed, gasPrice) {
184
+ const { computationCost, storageCost } = gasUsed;
185
+ const safeOverhead = GAS_SAFE_OVERHEAD * gasPrice;
186
+ const baseComputationCostWithOverhead = BigInt(computationCost) + safeOverhead;
187
+ const gasBudget = baseComputationCostWithOverhead + BigInt(storageCost);
188
+ return gasBudget > baseComputationCostWithOverhead ? gasBudget : baseComputationCostWithOverhead;
189
+ }
190
+ isFixedValue(option) {
191
+ return "fixedVal" in option;
192
+ }
193
+ isMultiplier(option) {
194
+ return "multiplier" in option;
195
+ }
196
+ applyGasOption(val, option) {
197
+ if (this.isFixedValue(option)) {
198
+ return option.fixedVal;
199
+ }
200
+ if (this.isMultiplier(option)) {
201
+ const { multiplier } = option;
202
+ return val * multiplier.numerator / multiplier.denominator;
203
+ }
204
+ throw new Error("Sanity: Unknown gas price option");
205
+ }
206
+ copyTransactionBlock(tx) {
207
+ return TransactionBlock.from(tx.serialize());
208
+ }
209
+ };
210
+
138
211
  // src/utils/buffer.ts
139
212
  function stringToBuffer(s) {
140
213
  return Buffer.from(s, "utf-8");
@@ -484,9 +557,11 @@ var MSafeAccount = class _MSafeAccount {
484
557
  creationNonce: info.creationNonce
485
558
  });
486
559
  this.coinHelper = new CoinHelper(this.suiClient);
560
+ this.simulator = new Simulator(globals);
487
561
  }
488
562
  multiSig;
489
563
  coinHelper;
564
+ simulator;
490
565
  static async New(globals, address) {
491
566
  const info = await globals.backend.getMSafeAccountInfo(address);
492
567
  const ms = new _MSafeAccount(globals, info);
@@ -515,7 +590,6 @@ var MSafeAccount = class _MSafeAccount {
515
590
  };
516
591
  return getAllOwnedObjects(this.suiClient, this.address, filterCoinObjectOptions);
517
592
  }
518
- // TODO: Calculate the votes
519
593
  async pendingTransaction() {
520
594
  const res = await this.backend.getPendingTransactions({ msafeAddress: this.address });
521
595
  if (!res.pending) {
@@ -541,7 +615,6 @@ var MSafeAccount = class _MSafeAccount {
541
615
  rejectWeight: this.calculateWeightFromVotes(rejectPending?.votes ?? [])
542
616
  };
543
617
  }
544
- // TODO: Calculate the votes.
545
618
  async historyTransaction(pagination) {
546
619
  return this.backend.getHistoryTransactions({
547
620
  msafeAddress: this.address,
@@ -557,6 +630,22 @@ var MSafeAccount = class _MSafeAccount {
557
630
  async nextSequenceNumber() {
558
631
  return this.backend.getNextSequenceNumber(this.address);
559
632
  }
633
+ async simulateIntention(request) {
634
+ const appHelper = appHelpers.getAppHelper(request.application);
635
+ if (!appHelper) {
636
+ throw new Error(`Can't find app helper for application ${request.application}`);
637
+ }
638
+ const txb = await appHelper.build({
639
+ intentionData: request.intention,
640
+ txType: request.txType,
641
+ txSubType: request.txSubType,
642
+ suiClient: this.globals.suiClient,
643
+ account: {
644
+ address: this.address
645
+ }
646
+ });
647
+ return this.simulator.simulate({ txb, sender: this.address });
648
+ }
560
649
  async proposeIntention(input) {
561
650
  const message = SigningMessageHelper3.proposeIntentionMessage({
562
651
  msafeAddress: this.address,
@@ -566,12 +655,22 @@ var MSafeAccount = class _MSafeAccount {
566
655
  const signature = await this.wallet.signPersonalMessage({
567
656
  messageStr: message
568
657
  });
569
- await this.backend.proposeIntention({
658
+ return this.backend.proposeIntention({
570
659
  ...input,
571
660
  msafeAddress: this.address,
572
661
  signature: signature.signature
573
662
  });
574
663
  }
664
+ async simulateCoinTransferIntention(intention) {
665
+ const sn = await this.nextSequenceNumber();
666
+ return this.simulateIntention({
667
+ application: TransactionDefaultApplication,
668
+ txType: TransactionType.Assets,
669
+ txSubType: TransactionSubTypes.assets.coin.send,
670
+ sequenceNumber: sn,
671
+ intention
672
+ });
673
+ }
575
674
  async proposeCoinTransferIntention(intention) {
576
675
  const sn = await this.nextSequenceNumber();
577
676
  return this.proposeIntention({
@@ -595,7 +694,7 @@ var MSafeAccount = class _MSafeAccount {
595
694
  }
596
695
  async proposePlainPayloadIntention(intention) {
597
696
  const sn = await this.nextSequenceNumber();
598
- const tb = TransactionBlock.from(intention.payload);
697
+ const tb = TransactionBlock2.from(intention.payload);
599
698
  if (!tb.blockData.sender || !isSameAddress2(tb.blockData.sender, this.address)) {
600
699
  throw new Error("Transaction sender is not same as the multisig address");
601
700
  }
@@ -619,7 +718,7 @@ var MSafeAccount = class _MSafeAccount {
619
718
  // Shortcut for proposing a transaction to be a pending transaction, and add user vote to it.
620
719
  // Requires the multi-sig to be empty in pending transaction.
621
720
  async proposePendingTransaction(intention) {
622
- const txb = new TransactionBlock();
721
+ const txb = new TransactionBlock2();
623
722
  const payload = await txb.build({ client: this.suiClient });
624
723
  const digest = await txb.getDigest({ client: this.suiClient });
625
724
  const signature = await this.wallet.signTransactionBlock({ transactionBlock: payload });
@@ -647,33 +746,34 @@ var MSafeAccount = class _MSafeAccount {
647
746
  signature: signature.signature
648
747
  });
649
748
  }
650
- async buildNextIntentionAndAddToPending() {
651
- return this.backend.buildNextIntentionAndAddToPending({ msafeAddress: this.address });
749
+ async simulateBuildTransaction() {
750
+ const intention = await this.backend.getNextIntention({ msafeAddress: this.address });
751
+ const appHelper = appHelpers.getAppHelper(intention.application);
752
+ if (!appHelper) {
753
+ throw new Error(`Can't find app helper for application ${intention.application}`);
754
+ }
755
+ const txb = await appHelper.build({
756
+ intentionData: intention.intention,
757
+ txType: intention.txType,
758
+ txSubType: intention.txSubType,
759
+ suiClient: this.globals.suiClient,
760
+ account: {
761
+ address: this.address
762
+ }
763
+ });
764
+ return this.simulator.simulate({ txb, sender: this.address });
765
+ }
766
+ async buildNextIntentionAndAddToPending(gasOption) {
767
+ return this.backend.buildNextIntentionAndAddToPending({
768
+ msafeAddress: this.address,
769
+ forceBuild: gasOption.forceBuild,
770
+ gasPrice: gasOption.gasPrice,
771
+ gasBudget: gasOption.gasBudget
772
+ });
652
773
  }
653
774
  async skipNextFailedIntention() {
654
775
  return this.backend.skipNextFailedIntention({ msafeAddress: this.address });
655
776
  }
656
- async simulateIntention() {
657
- const txb = new TransactionBlock();
658
- txb.setSender(this.address);
659
- if (!txb.blockData.gasConfig.price) {
660
- const refGas = await this.suiClient.getReferenceGasPrice();
661
- txb.setGasPrice(refGas);
662
- }
663
- const payload = await txb.build({ client: this.suiClient });
664
- const dryRunResult = await this.suiClient.dryRunTransactionBlock({ transactionBlock: payload });
665
- const success = dryRunResult.effects.status.status === "success";
666
- const errorMsg = dryRunResult.effects.status.error;
667
- const gasPrice = BigInt(txb.blockData.gasConfig.price);
668
- const { gasUsed } = dryRunResult.effects;
669
- return {
670
- success,
671
- errorMsg,
672
- gasPrice,
673
- gasUsed,
674
- dryRunResult
675
- };
676
- }
677
777
  async executePendingTx(pending, isRejectTx = false) {
678
778
  const votes = isRejectTx ? pending.rejectVotes : pending.votes;
679
779
  const payload = isRejectTx ? pending.rejectPayload : pending.payload;
@@ -916,6 +1016,13 @@ var BackendImpl = class _BackendImpl {
916
1016
  });
917
1017
  return res.data;
918
1018
  }
1019
+ async getNextIntention(input) {
1020
+ const res = await this.get(`/transaction/intention/next`, {
1021
+ params: input,
1022
+ headers: this.headers()
1023
+ });
1024
+ return res.data;
1025
+ }
919
1026
  async getCurrentSequenceNumber(address) {
920
1027
  const res = await this.get(`/transaction/sn/current`, {
921
1028
  params: {
@@ -942,7 +1049,6 @@ var BackendImpl = class _BackendImpl {
942
1049
  async proposeIntention(input) {
943
1050
  await this.post(`/transaction/intention`, input, { headers: this.headers() });
944
1051
  }
945
- // TODO later
946
1052
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
947
1053
  async proposePendingTransaction(_input) {
948
1054
  return void 0;
@@ -958,7 +1064,11 @@ var BackendImpl = class _BackendImpl {
958
1064
  });
959
1065
  }
960
1066
  async buildNextIntentionAndAddToPending(input) {
961
- await this.post(`/transaction/pending/build`, input, { headers: this.headers() });
1067
+ await this.post(
1068
+ `/transaction/pending/build`,
1069
+ { ...input, gasPrice: input.gasPrice.toString(), gasBudget: input.gasBudget.toString() },
1070
+ { headers: this.headers() }
1071
+ );
962
1072
  }
963
1073
  async skipNextFailedIntention(input) {
964
1074
  await this.post(`/transaction/pending/skip`, input, { headers: this.headers() });
@@ -1061,7 +1171,6 @@ var MSafeEnv = /* @__PURE__ */ ((MSafeEnv3) => {
1061
1171
  MSafeEnv3["prod"] = "prod";
1062
1172
  return MSafeEnv3;
1063
1173
  })(MSafeEnv || {});
1064
- var MSAFE_APPLICATION = "msafe";
1065
1174
  var TESTNET_RPC_URL = "https://sui-testnet.blockvision.org/v1/2Sgk89ivT64MnKdcGzjmyjY2ndD";
1066
1175
  var MAINNET_RPC_URL = "https://sui-mainnet.blockvision.org/v1/2Sgk7NPvqkd7mESYkxF01yX15l7";
1067
1176
  var LOCAL_API_URL = "http://127.0.0.1:3000";
@@ -1258,7 +1367,6 @@ export {
1258
1367
  LOCAL_API_URL,
1259
1368
  LOCAL_SYNCING_URL,
1260
1369
  MAINNET_RPC_URL,
1261
- MSAFE_APPLICATION,
1262
1370
  MSafeAccount,
1263
1371
  MSafeClient,
1264
1372
  MSafeEnv,