@msafe/sui3-sdk 0.0.4-pre-113020e.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 +969 -258
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +89 -24
- package/dist/index.d.ts +89 -24
- package/dist/index.js +958 -251
- package/dist/index.js.map +1 -1
- package/package.json +3 -6
- package/src/backend/PseudoBackend.ts +14 -25
- package/src/backend/interface.ts +10 -10
- package/src/backend/types.ts +21 -0
- package/src/core/CreateHelper.ts +12 -22
- package/src/core/MSafeAccount.ts +5 -9
- package/src/core/MSafeClient.ts +6 -2
- package/src/globals/MSafeGlobals.ts +1 -2
- package/src/globals/const.ts +1 -8
- package/src/types/msafe.ts +20 -0
- package/src/utils/index.ts +1 -0
- package/src/utils/multi-sig.ts +113 -0
- package/src/backend/BackendImpl.ts +0 -196
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
|
-
|
|
59
|
+
makeNoncePublicKey: () => makeNoncePublicKey,
|
|
60
|
+
stringToBuffer: () => stringToBuffer,
|
|
61
|
+
validateMultiSigConfig: () => validateMultiSigConfig
|
|
62
62
|
});
|
|
63
63
|
module.exports = __toCommonJS(src_exports);
|
|
64
64
|
|
|
65
|
-
// src/
|
|
66
|
-
var
|
|
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.
|
|
565
|
-
threshold: info.threshold,
|
|
566
|
-
ownersWithWeight: info.ownersWithWeightPK,
|
|
567
|
-
creationNonce: info.creationNonce
|
|
568
|
-
});
|
|
647
|
+
this.rawMultiSig = RawMultiSig.fromMSafeAccountInfo(info);
|
|
569
648
|
}
|
|
570
|
-
|
|
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.
|
|
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:
|
|
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 =
|
|
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
|
-
|
|
1827
|
+
makeNoncePublicKey,
|
|
1828
|
+
stringToBuffer,
|
|
1829
|
+
validateMultiSigConfig
|
|
1119
1830
|
});
|
|
1120
1831
|
//# sourceMappingURL=index.cjs.map
|