@msafe/sui3-sdk 0.0.12 → 0.0.14

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.
@@ -1,44 +1,51 @@
1
1
  import {
2
2
  buildIntentionTransaction,
3
- getIntentionType,
4
- MSafeAccountInfo,
5
- MultisigAccountManager,
3
+ IMSafeConfig,
4
+ IPageOptions,
5
+ MultiSigAccount,
6
+ PublicKeySerde,
7
+ SigningMessageHelper,
6
8
  } from '@msafe/sui3-utils';
7
9
  import { SuiObjectData } from '@mysten/sui.js/client';
8
10
  import { SerializedSignature } from '@mysten/sui.js/cryptography';
9
11
  import { SuiObjectResponse } from '@mysten/sui.js/src/client';
10
12
  import { normalizeStructTag } from '@mysten/sui.js/utils';
11
13
 
12
- import { MessageHelper } from '@/core/MessageHelper';
13
- import { MSAFE_APPLICATION } from '@/globals';
14
14
  import { MSafeGlobals } from '@/globals/MSafeGlobals';
15
15
  import { IntentionHelper, TxIntention } from '@/transactions/intention';
16
16
  import { OwnedCoin } from '@/types/assets';
17
- import { PaginationOption } from '@/types/backend';
18
17
  import { PendingTx, SimulationResult } from '@/types/msafe';
19
18
  import { CoinHelper } from '@/utils';
20
19
  import { HexToUint8Array } from '@/utils/buffer';
21
20
  import { BatchObjectOptions, getAllOwnedObjects } from '@/utils/iter/object';
22
21
 
