@msafe/sui3-sdk 0.0.11 → 0.0.12-pre-84adfec.0

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