@msafe/sui3-sdk 0.0.12-pre-0fb7c20.0 → 0.0.12

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