suidouble 2.5.0 → 2.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.local.json +7 -0
- package/README.md +222 -131
- package/index.js +0 -2
- package/lib/SuiCliCommands.js +18 -25
- package/lib/SuiCoin.js +79 -137
- package/lib/SuiCoins.js +41 -29
- package/lib/SuiCommonMethods.js +40 -3
- package/lib/SuiEvent.js +54 -6
- package/lib/SuiInBrowser.js +143 -15
- package/lib/SuiInBrowserAdapter.js +185 -40
- package/lib/SuiLocalTestValidator.js +76 -14
- package/lib/SuiMaster.js +335 -139
- package/lib/SuiMemoryObjectStorage.js +66 -73
- package/lib/SuiObject.js +128 -153
- package/lib/SuiPackage.js +292 -187
- package/lib/SuiPackageModule.js +176 -221
- package/lib/SuiPaginatedResponse.js +288 -25
- package/lib/SuiPseudoRandomAddress.js +29 -2
- package/lib/SuiTransaction.js +115 -70
- package/lib/SuiUtils.js +179 -127
- package/package.json +29 -13
- package/test/build_modules.test.js +41 -0
- package/test/coins.test.js +17 -16
- package/test/custom_transaction.test.js +167 -0
- package/test/event_listeners.test.js +171 -0
- package/test/failed_transaction.test.js +184 -0
- package/test/name_service.test.js +28 -0
- package/test/owned_objects.test.js +148 -0
- package/test/rpc.test.js +3 -6
- package/test/sui_in_browser.test.js +2 -2
- package/test/sui_master_basic.test.js +4 -5
- package/test/sui_master_onlocal.test.js +84 -22
- package/test/sui_object_properties.test.js +85 -0
- package/test/test_move_contracts/different_types/Move.lock +18 -0
- package/test/test_move_contracts/suidouble_chat/Move.lock +18 -0
- package/tsconfig.json +15 -0
- package/types/index.d.ts +15 -0
- package/types/lib/SuiCliCommands.d.ts +6 -0
- package/types/lib/SuiCoin.d.ts +183 -0
- package/types/lib/SuiCoins.d.ts +93 -0
- package/types/lib/SuiCommonMethods.d.ts +37 -0
- package/types/lib/SuiEvent.d.ts +95 -0
- package/types/lib/SuiInBrowser.d.ts +189 -0
- package/types/lib/SuiInBrowserAdapter.d.ts +171 -0
- package/types/lib/SuiLocalTestValidator.d.ts +92 -0
- package/types/lib/SuiMaster.d.ts +333 -0
- package/types/lib/SuiMemoryObjectStorage.d.ts +96 -0
- package/types/lib/SuiObject.d.ts +135 -0
- package/types/lib/SuiPackage.d.ts +233 -0
- package/types/lib/SuiPackageModule.d.ts +139 -0
- package/types/lib/SuiPaginatedResponse.d.ts +148 -0
- package/types/lib/SuiPseudoRandomAddress.d.ts +33 -0
- package/types/lib/SuiTransaction.d.ts +92 -0
- package/types/lib/SuiUtils.d.ts +152 -0
- package/types/lib/data/icons.d.ts +12 -0
- package/lib/SuiTestScenario.js +0 -169
- package/test/sui_test_scenario.test.js +0 -61
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
import SuiCommonMethods from './SuiCommonMethods.js';
|
|
2
2
|
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @typedef {import("@mysten/sui/cryptography").SignatureWithBytes} SignatureWithBytes
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Wallet Standard feature identifiers — keys map to the string feature names used by the
|
|
10
|
+
* `@wallet-standard/core` registry.
|
|
11
|
+
* @enum {string}
|
|
12
|
+
*/
|
|
3
13
|
const Feature = {
|
|
4
14
|
DISCONNECT: 'standard:disconnect',
|
|
5
15
|
CONNECT: 'standard:connect',
|
|
@@ -12,25 +22,53 @@ const Feature = {
|
|
|
12
22
|
SUI_SIGN_PERSONAL_MESSAGE: 'sui:signPersonalMessage',
|
|
13
23
|
};
|
|
14
24
|
|
|
25
|
+
/**
|
|
26
|
+
* Wrapper over a single Wallet Standard adapter (e.g. Sui Wallet, Martian, Suiet).
|
|
27
|
+
* Abstracts away legacy `signAndExecuteTransactionBlock` vs the current
|
|
28
|
+
* `signAndExecuteTransaction` API, and normalises connection state changes into
|
|
29
|
+
* `'connected'` / `'disconnected'` events on this instance.
|
|
30
|
+
*/
|
|
15
31
|
export default class SuiInBrowserAdapter extends SuiCommonMethods {
|
|
32
|
+
/**
|
|
33
|
+
* @param {Object} [params]
|
|
34
|
+
* @param {Object} [params.standardAdapter] - raw Wallet Standard adapter from `@wallet-standard/core`
|
|
35
|
+
* @param {?string} [params.name] - display name used when no adapter is attached (e.g. "not installed" placeholder)
|
|
36
|
+
* @param {?string} [params.icon] - data-URI icon used when no adapter is attached
|
|
37
|
+
* @param {Object} [params.downloadUrls] - map of browser name → extension store URL (e.g. `{ chrome: 'https://…' }`)
|
|
38
|
+
* @param {boolean} [params.debug]
|
|
39
|
+
*/
|
|
16
40
|
constructor(params = {}) {
|
|
17
41
|
super(params);
|
|
18
42
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
if (params.
|
|
22
|
-
this.setStandartAdapter(params.
|
|
43
|
+
/** @type {?Object} raw Wallet Standard adapter */
|
|
44
|
+
this._standardAdapter = null;
|
|
45
|
+
if (params.standardAdapter) {
|
|
46
|
+
this.setStandartAdapter(params.standardAdapter);
|
|
23
47
|
}
|
|
24
|
-
|
|
48
|
+
|
|
49
|
+
/** @type {?string} */
|
|
25
50
|
this._name = params.name || null;
|
|
51
|
+
/** @type {?string} */
|
|
26
52
|
this._icon = params.icon || null;
|
|
53
|
+
/** @type {Object.<string, string>} */
|
|
27
54
|
this._downloadUrls = params.downloadUrls || {};
|
|
28
55
|
|
|
56
|
+
/** @type {?string} */
|
|
29
57
|
this._connectedAddress = null;
|
|
58
|
+
/** @type {?string} */
|
|
30
59
|
this._connectedChain = null;
|
|
60
|
+
/** @type {boolean} */
|
|
31
61
|
this._isConnected = false;
|
|
62
|
+
/** @type {boolean} */
|
|
63
|
+
this._userDisconnected = false;
|
|
32
64
|
}
|
|
33
65
|
|
|
66
|
+
/**
|
|
67
|
+
* Sign and execute a transaction. Prefers the current `sui:signAndExecuteTransaction`
|
|
68
|
+
* feature; falls back to the legacy `sui:signAndExecuteTransactionBlock` for older wallets.
|
|
69
|
+
* @param {Object} params
|
|
70
|
+
* @returns {Promise<*>}
|
|
71
|
+
*/
|
|
34
72
|
async signAndExecuteTransaction(params) {
|
|
35
73
|
if (this.hasFeature(Feature.SUI_SIGN_AND_EXECUTE_TX)) {
|
|
36
74
|
return await this.getFeature(Feature.SUI_SIGN_AND_EXECUTE_TX).signAndExecuteTransaction(params);
|
|
@@ -41,10 +79,32 @@ export default class SuiInBrowserAdapter extends SuiCommonMethods {
|
|
|
41
79
|
}
|
|
42
80
|
}
|
|
43
81
|
|
|
82
|
+
/**
|
|
83
|
+
* Sign and execute a transaction using the legacy `sui:signAndExecuteTransactionBlock` feature.
|
|
84
|
+
* @param {Object} params
|
|
85
|
+
* @returns {Promise<*>}
|
|
86
|
+
*/
|
|
44
87
|
async signAndExecuteTransactionBlock(params) {
|
|
45
88
|
return await this.getFeature(Feature.SUI_SIGN_AND_EXECUTE_TX_BLOCK).signAndExecuteTransactionBlock(params);
|
|
46
89
|
}
|
|
47
90
|
|
|
91
|
+
/**
|
|
92
|
+
* Sign a transaction using the current `sui:signTransaction` feature.
|
|
93
|
+
* @param {Object} params
|
|
94
|
+
* @returns {Promise<SignatureWithBytes>}
|
|
95
|
+
*/
|
|
96
|
+
async signTransaction(params) {
|
|
97
|
+
/** @type {SignatureWithBytes} */
|
|
98
|
+
const resp = await this.getFeature(Feature.SUI_SIGN_TX).signTransaction(params);
|
|
99
|
+
return resp;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Sign a transaction. Prefers the current `sui:signTransaction` feature;
|
|
104
|
+
* falls back to the legacy `sui:signTransactionBlock` for older wallets.
|
|
105
|
+
* @param {Object} params
|
|
106
|
+
* @returns {Promise<*>}
|
|
107
|
+
*/
|
|
48
108
|
async signTransactionBlock(params) {
|
|
49
109
|
if (this.hasFeature(Feature.SUI_SIGN_TX)) {
|
|
50
110
|
return await this.getFeature(Feature.SUI_SIGN_TX).signTransaction(params);
|
|
@@ -55,10 +115,12 @@ export default class SuiInBrowserAdapter extends SuiCommonMethods {
|
|
|
55
115
|
}
|
|
56
116
|
}
|
|
57
117
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
118
|
+
/**
|
|
119
|
+
* Sign a personal/arbitrary message. Prefers `sui:signPersonalMessage`;
|
|
120
|
+
* falls back to `sui:signMessage` for older wallets.
|
|
121
|
+
* @param {Object} params
|
|
122
|
+
* @returns {Promise<*>}
|
|
123
|
+
*/
|
|
62
124
|
async signPersonalMessage(params) {
|
|
63
125
|
if (this.hasFeature(Feature.SUI_SIGN_PERSONAL_MESSAGE)) {
|
|
64
126
|
return await this.getFeature(Feature.SUI_SIGN_PERSONAL_MESSAGE).signPersonalMessage(params);
|
|
@@ -67,16 +129,43 @@ export default class SuiInBrowserAdapter extends SuiCommonMethods {
|
|
|
67
129
|
}
|
|
68
130
|
}
|
|
69
131
|
|
|
132
|
+
/**
|
|
133
|
+
* Alias for `signPersonalMessage`.
|
|
134
|
+
* @param {Object} params
|
|
135
|
+
* @returns {Promise<*>}
|
|
136
|
+
*/
|
|
70
137
|
async signMessage(params) {
|
|
71
138
|
return await this.signPersonalMessage(params);
|
|
72
139
|
}
|
|
73
140
|
|
|
141
|
+
/**
|
|
142
|
+
* Disconnect from the wallet and refresh connection state.
|
|
143
|
+
* Force-clears local connection state even if the wallet doesn't support
|
|
144
|
+
* standard:disconnect or doesn't revoke site authorization (e.g. Phantom).
|
|
145
|
+
* @param {Object} [params]
|
|
146
|
+
* @returns {Promise<void>}
|
|
147
|
+
*/
|
|
74
148
|
async disconnect(params) {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
149
|
+
try {
|
|
150
|
+
const feature = this.getFeature(Feature.DISCONNECT);
|
|
151
|
+
if (feature) {
|
|
152
|
+
await feature.disconnect(params);
|
|
153
|
+
}
|
|
154
|
+
} catch (e) {
|
|
155
|
+
console.warn('[SuiInBrowserAdapter] standard:disconnect failed:', e);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
this._connectedAddress = null;
|
|
159
|
+
this._connectedChain = null;
|
|
160
|
+
this._isConnected = false;
|
|
161
|
+
this._userDisconnected = true;
|
|
162
|
+
this.emit('disconnected', this);
|
|
78
163
|
}
|
|
79
164
|
|
|
165
|
+
/**
|
|
166
|
+
* Return the Chrome Web Store download URL, or null if not configured.
|
|
167
|
+
* @returns {?string}
|
|
168
|
+
*/
|
|
80
169
|
getDownloadURL() {
|
|
81
170
|
if (this._downloadUrls && this._downloadUrls.chrome) {
|
|
82
171
|
return this._downloadUrls.chrome;
|
|
@@ -84,26 +173,36 @@ export default class SuiInBrowserAdapter extends SuiCommonMethods {
|
|
|
84
173
|
return null;
|
|
85
174
|
}
|
|
86
175
|
|
|
176
|
+
/**
|
|
177
|
+
* True when no underlying adapter has been attached (i.e. this is a "not installed" placeholder).
|
|
178
|
+
* @returns {boolean}
|
|
179
|
+
*/
|
|
87
180
|
get isDefault() {
|
|
88
|
-
|
|
89
|
-
return true;
|
|
90
|
-
}
|
|
91
|
-
return false;
|
|
181
|
+
return !this._standardAdapter;
|
|
92
182
|
}
|
|
93
183
|
|
|
184
|
+
/** @returns {?string} currently connected Sui address, or null */
|
|
94
185
|
get connectedAddress() {
|
|
95
186
|
return this._connectedAddress;
|
|
96
187
|
}
|
|
97
188
|
|
|
189
|
+
/** @returns {?string} currently connected chain identifier (e.g. `'sui:mainnet'`), or null */
|
|
98
190
|
get connectedChain() {
|
|
99
191
|
return this._connectedChain;
|
|
100
192
|
}
|
|
101
193
|
|
|
194
|
+
/** @returns {boolean} true if the wallet is connected and an address is available */
|
|
102
195
|
get isConnected() {
|
|
103
196
|
return this._isConnected;
|
|
104
197
|
}
|
|
105
198
|
|
|
199
|
+
/**
|
|
200
|
+
* Request connection to the wallet. Errors are swallowed; connection state is refreshed
|
|
201
|
+
* via `connectionUpdated` regardless.
|
|
202
|
+
* @returns {Promise<void>}
|
|
203
|
+
*/
|
|
106
204
|
async connect() {
|
|
205
|
+
this._userDisconnected = false;
|
|
107
206
|
try {
|
|
108
207
|
await this.getFeature(Feature.CONNECT).connect();
|
|
109
208
|
} catch (e) {
|
|
@@ -113,14 +212,21 @@ export default class SuiInBrowserAdapter extends SuiCommonMethods {
|
|
|
113
212
|
this.connectionUpdated();
|
|
114
213
|
}
|
|
115
214
|
|
|
215
|
+
/**
|
|
216
|
+
* Read the current connection state from the underlying adapter and update
|
|
217
|
+
* `connectedAddress`, `connectedChain`, and `isConnected`. Emits `'connected'` or
|
|
218
|
+
* `'disconnected'` if the state changed.
|
|
219
|
+
*/
|
|
116
220
|
connectionUpdated() {
|
|
221
|
+
if (this._userDisconnected) return;
|
|
222
|
+
|
|
117
223
|
const wasConnectedAddress = ''+this._connectedAddress;
|
|
118
224
|
const wasConnectedChain = ''+this._connectedChain;
|
|
119
225
|
|
|
120
226
|
try {
|
|
121
|
-
if (this.
|
|
122
|
-
this._connectedAddress = this.
|
|
123
|
-
this._connectedChain = this.
|
|
227
|
+
if (this._standardAdapter && this._standardAdapter.accounts && this._standardAdapter.accounts.length) {
|
|
228
|
+
this._connectedAddress = this._standardAdapter.accounts[0].address;
|
|
229
|
+
this._connectedChain = this._standardAdapter.accounts[0].chains[0];
|
|
124
230
|
} else {
|
|
125
231
|
this._connectedAddress = null;
|
|
126
232
|
this._connectedChain = null;
|
|
@@ -141,16 +247,23 @@ export default class SuiInBrowserAdapter extends SuiCommonMethods {
|
|
|
141
247
|
}
|
|
142
248
|
}
|
|
143
249
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
250
|
+
/**
|
|
251
|
+
* Attach a Wallet Standard adapter to this instance. No-op if already attached.
|
|
252
|
+
* Returns false and does nothing if the adapter has no `sui:` features.
|
|
253
|
+
* Subscribes to adapter `'change'` events to keep connection state up to date.
|
|
254
|
+
*
|
|
255
|
+
* @param {Object} standardAdapter - raw adapter from `@wallet-standard/core`
|
|
256
|
+
* @returns {boolean} false if the adapter lacks Sui features, undefined on success
|
|
257
|
+
*/
|
|
258
|
+
setStandartAdapter(standardAdapter) {
|
|
259
|
+
if (this._standardAdapter) {
|
|
147
260
|
// no need to re-attach
|
|
148
261
|
return true;
|
|
149
262
|
}
|
|
150
263
|
|
|
151
264
|
// check if it has sui: features
|
|
152
265
|
let hasSuiFeatures = false;
|
|
153
|
-
for (const key in
|
|
266
|
+
for (const key in standardAdapter.features) {
|
|
154
267
|
if ((''+key).indexOf('sui:') === 0) {
|
|
155
268
|
hasSuiFeatures = true;
|
|
156
269
|
}
|
|
@@ -160,65 +273,97 @@ export default class SuiInBrowserAdapter extends SuiCommonMethods {
|
|
|
160
273
|
return false;
|
|
161
274
|
}
|
|
162
275
|
|
|
163
|
-
this.
|
|
164
|
-
if (!this.
|
|
165
|
-
this.
|
|
276
|
+
this._standardAdapter = standardAdapter;
|
|
277
|
+
if (!this.__standardAdapterChangeListener) {
|
|
278
|
+
this.__standardAdapterChangeListener = () => {
|
|
166
279
|
this.connectionUpdated();
|
|
167
280
|
};
|
|
168
281
|
}
|
|
169
|
-
this.getFeature(Feature.EVENTS).on('change', this.
|
|
282
|
+
this.getFeature(Feature.EVENTS).on('change', this.__standardAdapterChangeListener);
|
|
170
283
|
|
|
171
284
|
this.connectionUpdated();
|
|
172
285
|
}
|
|
173
286
|
|
|
287
|
+
/**
|
|
288
|
+
* True if the adapter is installed and supports the minimum required Sui features
|
|
289
|
+
* (`sui:signAndExecuteTransaction` or `sui:signAndExecuteTransactionBlock`, plus `standard:events`).
|
|
290
|
+
* @returns {boolean}
|
|
291
|
+
*/
|
|
174
292
|
get okForSui() {
|
|
175
293
|
if (!this.isInstalled) {
|
|
176
294
|
return false;
|
|
177
295
|
}
|
|
178
296
|
|
|
179
|
-
return this.hasFeature(Feature.SUI_SIGN_AND_EXECUTE_TX_BLOCK) && this.hasFeature(Feature.EVENTS);
|
|
297
|
+
return (this.hasFeature(Feature.SUI_SIGN_AND_EXECUTE_TX_BLOCK) || this.hasFeature(Feature.SUI_SIGN_AND_EXECUTE_TX)) && this.hasFeature(Feature.EVENTS);
|
|
180
298
|
}
|
|
181
299
|
|
|
300
|
+
/** @returns {boolean} true if a Wallet Standard adapter has been attached */
|
|
182
301
|
get isInstalled() {
|
|
183
|
-
|
|
184
|
-
return true;
|
|
185
|
-
}
|
|
186
|
-
return false;
|
|
302
|
+
return !!this._standardAdapter;
|
|
187
303
|
}
|
|
188
304
|
|
|
305
|
+
/**
|
|
306
|
+
* Feature map from the underlying adapter, or an empty object if not installed.
|
|
307
|
+
* Keys are Wallet Standard feature strings (e.g. `'sui:signAndExecuteTransaction'`).
|
|
308
|
+
* @returns {Object}
|
|
309
|
+
*/
|
|
189
310
|
get features() {
|
|
190
|
-
if (this.
|
|
191
|
-
return this.
|
|
311
|
+
if (this._standardAdapter) {
|
|
312
|
+
return this._standardAdapter.features;
|
|
192
313
|
}
|
|
193
314
|
return {};
|
|
194
315
|
}
|
|
195
316
|
|
|
317
|
+
/**
|
|
318
|
+
* Display name — from the adapter if installed, otherwise from the constructor param.
|
|
319
|
+
* @returns {?string}
|
|
320
|
+
*/
|
|
196
321
|
get name() {
|
|
197
|
-
if (this.
|
|
198
|
-
return this.
|
|
322
|
+
if (this._standardAdapter) {
|
|
323
|
+
return this._standardAdapter.name;
|
|
199
324
|
} else {
|
|
200
325
|
return this._name;
|
|
201
326
|
}
|
|
202
327
|
}
|
|
203
328
|
|
|
329
|
+
/**
|
|
330
|
+
* Data-URI icon — from the adapter if installed, otherwise from the constructor param.
|
|
331
|
+
* @returns {?string}
|
|
332
|
+
*/
|
|
204
333
|
get icon() {
|
|
205
|
-
if (this.
|
|
206
|
-
return this.
|
|
334
|
+
if (this._standardAdapter) {
|
|
335
|
+
return this._standardAdapter.icon;
|
|
207
336
|
} else {
|
|
208
337
|
return this._icon;
|
|
209
338
|
}
|
|
210
339
|
}
|
|
211
340
|
|
|
341
|
+
/**
|
|
342
|
+
* Wallet version string from the adapter, or undefined if not installed.
|
|
343
|
+
* @returns {?string}
|
|
344
|
+
*/
|
|
212
345
|
get version() {
|
|
213
|
-
if (this.
|
|
214
|
-
return this.
|
|
346
|
+
if (this._standardAdapter) {
|
|
347
|
+
return this._standardAdapter.version;
|
|
215
348
|
}
|
|
216
349
|
}
|
|
217
350
|
|
|
351
|
+
/**
|
|
352
|
+
* Returns true if this adapter supports the given feature.
|
|
353
|
+
* Accepts either a `Feature` enum key (e.g. `'SUI_SIGN_TX'`) or a raw feature string.
|
|
354
|
+
* @param {string} featureName
|
|
355
|
+
* @returns {boolean}
|
|
356
|
+
*/
|
|
218
357
|
hasFeature(featureName) {
|
|
219
358
|
return (!!this.getFeature(featureName));
|
|
220
359
|
}
|
|
221
360
|
|
|
361
|
+
/**
|
|
362
|
+
* Return the feature object for `featureName`, or null if not available.
|
|
363
|
+
* Accepts either a `Feature` enum key (e.g. `'SUI_SIGN_TX'`) or a raw feature string.
|
|
364
|
+
* @param {string} featureName
|
|
365
|
+
* @returns {?Object}
|
|
366
|
+
*/
|
|
222
367
|
getFeature(featureName) {
|
|
223
368
|
const features = this.features;
|
|
224
369
|
|
|
@@ -2,29 +2,55 @@ import SuiCliCommands from "./SuiCliCommands.js";
|
|
|
2
2
|
import SuiCommonMethods from "./SuiCommonMethods.js";
|
|
3
3
|
import SuiUtils from "./SuiUtils.js";
|
|
4
4
|
|
|
5
|
+
/** @typedef {import("@mysten/sui/grpc").SuiGrpcClient} SuiGrpcClient */
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Manages a local `sui start` test-validator process. The singleton pattern (`launch` / `stop`)
|
|
9
|
+
* means only one validator runs per test suite even when called from multiple test files.
|
|
10
|
+
*
|
|
11
|
+
* When `testFallbackEnabled` is true and `sui start` fails (e.g. Sui CLI not installed),
|
|
12
|
+
* the instance transparently switches to `sui:devnet` so tests can still run against a live node.
|
|
13
|
+
*/
|
|
5
14
|
export default class SuiLocalTestValidator extends SuiCommonMethods {
|
|
15
|
+
/**
|
|
16
|
+
* @param {Object} [params]
|
|
17
|
+
* @param {boolean} [params.testFallbackEnabled] - fall back to devnet if the local node can't start
|
|
18
|
+
* @param {?number} [params.epochDuration] - custom epoch duration in ms (only valid with `--force-regenesis`)
|
|
19
|
+
* @param {boolean} [params.debug]
|
|
20
|
+
*/
|
|
6
21
|
constructor(params = {}) {
|
|
7
22
|
super(params);
|
|
8
23
|
|
|
24
|
+
/** @type {?Object} spawned child process */
|
|
9
25
|
this._child = null;
|
|
26
|
+
/** @type {boolean} */
|
|
10
27
|
this._active = false;
|
|
11
28
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}
|
|
29
|
+
/**
|
|
30
|
+
* When true, falls back to sui:devnet if the local node can't be started.
|
|
31
|
+
* @type {boolean}
|
|
32
|
+
*/
|
|
33
|
+
this._testFallbackEnabled = !!params.testFallbackEnabled;
|
|
18
34
|
|
|
35
|
+
/** @type {?number} */
|
|
19
36
|
this._epochDuration = params.epochDuration || null;
|
|
20
37
|
|
|
38
|
+
/** @type {string} */
|
|
21
39
|
this._providerName = 'sui:localnet';
|
|
22
40
|
}
|
|
23
41
|
|
|
42
|
+
/** @returns {string} active chain identifier, e.g. `'sui:localnet'` or `'sui:devnet'` after fallback */
|
|
24
43
|
get providerName() {
|
|
25
44
|
return this._providerName;
|
|
26
45
|
}
|
|
27
46
|
|
|
47
|
+
/** @type {?SuiLocalTestValidator} */
|
|
48
|
+
static __instance = null;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* gRPC client for the currently active chain.
|
|
52
|
+
* @returns {SuiGrpcClient}
|
|
53
|
+
*/
|
|
28
54
|
get client() {
|
|
29
55
|
if (this._providerName === 'sui:localnet') {
|
|
30
56
|
return SuiUtils.suiClientFor('localnet');
|
|
@@ -34,15 +60,19 @@ export default class SuiLocalTestValidator extends SuiCommonMethods {
|
|
|
34
60
|
}
|
|
35
61
|
}
|
|
36
62
|
|
|
63
|
+
/** @returns {boolean} true once the node is up and accepting transactions */
|
|
37
64
|
get active() {
|
|
38
65
|
return this._active;
|
|
39
66
|
}
|
|
40
67
|
|
|
41
68
|
/**
|
|
42
|
-
* Launch
|
|
43
|
-
* Don't forget to
|
|
44
|
-
*
|
|
45
|
-
* @
|
|
69
|
+
* Launch the local sui node (singleton). If already running, returns the existing instance.
|
|
70
|
+
* Don't forget to call `.stop()` after usage.
|
|
71
|
+
*
|
|
72
|
+
* @param {Object} [params]
|
|
73
|
+
* @param {boolean} [params.testFallbackEnabled]
|
|
74
|
+
* @param {?number} [params.epochDuration]
|
|
75
|
+
* @returns {Promise<SuiLocalTestValidator>}
|
|
46
76
|
*/
|
|
47
77
|
static async launch(params = {}) {
|
|
48
78
|
if (SuiLocalTestValidator.__instance) {
|
|
@@ -54,7 +84,8 @@ export default class SuiLocalTestValidator extends SuiCommonMethods {
|
|
|
54
84
|
}
|
|
55
85
|
|
|
56
86
|
/**
|
|
57
|
-
* Stop the local sui node
|
|
87
|
+
* Stop the singleton local sui node if running.
|
|
88
|
+
* @returns {Promise<void>}
|
|
58
89
|
*/
|
|
59
90
|
static async stop() {
|
|
60
91
|
if (SuiLocalTestValidator.__instance) {
|
|
@@ -62,10 +93,20 @@ export default class SuiLocalTestValidator extends SuiCommonMethods {
|
|
|
62
93
|
}
|
|
63
94
|
}
|
|
64
95
|
|
|
96
|
+
/**
|
|
97
|
+
* @param {number} port
|
|
98
|
+
* @returns {Promise<boolean>} true if the port accepts a TCP connection within 3 seconds
|
|
99
|
+
*/
|
|
65
100
|
async isPortThere(port) {
|
|
66
101
|
return await SuiCliCommands.isPortThere(port);
|
|
67
102
|
}
|
|
68
103
|
|
|
104
|
+
/**
|
|
105
|
+
* Poll `isPortThere` every 500 ms until the port is open or the timeout elapses.
|
|
106
|
+
* @param {number} port
|
|
107
|
+
* @param {number} timeout - total wait time in ms
|
|
108
|
+
* @returns {Promise<boolean>}
|
|
109
|
+
*/
|
|
69
110
|
async waitForPort(port, timeout) {
|
|
70
111
|
this.log('waiting for port', port);
|
|
71
112
|
const startedCheckingAt = (new Date()).getTime();
|
|
@@ -82,9 +123,13 @@ export default class SuiLocalTestValidator extends SuiCommonMethods {
|
|
|
82
123
|
}
|
|
83
124
|
|
|
84
125
|
/**
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
*
|
|
126
|
+
* Start `sui start --with-faucet --with-indexer --with-graphql --force-regenesis`,
|
|
127
|
+
* wait for the faucet (port 9123) and GraphQL (port 9125) to come up,
|
|
128
|
+
* then return this instance with `active === true`.
|
|
129
|
+
*
|
|
130
|
+
* If `testFallbackEnabled` is set and the spawn fails, silently switches to devnet.
|
|
131
|
+
*
|
|
132
|
+
* @returns {Promise<SuiLocalTestValidator>}
|
|
88
133
|
*/
|
|
89
134
|
async launch() {
|
|
90
135
|
if (this._active) {
|
|
@@ -98,6 +143,8 @@ export default class SuiLocalTestValidator extends SuiCommonMethods {
|
|
|
98
143
|
const params = [];
|
|
99
144
|
params.push('start');
|
|
100
145
|
params.push('--with-faucet');
|
|
146
|
+
params.push('--with-indexer');
|
|
147
|
+
params.push('--with-graphql');
|
|
101
148
|
params.push('--force-regenesis');
|
|
102
149
|
this._child = await SuiCliCommands.spawn('sui', params, { RUST_LOG: 'off,sui_node=info' });
|
|
103
150
|
} catch (e) {
|
|
@@ -120,22 +167,37 @@ export default class SuiLocalTestValidator extends SuiCommonMethods {
|
|
|
120
167
|
this.log(`child process exited with code ${code}`);
|
|
121
168
|
});
|
|
122
169
|
|
|
170
|
+
// @ts-ignore — process is a Node.js global; not available in TypeScript without @types/node
|
|
123
171
|
process.on('exit', ()=>{
|
|
124
172
|
if (this._child) {
|
|
125
173
|
this._child.kill();
|
|
126
174
|
}
|
|
127
175
|
});
|
|
176
|
+
// @ts-ignore
|
|
128
177
|
const cleanExit = function() { process.exit() };
|
|
178
|
+
// @ts-ignore
|
|
129
179
|
process.on('SIGINT', cleanExit); // catch ctrl-c
|
|
180
|
+
// @ts-ignore
|
|
130
181
|
process.on('SIGTERM', cleanExit); // catch kill
|
|
131
182
|
|
|
132
183
|
this._active = await this.waitForPort(9123, 30000);
|
|
133
184
|
|
|
185
|
+
if (this._active) {
|
|
186
|
+
const graphqlUp = await this.waitForPort(9125, 30000);
|
|
187
|
+
if (!graphqlUp) {
|
|
188
|
+
this.log('warning: GraphQL port 9125 did not come up in time');
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
134
192
|
// await this.__readyLaunchedPromise;
|
|
135
193
|
|
|
136
194
|
return this;
|
|
137
195
|
}
|
|
138
196
|
|
|
197
|
+
/**
|
|
198
|
+
* Kill the child `sui start` process if it is running.
|
|
199
|
+
* @returns {Promise<void>}
|
|
200
|
+
*/
|
|
139
201
|
async stop() {
|
|
140
202
|
if (this._child) {
|
|
141
203
|
await this._child.kill();
|