@msafe/sui3-sdk 0.0.4-pre-6732d98.0 → 0.0.4

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
@@ -1,9 +1,7 @@
1
1
  "use strict";
2
- var __create = Object.create;
3
2
  var __defProp = Object.defineProperty;
4
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __getProtoOf = Object.getPrototypeOf;
7
5
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
6
  var __export = (target, all) => {
9
7
  for (var name in all)
@@ -17,14 +15,6 @@ var __copyProps = (to, from, except, desc) => {
17
15
  }
18
16
  return to;
19
17
  };
20
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
- // If the importer is in node compatibility mode or this is not an ESM
22
- // file that has been converted to a CommonJS file using a Babel-
23
- // compatible transform (i.e. "__esModule" has not been set), then set
24
- // "default" to the CommonJS "module.exports" for node compatibility.
25
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
- mod
27
- ));
28
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
19
 
30
20
  // src/index.ts
@@ -35,21 +25,28 @@ __export(src_exports, {
35
25
  Coin: () => Coin,
36
26
  CoinHelper: () => CoinHelper,
37
27
  CreateHelper: () => CreateHelper,
38
- DEV_API_URL: () => DEV_API_URL,
39
28
  DEV_DATABASE_CONFIG: () => DEV_DATABASE_CONFIG,
40
29
  ENV_CONFIGS: () => ENV_CONFIGS,
41
30
  Formatter: () => Formatter,
42
31
  HexToUint8Array: () => HexToUint8Array,
43
32
  IntentionHelper: () => IntentionHelper,
44
- LOCAL_API_URL: () => LOCAL_API_URL,
45
33
  LOCAL_DATABASE_CONFIG: () => LOCAL_DATABASE_CONFIG,
46
34
  MAINNET_RPC_URL: () => MAINNET_RPC_URL,
35
+ MAX_OWNER_WITHOUT_NONCE: () => MAX_OWNER_WITHOUT_NONCE,
36
+ MAX_OWNER_WITH_NONCE: () => MAX_OWNER_WITH_NONCE,
37
+ MAX_WEIGHT: () => MAX_WEIGHT,
38
+ MIN_THRESHOLD: () => MIN_THRESHOLD,
39
+ MIN_WEIGHT: () => MIN_WEIGHT,
47
40
  MSafeAccount: () => MSafeAccount,
48
41
  MSafeClient: () => MSafeClient,
49
42
  MSafeEnv: () => MSafeEnv,
50
43
  MSafeGlobals: () => MSafeGlobals,
51
44
  MessageHelper: () => MessageHelper,
45
+ NONCE_PK_PREFIX: () => NONCE_PK_PREFIX,
46
+ NONCE_PK_WEIGHT: () => NONCE_PK_WEIGHT,
47
+ NONCE_PREFIX_MAX_SIZE: () => NONCE_PREFIX_MAX_SIZE,
52
48
  PublicKeySerde: () => PublicKeySerde,
49
+ RawMultiSig: () => RawMultiSig,
53
50
  SUI_COIN: () => SUI_COIN,
54
51
  SignatureVerifier: () => SignatureVerifier,
55
52
  TESTNET_RPC_URL: () => TESTNET_RPC_URL,
@@ -57,31 +54,16 @@ __export(src_exports, {
57
54
  Uint8ArrayToHex: () => Uint8ArrayToHex,
58
55
  getAllCoins: () => getAllCoins,
59
56
  getMSafeConfig: () => getMSafeConfig,
57
+ getMultiSigPublicKey: () => getMultiSigPublicKey,
60
58
  getPublicKeyFromChain: () => getPublicKeyFromChain,
61
- stringToBuffer: () => stringToBuffer
59
+ makeNoncePublicKey: () => makeNoncePublicKey,
60
+ stringToBuffer: () => stringToBuffer,
61
+ validateMultiSigConfig: () => validateMultiSigConfig
62
62
  });
63
63
  module.exports = __toCommonJS(src_exports);
64
64
 
65
- // src/core/CreateHelper.ts
66
- var import_sui3_utils = require("@msafe/sui3-utils");
67
-
68
- // src/utils/crypto.ts
69
- var import_cryptography = require("@mysten/sui.js/cryptography");
70
- var import_ed25519 = require("@mysten/sui.js/keypairs/ed25519");
71
- var import_secp256k1 = require("@mysten/sui.js/keypairs/secp256k1");
72
- var import_secp256r1 = require("@mysten/sui.js/keypairs/secp256r1");
73
- var import_verify = require("@mysten/sui.js/verify");
74
-
75
- // src/utils/buffer.ts
76
- function stringToBuffer(s) {
77
- return Buffer.from(s, "utf-8");
78
- }
79
- function Uint8ArrayToHex(b) {
80
- return `0x${Array.prototype.map.call(b, (x) => `0${x.toString(16)}`.slice(-2)).join("")}`;
81
- }
82
- function HexToUint8Array(hex) {
83
- return Uint8Array.from(Buffer.from(hex.startsWith("0x") ? hex.slice(2) : hex, "hex"));
84
- }
65
+ // src/transactions/coin-transfer.ts
66
+ var import_transactions = require("@mysten/sui.js/transactions");
85
67
 
86
68
  // src/utils/format.ts
87
69
  var import_utils2 = require("@mysten/sui.js/utils");
@@ -157,6 +139,28 @@ var Formatter = class {
157
139
  }
158
140
  };
159
141
 
142
+ // src/utils/sui.ts
143
+ var import_cryptography2 = require("@mysten/sui.js/cryptography");
144
+ var import_multisig = require("@mysten/sui.js/multisig");
145
+
146
+ // src/utils/crypto.ts
147
+ var import_cryptography = require("@mysten/sui.js/cryptography");
148
+ var import_ed25519 = require("@mysten/sui.js/keypairs/ed25519");
149
+ var import_secp256k1 = require("@mysten/sui.js/keypairs/secp256k1");
150
+ var import_secp256r1 = require("@mysten/sui.js/keypairs/secp256r1");
151
+ var import_verify = require("@mysten/sui.js/verify");
152
+
153
+ // src/utils/buffer.ts
154
+ function stringToBuffer(s) {
155
+ return Buffer.from(s, "utf-8");
156
+ }
157
+ function Uint8ArrayToHex(b) {
158
+ return `0x${Array.prototype.map.call(b, (x) => `0${x.toString(16)}`.slice(-2)).join("")}`;
159
+ }
160
+ function HexToUint8Array(hex) {
161
+ return Uint8Array.from(Buffer.from(hex.startsWith("0x") ? hex.slice(2) : hex, "hex"));
162
+ }
163
+
160
164
  // src/utils/crypto.ts
161
165
  var SignatureVerifier = class _SignatureVerifier {
162
166
  static async getPublicKeyFromSignature(input) {
@@ -216,78 +220,7 @@ var PublicKeySerde = class {
216
220
  }
217
221
  };
218
222
 
219
- // src/core/CreateHelper.ts
220
- var CreateHelper = class {
221
- constructor(globals, pkHelper) {
222
- this.globals = globals;
223
- this.pkHelper = pkHelper;
224
- }
225
- async getPublicKeyBatch(addresses) {
226
- return this.pkHelper.getPublicKeyBatch(addresses);
227
- }
228
- async calculateMSafeAddress(info) {
229
- const msConfig = await this.reduceCreationInfoToRawConfig(info);
230
- const ms = new import_sui3_utils.MultisigAccountManager(msConfig);
231
- return ms.address;
232
- }
233
- // Validate the create info and return the msafe address.
234
- async validateCreateInfo(createInfo) {
235
- const rawConfig = await this.reduceCreationInfoToRawConfig(createInfo);
236
- (0, import_sui3_utils.validateCreateAccountRequest)(rawConfig);
237
- return this.calculateMSafeAddress(createInfo);
238
- }
239
- async submitMSafeCreation(creationInfo) {
240
- const msafeAddress = await this.validateCreateInfo(creationInfo);
241
- const signingMessage = (0, import_sui3_utils.createAccountCreationMessage)(msafeAddress);
242
- const signature = await this.globals.wallet.signPersonalMessage({ messageStr: signingMessage });
243
- await this.submitToBackend(creationInfo, signature.signature);
244
- return msafeAddress;
245
- }
246
- async reduceCreationInfoToRawConfig(info) {
247
- const publicKeys = await this.getPublicKeyBatch(info.ownerWithWeight.map((oww) => oww.address));
248
- publicKeys.forEach((pk, i) => {
249
- if (pk === void 0) {
250
- throw new Error(`Unknown public key for address: ${info.ownerWithWeight[i].address}`);
251
- }
252
- });
253
- return {
254
- threshold: info.threshold,
255
- ownersWithWeight: info.ownerWithWeight.map((owner, i) => ({
256
- publicKey: publicKeys[i],
257
- weight: owner.weight
258
- })),
259
- creationNonce: info.creationNonce
260
- };
261
- }
262
- async submitToBackend(createInfo, signature) {
263
- const pks = await this.pkHelper.getPublicKeyBatch(createInfo.ownerWithWeight.map((owner) => owner.address));
264
- await this.globals.backend.createMSafeAccount({
265
- ownersWithWeightPKEncoded: createInfo.ownerWithWeight.map((owner, i) => {
266
- const publicKeySer = PublicKeySerde.ser(pks[i]);
267
- return {
268
- address: owner.address,
269
- weight: owner.weight,
270
- publicKeyEncoded: publicKeySer.publicKey,
271
- schema: publicKeySer.scheme
272
- };
273
- }),
274
- threshold: createInfo.threshold,
275
- name: createInfo.name,
276
- // name validation is deferred to backend
277
- description: createInfo.description,
278
- // description validation is deferred to backend
279
- creationNonce: createInfo.creationNonce,
280
- signature
281
- });
282
- }
283
- };
284
-
285
- // src/transactions/coin-transfer.ts
286
- var import_transactions = require("@mysten/sui.js/transactions");
287
-
288
223
  // src/utils/sui.ts
289
- var import_cryptography2 = require("@mysten/sui.js/cryptography");
290
- var import_multisig = require("@mysten/sui.js/multisig");
291
224
  var SUI_COIN = "0x2::sui::SUI";
292
225
  async function getPublicKeyFromChain(suiClient, address) {
293
226
  let txs;
@@ -555,19 +488,165 @@ var MessageHelper = class {
555
488
  }
556
489
  };
557
490
 
491
+ // src/utils/multi-sig.ts
492
+ var import_ed255192 = require("@mysten/sui.js/keypairs/ed25519");
493
+ var import_multisig2 = require("@mysten/sui.js/multisig");
494
+ var NONCE_PK_PREFIX = "maven";
495
+ var NONCE_PREFIX_MAX_SIZE = 16;
496
+ var NONCE_PK_WEIGHT = 1;
497
+ var MAX_WEIGHT = 255;
498
+ var MIN_WEIGHT = 1;
499
+ var MAX_OWNER_WITH_NONCE = 9;
500
+ var MAX_OWNER_WITHOUT_NONCE = 10;
501
+ var MIN_THRESHOLD = 1;
502
+ var RawMultiSig = class _RawMultiSig {
503
+ constructor(config) {
504
+ this.config = config;
505
+ this.rawMsPK = getMultiSigPublicKey(config);
506
+ }
507
+ rawMsPK;
508
+ static fromMSafeAccountInfo(info) {
509
+ const parsed = {
510
+ threshold: info.threshold,
511
+ ownerWithWeight: info.ownersWithWeightPK,
512
+ creationNonce: info.creationNonce
513
+ };
514
+ return new _RawMultiSig(parsed);
515
+ }
516
+ get suiAddress() {
517
+ return this.rawMsPK.toSuiAddress();
518
+ }
519
+ get publicKeys() {
520
+ return this.rawMsPK.getPublicKeys();
521
+ }
522
+ get threshold() {
523
+ return this.config.threshold;
524
+ }
525
+ combinePartialSignatures(signatures) {
526
+ return this.rawMsPK.combinePartialSignatures(signatures);
527
+ }
528
+ async verifyPersonalMessage(messageStr, multiSigSignature) {
529
+ const message = stringToBuffer(messageStr);
530
+ return this.rawMsPK.verifyPersonalMessage(message, multiSigSignature);
531
+ }
532
+ };
533
+ function getMultiSigPublicKey(config) {
534
+ const { ownerWithWeight, threshold, creationNonce } = config;
535
+ const pks = ownerWithWeight.map((pk) => ({
536
+ publicKey: pk.publicKey,
537
+ weight: pk.weight
538
+ }));
539
+ if (creationNonce !== void 0) {
540
+ pks.push({
541
+ publicKey: makeNoncePublicKey(creationNonce),
542
+ weight: NONCE_PK_WEIGHT
543
+ });
544
+ }
545
+ return import_multisig2.MultiSigPublicKey.fromPublicKeys({ threshold, publicKeys: pks });
546
+ }
547
+ function makeNoncePublicKey(nonce) {
548
+ const buffer = new ArrayBuffer(import_ed255192.Ed25519PublicKey.SIZE);
549
+ const textEncoder = new TextEncoder();
550
+ textEncoder.encodeInto(NONCE_PK_PREFIX, new Uint8Array(buffer, 0, NONCE_PREFIX_MAX_SIZE));
551
+ const nonceView = new DataView(buffer, NONCE_PREFIX_MAX_SIZE, 4);
552
+ nonceView.setUint32(0, nonce, true);
553
+ return new import_ed255192.Ed25519PublicKey(new Uint8Array(buffer));
554
+ }
555
+ function validateMultiSigConfig(config) {
556
+ config.ownerWithWeight.forEach((pk) => {
557
+ const { weight } = pk;
558
+ if (weight < MIN_WEIGHT || weight > MAX_WEIGHT) {
559
+ throw new Error(`Invalid multi-sig weight: ${weight} (1-${MAX_WEIGHT})`);
560
+ }
561
+ });
562
+ const totalWeight = config.ownerWithWeight.reduce((s, pk) => s + pk.weight, 0);
563
+ if (config.threshold > totalWeight) {
564
+ throw new Error("Threshold is larger than total weight");
565
+ }
566
+ if (config.threshold < MIN_THRESHOLD) {
567
+ throw new Error("Threshold is smaller than 1");
568
+ }
569
+ const maxOwner = config.creationNonce === void 0 ? MAX_OWNER_WITHOUT_NONCE : MAX_OWNER_WITH_NONCE;
570
+ if (config.ownerWithWeight.length > maxOwner) {
571
+ throw new Error("Owner number bigger than upper cap");
572
+ }
573
+ const addressSet = new Set(config.ownerWithWeight.map((pk) => pk.publicKey.toSuiAddress()));
574
+ if (addressSet.size !== config.ownerWithWeight.length) {
575
+ throw new Error("Duplicate address detected");
576
+ }
577
+ }
578
+
579
+ // src/core/CreateHelper.ts
580
+ var CreateHelper = class {
581
+ constructor(globals, pkHelper) {
582
+ this.globals = globals;
583
+ this.pkHelper = pkHelper;
584
+ }
585
+ async getPublicKeyBatch(addresses) {
586
+ return this.pkHelper.getPublicKeyBatch(addresses);
587
+ }
588
+ async calculateMSafeAddress(info) {
589
+ const msConfig = await this.reduceCreationInfoToRawConfig(info);
590
+ const ms = new RawMultiSig(msConfig);
591
+ return ms.suiAddress;
592
+ }
593
+ // Validate the create info and return the msafe address.
594
+ async validateCreateInfo(createInfo) {
595
+ const rawConfig = await this.reduceCreationInfoToRawConfig(createInfo);
596
+ validateMultiSigConfig(rawConfig);
597
+ return this.calculateMSafeAddress(createInfo);
598
+ }
599
+ async submitMSafeCreation(creationInfo) {
600
+ const msafeAddress = await this.validateCreateInfo(creationInfo);
601
+ const signingMessage = MessageHelper.createMSafeMessage(msafeAddress);
602
+ const signature = await this.globals.wallet.signPersonalMessage({ messageStr: signingMessage });
603
+ await this.submitToBackend(creationInfo, signature.signature);
604
+ return msafeAddress;
605
+ }
606
+ async reduceCreationInfoToRawConfig(info) {
607
+ const publicKeys = await this.getPublicKeyBatch(info.ownerWithWeight.map((oww) => oww.address));
608
+ publicKeys.forEach((pk, i) => {
609
+ if (pk === void 0) {
610
+ throw new Error(`Unknown public key for address: ${info.ownerWithWeight[i].address}`);
611
+ }
612
+ });
613
+ return {
614
+ threshold: info.threshold,
615
+ ownerWithWeight: info.ownerWithWeight.map((owner, i) => ({
616
+ publicKey: publicKeys[i],
617
+ weight: owner.weight
618
+ })),
619
+ creationNonce: info.creationNonce
620
+ };
621
+ }
622
+ async submitToBackend(createInfo, signature) {
623
+ const pks = await this.pkHelper.getPublicKeyBatch(createInfo.ownerWithWeight.map((owner) => owner.address));
624
+ await this.globals.backend.createMSafeAccount({
625
+ ownerWithWeight: createInfo.ownerWithWeight.map((owner, i) => ({
626
+ address: owner.address,
627
+ weight: owner.weight,
628
+ publicKey: pks[i]
629
+ // PublicKey has been verified.
630
+ })),
631
+ threshold: createInfo.threshold,
632
+ name: createInfo.name,
633
+ // name validation is deferred to backend
634
+ description: createInfo.description,
635
+ // description validation is deferred to backend
636
+ creationNonce: createInfo.creationNonce,
637
+ signature
638
+ });
639
+ }
640
+ };
641
+
558
642
  // src/core/MSafeAccount.ts
559
- var import_sui3_utils2 = require("@msafe/sui3-utils");
560
643
  var MSafeAccount = class _MSafeAccount {
561
644
  constructor(globals, info) {
562
645
  this.globals = globals;
563
646
  this.info = info;
564
- this.multisigManager = new import_sui3_utils2.MultisigAccountManager({
565
- threshold: info.threshold,
566
- ownersWithWeight: info.ownersWithWeightPK,
567
- creationNonce: info.creationNonce
568
- });
647
+ this.rawMultiSig = RawMultiSig.fromMSafeAccountInfo(info);
569
648
  }
570
- multisigManager;
649
+ rawMultiSig;
571
650
  static async new(globals, address) {
572
651
  const info = await globals.backend.getMSafeAccountInfo(address);
573
652
  return new _MSafeAccount(globals, info);
@@ -676,7 +755,7 @@ var MSafeAccount = class _MSafeAccount {
676
755
  sigs.push(signature);
677
756
  }
678
757
  }
679
- const multiSignature = this.multisigManager.combinePartialSignatures(sigs);
758
+ const multiSignature = this.rawMultiSig.combinePartialSignatures(sigs);
680
759
  return this.suiClient.executeTransactionBlock({
681
760
  transactionBlock: HexToUint8Array(pending.payload),
682
761
  signature: multiSignature,
@@ -769,6 +848,762 @@ var PublicKeyHelper = class {
769
848
  // src/globals/MSafeGlobals.ts
770
849
  var import_client = require("@mysten/sui.js/client");
771
850
 
851
+ // src/backend/PseudoBackend.ts
852
+ var import_reflect_metadata2 = require("reflect-metadata");
853
+ var import_typeorm = require("typeorm");
854
+
855
+ // src/backend/CoreDatabase.ts
856
+ var import_reflect_metadata = require("reflect-metadata");
857
+ var import_core = require("@msafe/sui3-model/core");
858
+ var WALLET_TYPE_KEY = "wallet_type";
859
+ var CoreDB = class _CoreDB {
860
+ constructor(coreModel) {
861
+ this.coreModel = coreModel;
862
+ }
863
+ static async New(dbConfig) {
864
+ const core = await import_core.CoreModel.New(dbConfig);
865
+ return new _CoreDB(core);
866
+ }
867
+ async upsertUser(input) {
868
+ const currentUser = await this.coreModel.user.findOneBy({
869
+ address: input.address
870
+ });
871
+ if (currentUser !== null) {
872
+ currentUser.lastLogin = input.lastLogin;
873
+ await this.coreModel.user.save(currentUser);
874
+ } else {
875
+ const serializedPublicKey = PublicKeySerde.ser(input.publicKey);
876
+ const user = {
877
+ address: input.address,
878
+ publicKey: serializedPublicKey.publicKey,
879
+ schema: serializedPublicKey.scheme,
880
+ nonce: 0,
881
+ lastLogin: /* @__PURE__ */ new Date()
882
+ };
883
+ await this.coreModel.user.save(user);
884
+ }
885
+ }
886
+ async updateUserWalletType(input) {
887
+ const exist = await this.coreModel.userSetting.findOneBy({
888
+ userAddress: input.address,
889
+ key: WALLET_TYPE_KEY
890
+ });
891
+ const walletType = input.walletType.trim();
892
+ if (exist === null || exist.value !== walletType) {
893
+ const userSetting = {
894
+ userAddress: input.address,
895
+ key: WALLET_TYPE_KEY,
896
+ value: walletType
897
+ };
898
+ await this.coreModel.userSetting.save(userSetting);
899
+ }
900
+ }
901
+ };
902
+
903
+ // src/backend/PseudoBackend.ts
904
+ var PseudoBackend = class _PseudoBackend {
905
+ constructor(db, _suiClient) {
906
+ this.db = db;
907
+ this._suiClient = _suiClient;
908
+ }
909
+ _token;
910
+ static async New(dbConfig, suiClient) {
911
+ const db = await CoreDB.New(dbConfig);
912
+ return new _PseudoBackend(db, suiClient);
913
+ }
914
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars,unused-imports/no-unused-vars
915
+ async isJWTTokenValid(_jwt) {
916
+ return true;
917
+ }
918
+ async authSign(input) {
919
+ const timestamp = MessageHelper.deWelcomeMessage(input.message);
920
+ if (!timestamp) {
921
+ throw new Error("Invalid welcome message");
922
+ }
923
+ const date = Date.parse(timestamp);
924
+ if ((/* @__PURE__ */ new Date()).getTime() - date < 0) {
925
+ throw new Error("Invalid timestamp");
926
+ }
927
+ if ((/* @__PURE__ */ new Date()).getTime() - date > 10 * 1e3) {
928
+ throw new Error("Signing message expired");
929
+ }
930
+ const publicKey = await SignatureVerifier.getPublicKeyFromPersonalSignature({
931
+ messageStr: input.message,
932
+ signature: input.signature
933
+ });
934
+ if (!Formatter.isSuiAddressEqual(input.address, publicKey.toSuiAddress())) {
935
+ throw new Error("Invalid signature");
936
+ }
937
+ await this.db.upsertUser({
938
+ address: input.address,
939
+ publicKey,
940
+ lastLogin: /* @__PURE__ */ new Date()
941
+ });
942
+ await this.db.updateUserWalletType({
943
+ address: input.address,
944
+ walletType: input.walletType
945
+ });
946
+ this._token = "";
947
+ return this._token;
948
+ }
949
+ setJWTToken(token) {
950
+ this._token = token;
951
+ }
952
+ async getPublicKey(address) {
953
+ const user = await this.model.user.findOneBy({
954
+ address
955
+ });
956
+ if (user === null) {
957
+ return void 0;
958
+ }
959
+ return PublicKeySerde.de({
960
+ publicKey: user.publicKey,
961
+ scheme: user.schema
962
+ });
963
+ }
964
+ async getPublicKeyBatch(addresses) {
965
+ const res = [];
966
+ for (let i = 0; i < addresses.length; i++) {
967
+ const address = addresses[i];
968
+ const user = await this.getUser(address);
969
+ res.push(
970
+ user ? PublicKeySerde.de({
971
+ publicKey: user.publicKey,
972
+ scheme: user.schema
973
+ }) : void 0
974
+ );
975
+ }
976
+ return res;
977
+ }
978
+ async createMSafeAccount(input) {
979
+ const ms = new RawMultiSig(input);
980
+ const msafeAddr = ms.suiAddress;
981
+ const signingMsg = MessageHelper.createMSafeMessage(msafeAddr);
982
+ const targetAddr = input.ownerWithWeight[0].address;
983
+ const verifyResult = await SignatureVerifier.verifyPersonalSignature({
984
+ messageStr: signingMsg,
985
+ signature: input.signature,
986
+ targetAddress: targetAddr
987
+ });
988
+ if (!verifyResult) {
989
+ throw new Error("Signature verification failed");
990
+ }
991
+ if (input.name.length > 128) {
992
+ throw new Error("Name too long");
993
+ }
994
+ if (input.description && input.description.length > 512) {
995
+ throw new Error("Description too long");
996
+ }
997
+ const creatorAddress = input.ownerWithWeight[0].address;
998
+ const creator = await this.getUser(creatorAddress);
999
+ if (creator === null) {
1000
+ throw new Error("Creator not found");
1001
+ }
1002
+ if (creator.nonce !== input.creationNonce) {
1003
+ throw new Error("Nonce not match");
1004
+ }
1005
+ const msafeExistCheck = await this.model.msafe.findOneBy({
1006
+ address: msafeAddr
1007
+ });
1008
+ if (msafeExistCheck !== null) {
1009
+ throw new Error("MSafe already exist in database");
1010
+ }
1011
+ input.ownerWithWeight.forEach((ownerInfo) => {
1012
+ if (!Formatter.isSuiAddressEqual(ownerInfo.address, ownerInfo.publicKey.toSuiAddress())) {
1013
+ throw new Error("Sui address public key not match");
1014
+ }
1015
+ });
1016
+ for (let i = 0; i !== input.ownerWithWeight.length; i++) {
1017
+ const ownerInfo = input.ownerWithWeight[i];
1018
+ if (i !== 0) {
1019
+ const coManager = await this.getUser(ownerInfo.address);
1020
+ const serPK = PublicKeySerde.ser(ownerInfo.publicKey);
1021
+ if (coManager === null) {
1022
+ const user = {
1023
+ address: ownerInfo.address,
1024
+ publicKey: serPK.publicKey,
1025
+ schema: serPK.scheme,
1026
+ nonce: 0,
1027
+ lastLogin: /* @__PURE__ */ new Date()
1028
+ };
1029
+ await this.model.user.save(user);
1030
+ }
1031
+ }
1032
+ const userMSafe = {
1033
+ userAddress: ownerInfo.address,
1034
+ msafeAddress: msafeAddr,
1035
+ index: i,
1036
+ weight: ownerInfo.weight,
1037
+ status: i === 0 ? "active" : "pending"
1038
+ };
1039
+ await this.model.userMSafe.save(userMSafe);
1040
+ }
1041
+ const creationNonce = creator.nonce;
1042
+ creator.nonce++;
1043
+ await this.model.user.save(creator);
1044
+ const msafe = {
1045
+ address: msafeAddr,
1046
+ creationNonce,
1047
+ creator: creatorAddress,
1048
+ name: input.name,
1049
+ description: input.description,
1050
+ threshold: input.threshold
1051
+ };
1052
+ await this.model.msafe.save(msafe);
1053
+ }
1054
+ async getMSafeAccountInfo(msafeAddress) {
1055
+ const msafe = await this.model.msafe.findOneBy({ address: msafeAddress });
1056
+ if (msafe === null) {
1057
+ throw new Error("MSafe not found");
1058
+ }
1059
+ const userMSafes = await this.model.userMSafe.find({
1060
+ where: {
1061
+ msafeAddress
1062
+ },
1063
+ order: {
1064
+ index: "asc"
1065
+ }
1066
+ });
1067
+ if (userMSafes.length === 0) {
1068
+ throw new Error("MSafe does not have user info.");
1069
+ }
1070
+ const users = await Promise.all(userMSafes.map((um) => this.getUser(um.userAddress)));
1071
+ users.forEach((user) => {
1072
+ if (user === null) {
1073
+ throw new Error("User not found");
1074
+ }
1075
+ });
1076
+ const ownersWithWeightPK = userMSafes.map((userMSafe, i) => ({
1077
+ address: userMSafe.userAddress,
1078
+ weight: userMSafe.weight,
1079
+ publicKey: PublicKeySerde.de({ publicKey: users[i].publicKey, scheme: users[i].schema })
1080
+ }));
1081
+ return {
1082
+ address: msafeAddress,
1083
+ ownersWithWeightPK,
1084
+ threshold: msafe.threshold,
1085
+ name: msafe.name,
1086
+ description: msafe.description,
1087
+ creationNonce: msafe.creationNonce
1088
+ };
1089
+ }
1090
+ async getUserInfo(userAddress) {
1091
+ const user = await this.getUser(userAddress);
1092
+ if (user === null) {
1093
+ throw new Error("404: user not found");
1094
+ }
1095
+ const msafeAccounts = await this.model.userMSafe.findBy({ userAddress });
1096
+ const ownedMSafe = await Promise.all(
1097
+ msafeAccounts.map(async (msafeAccount) => this.getMSafeAccountInfo(msafeAccount.msafeAddress))
1098
+ );
1099
+ return {
1100
+ address: userAddress,
1101
+ publicKey: user.publicKey,
1102
+ schema: user.schema,
1103
+ creationNonce: user.nonce,
1104
+ ownedMSafe
1105
+ };
1106
+ }
1107
+ async getPendingTransactions(msafeAddress) {
1108
+ const pendings = await this.db.coreModel.pendingTransaction.findBy({
1109
+ msafeAddress
1110
+ });
1111
+ if (pendings.length === 0) {
1112
+ return [];
1113
+ }
1114
+ const votes = await Promise.all(
1115
+ pendings.map((pending) => this.db.coreModel.userVote.findBy({ txDigest: pending.digest, isValid: true }))
1116
+ );
1117
+ const intention = await this.model.transactionIntention.findOneBy({
1118
+ msafeAddress,
1119
+ sequenceNumber: pendings[0].sequenceNumber
1120
+ });
1121
+ if (intention === null) {
1122
+ throw new Error("Intention not found");
1123
+ }
1124
+ const intent = IntentionHelper.de(intention.data);
1125
+ return pendings.map((pending, i) => ({
1126
+ digest: pending.digest,
1127
+ payload: pending.payload,
1128
+ msafeAddress: pending.msafeAddress,
1129
+ isRejectTx: pending.isRejectTx,
1130
+ creator: pending.creator,
1131
+ createdAt: pending.createdAt,
1132
+ votes: votes[i].map((vote) => ({
1133
+ userAddress: vote.userAddress,
1134
+ signature: vote.signature,
1135
+ timestamp: vote.updatedAt
1136
+ })),
1137
+ sequenceNumber: pending.sequenceNumber,
1138
+ intention: pending.isRejectTx ? void 0 : intent
1139
+ }));
1140
+ }
1141
+ async getCurrentSequenceNumber(msafeAddress) {
1142
+ const maxSNHistory = await this.model.historyTransaction.findOne({
1143
+ where: { msafeAddress },
1144
+ order: { sequenceNumber: "desc" }
1145
+ });
1146
+ return maxSNHistory === null ? 0 : maxSNHistory.sequenceNumber + 1;
1147
+ }
1148
+ async getNextSequenceNumber(msafeAddress) {
1149
+ const maxSNIntention = await this.model.transactionIntention.findOne({
1150
+ where: { msafeAddress },
1151
+ order: { sequenceNumber: "desc" }
1152
+ });
1153
+ return maxSNIntention === null ? 0 : maxSNIntention.sequenceNumber + 1;
1154
+ }
1155
+ async getHistoryTransactions(msafeAddress) {
1156
+ const transactions = await this.db.coreModel.historyTransaction.find({
1157
+ where: {
1158
+ msafeAddress
1159
+ },
1160
+ order: { sequenceNumber: "desc" }
1161
+ });
1162
+ const votes = await Promise.all(
1163
+ transactions.map(
1164
+ (tx) => this.db.coreModel.userVote.findBy({
1165
+ txDigest: tx.digest,
1166
+ isValid: true
1167
+ })
1168
+ )
1169
+ );
1170
+ return transactions.map((tx, i) => ({
1171
+ digest: tx.digest,
1172
+ payload: tx.payload,
1173
+ msafeAddress: tx.msafeAddress,
1174
+ isRejectTx: tx.isRejectTx,
1175
+ status: tx.status,
1176
+ creator: tx.creator,
1177
+ createdAt: tx.createdAt,
1178
+ sequenceNumber: tx.sequenceNumber,
1179
+ votes: votes[i].map((vote) => ({
1180
+ userAddress: vote.userAddress,
1181
+ timestamp: vote.updatedAt
1182
+ }))
1183
+ }));
1184
+ }
1185
+ async getFutureIntentions(msafeAddress) {
1186
+ const currentSequenceNumber = await this.getCurrentSequenceNumber(msafeAddress);
1187
+ const hasPending = await this.model.pendingTransaction.findOneBy({ msafeAddress }) !== null;
1188
+ const futureSNStart = hasPending ? currentSequenceNumber + 1 : currentSequenceNumber;
1189
+ const futureTxs = await this.model.transactionIntention.find({
1190
+ where: { msafeAddress, sequenceNumber: (0, import_typeorm.MoreThanOrEqual)(futureSNStart) },
1191
+ order: { sequenceNumber: "asc" }
1192
+ });
1193
+ return futureTxs.map((tx) => ({
1194
+ intention: IntentionHelper.de(tx.data),
1195
+ msafeAddress: tx.msafeAddress,
1196
+ sequenceNumber: tx.sequenceNumber,
1197
+ rawData: tx.data,
1198
+ txType: tx.txType,
1199
+ txSubType: tx.txSubType,
1200
+ processed: tx.processed,
1201
+ status: tx.status,
1202
+ statusRemark: tx.statusRemark,
1203
+ creator: tx.creator,
1204
+ createdAt: tx.createdAt
1205
+ }));
1206
+ }
1207
+ async proposeIntention(input) {
1208
+ const userMSafe = await this.model.userMSafe.findOneBy({
1209
+ msafeAddress: input.msafeAddress,
1210
+ userAddress: input.userAddress
1211
+ });
1212
+ if (!userMSafe) {
1213
+ throw new Error("User does not have permission to propose intention");
1214
+ }
1215
+ const verified = await SignatureVerifier.verifyPersonalSignature({
1216
+ messageStr: MessageHelper.proposeIntentionMessage({ intention: input.intention, sn: input.sequenceNumber }),
1217
+ signature: input.signature,
1218
+ targetAddress: input.userAddress
1219
+ });
1220
+ if (!verified) {
1221
+ throw new Error("Invalid signature");
1222
+ }
1223
+ const sequenceNumber = await this.model.transactionIntention.count({
1224
+ where: {
1225
+ msafeAddress: input.msafeAddress
1226
+ }
1227
+ });
1228
+ if (sequenceNumber !== input.sequenceNumber) {
1229
+ throw new Error("Sequence number not expected");
1230
+ }
1231
+ const intention = {
1232
+ msafeAddress: input.msafeAddress,
1233
+ sequenceNumber,
1234
+ processed: false,
1235
+ ...IntentionHelper.getTxType(input.intention),
1236
+ data: IntentionHelper.ser(input.intention),
1237
+ status: "NEW",
1238
+ creator: input.userAddress
1239
+ };
1240
+ await this.model.transactionIntention.save(intention);
1241
+ }
1242
+ // Propose a pending transaction. Require the msafe account
1243
+ // Does not have any pending transactions.
1244
+ async proposePendingTransaction(input) {
1245
+ const userMSafe = await this.model.userMSafe.findOneBy({
1246
+ msafeAddress: input.msafeAddress,
1247
+ userAddress: input.userAddress
1248
+ });
1249
+ if (userMSafe === null) {
1250
+ throw new Error("Unauthorized");
1251
+ }
1252
+ const msafePendings = await this.model.pendingTransaction.findBy({
1253
+ msafeAddress: input.msafeAddress
1254
+ });
1255
+ if (msafePendings.length !== 0) {
1256
+ throw new Error("Still have pending transaction");
1257
+ }
1258
+ const txb = await IntentionHelper.buildTxb({
1259
+ suiClient: this._suiClient,
1260
+ intention: input.intention,
1261
+ sender: input.msafeAddress
1262
+ });
1263
+ const payload = await txb.build({ client: this._suiClient });
1264
+ const txDigest = await txb.getDigest({ client: this._suiClient });
1265
+ if (txDigest !== input.digest) {
1266
+ throw new Error("Transaction digest un-match");
1267
+ }
1268
+ const verified = await SignatureVerifier.verifyTransactionSignature({
1269
+ payload,
1270
+ targetAddress: input.userAddress,
1271
+ signature: input.signature
1272
+ });
1273
+ if (!verified) {
1274
+ throw new Error("Failed to verify signature");
1275
+ }
1276
+ const maxSNHistory = await this.model.historyTransaction.findOne({
1277
+ where: { msafeAddress: input.msafeAddress },
1278
+ order: { sequenceNumber: "desc" }
1279
+ });
1280
+ const sequenceNumber = maxSNHistory === null ? 0 : maxSNHistory.sequenceNumber + 1;
1281
+ const intention = {
1282
+ msafeAddress: input.msafeAddress,
1283
+ sequenceNumber,
1284
+ processed: false,
1285
+ ...IntentionHelper.getTxType(input.intention),
1286
+ data: IntentionHelper.ser(input.intention),
1287
+ status: "SUCCESS",
1288
+ creator: input.userAddress
1289
+ };
1290
+ await this.model.transactionIntention.save(intention);
1291
+ const pendingTx = {
1292
+ digest: txDigest,
1293
+ msafeAddress: input.msafeAddress,
1294
+ payload: Uint8ArrayToHex(payload),
1295
+ sequenceNumber,
1296
+ isRejectTx: false,
1297
+ creator: input.userAddress
1298
+ };
1299
+ await this.model.pendingTransaction.save(pendingTx);
1300
+ const userVote = {
1301
+ userAddress: input.userAddress,
1302
+ txDigest,
1303
+ msafeAddress: input.msafeAddress,
1304
+ signature: input.signature,
1305
+ isValid: true
1306
+ };
1307
+ await this.model.userVote.save(userVote);
1308
+ }
1309
+ // Calls for the first reject transaction
1310
+ async rejectCurrentTx(input) {
1311
+ const userMSafe = await this.model.userMSafe.findOneBy({
1312
+ userAddress: input.userAddress,
1313
+ msafeAddress: input.msafeAddress
1314
+ });
1315
+ if (userMSafe === null) {
1316
+ throw new Error("User does not have permission to MSafe");
1317
+ }
1318
+ const currentPending = await this.model.pendingTransaction.findOneBy({
1319
+ msafeAddress: input.msafeAddress,
1320
+ isRejectTx: false
1321
+ });
1322
+ if (currentPending === null) {
1323
+ throw new Error("No active pending transaction");
1324
+ }
1325
+ const txb = await IntentionHelper.buildRejectTransaction({
1326
+ msafeAddress: input.msafeAddress,
1327
+ payloadToReject: currentPending.payload
1328
+ });
1329
+ const payload = await txb.build({ client: this._suiClient });
1330
+ const digest = await txb.getDigest({ client: this._suiClient });
1331
+ if (input.digest !== digest) {
1332
+ throw new Error("Digest not match");
1333
+ }
1334
+ const verified = await SignatureVerifier.verifyTransactionSignature({
1335
+ payload,
1336
+ targetAddress: input.userAddress,
1337
+ signature: input.signature
1338
+ });
1339
+ if (!verified) {
1340
+ throw new Error("Signature unverified");
1341
+ }
1342
+ const existPendingReject = await this.model.pendingTransaction.findOneBy({
1343
+ msafeAddress: input.msafeAddress,
1344
+ isRejectTx: true
1345
+ });
1346
+ if (existPendingReject !== null) {
1347
+ await this.voteForTransaction({
1348
+ txDigest: existPendingReject.digest,
1349
+ msafeAddress: input.msafeAddress,
1350
+ userAddress: input.userAddress,
1351
+ signature: input.signature
1352
+ });
1353
+ return;
1354
+ }
1355
+ const rejectPayloadStr = Uint8ArrayToHex(payload);
1356
+ const rejectDigest = await txb.getDigest({ client: this._suiClient });
1357
+ const rejectPending = {
1358
+ msafeAddress: input.msafeAddress,
1359
+ digest: rejectDigest,
1360
+ payload: rejectPayloadStr,
1361
+ sequenceNumber: currentPending.sequenceNumber,
1362
+ isRejectTx: true,
1363
+ creator: input.userAddress
1364
+ };
1365
+ await this.model.pendingTransaction.save(rejectPending);
1366
+ const rejectVote = {
1367
+ userAddress: input.userAddress,
1368
+ msafeAddress: input.msafeAddress,
1369
+ txDigest: rejectDigest,
1370
+ signature: input.signature,
1371
+ isValid: true
1372
+ };
1373
+ await this.model.userVote.save(rejectVote);
1374
+ const existVote = await this.model.userVote.findOneBy({
1375
+ txDigest: currentPending.digest,
1376
+ userAddress: input.userAddress
1377
+ });
1378
+ if (existVote !== null) {
1379
+ await this.model.userVote.update(
1380
+ { userAddress: input.userAddress, txDigest: currentPending.digest },
1381
+ { isValid: false }
1382
+ );
1383
+ }
1384
+ }
1385
+ async voteForTransaction(input) {
1386
+ const pendingTx = await this.model.pendingTransaction.findOneBy({ digest: input.txDigest });
1387
+ if (!pendingTx) {
1388
+ throw new Error(`Pending transaction not found: ${input.txDigest}`);
1389
+ }
1390
+ if (pendingTx.msafeAddress !== input.msafeAddress) {
1391
+ throw new Error("MSafe address not match");
1392
+ }
1393
+ const userMSafe = await this.model.userMSafe.findOneBy({
1394
+ userAddress: input.userAddress,
1395
+ msafeAddress: input.msafeAddress
1396
+ });
1397
+ if (userMSafe === null) {
1398
+ throw new Error(`User (${input.userAddress}) does not have permission on MSafe account (${input.msafeAddress})`);
1399
+ }
1400
+ const payload = HexToUint8Array(pendingTx.payload);
1401
+ const verified = await SignatureVerifier.verifyTransactionSignature({
1402
+ payload,
1403
+ targetAddress: input.userAddress,
1404
+ signature: input.signature
1405
+ });
1406
+ if (!verified) {
1407
+ throw new Error("Invalid signature");
1408
+ }
1409
+ const rejectPendingTx = await this.model.pendingTransaction.findOneBy({
1410
+ msafeAddress: input.msafeAddress,
1411
+ sequenceNumber: pendingTx.sequenceNumber,
1412
+ isRejectTx: !pendingTx.isRejectTx
1413
+ });
1414
+ if (rejectPendingTx !== null) {
1415
+ await this.model.userVote.update(
1416
+ {
1417
+ userAddress: input.userAddress,
1418
+ txDigest: rejectPendingTx.digest,
1419
+ isValid: true
1420
+ },
1421
+ { isValid: false }
1422
+ );
1423
+ }
1424
+ const existVote = await this.model.userVote.exist({
1425
+ where: {
1426
+ txDigest: input.txDigest,
1427
+ userAddress: input.userAddress
1428
+ }
1429
+ });
1430
+ if (!existVote) {
1431
+ const userVote = {
1432
+ txDigest: input.txDigest,
1433
+ userAddress: input.userAddress,
1434
+ msafeAddress: input.msafeAddress,
1435
+ signature: input.signature,
1436
+ isValid: true
1437
+ };
1438
+ await this.model.userVote.save(userVote);
1439
+ } else {
1440
+ await this.model.userVote.update(
1441
+ {
1442
+ txDigest: input.txDigest,
1443
+ userAddress: input.userAddress
1444
+ },
1445
+ { isValid: true }
1446
+ );
1447
+ }
1448
+ }
1449
+ // Mock the process of an executed transaction
1450
+ // Here only the essential logic of transaction processing logic
1451
+ // is implemented. Need more transaction parsing from the fetcher
1452
+ // module.
1453
+ //
1454
+ // TODO: User queryRunner to make the transaction atomic.
1455
+ async processExecutedTransaction(digest) {
1456
+ const historyTx = await this.model.historyTransaction.findOneBy({ digest });
1457
+ if (historyTx) {
1458
+ return;
1459
+ }
1460
+ const pendingTx = await this.model.pendingTransaction.findOneBy({ digest });
1461
+ if (!pendingTx) {
1462
+ throw new Error("Transaction digest not found");
1463
+ }
1464
+ await this.model.transactionIntention.update(
1465
+ { msafeAddress: pendingTx.msafeAddress, sequenceNumber: pendingTx.sequenceNumber },
1466
+ { processed: true }
1467
+ );
1468
+ const pendings = await this.model.pendingTransaction.findBy({
1469
+ msafeAddress: pendingTx.msafeAddress,
1470
+ sequenceNumber: pendingTx.sequenceNumber
1471
+ });
1472
+ if (pendings.length === 0) {
1473
+ throw new Error("Pending transaction not found");
1474
+ }
1475
+ const executionResult = "success";
1476
+ for (let i = 0; i !== pendings.length; i++) {
1477
+ const pending = pendings[i];
1478
+ const history = {
1479
+ digest: pending.digest,
1480
+ payload: pending.payload,
1481
+ msafeAddress: pending.msafeAddress,
1482
+ sequenceNumber: pending.sequenceNumber,
1483
+ isRejectTx: pending.isRejectTx,
1484
+ creator: pending.creator,
1485
+ createdAt: pending.createdAt,
1486
+ // TODO: Fill in this field based on transaction processing result
1487
+ status: pending.digest === digest ? executionResult : "rejected"
1488
+ };
1489
+ await this.model.historyTransaction.save(history);
1490
+ await this.model.pendingTransaction.delete({ digest: pending.digest });
1491
+ }
1492
+ }
1493
+ /**
1494
+ * Build the next transaction intention, and add the built transaction to pendings.
1495
+ * @param input
1496
+ */
1497
+ async buildNextIntentionAndAddToPending(input) {
1498
+ const maxSNHistory = await this.model.historyTransaction.findOne({
1499
+ where: { msafeAddress: input.msafeAddress },
1500
+ order: { sequenceNumber: "desc" }
1501
+ });
1502
+ const nextSequenceNumber = maxSNHistory ? maxSNHistory.sequenceNumber + 1 : 0;
1503
+ const currentPendings = await this.model.pendingTransaction.findBy({
1504
+ msafeAddress: input.msafeAddress
1505
+ });
1506
+ if (currentPendings.length !== 0) {
1507
+ throw new Error("Still have pendings");
1508
+ }
1509
+ const nextTx = await this.model.transactionIntention.findOneBy({
1510
+ msafeAddress: input.msafeAddress,
1511
+ sequenceNumber: nextSequenceNumber
1512
+ });
1513
+ if (nextTx === null) {
1514
+ throw new Error("No future intentions to build");
1515
+ }
1516
+ const nextIntention = IntentionHelper.de(nextTx.data);
1517
+ try {
1518
+ const newTxb = await IntentionHelper.buildTxb({
1519
+ suiClient: this._suiClient,
1520
+ sender: input.msafeAddress,
1521
+ intention: nextIntention
1522
+ });
1523
+ const payload = await newTxb.build({ client: this._suiClient });
1524
+ const newDigest = await newTxb.getDigest({ client: this._suiClient });
1525
+ const newPending = {
1526
+ digest: newDigest,
1527
+ payload: Uint8ArrayToHex(payload),
1528
+ msafeAddress: input.msafeAddress,
1529
+ sequenceNumber: nextTx.sequenceNumber,
1530
+ isRejectTx: false,
1531
+ creator: nextTx.creator
1532
+ };
1533
+ await this.model.pendingTransaction.save(newPending);
1534
+ await this.model.transactionIntention.update(
1535
+ {
1536
+ msafeAddress: input.msafeAddress,
1537
+ sequenceNumber: nextSequenceNumber
1538
+ },
1539
+ {
1540
+ status: "SUCCESS"
1541
+ }
1542
+ );
1543
+ } catch (e) {
1544
+ await this.model.transactionIntention.update(
1545
+ {
1546
+ msafeAddress: input.msafeAddress,
1547
+ sequenceNumber: nextSequenceNumber
1548
+ },
1549
+ {
1550
+ status: "FAILED",
1551
+ statusRemark: e.toString()
1552
+ }
1553
+ );
1554
+ throw new Error(`Intention build failed: {sequenceNumber: ${nextSequenceNumber}}`);
1555
+ }
1556
+ }
1557
+ /**
1558
+ * Skip next failed transaction if build of the intention has been failed before.
1559
+ */
1560
+ async skipNextFailedIntention(input) {
1561
+ const userMSafe = await this.model.userMSafe.findOneBy({
1562
+ msafeAddress: input.msafeAddress,
1563
+ userAddress: input.userAddress
1564
+ });
1565
+ if (userMSafe === null) {
1566
+ throw new Error("user does not have permission to MSafe");
1567
+ }
1568
+ const curSequenceNumber = await this.model.historyTransaction.findOne({
1569
+ where: { msafeAddress: input.msafeAddress },
1570
+ order: { sequenceNumber: "desc" }
1571
+ });
1572
+ const nextSequenceNumber = curSequenceNumber ? curSequenceNumber.sequenceNumber + 1 : 0;
1573
+ const failedIntention = await this.model.transactionIntention.findOneBy({
1574
+ msafeAddress: input.msafeAddress,
1575
+ sequenceNumber: nextSequenceNumber
1576
+ });
1577
+ if (failedIntention === null) {
1578
+ throw new Error("Next intention not found");
1579
+ }
1580
+ if (failedIntention.status !== "FAILED") {
1581
+ throw new Error("Next intention not failed");
1582
+ }
1583
+ const history = {
1584
+ msafeAddress: input.msafeAddress,
1585
+ digest: "0x0",
1586
+ // Special case for build has been failed,
1587
+ payload: "",
1588
+ sequenceNumber: nextSequenceNumber,
1589
+ creator: failedIntention.creator,
1590
+ isRejectTx: false,
1591
+ status: "build-failed"
1592
+ };
1593
+ await this.model.historyTransaction.save(history);
1594
+ await this.model.transactionIntention.update(
1595
+ { msafeAddress: input.msafeAddress, sequenceNumber: nextSequenceNumber },
1596
+ { processed: true }
1597
+ );
1598
+ }
1599
+ async getUser(address) {
1600
+ return this.model.user.findOneBy({ address });
1601
+ }
1602
+ get model() {
1603
+ return this.db.coreModel;
1604
+ }
1605
+ };
1606
+
772
1607
  // src/globals/const.ts
773
1608
  var MSafeEnv = /* @__PURE__ */ ((MSafeEnv3) => {
774
1609
  MSafeEnv3["local"] = "local";
@@ -803,8 +1638,6 @@ var DEV_DATABASE_CONFIG = {
803
1638
  };
804
1639
  var TESTNET_RPC_URL = "https://sui-testnet.blockvision.org/v1/2Sgk89ivT64MnKdcGzjmyjY2ndD";
805
1640
  var MAINNET_RPC_URL = "https://sui-mainnet.blockvision.org/v1/2Sgk7NPvqkd7mESYkxF01yX15l7";
806
- var LOCAL_API_URL = "http://127.0.0.1:3000";
807
- var DEV_API_URL = "http://13.56.226.148";
808
1641
  var ENV_CONFIGS = /* @__PURE__ */ new Map([
809
1642
  [
810
1643
  "unit" /* unit */,
@@ -812,8 +1645,7 @@ var ENV_CONFIGS = /* @__PURE__ */ new Map([
812
1645
  suiClient: {
813
1646
  url: TESTNET_RPC_URL
814
1647
  },
815
- backend: LOCAL_DATABASE_CONFIG,
816
- apiURL: LOCAL_API_URL
1648
+ backend: UNIT_DATABASE_CONFIG
817
1649
  }
818
1650
  ],
819
1651
  [
@@ -822,8 +1654,7 @@ var ENV_CONFIGS = /* @__PURE__ */ new Map([
822
1654
  suiClient: {
823
1655
  url: TESTNET_RPC_URL
824
1656
  },
825
- backend: LOCAL_DATABASE_CONFIG,
826
- apiURL: LOCAL_API_URL
1657
+ backend: LOCAL_DATABASE_CONFIG
827
1658
  }
828
1659
  ],
829
1660
  [
@@ -832,8 +1663,7 @@ var ENV_CONFIGS = /* @__PURE__ */ new Map([
832
1663
  suiClient: {
833
1664
  url: TESTNET_RPC_URL
834
1665
  },
835
- backend: DEV_DATABASE_CONFIG,
836
- apiURL: DEV_API_URL
1666
+ backend: DEV_DATABASE_CONFIG
837
1667
  }
838
1668
  ]
839
1669
  ]);
@@ -852,140 +1682,6 @@ function getMSafeConfig(env, options) {
852
1682
  }
853
1683
  var AUTH_SIGN_MESSAGE = "Welcome to MSafe";
854
1684
 
855
- // src/backend/BackendImpl.ts
856
- var import_axios = __toESM(require("axios"), 1);
857
- var BackendImpl = class {
858
- constructor(apiURL) {
859
- this.apiURL = apiURL;
860
- }
861
- _token;
862
- async authSign(input) {
863
- const res = await import_axios.default.post(`${this.apiURL}/auth/login`, input);
864
- if (res.status !== 200 && res.status !== 201) {
865
- throw new Error(`invalid authSign return: ${res}`);
866
- }
867
- this._token = res.data.accessToken;
868
- return this._token;
869
- }
870
- setJWTToken(token) {
871
- this._token = token;
872
- }
873
- async getPublicKey(address) {
874
- return (await this.getPublicKeyBatch([address]))[0];
875
- }
876
- async getPublicKeyBatch(addresses) {
877
- const res = await import_axios.default.post(
878
- `${this.apiURL}/account/getPublicKeyBatch`,
879
- addresses,
880
- {
881
- headers: this.headers()
882
- }
883
- );
884
- if (res.status !== 200 && res.status !== 201) {
885
- throw new Error(`invalid getPublicKeyBatch return: ${res}`);
886
- }
887
- return res.data?.map(
888
- (publicKeyWithSchema) => publicKeyWithSchema ? PublicKeySerde.de({ ...publicKeyWithSchema }) : void 0
889
- );
890
- }
891
- async getMSafeAccountInfo(msafeAddress) {
892
- const res = await import_axios.default.get(
893
- `${this.apiURL}/account/getMSafeAccountInfo/${msafeAddress}`,
894
- {
895
- headers: this.headers()
896
- }
897
- );
898
- if (res.status !== 200 && res.status !== 201) {
899
- throw new Error(`invalid getPublicKeyBatch return: ${res}`);
900
- }
901
- const msafeResp = res.data;
902
- return {
903
- address: msafeResp.address,
904
- ownersWithWeightPK: msafeResp.ownersWithWeightPKEncoded.map(
905
- (owner) => ({
906
- publicKey: PublicKeySerde.de({ publicKey: owner.publicKeyEncoded, scheme: owner.schema }),
907
- address: owner.address,
908
- weight: owner.weight
909
- })
910
- ),
911
- threshold: msafeResp.threshold,
912
- name: msafeResp.name,
913
- description: msafeResp.description,
914
- creationNonce: msafeResp.creationNonce
915
- };
916
- }
917
- async getUserInfo(userAddress) {
918
- const res = await import_axios.default.get(`${this.apiURL}/account/user/${userAddress}`, {
919
- headers: this.headers()
920
- });
921
- if (res.status !== 200 && res.status !== 201) {
922
- throw new Error(`invalid getPublicKeyBatch return: ${res}`);
923
- }
924
- return {
925
- address: res.data.address,
926
- publicKey: res.data.publicKey,
927
- schema: res.data.schema,
928
- creationNonce: res.data.creationNonce,
929
- ownedMSafe: res.data.ownedMSafe.map(
930
- (msafe) => ({
931
- address: msafe.address,
932
- ownersWithWeightPK: msafe.ownersWithWeightPKEncoded.map(
933
- (owner) => ({
934
- publicKey: PublicKeySerde.de({ publicKey: owner.publicKeyEncoded, scheme: owner.schema }),
935
- address: owner.address,
936
- weight: owner.weight
937
- })
938
- ),
939
- threshold: msafe.threshold,
940
- name: msafe.name,
941
- description: msafe.description,
942
- creationNonce: msafe.creationNonce
943
- })
944
- )
945
- };
946
- }
947
- async getPendingTransactions(msafeAddress) {
948
- return [];
949
- }
950
- async getHistoryTransactions(msafeAddress) {
951
- return [];
952
- }
953
- async getFutureIntentions(msafeAddress) {
954
- return [];
955
- }
956
- async getCurrentSequenceNumber(msafeAddress) {
957
- return 0;
958
- }
959
- async getNextSequenceNumber(msafeAddress) {
960
- return 0;
961
- }
962
- async createMSafeAccount(input) {
963
- const res = await import_axios.default.post(`${this.apiURL}/account`, input, {
964
- headers: this.headers()
965
- });
966
- if (res.status !== 200 && res.status !== 201) {
967
- throw new Error(`invalid createMSafeAccount return: ${res}`);
968
- }
969
- }
970
- async proposeIntention(input) {
971
- }
972
- async proposePendingTransaction(input) {
973
- }
974
- async rejectCurrentTx(input) {
975
- }
976
- async voteForTransaction(input) {
977
- }
978
- async buildNextIntentionAndAddToPending(input) {
979
- }
980
- async skipNextFailedIntention(input) {
981
- }
982
- async processExecutedTransaction(digest) {
983
- }
984
- headers() {
985
- return { Authorization: `Bearer ${this._token}` };
986
- }
987
- };
988
-
989
1685
  // src/globals/MSafeGlobals.ts
990
1686
  var MSafeGlobals = class _MSafeGlobals {
991
1687
  backend;
@@ -1000,7 +1696,7 @@ var MSafeGlobals = class _MSafeGlobals {
1000
1696
  static async New(env, options) {
1001
1697
  const config = getMSafeConfig(env, options);
1002
1698
  const suiClient = new import_client.SuiClient(config.suiClient);
1003
- const backend = new BackendImpl(config.apiURL);
1699
+ const backend = await PseudoBackend.New(config.backend, suiClient);
1004
1700
  return new _MSafeGlobals({
1005
1701
  backend,
1006
1702
  suiClient,
@@ -1034,6 +1730,11 @@ var MSafeClient = class _MSafeClient {
1034
1730
  }
1035
1731
  async connectWallet(input) {
1036
1732
  this.globals.wallet = input.wallet;
1733
+ const isValidJWT = input.jwtToken && await this.backend.isJWTTokenValid(input.jwtToken);
1734
+ if (isValidJWT) {
1735
+ this.backend.setJWTToken(input.jwtToken);
1736
+ return input.jwtToken;
1737
+ }
1037
1738
  const messageStr = MessageHelper.welcomeMessage((/* @__PURE__ */ new Date()).toUTCString());
1038
1739
  const sig = await input.wallet.signPersonalMessage({
1039
1740
  messageStr
@@ -1092,21 +1793,28 @@ var MSafeClient = class _MSafeClient {
1092
1793
  Coin,
1093
1794
  CoinHelper,
1094
1795
  CreateHelper,
1095
- DEV_API_URL,
1096
1796
  DEV_DATABASE_CONFIG,
1097
1797
  ENV_CONFIGS,
1098
1798
  Formatter,
1099
1799
  HexToUint8Array,
1100
1800
  IntentionHelper,
1101
- LOCAL_API_URL,
1102
1801
  LOCAL_DATABASE_CONFIG,
1103
1802
  MAINNET_RPC_URL,
1803
+ MAX_OWNER_WITHOUT_NONCE,
1804
+ MAX_OWNER_WITH_NONCE,
1805
+ MAX_WEIGHT,
1806
+ MIN_THRESHOLD,
1807
+ MIN_WEIGHT,
1104
1808
  MSafeAccount,
1105
1809
  MSafeClient,
1106
1810
  MSafeEnv,
1107
1811
  MSafeGlobals,
1108
1812
  MessageHelper,
1813
+ NONCE_PK_PREFIX,
1814
+ NONCE_PK_WEIGHT,
1815
+ NONCE_PREFIX_MAX_SIZE,
1109
1816
  PublicKeySerde,
1817
+ RawMultiSig,
1110
1818
  SUI_COIN,
1111
1819
  SignatureVerifier,
1112
1820
  TESTNET_RPC_URL,
@@ -1114,7 +1822,10 @@ var MSafeClient = class _MSafeClient {
1114
1822
  Uint8ArrayToHex,
1115
1823
  getAllCoins,
1116
1824
  getMSafeConfig,
1825
+ getMultiSigPublicKey,
1117
1826
  getPublicKeyFromChain,
1118
- stringToBuffer
1827
+ makeNoncePublicKey,
1828
+ stringToBuffer,
1829
+ validateMultiSigConfig
1119
1830
  });
1120
1831
  //# sourceMappingURL=index.cjs.map