@msafe/sui3-sdk 0.0.12 → 0.0.13

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
@@ -536,818 +536,797 @@ var AddressBookSDK = class {
536
536
  };
537
537
 
538
538
  // src/core/MSafeAccount.ts
539
- import {
540
- buildIntentionTransaction,
541
- getIntentionType,
542
- MultisigAccountManager as MultisigAccountManager2
543
- } from "@msafe/sui3-utils";
539
+ import { buildIntentionTransaction, MultisigAccountManager as MultisigAccountManager2 } from "@msafe/sui3-utils";
544
540
  import { normalizeStructTag as normalizeStructTag3 } from "@mysten/sui.js/utils";
545
541
 
546
- // src/globals/const.ts
547
- var MSafeEnv = /* @__PURE__ */ ((MSafeEnv3) => {
548
- MSafeEnv3["local"] = "local";
549
- MSafeEnv3["unit"] = "unit";
550
- MSafeEnv3["dev"] = "dev";
551
- MSafeEnv3["prev"] = "prev";
552
- MSafeEnv3["prod"] = "prod";
553
- return MSafeEnv3;
554
- })(MSafeEnv || {});
555
- var UNIT_DATABASE_CONFIG = {
556
- type: "sqlite",
557
- database: ":memory:",
558
- logging: false
559
- };
560
- var LOCAL_DATABASE_CONFIG = {
561
- type: "mysql",
562
- host: "127.0.0.1",
563
- port: 3306,
564
- username: "msafe",
565
- password: "msafe",
566
- database: "msafe_sui_local",
567
- logging: false
568
- };
569
- var DEV_DATABASE_CONFIG = {
570
- type: "mysql",
571
- host: "msafe-dev-database.cluster-caos3ssocrx6.us-west-1.rds.amazonaws.com",
572
- port: 3306,
573
- username: "msafe",
574
- password: "Momentum.Safe2022",
575
- database: "msafe_sui_dev",
576
- logging: false
577
- };
578
- var MSAFE_APPLICATION = "msafe";
579
- var TESTNET_RPC_URL = "https://sui-testnet.blockvision.org/v1/2Sgk89ivT64MnKdcGzjmyjY2ndD";
580
- var MAINNET_RPC_URL = "https://sui-mainnet.blockvision.org/v1/2Sgk7NPvqkd7mESYkxF01yX15l7";
581
- var LOCAL_API_URL = "http://127.0.0.1:3000";
582
- var LOCAL_SYNCING_URL = "http://127.0.0.1:3001";
583
- var DEV_API_URL = "http://13.56.226.148";
584
- var DEV_SYNCING_URL = "http://52.53.228.20";
585
- var ENV_CONFIGS = /* @__PURE__ */ new Map([
586
- [
587
- "unit" /* unit */,
588
- {
589
- suiClient: {
590
- url: TESTNET_RPC_URL
591
- },
592
- backend: LOCAL_DATABASE_CONFIG,
593
- apiURL: LOCAL_API_URL,
594
- syncingURL: LOCAL_SYNCING_URL
595
- }
596
- ],
597
- [
598
- "local" /* local */,
599
- {
600
- suiClient: {
601
- url: TESTNET_RPC_URL
602
- },
603
- backend: LOCAL_DATABASE_CONFIG,
604
- apiURL: LOCAL_API_URL,
605
- syncingURL: LOCAL_SYNCING_URL
606
- }
607
- ],
608
- [
609
- "dev" /* dev */,
610
- {
611
- suiClient: {
612
- url: TESTNET_RPC_URL
613
- },
614
- backend: DEV_DATABASE_CONFIG,
615
- apiURL: DEV_API_URL,
616
- syncingURL: DEV_SYNCING_URL
617
- }
618
- ]
619
- ]);
620
- function getMSafeConfig(env, options) {
621
- const config = ENV_CONFIGS.get(env);
622
- if (!config) {
623
- throw new Error("Unknown environment");
624
- }
625
- if (options?.suiClient?.url) {
626
- config.suiClient.url = options.suiClient.url;
542
+ // src/utils/iter/iterator.ts
543
+ var REQUEST_PAGE_SIZE = 25;
544
+ async function getAllFromIterator(it) {
545
+ const res = [];
546
+ while (await it.hasNext()) {
547
+ const val = await it.next();
548
+ res.push(val);
627
549
  }
628
- if (options?.backend) {
629
- config.backend = options.backend;
550
+ if (res && Array.isArray(res[0])) {
551
+ return res.flat(1);
630
552
  }
631
- return config;
553
+ return res;
632
554
  }
633
- var AUTH_SIGN_MESSAGE = "Welcome to MSafe";
634
-
635
- // src/globals/MSafeGlobals.ts
636
- import { SuiClient } from "@mysten/sui.js/client";
637
-
638
- // src/backend/BackendImpl.ts
639
- import axios from "axios";
640
- var BackendImpl = class {
641
- constructor(apiURL) {
642
- this.apiURL = apiURL;
555
+ var PagedIterator = class {
556
+ constructor(requester) {
557
+ this.requester = requester;
558
+ this.curPage = void 0;
559
+ this.init = true;
643
560
  }
644
- _token;
645
- async authSign(input) {
646
- const res = await axios.post(`${this.apiURL}/auth/login`, input);
647
- if (res.status !== 200 && res.status !== 201) {
648
- throw new Error(`invalid authSign return: ${res}`);
561
+ curPage;
562
+ init;
563
+ async hasNext() {
564
+ if (this.init) {
565
+ if (!this.curPage) {
566
+ this.curPage = await this.requester.doNextRequest();
567
+ }
568
+ return !!this.curPage.data?.length || this.curPage.hasNext;
649
569
  }
650
- this._token = res.data.accessToken;
651
- return this._token;
570
+ if (!this.curPage) {
571
+ throw new Error("invalid implementation of iterator");
572
+ }
573
+ return this.curPage.hasNext;
652
574
  }
653
- async verifyToken(jwt) {
654
- try {
655
- const res = await axios.get(`${this.apiURL}/auth`, { headers: this.headers(jwt) });
656
- return res.status === 200;
657
- } catch (_) {
658
- return false;
575
+ async next() {
576
+ if (this.init) {
577
+ this.init = false;
578
+ if (!this.curPage) {
579
+ this.curPage = await this.requester.doNextRequest();
580
+ }
581
+ return this.curPage.data;
659
582
  }
583
+ this.curPage = await this.requester.doNextRequest();
584
+ return this.curPage.data;
660
585
  }
661
- setJWTToken(token) {
662
- this._token = token;
586
+ };
587
+ var EntryIterator = class {
588
+ constructor(requester) {
589
+ this.requester = requester;
590
+ this.pager = new PagedIterator(requester);
591
+ this.curData = [];
592
+ this.cursor = 0;
663
593
  }
664
- async getPublicKey(address) {
665
- return (await this.getPublicKeyBatch([address]))[0];
594
+ cursor;
595
+ pager;
596
+ curData;
597
+ async hasNext() {
598
+ if (this.cursor < this.curData.length - 1) {
599
+ return true;
600
+ }
601
+ return this.pager.hasNext();
666
602
  }
667
- async getPublicKeyBatch(addresses) {
668
- const res = await axios.post(
669
- `${this.apiURL}/account/getPublicKeyBatch`,
670
- addresses,
671
- {
672
- headers: this.headers()
603
+ async next() {
604
+ this.cursor += 1;
605
+ while (this.cursor >= this.curData.length) {
606
+ if (!await this.pager.hasNext()) {
607
+ throw new Error("not more data");
608
+ } else {
609
+ this.curData = await this.pager.next();
610
+ this.cursor = 0;
673
611
  }
674
- );
675
- if (res.status !== 200 && res.status !== 201) {
676
- throw new Error(`invalid getPublicKeyBatch return: ${res}`);
677
612
  }
678
- return res.data?.map(
679
- (publicKeyWithSchema) => publicKeyWithSchema ? PublicKeySerde.de({ ...publicKeyWithSchema }) : void 0
680
- );
613
+ return this.curData[this.cursor];
681
614
  }
682
- async getMSafeAccountInfo(msafeAddress) {
683
- const res = await axios.get(
684
- `${this.apiURL}/account/getMSafeAccountInfo/${msafeAddress}`,
685
- {
686
- headers: this.headers()
687
- }
688
- );
689
- if (res.status !== 200 && res.status !== 201) {
690
- throw new Error(`invalid getPublicKeyBatch return: ${res}`);
615
+ };
616
+
617
+ // src/utils/iter/object.ts
618
+ async function getAllOwnedObjects(provider, owner, options) {
619
+ const iter = new OwnedObjectIterator(provider, owner, options);
620
+ return await getAllFromIterator(iter);
621
+ }
622
+ var OwnedObjectIterator = class extends EntryIterator {
623
+ constructor(provider, owner, options) {
624
+ super(new OwnedObjectRequester(provider, owner, options));
625
+ this.provider = provider;
626
+ this.owner = owner;
627
+ this.options = options;
628
+ }
629
+ };
630
+ var OwnedObjectRequester = class {
631
+ constructor(provider, owner, options) {
632
+ this.provider = provider;
633
+ this.owner = owner;
634
+ this.options = options;
635
+ this.nextCursor = null;
636
+ this.filter = options?.filter;
637
+ this.pageSize = options?.pageSize || REQUEST_PAGE_SIZE;
638
+ this.objectOptions = options?.objectOptions || {
639
+ showType: true,
640
+ showContent: true
641
+ };
642
+ }
643
+ nextCursor;
644
+ filter;
645
+ pageSize;
646
+ objectOptions;
647
+ async doNextRequest() {
648
+ const res = await this.provider.getOwnedObjects({
649
+ owner: this.owner,
650
+ options: this.objectOptions,
651
+ cursor: this.nextCursor,
652
+ limit: this.pageSize
653
+ });
654
+ this.nextCursor = res.nextCursor;
655
+ let filtered;
656
+ if (this.filter) {
657
+ const { filter } = this;
658
+ filtered = res.data.filter((obj) => filter?.(obj));
659
+ } else {
660
+ filtered = res.data;
691
661
  }
692
- const msafeResp = res.data;
693
662
  return {
694
- address: msafeResp.address,
695
- ownersWithWeightPK: msafeResp.ownersWithWeightPKEncoded.map(
696
- (owner) => ({
697
- publicKey: PublicKeySerde.de({ publicKey: owner.publicKeyEncoded, scheme: owner.schema }),
698
- address: owner.address,
699
- weight: owner.weight
700
- })
701
- ),
702
- threshold: msafeResp.threshold,
703
- name: msafeResp.name,
704
- description: msafeResp.description,
705
- creationNonce: msafeResp.creationNonce
663
+ data: filtered.map((r) => r.data).filter((data) => data),
664
+ hasNext: res.hasNextPage
706
665
  };
707
666
  }
708
- async getUserInfo(userAddress) {
709
- const res = await axios.get(`${this.apiURL}/account/user/${userAddress}`, {
710
- headers: this.headers()
667
+ };
668
+
669
+ // src/core/MSafeAccount.ts
670
+ var MSafeAccount = class {
671
+ constructor(globals, info) {
672
+ this.globals = globals;
673
+ this.info = info;
674
+ this.multisigManager = new MultisigAccountManager2({
675
+ threshold: info.threshold,
676
+ ownersWithWeight: info.ownersWithWeightPK,
677
+ creationNonce: info.creationNonce
711
678
  });
712
- if (res.status !== 200 && res.status !== 201) {
713
- throw new Error(`invalid getPublicKeyBatch return: ${res}`);
679
+ this.coinHelper = new CoinHelper(this.suiClient);
680
+ }
681
+ multisigManager;
682
+ coinHelper;
683
+ static async new(globals, address) {
684
+ return globals.backend.getMSafeAccountInfo(address);
685
+ }
686
+ async ownedCoins() {
687
+ const balances = await this.suiClient.getAllBalances({ owner: this.address });
688
+ return Promise.all(
689
+ balances.map(async (balance) => {
690
+ const meta = await this.coinHelper.getCoinMeta(balance.coinType);
691
+ const unlockedBalance = balance.lockedBalance.number ? BigInt(balance.totalBalance) - BigInt(balance.lockedBalance.number) : BigInt(balance.totalBalance);
692
+ return {
693
+ type: normalizeStructTag3(balance.coinType),
694
+ balance: BigInt(unlockedBalance),
695
+ metadata: meta
696
+ };
697
+ })
698
+ );
699
+ }
700
+ async ownedObjects(options) {
701
+ const filterCoinObjectOptions = {
702
+ filter: (objRes) => !objRes?.data?.type?.startsWith("0x2::coin::Coin"),
703
+ ...options
704
+ };
705
+ return getAllOwnedObjects(this.suiClient, this.address, filterCoinObjectOptions);
706
+ }
707
+ async pendingTransaction() {
708
+ const pendings = await this.backend.getPendingTransactions(this.address);
709
+ if (pendings.length > 2) {
710
+ throw new Error(`invalid backend getPendingTransactions resp, length should not > 2: ${pendings}`);
711
+ }
712
+ if (pendings.length === 0) {
713
+ return void 0;
714
714
  }
715
+ const pendingTx = pendings.find((tx) => !tx.isRejectTx);
716
+ const rejectPending = pendings.find((tx) => tx.isRejectTx);
715
717
  return {
716
- address: res.data.address,
717
- publicKey: res.data.publicKey,
718
- schema: res.data.schema,
719
- creationNonce: res.data.creationNonce,
720
- ownedMSafe: res.data.ownedMSafe.map(
721
- (msafe) => ({
722
- address: msafe.address,
723
- ownersWithWeightPK: msafe.ownersWithWeightPKEncoded.map(
724
- (owner) => ({
725
- publicKey: PublicKeySerde.de({ publicKey: owner.publicKeyEncoded, scheme: owner.schema }),
726
- address: owner.address,
727
- weight: owner.weight
728
- })
729
- ),
730
- threshold: msafe.threshold,
731
- name: msafe.name,
732
- description: msafe.description,
733
- creationNonce: msafe.creationNonce
734
- })
735
- )
718
+ ...pendingTx,
719
+ rejectDigest: rejectPending?.digest ?? "",
720
+ rejectPayload: rejectPending?.payload ?? "",
721
+ rejectVotes: rejectPending?.votes ?? []
736
722
  };
737
723
  }
738
- async getPendingTransactions(msafeAddress) {
739
- const res = await axios.get(`${this.apiURL}/transaction/pending/${msafeAddress}`, {
740
- headers: this.headers()
741
- });
742
- if (res.status !== 200 && res.status !== 201) {
743
- throw new Error(`invalid getPublicKeyBatch return: ${res}`);
744
- }
745
- return res.data;
724
+ async historyTransaction(paginationOption) {
725
+ return this.backend.getHistoryTransactions(this.address, paginationOption);
746
726
  }
747
- async getHistoryTransactions(msafeAddress, paginationOption) {
748
- const res = await axios.get(
749
- `${this.apiURL}/transaction/history?address=${msafeAddress}`,
750
- {
751
- params: {
752
- page: paginationOption?.page,
753
- limit: paginationOption?.limit
754
- },
755
- headers: this.headers()
756
- }
757
- );
758
- if (res.status !== 200 && res.status !== 201) {
759
- throw new Error(`invalid getCurrentSequenceNumber return: ${res}`);
760
- }
761
- return res.data;
727
+ async futureIntentions(paginationOption) {
728
+ const paginatedIntentions = await this.backend.getFutureIntentions(this.address, paginationOption);
729
+ return paginatedIntentions.data;
762
730
  }
763
- async getFutureIntentions(msafeAddress, paginationOption) {
764
- const res = await axios.get(`${this.apiURL}/transaction/intention/${msafeAddress}`, {
765
- params: {
766
- page: paginationOption?.page,
767
- limit: paginationOption?.limit
768
- },
769
- headers: this.headers()
770
- });
771
- if (res.status !== 200 && res.status !== 201) {
772
- throw new Error(`invalid getCurrentSequenceNumber return: ${res}`);
773
- }
774
- return res.data;
731
+ async currentSequenceNumber() {
732
+ return this.backend.getCurrentSequenceNumber(this.address);
775
733
  }
776
- async getCurrentSequenceNumber(msafeAddress) {
777
- const res = await axios.get(`${this.apiURL}/transaction/sn/current/${msafeAddress}`, {
778
- headers: this.headers()
734
+ async nextSequenceNumber() {
735
+ return this.backend.getNextSequenceNumber(this.address);
736
+ }
737
+ async proposeIntention(input) {
738
+ const message = MessageHelper.proposeIntentionMessage({
739
+ msafeAddress: this.address,
740
+ intention: input.intention,
741
+ sn: input.sequenceNumber
742
+ });
743
+ const signature = await this.wallet.signPersonalMessage({
744
+ messageStr: message
745
+ });
746
+ await this.backend.proposeIntention({
747
+ ...input,
748
+ msafeAddress: this.address,
749
+ userAddress: await this.userAddress(),
750
+ signature: signature.signature
779
751
  });
780
- if (res.status !== 200 && res.status !== 201) {
781
- throw new Error(`invalid getCurrentSequenceNumber return: ${res}`);
782
- }
783
- return res.data;
784
752
  }
785
- async getNextSequenceNumber(msafeAddress) {
786
- const res = await axios.get(`${this.apiURL}/transaction/sn/next/${msafeAddress}`, {
787
- headers: this.headers()
753
+ async voteForTransaction(digest, payload) {
754
+ const payloadBytes = HexToUint8Array(payload);
755
+ const signature = await this.wallet.signTransactionBlock({ transactionBlock: payloadBytes });
756
+ return this.backend.voteForTransaction({
757
+ msafeAddress: this.address,
758
+ userAddress: await this.userAddress(),
759
+ txDigest: digest,
760
+ signature: signature.signature
788
761
  });
789
- if (res.status !== 200 && res.status !== 201) {
790
- throw new Error(`invalid getNextSequenceNumber return: ${res}`);
791
- }
792
- return res.data;
793
762
  }
794
- async createMSafeAccount(input) {
795
- const res = await axios.post(`${this.apiURL}/account`, input, {
796
- headers: this.headers()
763
+ // Shortcut for proposing a transaction to be a pending transaction, and add user vote to it.
764
+ // Requires the multi-sig to be empty in pending transaction.
765
+ async proposePendingTransaction(intention) {
766
+ const txb = await IntentionHelper.buildTxb({
767
+ suiClient: this.suiClient,
768
+ intention,
769
+ sender: this.address
770
+ });
771
+ const payload = await txb.build({ client: this.suiClient });
772
+ const digest = await txb.getDigest({ client: this.suiClient });
773
+ const signature = await this.wallet.signTransactionBlock({ transactionBlock: payload });
774
+ return this.backend.proposePendingTransaction({
775
+ msafeAddress: this.address,
776
+ userAddress: await this.userAddress(),
777
+ intention,
778
+ digest,
779
+ signature: signature.signature
797
780
  });
798
- if (res.status !== 200 && res.status !== 201) {
799
- throw new Error(`invalid createMSafeAccount return: ${res}`);
800
- }
801
781
  }
802
- async proposeIntention(input) {
803
- try {
804
- const res = await axios.post(
805
- `${this.apiURL}/transaction/intention`,
806
- {
807
- intention: input.intention,
808
- sequenceNumber: input.sequenceNumber,
809
- address: input.msafeAddress,
810
- signature: input.signature,
811
- application: input.application,
812
- txType: input.txType,
813
- txSubType: input.txSubType
814
- },
815
- { headers: this.headers() }
816
- );
817
- if (res.status !== 200 && res.status !== 201) {
818
- throw new Error(`invalid proposeIntention return: ${res}`);
782
+ async rejectCurrentTx(pending) {
783
+ let payloadToReject;
784
+ if (pending) {
785
+ if (pending.isRejectTx) {
786
+ throw new Error("Pending not reject transaction");
819
787
  }
820
- } catch (e) {
821
- console.log(e);
788
+ payloadToReject = pending.payload;
789
+ } else {
790
+ const pendingTx = await this.pendingTransaction();
791
+ if (!pendingTx || pendingTx.rejectDigest !== "") {
792
+ throw new Error("Already rejected");
793
+ }
794
+ payloadToReject = pendingTx.payload;
822
795
  }
796
+ const rejectTxb = await IntentionHelper.buildRejectTransaction({
797
+ msafeAddress: this.address,
798
+ payloadToReject
799
+ });
800
+ const digest = await rejectTxb.getDigest({ client: this.suiClient });
801
+ const payload = await rejectTxb.build({ client: this.suiClient });
802
+ const signature = await this.wallet.signTransactionBlock({ transactionBlock: payload });
803
+ return this.backend.rejectCurrentTx({
804
+ msafeAddress: this.address,
805
+ userAddress: await this.userAddress(),
806
+ digest,
807
+ signature: signature.signature
808
+ });
823
809
  }
824
- // TODO later
825
- async proposePendingTransaction(input) {
810
+ async buildNextIntentionAndAddToPending() {
811
+ return this.backend.buildNextIntentionAndAddToPending({ msafeAddress: this.address });
826
812
  }
827
- async rejectCurrentTx(input) {
828
- try {
829
- const res = await axios.post(
830
- `${this.apiURL}/transaction/pending/reject`,
831
- {
832
- address: input.msafeAddress,
833
- digest: input.digest,
834
- signature: input.signature
835
- },
836
- {
837
- headers: this.headers()
838
- }
839
- );
840
- if (res.status !== 200 && res.status !== 201) {
841
- throw new Error(`invalid voteForTransaction return: ${res}`);
842
- }
843
- } catch (e) {
844
- console.log("e:", e);
813
+ async skipNextFailedIntention() {
814
+ return this.backend.skipNextFailedIntention({ msafeAddress: this.address, userAddress: await this.userAddress() });
815
+ }
816
+ async simulateIntention(intention) {
817
+ const txb = await buildIntentionTransaction(this.suiClient, intention, this.address);
818
+ if (!txb.blockData.gasConfig.price) {
819
+ const refGas = await this.suiClient.getReferenceGasPrice();
820
+ txb.setGasPrice(refGas);
845
821
  }
822
+ const payload = await txb.build({ client: this.suiClient });
823
+ const dryRunResult = await this.suiClient.dryRunTransactionBlock({ transactionBlock: payload });
824
+ const success = dryRunResult.effects.status.status === "success";
825
+ const errorMsg = dryRunResult.effects.status.error;
826
+ const gasPrice = BigInt(txb.blockData.gasConfig.price);
827
+ const { gasUsed } = dryRunResult.effects;
828
+ return {
829
+ success,
830
+ errorMsg,
831
+ gasPrice,
832
+ gasUsed,
833
+ dryRunResult
834
+ };
846
835
  }
847
- async voteForTransaction(input) {
848
- const res = await axios.post(
849
- `${this.apiURL}/transaction/pending/vote`,
850
- {
851
- address: input.msafeAddress,
852
- digest: input.txDigest,
853
- signature: input.signature
854
- },
855
- {
856
- headers: this.headers()
857
- }
858
- );
859
- if (res.status !== 200 && res.status !== 201) {
860
- throw new Error(`invalid voteForTransaction return: ${res}`);
836
+ async executePendingTx(pending) {
837
+ let gotSigs;
838
+ let payload;
839
+ if (pending.votes.length >= this.info.threshold) {
840
+ gotSigs = new Map(pending.votes.map((vote) => [vote.userAddress, vote.signature]));
841
+ payload = pending.payload;
842
+ } else if (pending.rejectVotes && pending.rejectPayload && pending.rejectVotes?.length >= this.info.threshold) {
843
+ gotSigs = new Map(pending.rejectVotes.map((vote) => [vote.userAddress, vote.signature]));
844
+ payload = pending.rejectPayload;
845
+ } else {
846
+ throw new Error("Not enough signatures");
861
847
  }
862
- }
863
- async buildNextIntentionAndAddToPending(input) {
864
- const res = await axios.post(
865
- `${this.apiURL}/transaction/pending/build`,
866
- {
867
- address: input.msafeAddress
868
- },
869
- { headers: this.headers() }
870
- );
871
- if (res.status !== 200 && res.status !== 201) {
872
- throw new Error(`invalid buildNextIntentionAndAddToPending return: ${res}`);
848
+ const sigs = [];
849
+ for (let i = 0; i < this.info.ownersWithWeightPK.length; i++) {
850
+ const owner = this.info.ownersWithWeightPK[i];
851
+ const signature = gotSigs.get(owner.publicKey.toSuiAddress());
852
+ if (signature) {
853
+ sigs.push(signature);
854
+ }
873
855
  }
856
+ const multiSignature = this.multisigManager.combinePartialSignatures(sigs);
857
+ return this.suiClient.executeTransactionBlock({
858
+ transactionBlock: HexToUint8Array(payload),
859
+ signature: multiSignature,
860
+ options: { showEffects: true }
861
+ });
874
862
  }
875
- async skipNextFailedIntention(input) {
876
- const res = await axios.post(
877
- `${this.apiURL}/transaction/pending/skip`,
878
- {
879
- msafeAddress: input.msafeAddress
880
- },
881
- { headers: this.headers() }
882
- );
883
- if (res.status !== 200 && res.status !== 201) {
884
- throw new Error(`invalid skipNextFailedIntention return: ${res}`);
885
- }
863
+ get address() {
864
+ return this.info.address;
886
865
  }
887
- async getAddressBookEntries(pagination) {
888
- const res = await axios.get(`${this.apiURL}/address-book`, {
889
- headers: this.headers(),
890
- params: pagination
891
- });
892
- if (res.status !== 200) {
893
- throw new Error(`Invalid address-book return: ${res}`);
894
- }
895
- return res.data;
866
+ get backend() {
867
+ return this.globals.backend;
896
868
  }
897
- async updateAddressBook(input) {
898
- const res = await axios.post(`${this.apiURL}/address-book`, input, { headers: this.headers() });
899
- if (res.status !== 200 && res.status !== 201) {
900
- throw new Error(`invalid updateAddressBook return: ${res}`);
901
- }
869
+ get wallet() {
870
+ return this.globals.wallet;
902
871
  }
903
- async processExecutedTransaction(digest) {
872
+ async userAddress() {
873
+ return this.globals.wallet.address();
904
874
  }
905
- headers(token) {
906
- return { Authorization: `Bearer ${token || this._token}` };
875
+ get suiClient() {
876
+ return this.globals.suiClient;
907
877
  }
908
878
  };
909
879
 
910
- // src/globals/MSafeGlobals.ts
911
- var MSafeGlobals = class _MSafeGlobals {
912
- backend;
913
- suiClient;
914
- config;
915
- _wallet;
916
- constructor(input) {
917
- this.backend = input.backend;
918
- this.suiClient = input.suiClient;
919
- this.config = input.config;
880
+ // src/core/PublicKeyHelper.ts
881
+ var PublicKeyHelper = class {
882
+ constructor(globals) {
883
+ this.globals = globals;
884
+ this.knownPublicKeys = /* @__PURE__ */ new Map();
920
885
  }
921
- static async New(env, options) {
922
- const config = getMSafeConfig(env, options);
923
- const suiClient = new SuiClient(config.suiClient);
924
- const backend = new BackendImpl(config.apiURL);
925
- return new _MSafeGlobals({
926
- backend,
927
- suiClient,
928
- config
929
- });
886
+ knownPublicKeys;
887
+ async getPublicKey(address) {
888
+ const cached = this.knownPublicKeys.get(address);
889
+ if (cached) {
890
+ return cached;
891
+ }
892
+ const pk = await this._getPublicKey(address);
893
+ if (pk) {
894
+ this.knownPublicKeys.set(address, pk);
895
+ }
896
+ return pk;
930
897
  }
931
- connectWallet(wallet) {
932
- this._wallet = wallet;
898
+ async getPublicKeyBatch(addresses) {
899
+ const results = new Array(addresses.length).fill(void 0);
900
+ for (let i = 0; i < addresses.length; i++) {
901
+ const address = addresses[i];
902
+ results[i] = this.knownPublicKeys.get(address);
903
+ }
904
+ const emptyIndexes = results.map((elem, index) => elem === void 0 ? index : -1).filter((index) => index !== -1);
905
+ const backendResult = await this.globals.backend.getPublicKeyBatch(emptyIndexes.map((index) => addresses[index]));
906
+ for (let i = 0; i < emptyIndexes.length; i++) {
907
+ const index = emptyIndexes[i];
908
+ results[index] = backendResult[i];
909
+ }
910
+ for (let i = 0; i < results.length; i++) {
911
+ if (results[i] === void 0) {
912
+ results[i] = await this.getPublicKeyFromChain(addresses[i]);
913
+ }
914
+ }
915
+ for (let i = 0; i < addresses.length; i++) {
916
+ if (results[i]) {
917
+ this.knownPublicKeys.set(addresses[i], results[i]);
918
+ }
919
+ }
920
+ return results;
933
921
  }
934
- get wallet() {
935
- if (!this._wallet) {
936
- throw new Error("wallet not connected");
922
+ async _getPublicKey(address) {
923
+ const pkBackend = await this.getPublicKeyFromBackend(address);
924
+ if (pkBackend) {
925
+ return pkBackend;
937
926
  }
938
- return this._wallet;
927
+ const pkChain = await this.getPublicKeyFromChain(address);
928
+ if (pkChain) {
929
+ return pkChain;
930
+ }
931
+ return void 0;
939
932
  }
940
- set wallet(val) {
941
- this._wallet = val;
933
+ async getPublicKeyFromBackend(address) {
934
+ try {
935
+ const pk = await this.globals.backend.getPublicKey(address);
936
+ return pk;
937
+ } catch (_) {
938
+ return void 0;
939
+ }
940
+ }
941
+ async getPublicKeyFromChain(address) {
942
+ return getPublicKeyFromChain(this.globals.suiClient, address);
942
943
  }
943
944
  };
944
945
 
945
- // src/utils/iter/iterator.ts
946
- var REQUEST_PAGE_SIZE = 25;
947
- async function getAllFromIterator(it) {
948
- const res = [];
949
- while (await it.hasNext()) {
950
- const val = await it.next();
951
- res.push(val);
946
+ // src/globals/MSafeGlobals.ts
947
+ import { SuiClient } from "@mysten/sui.js/client";
948
+
949
+ // src/backend/BackendImpl.ts
950
+ import axios from "axios";
951
+ var BackendImpl = class {
952
+ constructor(apiURL) {
953
+ this.apiURL = apiURL;
952
954
  }
953
- if (res && Array.isArray(res[0])) {
954
- return res.flat(1);
955
+ _token;
956
+ async authSign(input) {
957
+ const res = await axios.post(`${this.apiURL}/auth/login`, input);
958
+ if (res.status !== 200 && res.status !== 201) {
959
+ throw new Error(`invalid authSign return: ${res}`);
960
+ }
961
+ this._token = res.data.accessToken;
962
+ return this._token;
955
963
  }
956
- return res;
957
- }
958
- var PagedIterator = class {
959
- constructor(requester) {
960
- this.requester = requester;
961
- this.curPage = void 0;
962
- this.init = true;
964
+ async verifyToken(jwt) {
965
+ try {
966
+ const res = await axios.get(`${this.apiURL}/auth`, { headers: this.headers(jwt) });
967
+ return res.status === 200;
968
+ } catch (_) {
969
+ return false;
970
+ }
963
971
  }
964
- curPage;
965
- init;
966
- async hasNext() {
967
- if (this.init) {
968
- if (!this.curPage) {
969
- this.curPage = await this.requester.doNextRequest();
972
+ setJWTToken(token) {
973
+ this._token = token;
974
+ }
975
+ async getPublicKey(address) {
976
+ return (await this.getPublicKeyBatch([address]))[0];
977
+ }
978
+ async getPublicKeyBatch(addresses) {
979
+ const res = await axios.post(
980
+ `${this.apiURL}/account/getPublicKeyBatch`,
981
+ addresses,
982
+ {
983
+ headers: this.headers()
970
984
  }
971
- return !!this.curPage.data?.length || this.curPage.hasNext;
972
- }
973
- if (!this.curPage) {
974
- throw new Error("invalid implementation of iterator");
985
+ );
986
+ if (res.status !== 200 && res.status !== 201) {
987
+ throw new Error(`invalid getPublicKeyBatch return: ${res}`);
975
988
  }
976
- return this.curPage.hasNext;
989
+ return res.data?.map(
990
+ (publicKeyWithSchema) => publicKeyWithSchema ? PublicKeySerde.de({ ...publicKeyWithSchema }) : void 0
991
+ );
977
992
  }
978
- async next() {
979
- if (this.init) {
980
- this.init = false;
981
- if (!this.curPage) {
982
- this.curPage = await this.requester.doNextRequest();
993
+ async getMSafeAccountInfo(msafeAddress) {
994
+ const res = await axios.get(
995
+ `${this.apiURL}/account/getMSafeAccountInfo/${msafeAddress}`,
996
+ {
997
+ headers: this.headers()
983
998
  }
984
- return this.curPage.data;
999
+ );
1000
+ if (res.status !== 200 && res.status !== 201) {
1001
+ throw new Error(`invalid getPublicKeyBatch return: ${res}`);
985
1002
  }
986
- this.curPage = await this.requester.doNextRequest();
987
- return this.curPage.data;
988
- }
989
- };
990
- var EntryIterator = class {
991
- constructor(requester) {
992
- this.requester = requester;
993
- this.pager = new PagedIterator(requester);
994
- this.curData = [];
995
- this.cursor = 0;
996
- }
997
- cursor;
998
- pager;
999
- curData;
1000
- async hasNext() {
1001
- if (this.cursor < this.curData.length - 1) {
1002
- return true;
1003
- }
1004
- return this.pager.hasNext();
1005
- }
1006
- async next() {
1007
- this.cursor += 1;
1008
- while (this.cursor >= this.curData.length) {
1009
- if (!await this.pager.hasNext()) {
1010
- throw new Error("not more data");
1011
- } else {
1012
- this.curData = await this.pager.next();
1013
- this.cursor = 0;
1014
- }
1015
- }
1016
- return this.curData[this.cursor];
1017
- }
1018
- };
1019
-
1020
- // src/utils/iter/object.ts
1021
- async function getAllOwnedObjects(provider, owner, options) {
1022
- const iter = new OwnedObjectIterator(provider, owner, options);
1023
- return await getAllFromIterator(iter);
1024
- }
1025
- var OwnedObjectIterator = class extends EntryIterator {
1026
- constructor(provider, owner, options) {
1027
- super(new OwnedObjectRequester(provider, owner, options));
1028
- this.provider = provider;
1029
- this.owner = owner;
1030
- this.options = options;
1031
- }
1032
- };
1033
- var OwnedObjectRequester = class {
1034
- constructor(provider, owner, options) {
1035
- this.provider = provider;
1036
- this.owner = owner;
1037
- this.options = options;
1038
- this.nextCursor = null;
1039
- this.filter = options?.filter;
1040
- this.pageSize = options?.pageSize || REQUEST_PAGE_SIZE;
1041
- this.objectOptions = options?.objectOptions || {
1042
- showType: true,
1043
- showContent: true
1003
+ const msafeResp = res.data;
1004
+ return {
1005
+ address: msafeResp.address,
1006
+ ownersWithWeightPK: msafeResp.ownersWithWeightPKEncoded.map(
1007
+ (owner) => ({
1008
+ publicKey: PublicKeySerde.de({ publicKey: owner.publicKeyEncoded, scheme: owner.schema }),
1009
+ address: owner.address,
1010
+ weight: owner.weight
1011
+ })
1012
+ ),
1013
+ threshold: msafeResp.threshold,
1014
+ name: msafeResp.name,
1015
+ description: msafeResp.description,
1016
+ creationNonce: msafeResp.creationNonce
1044
1017
  };
1045
1018
  }
1046
- nextCursor;
1047
- filter;
1048
- pageSize;
1049
- objectOptions;
1050
- async doNextRequest() {
1051
- const res = await this.provider.getOwnedObjects({
1052
- owner: this.owner,
1053
- options: this.objectOptions,
1054
- cursor: this.nextCursor,
1055
- limit: this.pageSize
1019
+ async getUserInfo(userAddress) {
1020
+ const res = await axios.get(`${this.apiURL}/account/user/${userAddress}`, {
1021
+ headers: this.headers()
1056
1022
  });
1057
- this.nextCursor = res.nextCursor;
1058
- let filtered;
1059
- if (this.filter) {
1060
- const { filter } = this;
1061
- filtered = res.data.filter((obj) => filter?.(obj));
1062
- } else {
1063
- filtered = res.data;
1023
+ if (res.status !== 200 && res.status !== 201) {
1024
+ throw new Error(`invalid getPublicKeyBatch return: ${res}`);
1064
1025
  }
1065
1026
  return {
1066
- data: filtered.map((r) => r.data).filter((data) => data),
1067
- hasNext: res.hasNextPage
1027
+ address: res.data.address,
1028
+ publicKey: res.data.publicKey,
1029
+ schema: res.data.schema,
1030
+ creationNonce: res.data.creationNonce,
1031
+ ownedMSafe: res.data.ownedMSafe.map(
1032
+ (msafe) => ({
1033
+ address: msafe.address,
1034
+ ownersWithWeightPK: msafe.ownersWithWeightPKEncoded.map(
1035
+ (owner) => ({
1036
+ publicKey: PublicKeySerde.de({ publicKey: owner.publicKeyEncoded, scheme: owner.schema }),
1037
+ address: owner.address,
1038
+ weight: owner.weight
1039
+ })
1040
+ ),
1041
+ threshold: msafe.threshold,
1042
+ name: msafe.name,
1043
+ description: msafe.description,
1044
+ creationNonce: msafe.creationNonce
1045
+ })
1046
+ )
1068
1047
  };
1069
1048
  }
1070
- };
1071
-
1072
- // src/core/MSafeAccount.ts
1073
- var MSafeAccount = class {
1074
- constructor(globals, info) {
1075
- this.globals = globals;
1076
- this.info = info;
1077
- this.multisigManager = new MultisigAccountManager2({
1078
- threshold: info.threshold,
1079
- ownersWithWeight: info.ownersWithWeightPK,
1080
- creationNonce: info.creationNonce
1049
+ async getPendingTransactions(msafeAddress) {
1050
+ const res = await axios.get(`${this.apiURL}/transaction/pending/${msafeAddress}`, {
1051
+ headers: this.headers()
1081
1052
  });
1082
- this.coinHelper = new CoinHelper(this.suiClient);
1083
- }
1084
- multisigManager;
1085
- coinHelper;
1086
- static async new(globals, address) {
1087
- return globals.backend.getMSafeAccountInfo(address);
1053
+ if (res.status !== 200 && res.status !== 201) {
1054
+ throw new Error(`invalid getPublicKeyBatch return: ${res}`);
1055
+ }
1056
+ return res.data;
1088
1057
  }
1089
- async ownedCoins() {
1090
- const balances = await this.suiClient.getAllBalances({ owner: this.address });
1091
- return Promise.all(
1092
- balances.map(async (balance) => {
1093
- const meta = await this.coinHelper.getCoinMeta(balance.coinType);
1094
- const unlockedBalance = balance.lockedBalance.number ? BigInt(balance.totalBalance) - BigInt(balance.lockedBalance.number) : BigInt(balance.totalBalance);
1095
- return {
1096
- type: normalizeStructTag3(balance.coinType),
1097
- balance: BigInt(unlockedBalance),
1098
- metadata: meta
1099
- };
1100
- })
1058
+ async getHistoryTransactions(msafeAddress, paginationOption) {
1059
+ const res = await axios.get(
1060
+ `${this.apiURL}/transaction/history?address=${msafeAddress}`,
1061
+ {
1062
+ params: {
1063
+ page: paginationOption?.page,
1064
+ limit: paginationOption?.limit
1065
+ },
1066
+ headers: this.headers()
1067
+ }
1101
1068
  );
1069
+ if (res.status !== 200 && res.status !== 201) {
1070
+ throw new Error(`invalid getCurrentSequenceNumber return: ${res}`);
1071
+ }
1072
+ return res.data;
1102
1073
  }
1103
- async ownedObjects(options) {
1104
- const filterCoinObjectOptions = {
1105
- filter: (objRes) => !objRes?.data?.type?.startsWith("0x2::coin::Coin"),
1106
- ...options
1107
- };
1108
- return getAllOwnedObjects(this.suiClient, this.address, filterCoinObjectOptions);
1074
+ async getFutureIntentions(msafeAddress, paginationOption) {
1075
+ const res = await axios.get(`${this.apiURL}/transaction/intention/${msafeAddress}`, {
1076
+ params: {
1077
+ page: paginationOption?.page,
1078
+ limit: paginationOption?.limit
1079
+ },
1080
+ headers: this.headers()
1081
+ });
1082
+ if (res.status !== 200 && res.status !== 201) {
1083
+ throw new Error(`invalid getCurrentSequenceNumber return: ${res}`);
1084
+ }
1085
+ return res.data;
1109
1086
  }
1110
- async pendingTransaction() {
1111
- const pendings = await this.backend.getPendingTransactions(this.address);
1112
- if (pendings.length > 2) {
1113
- throw new Error(`invalid backend getPendingTransactions resp, length should not > 2: ${pendings}`);
1087
+ async getCurrentSequenceNumber(msafeAddress) {
1088
+ const res = await axios.get(`${this.apiURL}/transaction/sn/current/${msafeAddress}`, {
1089
+ headers: this.headers()
1090
+ });
1091
+ if (res.status !== 200 && res.status !== 201) {
1092
+ throw new Error(`invalid getCurrentSequenceNumber return: ${res}`);
1114
1093
  }
1115
- if (pendings.length === 0) {
1116
- return void 0;
1094
+ return res.data;
1095
+ }
1096
+ async getNextSequenceNumber(msafeAddress) {
1097
+ const res = await axios.get(`${this.apiURL}/transaction/sn/next/${msafeAddress}`, {
1098
+ headers: this.headers()
1099
+ });
1100
+ if (res.status !== 200 && res.status !== 201) {
1101
+ throw new Error(`invalid getNextSequenceNumber return: ${res}`);
1117
1102
  }
1118
- const pendingTx = pendings.find((tx) => !tx.isRejectTx);
1119
- const rejectPending = pendings.find((tx) => tx.isRejectTx);
1120
- return {
1121
- ...pendingTx,
1122
- rejectDigest: rejectPending?.digest ?? "",
1123
- rejectPayload: rejectPending?.payload ?? "",
1124
- rejectVotes: rejectPending?.votes ?? []
1125
- };
1103
+ return res.data;
1126
1104
  }
1127
- async historyTransaction(paginationOption) {
1128
- return this.backend.getHistoryTransactions(this.address, paginationOption);
1105
+ async createMSafeAccount(input) {
1106
+ const res = await axios.post(`${this.apiURL}/account`, input, {
1107
+ headers: this.headers()
1108
+ });
1109
+ if (res.status !== 200 && res.status !== 201) {
1110
+ throw new Error(`invalid createMSafeAccount return: ${res}`);
1111
+ }
1129
1112
  }
1130
- async futureIntentions(paginationOption) {
1131
- const paginatedIntentions = await this.backend.getFutureIntentions(this.address, paginationOption);
1132
- return paginatedIntentions.data;
1113
+ async proposeIntention(input) {
1114
+ try {
1115
+ const res = await axios.post(`${this.apiURL}/transaction/intention`, input, { headers: this.headers() });
1116
+ if (res.status !== 200 && res.status !== 201) {
1117
+ throw new Error(`invalid proposeIntention return: ${res}`);
1118
+ }
1119
+ } catch (e) {
1120
+ console.log(e);
1121
+ }
1133
1122
  }
1134
- async currentSequenceNumber() {
1135
- return this.backend.getCurrentSequenceNumber(this.address);
1123
+ // TODO later
1124
+ async proposePendingTransaction(input) {
1136
1125
  }
1137
- async nextSequenceNumber() {
1138
- return this.backend.getNextSequenceNumber(this.address);
1126
+ async rejectCurrentTx(input) {
1127
+ try {
1128
+ const res = await axios.post(
1129
+ `${this.apiURL}/transaction/pending/reject`,
1130
+ {
1131
+ address: input.msafeAddress,
1132
+ digest: input.digest,
1133
+ signature: input.signature
1134
+ },
1135
+ {
1136
+ headers: this.headers()
1137
+ }
1138
+ );
1139
+ if (res.status !== 200 && res.status !== 201) {
1140
+ throw new Error(`invalid voteForTransaction return: ${res}`);
1141
+ }
1142
+ } catch (e) {
1143
+ console.log("e:", e);
1144
+ }
1139
1145
  }
1140
- async proposeIntention(intention, sequenceNumber) {
1141
- const message = MessageHelper.proposeIntentionMessage({
1142
- intention,
1143
- sn: sequenceNumber,
1144
- msafeAddress: this.address
1145
- });
1146
- const signature = await this.wallet.signPersonalMessage({
1147
- messageStr: message
1148
- });
1149
- const txType = getIntentionType(intention);
1150
- await this.backend.proposeIntention({
1151
- intention,
1152
- sequenceNumber,
1153
- msafeAddress: this.address,
1154
- userAddress: await this.userAddress(),
1155
- signature: signature.signature,
1156
- application: MSAFE_APPLICATION,
1157
- txType: txType.txType,
1158
- txSubType: txType.txSubType
1159
- });
1160
- }
1161
- async voteForTransaction(digest, payload) {
1162
- const payloadBytes = HexToUint8Array(payload);
1163
- const signature = await this.wallet.signTransactionBlock({ transactionBlock: payloadBytes });
1164
- return this.backend.voteForTransaction({
1165
- msafeAddress: this.address,
1166
- userAddress: await this.userAddress(),
1167
- txDigest: digest,
1168
- signature: signature.signature
1169
- });
1170
- }
1171
- // Shortcut for proposing a transaction to be a pending transaction, and add user vote to it.
1172
- // Requires the multi-sig to be empty in pending transaction.
1173
- async proposePendingTransaction(intention) {
1174
- const txb = await IntentionHelper.buildTxb({
1175
- suiClient: this.suiClient,
1176
- intention,
1177
- sender: this.address
1178
- });
1179
- const payload = await txb.build({ client: this.suiClient });
1180
- const digest = await txb.getDigest({ client: this.suiClient });
1181
- const signature = await this.wallet.signTransactionBlock({ transactionBlock: payload });
1182
- return this.backend.proposePendingTransaction({
1183
- msafeAddress: this.address,
1184
- userAddress: await this.userAddress(),
1185
- intention,
1186
- digest,
1187
- signature: signature.signature
1188
- });
1189
- }
1190
- async rejectCurrentTx(pending) {
1191
- let payloadToReject;
1192
- if (pending) {
1193
- if (pending.isRejectTx) {
1194
- throw new Error("Pending not reject transaction");
1195
- }
1196
- payloadToReject = pending.payload;
1197
- } else {
1198
- const pendingTx = await this.pendingTransaction();
1199
- if (!pendingTx || pendingTx.rejectDigest !== "") {
1200
- throw new Error("Already rejected");
1146
+ async voteForTransaction(input) {
1147
+ const res = await axios.post(
1148
+ `${this.apiURL}/transaction/pending/vote`,
1149
+ {
1150
+ address: input.msafeAddress,
1151
+ digest: input.txDigest,
1152
+ signature: input.signature
1153
+ },
1154
+ {
1155
+ headers: this.headers()
1201
1156
  }
1202
- payloadToReject = pendingTx.payload;
1157
+ );
1158
+ if (res.status !== 200 && res.status !== 201) {
1159
+ throw new Error(`invalid voteForTransaction return: ${res}`);
1203
1160
  }
1204
- const rejectTxb = await IntentionHelper.buildRejectTransaction({
1205
- msafeAddress: this.address,
1206
- payloadToReject
1207
- });
1208
- const digest = await rejectTxb.getDigest({ client: this.suiClient });
1209
- const payload = await rejectTxb.build({ client: this.suiClient });
1210
- const signature = await this.wallet.signTransactionBlock({ transactionBlock: payload });
1211
- return this.backend.rejectCurrentTx({
1212
- msafeAddress: this.address,
1213
- userAddress: await this.userAddress(),
1214
- digest,
1215
- signature: signature.signature
1216
- });
1217
- }
1218
- async buildNextIntentionAndAddToPending() {
1219
- return this.backend.buildNextIntentionAndAddToPending({ msafeAddress: this.address });
1220
1161
  }
1221
- async skipNextFailedIntention() {
1222
- return this.backend.skipNextFailedIntention({ msafeAddress: this.address, userAddress: await this.userAddress() });
1223
- }
1224
- async simulateIntention(intention) {
1225
- const txb = await buildIntentionTransaction(this.suiClient, intention, this.address);
1226
- if (!txb.blockData.gasConfig.price) {
1227
- const refGas = await this.suiClient.getReferenceGasPrice();
1228
- txb.setGasPrice(refGas);
1162
+ async buildNextIntentionAndAddToPending(input) {
1163
+ const res = await axios.post(
1164
+ `${this.apiURL}/transaction/pending/build`,
1165
+ {
1166
+ address: input.msafeAddress
1167
+ },
1168
+ { headers: this.headers() }
1169
+ );
1170
+ if (res.status !== 200 && res.status !== 201) {
1171
+ throw new Error(`invalid buildNextIntentionAndAddToPending return: ${res}`);
1229
1172
  }
1230
- const payload = await txb.build({ client: this.suiClient });
1231
- const dryRunResult = await this.suiClient.dryRunTransactionBlock({ transactionBlock: payload });
1232
- const success = dryRunResult.effects.status.status === "success";
1233
- const errorMsg = dryRunResult.effects.status.error;
1234
- const gasPrice = BigInt(txb.blockData.gasConfig.price);
1235
- const { gasUsed } = dryRunResult.effects;
1236
- return {
1237
- success,
1238
- errorMsg,
1239
- gasPrice,
1240
- gasUsed,
1241
- dryRunResult
1242
- };
1243
1173
  }
1244
- async executePendingTx(pending) {
1245
- let gotSigs;
1246
- let payload;
1247
- if (pending.votes.length >= this.info.threshold) {
1248
- gotSigs = new Map(pending.votes.map((vote) => [vote.userAddress, vote.signature]));
1249
- payload = pending.payload;
1250
- } else if (pending.rejectVotes && pending.rejectPayload && pending.rejectVotes?.length >= this.info.threshold) {
1251
- gotSigs = new Map(pending.rejectVotes.map((vote) => [vote.userAddress, vote.signature]));
1252
- payload = pending.rejectPayload;
1253
- } else {
1254
- throw new Error("Not enough signatures");
1255
- }
1256
- const sigs = [];
1257
- for (let i = 0; i < this.info.ownersWithWeightPK.length; i++) {
1258
- const owner = this.info.ownersWithWeightPK[i];
1259
- const signature = gotSigs.get(owner.publicKey.toSuiAddress());
1260
- if (signature) {
1261
- sigs.push(signature);
1262
- }
1174
+ async skipNextFailedIntention(input) {
1175
+ const res = await axios.post(
1176
+ `${this.apiURL}/transaction/pending/skip`,
1177
+ {
1178
+ msafeAddress: input.msafeAddress
1179
+ },
1180
+ { headers: this.headers() }
1181
+ );
1182
+ if (res.status !== 200 && res.status !== 201) {
1183
+ throw new Error(`invalid skipNextFailedIntention return: ${res}`);
1263
1184
  }
1264
- const multiSignature = this.multisigManager.combinePartialSignatures(sigs);
1265
- return this.suiClient.executeTransactionBlock({
1266
- transactionBlock: HexToUint8Array(payload),
1267
- signature: multiSignature,
1268
- options: { showEffects: true }
1269
- });
1270
1185
  }
1271
- get address() {
1272
- return this.info.address;
1273
- }
1274
- get backend() {
1275
- return this.globals.backend;
1186
+ async getAddressBookEntries(pagination) {
1187
+ const res = await axios.get(`${this.apiURL}/address-book`, {
1188
+ headers: this.headers(),
1189
+ params: pagination
1190
+ });
1191
+ if (res.status !== 200) {
1192
+ throw new Error(`Invalid address-book return: ${res}`);
1193
+ }
1194
+ return res.data;
1276
1195
  }
1277
- get wallet() {
1278
- return this.globals.wallet;
1196
+ async updateAddressBook(input) {
1197
+ const res = await axios.post(`${this.apiURL}/address-book`, input, { headers: this.headers() });
1198
+ if (res.status !== 200 && res.status !== 201) {
1199
+ throw new Error(`invalid updateAddressBook return: ${res}`);
1200
+ }
1279
1201
  }
1280
- async userAddress() {
1281
- return this.globals.wallet.address();
1202
+ async processExecutedTransaction(digest) {
1282
1203
  }
1283
- get suiClient() {
1284
- return this.globals.suiClient;
1204
+ headers(token) {
1205
+ return { Authorization: `Bearer ${token || this._token}` };
1285
1206
  }
1286
1207
  };
1287
1208
 
1288
- // src/core/PublicKeyHelper.ts
1289
- var PublicKeyHelper = class {
1290
- constructor(globals) {
1291
- this.globals = globals;
1292
- this.knownPublicKeys = /* @__PURE__ */ new Map();
1293
- }
1294
- knownPublicKeys;
1295
- async getPublicKey(address) {
1296
- const cached = this.knownPublicKeys.get(address);
1297
- if (cached) {
1298
- return cached;
1299
- }
1300
- const pk = await this._getPublicKey(address);
1301
- if (pk) {
1302
- this.knownPublicKeys.set(address, pk);
1303
- }
1304
- return pk;
1305
- }
1306
- async getPublicKeyBatch(addresses) {
1307
- const results = new Array(addresses.length).fill(void 0);
1308
- for (let i = 0; i < addresses.length; i++) {
1309
- const address = addresses[i];
1310
- results[i] = this.knownPublicKeys.get(address);
1311
- }
1312
- const emptyIndexes = results.map((elem, index) => elem === void 0 ? index : -1).filter((index) => index !== -1);
1313
- const backendResult = await this.globals.backend.getPublicKeyBatch(emptyIndexes.map((index) => addresses[index]));
1314
- for (let i = 0; i < emptyIndexes.length; i++) {
1315
- const index = emptyIndexes[i];
1316
- results[index] = backendResult[i];
1209
+ // src/globals/const.ts
1210
+ var MSafeEnv = /* @__PURE__ */ ((MSafeEnv3) => {
1211
+ MSafeEnv3["local"] = "local";
1212
+ MSafeEnv3["unit"] = "unit";
1213
+ MSafeEnv3["dev"] = "dev";
1214
+ MSafeEnv3["prev"] = "prev";
1215
+ MSafeEnv3["prod"] = "prod";
1216
+ return MSafeEnv3;
1217
+ })(MSafeEnv || {});
1218
+ var UNIT_DATABASE_CONFIG = {
1219
+ type: "sqlite",
1220
+ database: ":memory:",
1221
+ logging: false
1222
+ };
1223
+ var LOCAL_DATABASE_CONFIG = {
1224
+ type: "mysql",
1225
+ host: "127.0.0.1",
1226
+ port: 3306,
1227
+ username: "msafe",
1228
+ password: "msafe",
1229
+ database: "msafe_sui_local",
1230
+ logging: false
1231
+ };
1232
+ var DEV_DATABASE_CONFIG = {
1233
+ type: "mysql",
1234
+ host: "msafe-dev-database.cluster-caos3ssocrx6.us-west-1.rds.amazonaws.com",
1235
+ port: 3306,
1236
+ username: "msafe",
1237
+ password: "Momentum.Safe2022",
1238
+ database: "msafe_sui_dev",
1239
+ logging: false
1240
+ };
1241
+ var MSAFE_APPLICATION = "msafe";
1242
+ var TESTNET_RPC_URL = "https://sui-testnet.blockvision.org/v1/2Sgk89ivT64MnKdcGzjmyjY2ndD";
1243
+ var MAINNET_RPC_URL = "https://sui-mainnet.blockvision.org/v1/2Sgk7NPvqkd7mESYkxF01yX15l7";
1244
+ var LOCAL_API_URL = "http://127.0.0.1:3000";
1245
+ var LOCAL_SYNCING_URL = "http://127.0.0.1:3001";
1246
+ var DEV_API_URL = "http://13.56.226.148";
1247
+ var DEV_SYNCING_URL = "http://52.53.228.20";
1248
+ var ENV_CONFIGS = /* @__PURE__ */ new Map([
1249
+ [
1250
+ "unit" /* unit */,
1251
+ {
1252
+ suiClient: {
1253
+ url: TESTNET_RPC_URL
1254
+ },
1255
+ backend: LOCAL_DATABASE_CONFIG,
1256
+ apiURL: LOCAL_API_URL,
1257
+ syncingURL: LOCAL_SYNCING_URL
1317
1258
  }
1318
- for (let i = 0; i < results.length; i++) {
1319
- if (results[i] === void 0) {
1320
- results[i] = await this.getPublicKeyFromChain(addresses[i]);
1321
- }
1259
+ ],
1260
+ [
1261
+ "local" /* local */,
1262
+ {
1263
+ suiClient: {
1264
+ url: TESTNET_RPC_URL
1265
+ },
1266
+ backend: LOCAL_DATABASE_CONFIG,
1267
+ apiURL: LOCAL_API_URL,
1268
+ syncingURL: LOCAL_SYNCING_URL
1322
1269
  }
1323
- for (let i = 0; i < addresses.length; i++) {
1324
- if (results[i]) {
1325
- this.knownPublicKeys.set(addresses[i], results[i]);
1326
- }
1270
+ ],
1271
+ [
1272
+ "dev" /* dev */,
1273
+ {
1274
+ suiClient: {
1275
+ url: TESTNET_RPC_URL
1276
+ },
1277
+ backend: DEV_DATABASE_CONFIG,
1278
+ apiURL: DEV_API_URL,
1279
+ syncingURL: DEV_SYNCING_URL
1327
1280
  }
1328
- return results;
1281
+ ]
1282
+ ]);
1283
+ function getMSafeConfig(env, options) {
1284
+ const config = ENV_CONFIGS.get(env);
1285
+ if (!config) {
1286
+ throw new Error("Unknown environment");
1329
1287
  }
1330
- async _getPublicKey(address) {
1331
- const pkBackend = await this.getPublicKeyFromBackend(address);
1332
- if (pkBackend) {
1333
- return pkBackend;
1334
- }
1335
- const pkChain = await this.getPublicKeyFromChain(address);
1336
- if (pkChain) {
1337
- return pkChain;
1338
- }
1339
- return void 0;
1288
+ if (options?.suiClient?.url) {
1289
+ config.suiClient.url = options.suiClient.url;
1340
1290
  }
1341
- async getPublicKeyFromBackend(address) {
1342
- try {
1343
- const pk = await this.globals.backend.getPublicKey(address);
1344
- return pk;
1345
- } catch (_) {
1346
- return void 0;
1291
+ if (options?.backend) {
1292
+ config.backend = options.backend;
1293
+ }
1294
+ return config;
1295
+ }
1296
+ var AUTH_SIGN_MESSAGE = "Welcome to MSafe";
1297
+
1298
+ // src/globals/MSafeGlobals.ts
1299
+ var MSafeGlobals = class _MSafeGlobals {
1300
+ backend;
1301
+ suiClient;
1302
+ config;
1303
+ _wallet;
1304
+ constructor(input) {
1305
+ this.backend = input.backend;
1306
+ this.suiClient = input.suiClient;
1307
+ this.config = input.config;
1308
+ }
1309
+ static async New(env, options) {
1310
+ const config = getMSafeConfig(env, options);
1311
+ const suiClient = new SuiClient(config.suiClient);
1312
+ const backend = new BackendImpl(config.apiURL);
1313
+ return new _MSafeGlobals({
1314
+ backend,
1315
+ suiClient,
1316
+ config
1317
+ });
1318
+ }
1319
+ connectWallet(wallet) {
1320
+ this._wallet = wallet;
1321
+ }
1322
+ get wallet() {
1323
+ if (!this._wallet) {
1324
+ throw new Error("wallet not connected");
1347
1325
  }
1326
+ return this._wallet;
1348
1327
  }
1349
- async getPublicKeyFromChain(address) {
1350
- return getPublicKeyFromChain(this.globals.suiClient, address);
1328
+ set wallet(val) {
1329
+ this._wallet = val;
1351
1330
  }
1352
1331
  };
1353
1332