@msafe/sui3-sdk 0.0.89 → 1.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 +377 -149
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +35 -29
- package/dist/index.d.ts +35 -29
- package/dist/index.js +386 -175
- package/dist/index.js.map +1 -1
- package/package.json +34 -19
- package/src/backend/BackendImpl.ts +3 -3
- package/src/backend/interface.ts +2 -2
- package/src/core/CreateHelper.ts +6 -6
- package/src/core/MSafeAccount.ts +76 -66
- package/src/core/PublicKeyHelper.ts +2 -2
- package/src/globals/MSafeGlobals.ts +20 -7
- package/src/globals/const.ts +21 -5
- package/src/simulate/simulator.ts +60 -17
- package/src/types/assets.ts +3 -1
- package/src/types/msafe.ts +15 -7
- package/src/types/wallet.ts +7 -12
- package/src/utils/coin.ts +20 -7
- package/src/utils/crypto.ts +8 -13
- package/src/utils/format.ts +1 -1
- package/src/utils/index.ts +1 -0
- package/src/utils/iter/object.ts +56 -43
- package/src/utils/sui.ts +71 -21
- package/src/utils/transaction.ts +12 -0
- package/tsconfig.json +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@msafe/sui3-sdk",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1.0.4",
|
|
4
4
|
"description": "SDK for MSafe SUI V3",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "./dist/index.js",
|
|
@@ -17,7 +17,10 @@
|
|
|
17
17
|
"src/**/*",
|
|
18
18
|
"tsconfig.json"
|
|
19
19
|
],
|
|
20
|
-
"repository":
|
|
20
|
+
"repository": {
|
|
21
|
+
"type": "git",
|
|
22
|
+
"url": "git+https://github.com/Momentum-Safe/msafe-sui3-sdk.git"
|
|
23
|
+
},
|
|
21
24
|
"author": "MSafe <admin@m-safe.io>",
|
|
22
25
|
"license": "MIT",
|
|
23
26
|
"dependencies": {
|
|
@@ -26,12 +29,14 @@
|
|
|
26
29
|
"buffer": "^6.0.3"
|
|
27
30
|
},
|
|
28
31
|
"devDependencies": {
|
|
32
|
+
"@changesets/changelog-github": "^0.7.0",
|
|
33
|
+
"@changesets/cli": "^2.31.0",
|
|
29
34
|
"@msafe/mpay-sdk-sui": "^1.0.25",
|
|
30
|
-
"@msafe/sui-app-store": "^0.0.
|
|
31
|
-
"@msafe/sui3-utils": "^5.0.
|
|
32
|
-
"@mysten/sui
|
|
33
|
-
"@mysten/wallet-standard": "^0.
|
|
34
|
-
"@types/jest": "^
|
|
35
|
+
"@msafe/sui-app-store": "^0.0.272",
|
|
36
|
+
"@msafe/sui3-utils": "^5.0.7",
|
|
37
|
+
"@mysten/sui": "^2.16.2",
|
|
38
|
+
"@mysten/wallet-standard": "^0.20.3",
|
|
39
|
+
"@types/jest": "^30.0.0",
|
|
35
40
|
"@types/node": "^20.9.2",
|
|
36
41
|
"@typescript-eslint/eslint-plugin": "^6.5.0",
|
|
37
42
|
"@typescript-eslint/parser": "^6.5.0",
|
|
@@ -46,31 +51,41 @@
|
|
|
46
51
|
"eslint-plugin-prettier": "^5.0.0",
|
|
47
52
|
"eslint-plugin-unused-imports": "^3.0.0",
|
|
48
53
|
"exponential-backoff": "^3.1.1",
|
|
49
|
-
"jest": "^
|
|
54
|
+
"jest": "^30.0.0",
|
|
50
55
|
"prettier": "^3.0.3",
|
|
56
|
+
"semver": "7.6.3",
|
|
51
57
|
"sqlite3": "^5.1.7",
|
|
52
|
-
"ts-jest": "^29.
|
|
58
|
+
"ts-jest": "^29.4.0",
|
|
53
59
|
"ts-node": "^10.9.1",
|
|
54
60
|
"tsconfig-paths": "^4.2.0",
|
|
55
61
|
"tsup": "^8.0.1",
|
|
56
62
|
"typescript": "^5.2.2"
|
|
57
63
|
},
|
|
58
64
|
"scripts": {
|
|
59
|
-
"test": "jest",
|
|
60
|
-
"test:e2e": "jest test/unit/core/msafe-e2e.test.ts",
|
|
61
|
-
"test:e2e:testnet": "jest test/unit/core/msafe-e2e-testnet.test.ts --maxWorkers=1",
|
|
62
|
-
"unit": "
|
|
65
|
+
"test": "NODE_OPTIONS='--experimental-vm-modules' jest --testPathIgnorePatterns=/test/unit/core/msafe-e2e\\\\.test\\\\.ts$ --testPathIgnorePatterns=/test/unit/core/msafe-e2e-testnet\\\\.test\\\\.ts$",
|
|
66
|
+
"test:e2e": "NODE_OPTIONS='--experimental-vm-modules' jest test/unit/core/msafe-e2e.test.ts",
|
|
67
|
+
"test:e2e:testnet": "NODE_OPTIONS='--experimental-vm-modules' jest test/unit/core/msafe-e2e-testnet.test.ts --maxWorkers=1",
|
|
68
|
+
"unit": "NODE_OPTIONS='--experimental-vm-modules' jest --testPathIgnorePatterns=/test/unit/core/msafe-e2e\\\\.test\\\\.ts$ --testPathIgnorePatterns=/test/unit/core/msafe-e2e-testnet\\\\.test\\\\.ts$",
|
|
63
69
|
"clean": "rm -rf ./dist",
|
|
64
70
|
"lint": "eslint . --ext .ts,.tsx",
|
|
65
|
-
"
|
|
66
|
-
"build
|
|
67
|
-
"
|
|
71
|
+
"typecheck": "tsc --noEmit",
|
|
72
|
+
"build": "bun run clean && tsup --platform browser --format cjs,esm --dts",
|
|
73
|
+
"build-yalc": "bun run build && yalc publish --private",
|
|
74
|
+
"changeset": "changeset",
|
|
75
|
+
"version-packages": "changeset version",
|
|
76
|
+
"release": "bun run build && changeset publish"
|
|
68
77
|
},
|
|
69
78
|
"peerDependencies": {
|
|
70
79
|
"@msafe/sui-app-store": ">0.0.100",
|
|
71
80
|
"@msafe/sui3-utils": ">3.0.0",
|
|
72
|
-
"@mysten/sui
|
|
73
|
-
"@mysten/wallet-standard": "
|
|
81
|
+
"@mysten/sui": "^2.0.0",
|
|
82
|
+
"@mysten/wallet-standard": "^0.20.0"
|
|
83
|
+
},
|
|
84
|
+
"overrides": {
|
|
85
|
+
"semver": "7.6.3"
|
|
74
86
|
},
|
|
75
|
-
"
|
|
87
|
+
"publishConfig": {
|
|
88
|
+
"access": "public",
|
|
89
|
+
"provenance": true
|
|
90
|
+
}
|
|
76
91
|
}
|
|
@@ -37,7 +37,7 @@ import {
|
|
|
37
37
|
UpdateAddressBookEntry,
|
|
38
38
|
UserMSafeStatus,
|
|
39
39
|
} from '@msafe/sui3-utils';
|
|
40
|
-
import { PublicKey
|
|
40
|
+
import { PublicKey } from '@mysten/sui/cryptography';
|
|
41
41
|
import axios, { AxiosError, AxiosRequestConfig, AxiosRequestTransformer, AxiosResponse } from 'axios';
|
|
42
42
|
|
|
43
43
|
import { IBackend } from '@/backend/interface';
|
|
@@ -104,7 +104,7 @@ export class BackendImpl implements IBackend {
|
|
|
104
104
|
headers: this.headers(),
|
|
105
105
|
});
|
|
106
106
|
return res.data?.map((publicKeyWithSchema) =>
|
|
107
|
-
publicKeyWithSchema ? PublicKeySerde.de(publicKeyWithSchema) : undefined,
|
|
107
|
+
publicKeyWithSchema ? (PublicKeySerde.de(publicKeyWithSchema) as unknown as PublicKey) : undefined,
|
|
108
108
|
);
|
|
109
109
|
}
|
|
110
110
|
|
|
@@ -265,7 +265,7 @@ export class BackendImpl implements IBackend {
|
|
|
265
265
|
return res.data;
|
|
266
266
|
}
|
|
267
267
|
|
|
268
|
-
async updateAddressBook(input: { updates: UpdateAddressBookEntry[]; signature:
|
|
268
|
+
async updateAddressBook(input: { updates: UpdateAddressBookEntry[]; signature: string }) {
|
|
269
269
|
await this.post(`/address-book`, input, { headers: this.headers() });
|
|
270
270
|
}
|
|
271
271
|
|
package/src/backend/interface.ts
CHANGED
|
@@ -29,7 +29,7 @@ import {
|
|
|
29
29
|
UpdateAddressBookEntry,
|
|
30
30
|
UserMSafeStatus,
|
|
31
31
|
} from '@msafe/sui3-utils';
|
|
32
|
-
import { PublicKey
|
|
32
|
+
import { PublicKey } from '@mysten/sui/cryptography';
|
|
33
33
|
|
|
34
34
|
import { NotificationInfo, NotificationSubscribeDto, NotificationUpdateDto } from './types/notification';
|
|
35
35
|
|
|
@@ -65,7 +65,7 @@ export interface IBackend {
|
|
|
65
65
|
proposeIntentionAndBuildVote(input: IProposeIntentionAndBuildAndVoteRequest): Promise<void>;
|
|
66
66
|
|
|
67
67
|
getAddressBookEntries(pagination?: IPageOptions): Promise<IGetAddressBookResult>;
|
|
68
|
-
updateAddressBook(input: { updates: UpdateAddressBookEntry[]; signature:
|
|
68
|
+
updateAddressBook(input: { updates: UpdateAddressBookEntry[]; signature: string }): Promise<void>;
|
|
69
69
|
getAddressBookMode(): Promise<IGetAddressBookModeResult>;
|
|
70
70
|
setAddressBookMode(input: ISetAddressBookModeReq): Promise<void>;
|
|
71
71
|
|
package/src/core/CreateHelper.ts
CHANGED
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
PublicKeyWithSchema,
|
|
7
7
|
SigningMessageHelper,
|
|
8
8
|
} from '@msafe/sui3-utils';
|
|
9
|
-
import { PublicKey
|
|
9
|
+
import { PublicKey } from '@mysten/sui/cryptography';
|
|
10
10
|
|
|
11
11
|
import { PublicKeyHelper } from '@/core/PublicKeyHelper';
|
|
12
12
|
import { MSafeGlobals } from '@/globals/MSafeGlobals';
|
|
@@ -47,7 +47,7 @@ export class CreateHelper {
|
|
|
47
47
|
if (!isSameAddress(address, pk.toSuiAddress())) {
|
|
48
48
|
throw new Error('Public key not match');
|
|
49
49
|
}
|
|
50
|
-
this.pkHelper.addPublicKey(address, pk);
|
|
50
|
+
this.pkHelper.addPublicKey(address, pk as unknown as PublicKey);
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
async submitMSafeCreation(creationInfo: CreateMSafeInfo) {
|
|
@@ -70,21 +70,21 @@ export class CreateHelper {
|
|
|
70
70
|
return {
|
|
71
71
|
threshold: info.threshold,
|
|
72
72
|
ownersWithWeight: info.owners.map((owner, i) => ({
|
|
73
|
-
publicKey: publicKeys[i] as PublicKey,
|
|
73
|
+
publicKey: publicKeys[i] as unknown as PublicKey,
|
|
74
74
|
weight: owner.weight,
|
|
75
75
|
})),
|
|
76
76
|
creationNonce: info.creationNonce,
|
|
77
|
-
};
|
|
77
|
+
} as unknown as MultiSigConfig;
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
-
private async submitToBackend(createInfo: CreateMSafeInfo, signature:
|
|
80
|
+
private async submitToBackend(createInfo: CreateMSafeInfo, signature: string) {
|
|
81
81
|
const pks = await this.pkHelper.getPublicKeyBatch(createInfo.owners.map((owner) => owner.address));
|
|
82
82
|
await this.globals.backend.createMSafeAccount({
|
|
83
83
|
owners: createInfo.owners.map((owner, i) => ({
|
|
84
84
|
address: owner.address,
|
|
85
85
|
weight: owner.weight,
|
|
86
86
|
status: '',
|
|
87
|
-
...PublicKeySerde.ser(pks[i] as
|
|
87
|
+
...PublicKeySerde.ser(pks[i] as never),
|
|
88
88
|
})),
|
|
89
89
|
threshold: createInfo.threshold,
|
|
90
90
|
name: createInfo.name, // name validation is deferred to backend
|
package/src/core/MSafeAccount.ts
CHANGED
|
@@ -15,10 +15,8 @@ import {
|
|
|
15
15
|
buildRejectTxb,
|
|
16
16
|
isSameAddress,
|
|
17
17
|
} from '@msafe/sui3-utils';
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
-
import { TransactionBlock } from '@mysten/sui.js/transactions';
|
|
21
|
-
import { fromHEX, normalizeStructTag, toHEX } from '@mysten/sui.js/utils';
|
|
18
|
+
import { Transaction } from '@mysten/sui/transactions';
|
|
19
|
+
import { fromHex, normalizeStructTag, toHex } from '@mysten/sui/utils';
|
|
22
20
|
import { SUI_MAINNET_CHAIN, SUI_TESTNET_CHAIN } from '@mysten/wallet-standard';
|
|
23
21
|
|
|
24
22
|
import { MSafeGlobals } from '@/globals/MSafeGlobals';
|
|
@@ -27,7 +25,8 @@ import { OwnedCoin } from '@/types/assets';
|
|
|
27
25
|
import { Pagination, PendingTx, SimulationResult } from '@/types/msafe';
|
|
28
26
|
import { CoinHelper } from '@/utils';
|
|
29
27
|
import { HexToUint8Array } from '@/utils/buffer';
|
|
30
|
-
import { BatchObjectOptions, getAllOwnedObjects } from '@/utils/iter/object';
|
|
28
|
+
import { BatchObjectOptions, getAllOwnedObjects, type OwnedObjectData } from '@/utils/iter/object';
|
|
29
|
+
import { toSuiTransaction } from '@/utils/transaction';
|
|
31
30
|
|
|
32
31
|
export class MSafeAccount {
|
|
33
32
|
public multiSig: MultiSigAccount;
|
|
@@ -58,26 +57,30 @@ export class MSafeAccount {
|
|
|
58
57
|
}
|
|
59
58
|
|
|
60
59
|
async ownedCoins(): Promise<OwnedCoin[]> {
|
|
61
|
-
const balances
|
|
60
|
+
const balances: { coinType: string; addressBalance: string }[] = [];
|
|
61
|
+
let cursor: string | null = null;
|
|
62
|
+
let hasNext = true;
|
|
63
|
+
while (hasNext) {
|
|
64
|
+
const page = await this.suiClient.listBalances({ owner: this.address, cursor, limit: 50 });
|
|
65
|
+
balances.push(...page.balances);
|
|
66
|
+
hasNext = page.hasNextPage;
|
|
67
|
+
cursor = page.cursor;
|
|
68
|
+
}
|
|
62
69
|
return Promise.all(
|
|
63
70
|
balances.map(async (balance): Promise<OwnedCoin> => {
|
|
64
71
|
const meta = await this.coinHelper.getCoinMeta(balance.coinType);
|
|
65
|
-
const unlockedBalance = balance.lockedBalance.number
|
|
66
|
-
? BigInt(balance.totalBalance) - BigInt(balance.lockedBalance.number)
|
|
67
|
-
: BigInt(balance.totalBalance);
|
|
68
|
-
|
|
69
72
|
return {
|
|
70
73
|
type: normalizeStructTag(balance.coinType),
|
|
71
|
-
balance: BigInt(
|
|
74
|
+
balance: BigInt(balance.addressBalance),
|
|
72
75
|
metadata: meta,
|
|
73
76
|
};
|
|
74
77
|
}),
|
|
75
78
|
);
|
|
76
79
|
}
|
|
77
80
|
|
|
78
|
-
async ownedObjects(options?: BatchObjectOptions): Promise<
|
|
81
|
+
async ownedObjects(options?: BatchObjectOptions): Promise<OwnedObjectData[]> {
|
|
79
82
|
const filterCoinObjectOptions = {
|
|
80
|
-
filter: (
|
|
83
|
+
filter: (obj: OwnedObjectData) => !obj?.type?.startsWith('0x2::coin::Coin'),
|
|
81
84
|
...options,
|
|
82
85
|
};
|
|
83
86
|
return getAllOwnedObjects(this.suiClient, this.address, filterCoinObjectOptions);
|
|
@@ -133,10 +136,10 @@ export class MSafeAccount {
|
|
|
133
136
|
|
|
134
137
|
async simulateIntention(
|
|
135
138
|
request: Omit<IProposeIntentionRequest, 'msafeAddress' | 'signature'> & {
|
|
136
|
-
txb?:
|
|
139
|
+
txb?: Transaction;
|
|
137
140
|
},
|
|
138
141
|
) {
|
|
139
|
-
let txb:
|
|
142
|
+
let txb: Transaction;
|
|
140
143
|
if (request.txb) {
|
|
141
144
|
txb = request.txb;
|
|
142
145
|
} else {
|
|
@@ -144,19 +147,21 @@ export class MSafeAccount {
|
|
|
144
147
|
if (!appHelper) {
|
|
145
148
|
throw new Error(`Can't find app helper for application ${request.application}`);
|
|
146
149
|
}
|
|
147
|
-
txb =
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
150
|
+
txb = toSuiTransaction(
|
|
151
|
+
await appHelper.build({
|
|
152
|
+
network: this.globals.config.network,
|
|
153
|
+
intentionData: request.intention,
|
|
154
|
+
txType: request.txType,
|
|
155
|
+
txSubType: request.txSubType,
|
|
156
|
+
clientUrl: this.globals.config.suiClient.url,
|
|
157
|
+
account: {
|
|
158
|
+
address: this.address,
|
|
159
|
+
publicKey: fromHex(this.address),
|
|
160
|
+
chains: [SUI_MAINNET_CHAIN, SUI_TESTNET_CHAIN],
|
|
161
|
+
features: [],
|
|
162
|
+
},
|
|
163
|
+
}),
|
|
164
|
+
);
|
|
160
165
|
}
|
|
161
166
|
txb.setSender(this.address);
|
|
162
167
|
return this.simulator.simulate({ txb, sender: this.address });
|
|
@@ -181,10 +186,10 @@ export class MSafeAccount {
|
|
|
181
186
|
|
|
182
187
|
async proposeIntentionAndBuildVote(
|
|
183
188
|
input: Omit<IProposeIntentionAndBuildAndVoteRequest, 'signature' | 'msafeAddress' | 'payload' | 'digest'> & {
|
|
184
|
-
txb?:
|
|
189
|
+
txb?: Transaction;
|
|
185
190
|
},
|
|
186
191
|
): Promise<void> {
|
|
187
|
-
let txb:
|
|
192
|
+
let txb: Transaction;
|
|
188
193
|
if (input.txb) {
|
|
189
194
|
txb = input.txb;
|
|
190
195
|
} else {
|
|
@@ -192,19 +197,21 @@ export class MSafeAccount {
|
|
|
192
197
|
if (!appHelper) {
|
|
193
198
|
throw new Error(`Can't find app helper for application ${input.application}`);
|
|
194
199
|
}
|
|
195
|
-
txb =
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
200
|
+
txb = toSuiTransaction(
|
|
201
|
+
await appHelper.build({
|
|
202
|
+
network: this.globals.config.network,
|
|
203
|
+
intentionData: input.intention,
|
|
204
|
+
txType: input.txType,
|
|
205
|
+
txSubType: input.txSubType,
|
|
206
|
+
clientUrl: this.globals.config.suiClient.url,
|
|
207
|
+
account: {
|
|
208
|
+
address: this.address,
|
|
209
|
+
publicKey: fromHex(this.address),
|
|
210
|
+
chains: [SUI_MAINNET_CHAIN, SUI_TESTNET_CHAIN],
|
|
211
|
+
features: [],
|
|
212
|
+
},
|
|
213
|
+
}),
|
|
214
|
+
);
|
|
208
215
|
}
|
|
209
216
|
txb.setGasPrice(input.gasPrice);
|
|
210
217
|
txb.setGasBudget(input.gasBudget);
|
|
@@ -216,7 +223,7 @@ export class MSafeAccount {
|
|
|
216
223
|
|
|
217
224
|
return this.backend.proposeIntentionAndBuildVote({
|
|
218
225
|
...input,
|
|
219
|
-
payload:
|
|
226
|
+
payload: toHex(payload),
|
|
220
227
|
digest,
|
|
221
228
|
msafeAddress: this.address,
|
|
222
229
|
signature: signature.signature,
|
|
@@ -281,9 +288,10 @@ export class MSafeAccount {
|
|
|
281
288
|
async proposePlainPayloadIntention(intention: PlainPayloadIntention) {
|
|
282
289
|
const sn = await this.nextSequenceNumber();
|
|
283
290
|
|
|
284
|
-
const tb =
|
|
291
|
+
const tb = Transaction.from(intention.payload);
|
|
285
292
|
|
|
286
|
-
|
|
293
|
+
const data = tb.getData();
|
|
294
|
+
if (!data.sender || !isSameAddress(data.sender, this.address)) {
|
|
287
295
|
throw new Error('Transaction sender is not same as the multisig address');
|
|
288
296
|
}
|
|
289
297
|
|
|
@@ -314,7 +322,7 @@ export class MSafeAccount {
|
|
|
314
322
|
throw new Error('Already rejected');
|
|
315
323
|
}
|
|
316
324
|
|
|
317
|
-
const txb = buildRejectTxb(this.address);
|
|
325
|
+
const txb = toSuiTransaction(buildRejectTxb(this.address));
|
|
318
326
|
txb.setSender(this.address);
|
|
319
327
|
return this.simulator.simulate({ txb, sender: this.address });
|
|
320
328
|
}
|
|
@@ -325,7 +333,7 @@ export class MSafeAccount {
|
|
|
325
333
|
throw new Error('Already rejected');
|
|
326
334
|
}
|
|
327
335
|
|
|
328
|
-
const rejectTxb = buildRejectTxb(this.address);
|
|
336
|
+
const rejectTxb = toSuiTransaction(buildRejectTxb(this.address));
|
|
329
337
|
const digest = await rejectTxb.getDigest({ client: this.suiClient });
|
|
330
338
|
const payload = await rejectTxb.build({ client: this.suiClient });
|
|
331
339
|
const signature = await this.wallet.signTransactionBlock({ transactionBlock: payload });
|
|
@@ -343,19 +351,21 @@ export class MSafeAccount {
|
|
|
343
351
|
if (!appHelper) {
|
|
344
352
|
throw new Error(`Can't find app helper for application ${intention.application}`);
|
|
345
353
|
}
|
|
346
|
-
const txb =
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
354
|
+
const txb = toSuiTransaction(
|
|
355
|
+
await appHelper.build({
|
|
356
|
+
network: this.globals.config.network,
|
|
357
|
+
intentionData: intention.intention,
|
|
358
|
+
txType: intention.txType as TransactionType,
|
|
359
|
+
txSubType: intention.txSubType,
|
|
360
|
+
clientUrl: this.globals.config.suiClient.url,
|
|
361
|
+
account: {
|
|
362
|
+
address: this.address,
|
|
363
|
+
publicKey: fromHex(this.address),
|
|
364
|
+
chains: [SUI_MAINNET_CHAIN, SUI_TESTNET_CHAIN],
|
|
365
|
+
features: [],
|
|
366
|
+
},
|
|
367
|
+
}),
|
|
368
|
+
);
|
|
359
369
|
txb.setSender(this.address);
|
|
360
370
|
return this.simulator.simulate({ txb, sender: this.address });
|
|
361
371
|
}
|
|
@@ -385,7 +395,7 @@ export class MSafeAccount {
|
|
|
385
395
|
throw new Error('Not enough signature');
|
|
386
396
|
}
|
|
387
397
|
|
|
388
|
-
const sortedSigs:
|
|
398
|
+
const sortedSigs: string[] = [];
|
|
389
399
|
const gotSigs = new Map(votes.map((vote) => [vote.userAddress, vote.signature]));
|
|
390
400
|
for (let i = 0; i < this.info.owners.length; i++) {
|
|
391
401
|
const owner = this.info.owners[i];
|
|
@@ -395,10 +405,10 @@ export class MSafeAccount {
|
|
|
395
405
|
}
|
|
396
406
|
}
|
|
397
407
|
const multiSignature = this.multiSig.combinePartialSignatures(sortedSigs);
|
|
398
|
-
return this.suiClient.
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
408
|
+
return this.suiClient.executeTransaction({
|
|
409
|
+
transaction: HexToUint8Array(payload),
|
|
410
|
+
signatures: [multiSignature],
|
|
411
|
+
include: { effects: true, events: true },
|
|
402
412
|
});
|
|
403
413
|
}
|
|
404
414
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { isSameAddress } from '@msafe/sui3-utils';
|
|
2
|
-
import { PublicKey } from '@mysten/sui
|
|
3
|
-
import { normalizeSuiAddress } from '@mysten/sui
|
|
2
|
+
import { PublicKey } from '@mysten/sui/cryptography';
|
|
3
|
+
import { normalizeSuiAddress } from '@mysten/sui/utils';
|
|
4
4
|
|
|
5
5
|
import { MSafeGlobals } from '@/globals/MSafeGlobals';
|
|
6
6
|
import { getPublicKeyFromChain } from '@/utils/sui';
|
|
@@ -1,20 +1,27 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { SuiGrpcClient } from '@mysten/sui/grpc';
|
|
2
2
|
|
|
3
3
|
import { BackendImpl } from '@/backend/BackendImpl';
|
|
4
4
|
import { IBackend } from '@/backend/interface';
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
getMSafeConfig,
|
|
7
|
+
httpUrlToGrpcBaseUrl,
|
|
8
|
+
MSafeConfig,
|
|
9
|
+
MSafeConfigOptions,
|
|
10
|
+
MSafeEnv,
|
|
11
|
+
msafeChainToSuiNetwork,
|
|
12
|
+
} from '@/globals/const';
|
|
6
13
|
import { IWallet } from '@/types/wallet';
|
|
7
14
|
|
|
8
15
|
export class MSafeGlobals {
|
|
9
16
|
public readonly backend: IBackend;
|
|
10
17
|
|
|
11
|
-
public readonly suiClient:
|
|
18
|
+
public readonly suiClient: SuiGrpcClient;
|
|
12
19
|
|
|
13
20
|
public readonly config: MSafeConfig;
|
|
14
21
|
|
|
15
22
|
_wallet: IWallet | undefined;
|
|
16
23
|
|
|
17
|
-
constructor(input: { backend: IBackend; suiClient:
|
|
24
|
+
constructor(input: { backend: IBackend; suiClient: SuiGrpcClient; config: MSafeConfig }) {
|
|
18
25
|
this.backend = input.backend;
|
|
19
26
|
this.suiClient = input.suiClient;
|
|
20
27
|
this.config = input.config;
|
|
@@ -22,9 +29,15 @@ export class MSafeGlobals {
|
|
|
22
29
|
|
|
23
30
|
static async New(env: MSafeEnv, options?: MSafeConfigOptions) {
|
|
24
31
|
const config = getMSafeConfig(env, options);
|
|
25
|
-
const suiClient =
|
|
26
|
-
|
|
27
|
-
|
|
32
|
+
const suiClient = config.suiClient.transport
|
|
33
|
+
? new SuiGrpcClient({
|
|
34
|
+
transport: config.suiClient.transport,
|
|
35
|
+
network: msafeChainToSuiNetwork(config.network),
|
|
36
|
+
})
|
|
37
|
+
: new SuiGrpcClient({
|
|
38
|
+
baseUrl: httpUrlToGrpcBaseUrl(config.suiClient.url),
|
|
39
|
+
network: msafeChainToSuiNetwork(config.network),
|
|
40
|
+
});
|
|
28
41
|
const backend = new BackendImpl(config.backend.url, options?.mockAddress);
|
|
29
42
|
return new MSafeGlobals({
|
|
30
43
|
backend,
|
package/src/globals/const.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { RpcTransport } from '@mysten/sui/grpc';
|
|
2
|
+
|
|
3
|
+
export function msafeChainToSuiNetwork(chain: 'sui:mainnet' | 'sui:testnet'): 'mainnet' | 'testnet' {
|
|
4
|
+
return chain === 'sui:mainnet' ? 'mainnet' : 'testnet';
|
|
5
|
+
}
|
|
2
6
|
|
|
3
7
|
export enum MSafeEnv {
|
|
4
8
|
local = 'local',
|
|
@@ -8,10 +12,22 @@ export enum MSafeEnv {
|
|
|
8
12
|
prod = 'prod',
|
|
9
13
|
}
|
|
10
14
|
|
|
15
|
+
/** Normalize HTTP(S) fullnode URL for SuiGrpcClient (gRPC-web) baseUrl. */
|
|
16
|
+
export function httpUrlToGrpcBaseUrl(url: string): string {
|
|
17
|
+
const parsed = new URL(url);
|
|
18
|
+
if (parsed.protocol === 'https:' && parsed.port === '') {
|
|
19
|
+
return `https://${parsed.hostname}:443${parsed.pathname}${parsed.search}`;
|
|
20
|
+
}
|
|
21
|
+
if (parsed.protocol === 'http:' && parsed.port === '') {
|
|
22
|
+
return `http://${parsed.hostname}:80${parsed.pathname}${parsed.search}`;
|
|
23
|
+
}
|
|
24
|
+
return `${parsed.origin}${parsed.pathname}${parsed.search}`;
|
|
25
|
+
}
|
|
26
|
+
|
|
11
27
|
export interface MSafeConfig {
|
|
12
28
|
suiClient: {
|
|
13
29
|
url: string;
|
|
14
|
-
transport?:
|
|
30
|
+
transport?: RpcTransport;
|
|
15
31
|
};
|
|
16
32
|
backend: {
|
|
17
33
|
url: string;
|
|
@@ -23,7 +39,7 @@ export interface MSafeConfig {
|
|
|
23
39
|
export interface MSafeConfigOptions {
|
|
24
40
|
suiClient?: {
|
|
25
41
|
url: string;
|
|
26
|
-
transport?:
|
|
42
|
+
transport?: RpcTransport;
|
|
27
43
|
};
|
|
28
44
|
backend?: {
|
|
29
45
|
url?: string;
|
|
@@ -52,9 +68,9 @@ export const ENV_CONFIGS = new Map<MSafeEnv, MSafeConfig>([
|
|
|
52
68
|
url: TESTNET_RPC_URL,
|
|
53
69
|
},
|
|
54
70
|
backend: {
|
|
55
|
-
url:
|
|
71
|
+
url: DEV_API_URL,
|
|
56
72
|
},
|
|
57
|
-
syncingURL:
|
|
73
|
+
syncingURL: DEV_SYNCING_URL,
|
|
58
74
|
network: 'sui:testnet',
|
|
59
75
|
},
|
|
60
76
|
],
|