23
22
  export class MSafeAccount {
24
- public multisigManager: MultisigAccountManager;
23
+ public multiSig: MultiSigAccount;
25
24
 
26
25
  private coinHelper: CoinHelper;
27
26
 
28
27
  constructor(
29
28
  public readonly globals: MSafeGlobals,
30
- public readonly info: MSafeAccountInfo,
29
+ public readonly info: IMSafeConfig,
31
30
  ) {
32
- this.multisigManager = new MultisigAccountManager({
31
+ this.multiSig = new MultiSigAccount({
33
32
  threshold: info.threshold,
34
- ownersWithWeight: info.ownersWithWeightPK,
33
+ ownersWithWeight: info.owners.map((owner) => ({
34
+ address: owner.address,
35
+ weight: owner.weight,
36
+ publicKey: PublicKeySerde.de({ publicKeyEncoded: owner.publicKeyEncoded, schema: owner.schema }),
37
+ })),
35
38
  creationNonce: info.creationNonce,
36
39
  });
37
40
  this.coinHelper = new CoinHelper(this.suiClient);
38
41
  }
39
42
 
40
- static async new(globals: MSafeGlobals, address: string) {
41
- return globals.backend.getMSafeAccountInfo(address);
43
+ static async New(globals: MSafeGlobals, address: string) {
44
+ const info = await globals.backend.getMSafeAccountInfo(address);
45
+ const ms = new MSafeAccount(globals, info);
46
+ if (ms.address !== address) {
47
+ throw new Error('Invalid msafe config with address');
48
+ }
42
49
  }
43
50
 
44
51
  async ownedCoins(): Promise<OwnedCoin[]> {
@@ -87,11 +94,11 @@ export class MSafeAccount {
87
94
  };
88
95
  }
89
96
 
90
- async historyTransaction(paginationOption?: PaginationOption) {
97
+ async historyTransaction(paginationOption?: IPageOptions) {
91
98
  return this.backend.getHistoryTransactions(this.address, paginationOption);
92
99
  }
93
100
 
94
- async futureIntentions(paginationOption?: PaginationOption) {
101
+ async futureIntentions(paginationOption?: IPageOptions) {
95
102
  const paginatedIntentions = await this.backend.getFutureIntentions(this.address, paginationOption);
96
103
  return paginatedIntentions.data;
97
104
  }
@@ -104,27 +111,28 @@ export class MSafeAccount {
104
111
  return this.backend.getNextSequenceNumber(this.address);
105
112
  }
106
113
 
107
- async proposeIntention(intention: TxIntention, sequenceNumber: number) {
108
- const message = MessageHelper.proposeIntentionMessage({
109
- intention,
110
- sn: sequenceNumber,
114
+ async proposeIntention(input: {
115
+ application: string;
116
+ txType: string;
117
+ txSubType: string;
118
+ intention: TxIntention;
119
+ sequenceNumber: number;
120
+ }) {
121
+ const message = SigningMessageHelper.proposeIntentionMessage({
111
122
  msafeAddress: this.address,
123
+ intention: input.intention,
124
+ sn: input.sequenceNumber,
112
125
  });
113
126
  const signature = await this.wallet.signPersonalMessage({
114
127
  messageStr: message,
115
128
  });
116
129
 
117
- const txType = getIntentionType(intention);
118
130
  // TODO get application from common utils
119
131
  await this.backend.proposeIntention({
120
- intention,
121
- sequenceNumber,
132
+ ...input,
122
133
  msafeAddress: this.address,
123
134
  userAddress: await this.userAddress(),
124
135
  signature: signature.signature,
125
- application: MSAFE_APPLICATION,
126
- txType: txType.txType,
127
- txSubType: txType.txSubType,
128
136
  });
129
137
  }
130
138
 
@@ -234,14 +242,14 @@ export class MSafeAccount {
234
242
  }
235
243
 
236
244
  const sigs: SerializedSignature[] = [];
237
- for (let i = 0; i < this.info.ownersWithWeightPK.length; i++) {
238
- const owner = this.info.ownersWithWeightPK[i];
239
- const signature = gotSigs.get(owner.publicKey.toSuiAddress());
245
+ for (let i = 0; i < this.info.owners.length; i++) {
246
+ const owner = this.info.owners[i];
247
+ const signature = gotSigs.get(owner.address);
240
248
  if (signature) {
241
249
  sigs.push(signature);
242
250
  }
243
251
  }
244
- const multiSignature = this.multisigManager.combinePartialSignatures(sigs);
252
+ const multiSignature = this.multiSig.combinePartialSignatures(sigs);
245
253
  return this.suiClient.executeTransactionBlock({
246
254
  transactionBlock: HexToUint8Array(payload),
247
255
  signature: multiSignature,
@@ -250,7 +258,7 @@ export class MSafeAccount {
250
258
  }
251
259
 
252
260
  get address() {
253
- return this.info.address;
261
+ return this.multiSig.address;
254
262
  }
255
263
 
256
264
  private get backend() {
@@ -1,14 +1,13 @@
1
- import { MSafeAccountInfo } from '@msafe/sui3-utils';
1
+ import { IMSafeConfig, IPageOptions, JWTToken, SigningMessageHelper, UserMSafeStatus } from '@msafe/sui3-utils';
2
2
 
3
3
  import { AddressBookSDK } from '@/core/AddressBookSDK';
4
4
  import { CreateHelper } from '@/core/CreateHelper';
5
- import { MessageHelper } from '@/core/MessageHelper';
5
+ import { InvitationSDK } from '@/core/InvitationSDK';
6
6
  import { MSafeAccount } from '@/core/MSafeAccount';
7
7
  import { PublicKeyHelper } from '@/core/PublicKeyHelper';
8
8
  import { MSafeConfigOptions, MSafeEnv } from '@/globals/const';
9
9
  import { MSafeGlobals } from '@/globals/MSafeGlobals';
10
- import { JWTToken } from '@/types/backend';
11
- import { CreateMSafeAccountInfo } from '@/types/creation';
10
+ import { CreateMSafeInfo } from '@/types';
12
11
  import { IWallet } from '@/types/wallet';
13
12
 
14
13
  export class MSafeClient {
@@ -39,7 +38,7 @@ export class MSafeClient {
39
38
  }
40
39
 
41
40
  private async authSign(wallet: IWallet): Promise<JWTToken> {
42
- const messageStr = MessageHelper.welcomeMessage(new Date().toUTCString());
41
+ const messageStr = SigningMessageHelper.loginMessageWithTimestamp(new Date().toUTCString());
43
42
  const sig = await wallet.signPersonalMessage({
44
43
  messageStr,
45
44
  });
@@ -52,14 +51,18 @@ export class MSafeClient {
52
51
  }
53
52
 
54
53
  async userInfo() {
55
- return this.globals.backend.getUserInfo(await this.walletAddress());
54
+ return this.globals.backend.getUserInfo();
56
55
  }
57
56
 
58
- async createAccount(info: CreateMSafeAccountInfo) {
57
+ async ownedMSafe(pagination?: IPageOptions) {
58
+ return this.globals.backend.getOwnedMSafeByStatus({ status: UserMSafeStatus.active, pagination });
59
+ }
60
+
61
+ async createAccount(info: CreateMSafeInfo) {
59
62
  return this.creationHelper.submitMSafeCreation(info);
60
63
  }
61
64
 
62
- getMSafeAccount(info: MSafeAccountInfo) {
65
+ getMSafeAccount(info: IMSafeConfig) {
63
66
  return new MSafeAccount(this.globals, info);
64
67
  }
65
68
 
@@ -100,6 +103,10 @@ export class MSafeClient {
100
103
  return new AddressBookSDK(this.globals);
101
104
  }
102
105
 
106
+ get Invitation(): InvitationSDK {
107
+ return new InvitationSDK(this.globals);
108
+ }
109
+
103
110
  private async walletAddress() {
104
111
  return this.wallet.address();
105
112
  }
@@ -39,6 +39,9 @@ export class PublicKeyHelper {
39
39
  const emptyIndexes = results
40
40
  .map((elem, index) => (elem === undefined ? index : -1))
41
41
  .filter((index) => index !== -1);
42
+ if (emptyIndexes.length === 0) {
43
+ return results;
44
+ }
42
45
  const backendResult = await this.globals.backend.getPublicKeyBatch(emptyIndexes.map((index) => addresses[index]));
43
46
  for (let i = 0; i < emptyIndexes.length; i++) {
44
47
  const index = emptyIndexes[i];
package/src/core/index.ts CHANGED
@@ -1,5 +1,4 @@
1
1
  export { CreateHelper } from './CreateHelper';
2
- export { MessageHelper } from './MessageHelper';
3
2
  export { MSafeClient } from './MSafeClient';
4
3
  export { MSafeAccount } from './MSafeAccount';
5
4
  export { AddressBookSDK } from './AddressBookSDK';
@@ -23,7 +23,7 @@ export class MSafeGlobals {
23
23
  static async New(env: MSafeEnv, options?: MSafeConfigOptions) {
24
24
  const config = getMSafeConfig(env, options);
25
25
  const suiClient = new SuiClient(config.suiClient);
26
- const backend = new BackendImpl(config.apiURL);
26
+ const backend = new BackendImpl(config.backend.url);
27
27
  return new MSafeGlobals({
28
28
  backend,
29
29
  suiClient,
@@ -1,5 +1,3 @@
1
- import { ModelConfig } from '@msafe/sui3-model/common';
2
-
3
1
  export enum MSafeEnv {
4
2
  local = 'local',
5
3
  unit = 'unit',
@@ -12,8 +10,9 @@ export interface MSafeConfig {
12
10
  suiClient: {
13
11
  url: string;
14
12
  };
15
- backend: DBConfig;
16
- apiURL: string;
13
+ backend: {
14
+ url: string;
15
+ };
17
16
  syncingURL: string;
18
17
  }
19
18
 
@@ -21,38 +20,10 @@ export interface MSafeConfigOptions {
21
20
  suiClient?: {
22
21
  url?: string;
23
22
  };
24
- backend?: DBConfig;
23
+ backend?: {
24
+ url?: string;
25
+ };
25
26
  }
26
-
27
- // Use pseudo backend for now.
28
- export type DBConfig = ModelConfig;
29
-
30
- export const UNIT_DATABASE_CONFIG: DBConfig = {
31
- type: 'sqlite',
32
- database: ':memory:',
33
- logging: false,
34
- };
35
-
36
- export const LOCAL_DATABASE_CONFIG: DBConfig = {
37
- type: 'mysql',
38
- host: '127.0.0.1',
39
- port: 3306,
40
- username: 'msafe',
41
- password: 'msafe',
42
- database: 'msafe_sui_local',
43
- logging: false,
44
- };
45
-
46
- export const DEV_DATABASE_CONFIG: DBConfig = {
47
- type: 'mysql',
48
- host: 'msafe-dev-database.cluster-caos3ssocrx6.us-west-1.rds.amazonaws.com',
49
- port: 3306,
50
- username: 'msafe',
51
- password: 'Momentum.Safe2022',
52
- database: 'msafe_sui_dev',
53
- logging: false,
54
- };
55
-
56
27
  export const MSAFE_APPLICATION = 'msafe';
57
28
 
58
29
  export const TESTNET_RPC_URL = 'https://sui-testnet.blockvision.org/v1/2Sgk89ivT64MnKdcGzjmyjY2ndD';
@@ -71,8 +42,9 @@ export const ENV_CONFIGS = new Map<MSafeEnv, MSafeConfig>([
71
42
  suiClient: {
72
43
  url: TESTNET_RPC_URL,
73
44
  },
74
- backend: LOCAL_DATABASE_CONFIG,
75
- apiURL: LOCAL_API_URL,
45
+ backend: {
46
+ url: LOCAL_API_URL,
47
+ },
76
48
  syncingURL: LOCAL_SYNCING_URL,
77
49
  },
78
50
  ],
@@ -82,8 +54,9 @@ export const ENV_CONFIGS = new Map<MSafeEnv, MSafeConfig>([
82
54
  suiClient: {
83
55
  url: TESTNET_RPC_URL,
84
56
  },
85
- backend: LOCAL_DATABASE_CONFIG,
86
- apiURL: LOCAL_API_URL,
57
+ backend: {
58
+ url: LOCAL_API_URL,
59
+ },
87
60
  syncingURL: LOCAL_SYNCING_URL,
88
61
  },
89
62
  ],
@@ -93,8 +66,9 @@ export const ENV_CONFIGS = new Map<MSafeEnv, MSafeConfig>([
93
66
  suiClient: {
94
67
  url: TESTNET_RPC_URL,
95
68
  },
96
- backend: DEV_DATABASE_CONFIG,
97
- apiURL: DEV_API_URL,
69
+ backend: {
70
+ url: DEV_API_URL,
71
+ },
98
72
  syncingURL: DEV_SYNCING_URL,
99
73
  },
100
74
  ],
@@ -108,10 +82,8 @@ export function getMSafeConfig(env: MSafeEnv, options?: MSafeConfigOptions) {
108
82
  if (options?.suiClient?.url) {
109
83
  config.suiClient.url = options.suiClient.url;
110
84
  }
111
- if (options?.backend) {
112
- config.backend = options.backend;
85
+ if (options?.backend?.url) {
86
+ config.backend.url = options.backend.url;
113
87
  }
114
88
  return config;
115
89
  }
116
-
117
- export const AUTH_SIGN_MESSAGE = 'Welcome to MSafe';
@@ -0,0 +1,11 @@
1
+ // TODO: Create a class and helper to deal with all the nasty stuff
2
+ export interface CreateMSafeInfo {
3
+ name: string;
4
+ description?: string;
5
+ owners: {
6
+ address: string;
7
+ weight: number;
8
+ }[];
9
+ creationNonce: number;
10
+ threshold: number;
11
+ }
@@ -1,6 +1,3 @@
1
- export * from './creation';
2
1
  export * from './msafe';
3
2
  export * from './wallet';
4
- export * from './pagination';
5
- export * from './address-book';
6
- export * from './backend';
3
+ export * from './create';
@@ -1,4 +1,5 @@
1
1
  import { GasCostSummary, DryRunTransactionBlockResponse } from '@mysten/sui.js/client';
2
+ import { SerializedSignature } from '@mysten/sui.js/cryptography';
2
3
 
3
4
  import { TxIntention } from '@/transactions/intention';
4
5
 
@@ -65,6 +66,17 @@ export interface FutureIntention {
65
66
  createdAt: Date;
66
67
  }
67
68
 
69
+ export interface ProposeIntention {
70
+ application: string;
71
+ txType: string;
72
+ txSubType: string;
73
+ intention: TxIntention;
74
+ sequenceNumber: number;
75
+ userAddress: string;
76
+ msafeAddress: string;
77
+ signature: SerializedSignature;
78
+ }
79
+
68
80
  export interface SimulationResult {
69
81
  success: boolean;
70
82
  errorMsg?: string;
@@ -1,13 +1,4 @@
1
- import {
2
- PublicKey,
3
- SerializedSignature,
4
- SIGNATURE_FLAG_TO_SCHEME,
5
- SignatureFlag,
6
- SignatureScheme,
7
- } from '@mysten/sui.js/cryptography';
8
- import { Ed25519PublicKey } from '@mysten/sui.js/keypairs/ed25519';
9
- import { Secp256k1PublicKey } from '@mysten/sui.js/keypairs/secp256k1';
10
- import { Secp256r1PublicKey } from '@mysten/sui.js/keypairs/secp256r1';
1
+ import { SerializedSignature } from '@mysten/sui.js/cryptography';
11
2
  import { verifyPersonalMessage, verifyTransactionBlock } from '@mysten/sui.js/verify';
12
3
 
13
4
  import { stringToBuffer } from '@/utils/buffer';
@@ -71,25 +62,3 @@ export class SignatureVerifier {
71
62
  });
72
63
  }
73
64
  }
74
-
75
- export class PublicKeySerde {
76
- static ser(publicKey: PublicKey) {
77
- return {
78
- publicKey: publicKey.toBase64(),
79
- scheme: SIGNATURE_FLAG_TO_SCHEME[publicKey.flag() as SignatureFlag],
80
- };
81
- }
82
-
83
- static de(input: { publicKey: string | Uint8Array; scheme: SignatureScheme }): PublicKey {
84
- switch (input.scheme) {
85
- case 'ED25519':
86
- return new Ed25519PublicKey(input.publicKey);
87
- case 'Secp256k1':
88
- return new Secp256k1PublicKey(input.publicKey);
89
- case 'Secp256r1':
90
- return new Secp256r1PublicKey(input.publicKey);
91
- default:
92
- throw new Error('Unsupported signature scheme: $input.scheme');
93
- }
94
- }
95
- }
package/src/utils/sui.ts CHANGED
@@ -1,8 +1,8 @@
1
+ import { PublicKeySerde } from '@msafe/sui3-utils';
1
2
  import { SuiClient, PaginatedTransactionResponse, PaginatedCoins, CoinStruct } from '@mysten/sui.js/client';
2
3
  import { parseSerializedSignature, PublicKey, SerializedSignature } from '@mysten/sui.js/cryptography';
3
4
  import { MultiSigPublicKey } from '@mysten/sui.js/multisig';
4
5
 
5
- import { PublicKeySerde } from '@/utils/crypto';
6
6
  import { Formatter } from '@/utils/format';
7
7
 
8
8
  export const SUI_COIN = '0x2::sui::SUI';
@@ -60,7 +60,7 @@ function getAddressFromSignatures(serializedSig: SerializedSignature, targetAddr
60
60
  case 'ED25519':
61
61
  case 'Secp256k1':
62
62
  case 'Secp256r1': {
63
- const pk = PublicKeySerde.de({ publicKey: decoded.publicKey, scheme: decoded.signatureScheme });
63
+ const pk = PublicKeySerde.de({ publicKeyEncoded: decoded.publicKey, schema: decoded.signatureScheme });
64
64
  if (Formatter.isSuiAddressEqual(pk.toSuiAddress(), targetAddress)) {
65
65
  return pk;
66
66
  }
@@ -1,55 +0,0 @@
1
- // eslint-disable-next-line import/no-extraneous-dependencies
2
- import 'reflect-metadata';
3
-
4
- import { CoreModel, User, UserSetting } from '@msafe/sui3-model/core';
5
- import { PublicKey } from '@mysten/sui.js/cryptography';
6
-
7
- import { DBConfig } from '@/globals/const';
8
- import { PublicKeySerde } from '@/utils/crypto';
9
-
10
- export const WALLET_TYPE_KEY = 'wallet_type';
11
-
12
- export class CoreDB {
13
- private constructor(public readonly coreModel: CoreModel) {}
14
-
15
- static async New(dbConfig: DBConfig) {
16
- const core = await CoreModel.New(dbConfig);
17
- return new CoreDB(core);
18
- }
19
-
20
- async upsertUser(input: { address: string; publicKey: PublicKey; lastLogin: Date }) {
21
- const currentUser = await this.coreModel.user.findOneBy({
22
- address: input.address,
23
- });
24
- if (currentUser !== null) {
25
- currentUser.lastLogin = input.lastLogin;
26
- await this.coreModel.user.save(currentUser);
27
- } else {
28
- const serializedPublicKey = PublicKeySerde.ser(input.publicKey);
29
- const user: User = {
30
- address: input.address,
31
- publicKey: serializedPublicKey.publicKey,
32
- schema: serializedPublicKey.scheme,
33
- nonce: 0,
34
- lastLogin: new Date(),
35
- };
36
- await this.coreModel.user.save(user);
37
- }
38
- }
39
-
40
- async updateUserWalletType(input: { address: string; walletType: string }) {
41
- const exist = await this.coreModel.userSetting.findOneBy({
42
- userAddress: input.address,
43
- key: WALLET_TYPE_KEY,
44
- });
45
- const walletType = input.walletType.trim();
46
- if (exist === null || exist.value !== walletType) {
47
- const userSetting: UserSetting = {
48
- userAddress: input.address,
49
- key: WALLET_TYPE_KEY,
50
- value: walletType,
51
- };
52
- await this.coreModel.userSetting.save(userSetting);
53
- }
54
- }
55
- }