suidouble 2.5.0 → 2.16.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 +164 -37
- 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/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 +167 -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
package/lib/SuiPackage.js
CHANGED
|
@@ -3,10 +3,14 @@ import SuiObject from './SuiObject.js';
|
|
|
3
3
|
import SuiPackageModule from './SuiPackageModule.js';
|
|
4
4
|
import SuiPaginatedResponse from './SuiPaginatedResponse.js';
|
|
5
5
|
import { Transaction } from '@mysten/sui/transactions';
|
|
6
|
-
|
|
6
|
+
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* @typedef {import("./SuiMaster.js").default} SuiMaster
|
|
10
|
+
* @typedef {import("./SuiTransaction.js").default} SuiTransaction
|
|
11
|
+
* @typedef {import("./SuiEvent.js").default} SuiEvent
|
|
12
|
+
* @typedef {import("./SuiMemoryObjectStorage.js").default} SuiMemoryObjectStorage
|
|
13
|
+
* @typedef {import("@mysten/sui/transactions").Inputs} Inputs
|
|
10
14
|
*/
|
|
11
15
|
|
|
12
16
|
export default class SuiPackage extends SuiObject {
|
|
@@ -20,14 +24,9 @@ export default class SuiPackage extends SuiObject {
|
|
|
20
24
|
* @param {?Array.<string>|string} [params.modules] - List of modules in the package to look on chain in the UpgradeCap owned by current address
|
|
21
25
|
* @param {boolean} [params.debug] - Enable debug mode
|
|
22
26
|
*/
|
|
23
|
-
constructor(params
|
|
27
|
+
constructor(params) {
|
|
24
28
|
super(params);
|
|
25
29
|
|
|
26
|
-
// set in super() :
|
|
27
|
-
// this._id
|
|
28
|
-
// this._suiMaster
|
|
29
|
-
|
|
30
|
-
|
|
31
30
|
/** @type {?string} */
|
|
32
31
|
this._path = params.path;
|
|
33
32
|
/** @type {?string} */
|
|
@@ -46,33 +45,58 @@ export default class SuiPackage extends SuiObject {
|
|
|
46
45
|
this._builtDependencies = null;
|
|
47
46
|
this._builtDigest = null;
|
|
48
47
|
|
|
48
|
+
/**
|
|
49
|
+
* Cached original package id (first published version). Stable across upgrades.
|
|
50
|
+
* Lazy — do not read directly, use `getOriginalPackageId()`.
|
|
51
|
+
* @type {?string}
|
|
52
|
+
*/
|
|
53
|
+
this._originalPackageId = null;
|
|
54
|
+
|
|
49
55
|
/** @type {Object.<string, SuiPackageModule>} */
|
|
50
56
|
this._modules = {
|
|
51
57
|
|
|
52
58
|
};
|
|
53
59
|
}
|
|
54
60
|
|
|
61
|
+
/** @returns {SuiMemoryObjectStorage} shared object storage for this suiMaster */
|
|
55
62
|
get objectStorage() {
|
|
56
63
|
return this._suiMaster.objectStorage;
|
|
57
64
|
}
|
|
58
65
|
|
|
66
|
+
/** @returns {Object.<string, SuiPackageModule>} map of module name → SuiPackageModule */
|
|
59
67
|
get modules() {
|
|
60
68
|
return this._modules;
|
|
61
69
|
}
|
|
62
70
|
|
|
71
|
+
/**
|
|
72
|
+
* Ensure the package is on chain, then return the named module.
|
|
73
|
+
* @param {string} moduleName
|
|
74
|
+
* @returns {Promise<SuiPackageModule|undefined>}
|
|
75
|
+
*/
|
|
63
76
|
async getModule(moduleName) {
|
|
64
77
|
await this.checkOnChainIfNeeded();
|
|
65
78
|
return this._modules[moduleName];
|
|
66
79
|
}
|
|
67
80
|
|
|
81
|
+
/** @returns {boolean} true if the local Move project has been built via `build()` */
|
|
68
82
|
get isBuilt() {
|
|
69
83
|
return this._isBuilt;
|
|
70
84
|
}
|
|
71
85
|
|
|
86
|
+
/**
|
|
87
|
+
* Published version of this package as a plain `number`.
|
|
88
|
+
* Returns `0` if the package has not been published yet (`_publishedVersion` is null).
|
|
89
|
+
* @returns {number}
|
|
90
|
+
*/
|
|
72
91
|
get version() {
|
|
73
92
|
return Number(this._publishedVersion); // return as Number in getter
|
|
74
93
|
}
|
|
75
94
|
|
|
95
|
+
/**
|
|
96
|
+
* Returns true if this package is confirmed published on chain.
|
|
97
|
+
* Swallows `checkOnChainIfNeeded` errors so it always resolves.
|
|
98
|
+
* @returns {Promise<boolean>}
|
|
99
|
+
*/
|
|
76
100
|
async isOnChain() {
|
|
77
101
|
try {
|
|
78
102
|
await this.checkOnChainIfNeeded();
|
|
@@ -87,18 +111,93 @@ export default class SuiPackage extends SuiObject {
|
|
|
87
111
|
return false;
|
|
88
112
|
}
|
|
89
113
|
|
|
114
|
+
/**
|
|
115
|
+
* Shortcut for `suiMaster.utils.pureInput(type, value)` — build a BCS-serialised Pure input
|
|
116
|
+
* to use as a moveCall parameter.
|
|
117
|
+
* @param {string} type - BCS type name, e.g. `'u64'`, `'address'`, `'string'`
|
|
118
|
+
* @param {*} value
|
|
119
|
+
* @returns {ReturnType<Inputs['Pure']>}
|
|
120
|
+
*/
|
|
90
121
|
arg(type, value) {
|
|
91
122
|
return this._suiMaster.utils.pureInput(type, value);
|
|
92
123
|
}
|
|
93
124
|
|
|
125
|
+
/**
|
|
126
|
+
* Convenience wrapper — delegates to `this.modules[moduleName].moveCall(...)`.
|
|
127
|
+
* @param {string} moduleName
|
|
128
|
+
* @param {string} methodName
|
|
129
|
+
* @param {Array} params - see `SuiPackageModule.moveCall` for element shapes
|
|
130
|
+
* @param {string[]} [typeArguments]
|
|
131
|
+
* @returns {Promise<SuiTransaction>}
|
|
132
|
+
*/
|
|
94
133
|
async moveCall(moduleName, methodName, params, typeArguments) {
|
|
95
134
|
await this.checkOnChainIfNeeded();
|
|
96
135
|
return await this.modules[moduleName].moveCall(methodName, params, typeArguments);
|
|
97
136
|
}
|
|
98
137
|
|
|
99
|
-
|
|
138
|
+
/**
|
|
139
|
+
* Fetch all events emitted by any module of this package, via the GraphQL `events` query.
|
|
140
|
+
* Uses the original (first-version) package id so the filter stays stable across upgrades.
|
|
141
|
+
* For module-scoped or event-type-scoped queries use `this.modules[name].fetchEvents(...)`.
|
|
142
|
+
*
|
|
143
|
+
* @param {Object} [params]
|
|
144
|
+
* @param {number} [params.limit=50]
|
|
145
|
+
* @param {string} [params.order] - Passed through to the underlying paginated response
|
|
146
|
+
* @returns {Promise<SuiPaginatedResponse<SuiEvent>>}
|
|
147
|
+
*/
|
|
148
|
+
async fetchEvents(params = {}) {
|
|
149
|
+
await this.checkOnChainIfNeeded();
|
|
150
|
+
|
|
151
|
+
const packageId = await this.getOriginalPackageId();
|
|
152
|
+
|
|
153
|
+
return await this._suiMaster.fetchEvents({
|
|
154
|
+
filter: { module: packageId },
|
|
155
|
+
limit: params.limit,
|
|
156
|
+
order: params.order,
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* List objects of any type belonging to this package owned by the current SuiMaster address.
|
|
162
|
+
* Uses the original (first-version) package id and GraphQL (gRPC can't filter by package alone).
|
|
163
|
+
*
|
|
164
|
+
* For module-scoped or full-struct-type filtering use `this.modules[name].getOwnedObjects(...)`.
|
|
165
|
+
*
|
|
166
|
+
* @param {Object} [params]
|
|
167
|
+
* @param {number} [params.limit=50]
|
|
168
|
+
* @param {string} [params.order]
|
|
169
|
+
* @returns {Promise<SuiPaginatedResponse<SuiObject>>}
|
|
170
|
+
*/
|
|
171
|
+
async getOwnedObjects(params = {}) {
|
|
100
172
|
await this.checkOnChainIfNeeded();
|
|
101
|
-
|
|
173
|
+
|
|
174
|
+
const packageId = await this.getOriginalPackageId();
|
|
175
|
+
|
|
176
|
+
return await this._suiMaster.getOwnedObjects({
|
|
177
|
+
owner: this._suiMaster.address,
|
|
178
|
+
type: packageId,
|
|
179
|
+
limit: params.limit || 50,
|
|
180
|
+
}, { order: params.order });
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Get the original (first-version) package id, stable across upgrades.
|
|
185
|
+
* Caches the value on first fetch.
|
|
186
|
+
*
|
|
187
|
+
* @returns {Promise<string>}
|
|
188
|
+
*/
|
|
189
|
+
async getOriginalPackageId() {
|
|
190
|
+
if (this._originalPackageId) {
|
|
191
|
+
return this._originalPackageId;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const { response } = await this._suiMaster._client.movePackageService.getPackage({
|
|
195
|
+
packageId: this.address,
|
|
196
|
+
});
|
|
197
|
+
const pkg = response?.package;
|
|
198
|
+
this._originalPackageId = pkg?.originalId || pkg?.storageId || this.address;
|
|
199
|
+
|
|
200
|
+
return this._originalPackageId;
|
|
102
201
|
}
|
|
103
202
|
|
|
104
203
|
async checkOnChainIfNeeded() {
|
|
@@ -132,7 +231,8 @@ export default class SuiPackage extends SuiObject {
|
|
|
132
231
|
* Try to find package on chain using its modules names.
|
|
133
232
|
* Search for packages you own, in last versions of it
|
|
134
233
|
* List all UpgradeCap -> List packages -> Filter ( max version, all modules )
|
|
135
|
-
*
|
|
234
|
+
*
|
|
235
|
+
* @returns {Promise<?string>} id of the highest-version package that contains all expected modules, or null if none matched
|
|
136
236
|
*/
|
|
137
237
|
async tryToFindByExpectedModules() {
|
|
138
238
|
this.log('trying to find Package by expected modules in its content...');
|
|
@@ -140,11 +240,9 @@ export default class SuiPackage extends SuiObject {
|
|
|
140
240
|
// normalize expected modules. May be an array or comma separated string
|
|
141
241
|
const expectModules = [];
|
|
142
242
|
|
|
143
|
-
let arr = this._expectedModules
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
arr = (''+this._expectedModules).split(',');
|
|
147
|
-
}
|
|
243
|
+
let arr = Array.isArray(this._expectedModules)
|
|
244
|
+
? this._expectedModules
|
|
245
|
+
: (''+this._expectedModules).split(',');
|
|
148
246
|
arr.forEach((item)=>{
|
|
149
247
|
if (item.trim()) {
|
|
150
248
|
if (expectModules.indexOf(item.trim()) === -1) {
|
|
@@ -159,23 +257,14 @@ export default class SuiPackage extends SuiObject {
|
|
|
159
257
|
|
|
160
258
|
// UpgradeCap references to most recent version of packages. But there're no modules fields in it
|
|
161
259
|
// So what we do is getting list of UpgradeCap first
|
|
162
|
-
const
|
|
260
|
+
const paginatedResponse = await this._suiMaster.getOwnedObjects({
|
|
163
261
|
owner: this._suiMaster.address,
|
|
164
|
-
|
|
165
|
-
limit: 50,
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
showOwner: true,
|
|
170
|
-
showDisplay: true,
|
|
262
|
+
type: '0x2::package::UpgradeCap',
|
|
263
|
+
limit: 50,
|
|
264
|
+
include: {
|
|
265
|
+
content: true,
|
|
266
|
+
json: true,
|
|
171
267
|
},
|
|
172
|
-
};
|
|
173
|
-
|
|
174
|
-
const paginatedResponse = new SuiPaginatedResponse({
|
|
175
|
-
debug: this._debug,
|
|
176
|
-
suiMaster: this._suiMaster,
|
|
177
|
-
params: queryParams,
|
|
178
|
-
method: 'getOwnedObjects',
|
|
179
268
|
});
|
|
180
269
|
|
|
181
270
|
await paginatedResponse.forEach((suiObject)=>{
|
|
@@ -186,36 +275,38 @@ export default class SuiPackage extends SuiObject {
|
|
|
186
275
|
}); // go through all available UpgradeCap
|
|
187
276
|
// paginatedResponse.forEach also accepts async callbacks
|
|
188
277
|
|
|
189
|
-
//
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
278
|
+
// fetch each package via movePackageService to check its modules list
|
|
279
|
+
const packagesResult = await Promise.all(
|
|
280
|
+
packagesOnChainIds.map(async (packageId) => {
|
|
281
|
+
try {
|
|
282
|
+
const { response } = await this._suiMaster._client.movePackageService.getPackage({ packageId });
|
|
283
|
+
return response?.package ? { packageId, pkg: response.package } : null;
|
|
284
|
+
} catch (e) {
|
|
285
|
+
return null;
|
|
286
|
+
}
|
|
287
|
+
})
|
|
288
|
+
);
|
|
196
289
|
|
|
197
|
-
let maxVersion =
|
|
290
|
+
let maxVersion = 0;
|
|
198
291
|
let packageIdWithMaxVersion = null;
|
|
199
292
|
let packagesWithOkModulesCount = 0; // just to log
|
|
200
293
|
|
|
201
294
|
// find package with highest version which has all needed modules
|
|
202
|
-
for (const
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
});
|
|
295
|
+
for (const item of packagesResult) {
|
|
296
|
+
if (!item) continue;
|
|
297
|
+
const { packageId, pkg } = item;
|
|
298
|
+
|
|
299
|
+
const moduleNames = (pkg.modules || []).map((m) => m.name);
|
|
300
|
+
const allNeededModules = expectModules.every((m) => moduleNames.includes(m));
|
|
209
301
|
|
|
210
|
-
const version =
|
|
302
|
+
const version = Number(pkg.version ?? 0);
|
|
211
303
|
|
|
212
304
|
if (allNeededModules) {
|
|
213
305
|
packagesWithOkModulesCount++;
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
packageIdWithMaxVersion = packagesResultItem.data.objectId;
|
|
306
|
+
if (version > maxVersion) {
|
|
307
|
+
maxVersion = version;
|
|
308
|
+
packageIdWithMaxVersion = pkg.storageId || packageId;
|
|
309
|
+
}
|
|
219
310
|
}
|
|
220
311
|
}
|
|
221
312
|
|
|
@@ -231,54 +322,69 @@ export default class SuiPackage extends SuiObject {
|
|
|
231
322
|
|
|
232
323
|
/**
|
|
233
324
|
* Get published package version
|
|
234
|
-
*
|
|
325
|
+
*
|
|
326
|
+
* @param {Object} [options]
|
|
327
|
+
* @param {number} [options.timeout=10000] - total time in ms to keep polling if package is not found
|
|
328
|
+
*
|
|
329
|
+
* @returns {Promise<?number>} on-chain package version, or null if it could not be read before the timeout
|
|
235
330
|
*/
|
|
236
|
-
async getVersionOnChain() {
|
|
331
|
+
async getVersionOnChain(options = {}) {
|
|
237
332
|
this.log('geting package version previously published on chain...');
|
|
238
333
|
|
|
334
|
+
const timeout = options.timeout !== undefined ? options.timeout : 10000;
|
|
335
|
+
const pollInterval = 1000;
|
|
336
|
+
const deadline = Date.now() + timeout;
|
|
337
|
+
|
|
239
338
|
const client = await this._suiMaster.getClient();
|
|
240
339
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
340
|
+
let pkg = null;
|
|
341
|
+
while (true) {
|
|
342
|
+
try {
|
|
343
|
+
const { response } = await client.movePackageService.getPackage({
|
|
344
|
+
packageId: this.address,
|
|
345
|
+
});
|
|
346
|
+
pkg = response?.package;
|
|
347
|
+
} catch (e) {
|
|
348
|
+
const willRetry = Date.now() + pollInterval <= deadline;
|
|
349
|
+
this.log('getPackage failed', e && e.message ? e.message : e, willRetry ? `will retry in ${pollInterval}ms` : 'giving up, timeout reached');
|
|
350
|
+
pkg = null;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
if (pkg) {
|
|
354
|
+
break;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
if (Date.now() + pollInterval > deadline) {
|
|
358
|
+
this.log('package not found on chain', this.address);
|
|
359
|
+
return this._publishedVersion;
|
|
360
|
+
}
|
|
253
361
|
|
|
254
|
-
|
|
255
|
-
|
|
362
|
+
await new Promise((resolve) => setTimeout(resolve, pollInterval));
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
if (pkg.version !== undefined) {
|
|
366
|
+
this._publishedVersion = Number(pkg.version);
|
|
256
367
|
this._isPublished = true;
|
|
257
368
|
}
|
|
258
369
|
|
|
259
|
-
if (
|
|
260
|
-
for (const
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
// this._modules[key] = new SuiPackageModule({
|
|
265
|
-
// suiMaster: this._suiMaster,
|
|
266
|
-
// debug: this._debug,
|
|
267
|
-
// moduleName: key,
|
|
268
|
-
// package: this,
|
|
269
|
-
// });
|
|
270
|
-
// }
|
|
370
|
+
if (pkg.modules) {
|
|
371
|
+
for (const moduleDef of pkg.modules) {
|
|
372
|
+
if (moduleDef.name) {
|
|
373
|
+
this.attachModule(moduleDef.name);
|
|
374
|
+
}
|
|
271
375
|
}
|
|
272
376
|
}
|
|
273
377
|
|
|
274
378
|
this.log('on chain version', this._publishedVersion, 'with modules', Object.keys(this._modules));
|
|
275
|
-
|
|
379
|
+
|
|
276
380
|
return this._publishedVersion;
|
|
277
381
|
}
|
|
278
382
|
|
|
279
383
|
/**
|
|
280
384
|
* Attach module to this package and add event listeners over it
|
|
281
|
-
*
|
|
385
|
+
*
|
|
386
|
+
* @param {string} moduleName
|
|
387
|
+
* @returns {boolean} true if the module was newly attached, false if it was already attached
|
|
282
388
|
*/
|
|
283
389
|
attachModule(moduleName) {
|
|
284
390
|
if (this._modules[moduleName]) {
|
|
@@ -292,7 +398,7 @@ export default class SuiPackage extends SuiObject {
|
|
|
292
398
|
package: this,
|
|
293
399
|
});
|
|
294
400
|
this._modules[moduleName].addEventListener('added', (data)=>{
|
|
295
|
-
const object = data.detail;
|
|
401
|
+
const object = /** @type {any} */ (data).detail;
|
|
296
402
|
this.emit('added', object);
|
|
297
403
|
});
|
|
298
404
|
|
|
@@ -304,7 +410,8 @@ export default class SuiPackage extends SuiObject {
|
|
|
304
410
|
/**
|
|
305
411
|
* UpgradeCap is capability object required to publish updates for a package.
|
|
306
412
|
* We are trying to find it in owned objects with this function
|
|
307
|
-
*
|
|
413
|
+
*
|
|
414
|
+
* @returns {Promise<?string>} id of UpgradeCap for this package, or null if none is owned by the current address
|
|
308
415
|
*/
|
|
309
416
|
async getUpgradeCapId() {
|
|
310
417
|
if (this._upgradeCap) {
|
|
@@ -313,103 +420,77 @@ export default class SuiPackage extends SuiObject {
|
|
|
313
420
|
|
|
314
421
|
this.log('trying to find UpgradeCap for this package in owned objects...');
|
|
315
422
|
|
|
316
|
-
|
|
317
|
-
let nextCursor = null;
|
|
318
|
-
|
|
319
|
-
do {
|
|
320
|
-
const queryParams = {
|
|
423
|
+
const ownedUpgradeCapsPaginated = await this._suiMaster.getOwnedObjects({
|
|
321
424
|
owner: this._suiMaster.address,
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
showOwner: true,
|
|
328
|
-
showDisplay: true,
|
|
425
|
+
type: '0x2::package::UpgradeCap',
|
|
426
|
+
include: {
|
|
427
|
+
content: true,
|
|
428
|
+
objectBcs: true,
|
|
429
|
+
json: true,
|
|
329
430
|
},
|
|
330
|
-
};
|
|
331
|
-
|
|
332
|
-
if (
|
|
333
|
-
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
const result = await this._suiMaster._client.getOwnedObjects(queryParams);
|
|
337
|
-
|
|
338
|
-
if (result.hasNextPage && result.nextCursor) {
|
|
339
|
-
hasNextPage = true;
|
|
340
|
-
nextCursor = result.nextCursor;
|
|
341
|
-
} else {
|
|
342
|
-
hasNextPage = false;
|
|
431
|
+
});
|
|
432
|
+
ownedUpgradeCapsPaginated.forEach((suiObject)=>{
|
|
433
|
+
if (suiObject?.fields?.package == this._id) {
|
|
434
|
+
this._upgradeCap = suiObject;
|
|
343
435
|
}
|
|
436
|
+
});
|
|
344
437
|
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
suiMaster: this._suiMaster,
|
|
350
|
-
debug: this._debug,
|
|
351
|
-
});
|
|
352
|
-
|
|
353
|
-
this.log('found UpgradeCap', this._upgradeCap.address);
|
|
354
|
-
|
|
355
|
-
return this._upgradeCap.address;
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
} while(hasNextPage && !this._upgradeCap);
|
|
438
|
+
if (this._upgradeCap) {
|
|
439
|
+
this.log('found UpgradeCap', this._upgradeCap.id);
|
|
440
|
+
return this._upgradeCap.id;
|
|
441
|
+
}
|
|
359
442
|
|
|
360
443
|
this.log('no UpgradeCap for this package found. Are you sure you work with most recent version of the package?');
|
|
361
|
-
|
|
362
444
|
return null;
|
|
363
445
|
}
|
|
364
446
|
|
|
447
|
+
/**
|
|
448
|
+
* Read the result of a publish/upgrade transaction and update local package state:
|
|
449
|
+
* sets `_id`, `_publishedVersion`, `_isPublished` from the created `package` object,
|
|
450
|
+
* records `_upgradeCapId` from the created `UpgradeCap`, and refreshes on-chain version.
|
|
451
|
+
*
|
|
452
|
+
* @param {SuiTransaction} result - transaction result returned from publish()/upgrade()
|
|
453
|
+
* @returns {Promise<boolean>} true if the package is now marked as published
|
|
454
|
+
*/
|
|
365
455
|
async storeInfoFromPublishResult(result) {
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
this._id = normalizeSuiAddress(objectChange.packageId);
|
|
456
|
+
if (result && result.created) {
|
|
457
|
+
for (const createdObject of result.created) {
|
|
458
|
+
if (createdObject.type == 'package') {
|
|
459
|
+
this._id = createdObject.id;
|
|
371
460
|
this._isPublished = true;
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
if (objectChange.modules) {
|
|
378
|
-
for (const module of objectChange.modules) {
|
|
379
|
-
this.attachModule(module);
|
|
380
|
-
}
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
if (objectChange.type === 'created' && objectChange.objectType.indexOf('::package::UpgradeCap') !== -1) {
|
|
385
|
-
this._upgradeCapId = objectChange.objectId;
|
|
461
|
+
this._publishedVersion = createdObject.version;
|
|
462
|
+
} else if (createdObject.typeName == 'UpgradeCap') {
|
|
463
|
+
this._upgradeCapId = createdObject.id;
|
|
386
464
|
this.log('UpgradeCap', this._upgradeCapId);
|
|
465
|
+
} else {
|
|
466
|
+
// objects created by the Move `init` function (e.g. shared objects)
|
|
467
|
+
this.objectStorage.push(createdObject);
|
|
387
468
|
}
|
|
388
469
|
}
|
|
389
470
|
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
if (objectChange.objectId && objectChange.objectType && objectChange.type && (objectChange.type == 'created' || objectChange.type == 'mutated')) {
|
|
393
|
-
// : not sure if it's good decision, but lets add objects to all modules we published
|
|
394
|
-
for (const moduleName in this._modules) {
|
|
395
|
-
const object = this._modules[moduleName].pushObject(objectChange.objectId);
|
|
396
|
-
if (object) {
|
|
397
|
-
object.tryToFillDataFromObjectChange(objectChange);
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
}
|
|
471
|
+
if (this._id) {
|
|
472
|
+
await this.getVersionOnChain();
|
|
401
473
|
}
|
|
474
|
+
}
|
|
402
475
|
|
|
403
|
-
this.log('got results:', this.address, 'version', this._publishedVersion, 'with modules', Object.keys(this._modules));
|
|
404
|
-
|
|
405
|
-
return true;
|
|
406
|
-
} else {
|
|
407
|
-
this.log('nothing is found in publish result. storing old values');
|
|
408
476
|
|
|
409
|
-
|
|
410
|
-
}
|
|
477
|
+
return this._isPublished;
|
|
411
478
|
}
|
|
412
479
|
|
|
480
|
+
/**
|
|
481
|
+
* Publish the Move package to the chain for the first time.
|
|
482
|
+
*
|
|
483
|
+
* Flow:
|
|
484
|
+
* - build the local Move project if it has not been built yet
|
|
485
|
+
* - throw if the package already has an on-chain address (use upgrade() instead)
|
|
486
|
+
* - submit a publish transaction and transfer the returned UpgradeCap to the current address
|
|
487
|
+
* - refresh local publish info from the result
|
|
488
|
+
*
|
|
489
|
+
* @param {Object} [params] - Configuration parameters
|
|
490
|
+
* @param {?string} [params.env] - Sui CLI env to switch to before building (forwarded to build())
|
|
491
|
+
* @returns {Promise<?string>} the on-chain package id, or null if publish info could not be read
|
|
492
|
+
* @throws if the package is already published
|
|
493
|
+
*/
|
|
413
494
|
async publish(params = {}) {
|
|
414
495
|
if (!this._isBuilt) {
|
|
415
496
|
await this.build(params);
|
|
@@ -427,33 +508,43 @@ export default class SuiPackage extends SuiObject {
|
|
|
427
508
|
});
|
|
428
509
|
|
|
429
510
|
tx.transferObjects([upgradeCap], this._suiMaster.address);
|
|
511
|
+
tx.setSenderIfNotSet(this._suiMaster.address);
|
|
430
512
|
|
|
431
513
|
const result = await this._suiMaster.signAndExecuteTransaction({
|
|
432
514
|
transaction: tx,
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
"showEvents": true, // @todo: remove?
|
|
437
|
-
"showObjectChanges": true,
|
|
515
|
+
include: {
|
|
516
|
+
effects: true,
|
|
517
|
+
objectTypes: true,
|
|
438
518
|
},
|
|
439
519
|
});
|
|
440
520
|
|
|
441
|
-
// const suiTransaction = new this._suiMaster.SuiTransaction({
|
|
442
|
-
// suiMaster: this._suiMaster,
|
|
443
|
-
// debug: this._debug,
|
|
444
|
-
// data: result,
|
|
445
|
-
// });
|
|
446
|
-
// await suiTransaction.waitForTransaction();
|
|
447
|
-
|
|
448
521
|
const success = await this.storeInfoFromPublishResult(result);
|
|
449
522
|
|
|
450
523
|
if (success) {
|
|
451
524
|
this.log('published');
|
|
452
525
|
}
|
|
453
526
|
|
|
527
|
+
this.log('published', this.address);
|
|
528
|
+
|
|
454
529
|
return this.address;
|
|
455
530
|
}
|
|
456
531
|
|
|
532
|
+
/**
|
|
533
|
+
* Upgrade an on-chain package to a newer version from local Move sources.
|
|
534
|
+
*
|
|
535
|
+
* Flow:
|
|
536
|
+
* - ensure the package is known on chain (checkOnChainIfNeeded)
|
|
537
|
+
* - build the local Move project if it has not been built yet
|
|
538
|
+
* - authorize the upgrade using the owned UpgradeCap (COMPATIBLE policy)
|
|
539
|
+
* - execute the upgrade transaction and commit it
|
|
540
|
+
* - refresh local publish info from the result
|
|
541
|
+
*
|
|
542
|
+
* Requires an UpgradeCap owned by the current address.
|
|
543
|
+
*
|
|
544
|
+
* @param {Object} [params] - Configuration parameters
|
|
545
|
+
* @param {?string} [params.env] - Sui CLI env to switch to before building (forwarded to build())
|
|
546
|
+
* @returns {Promise<boolean>} true on successful upgrade (version incremented), false otherwise
|
|
547
|
+
*/
|
|
457
548
|
async upgrade(params = {}) {
|
|
458
549
|
await this.checkOnChainIfNeeded();
|
|
459
550
|
|
|
@@ -487,7 +578,7 @@ export default class SuiPackage extends SuiObject {
|
|
|
487
578
|
const receipt = tx.upgrade({
|
|
488
579
|
modules: this._builtModules,
|
|
489
580
|
dependencies: this._builtDependencies,
|
|
490
|
-
package: this.address,
|
|
581
|
+
package: this.address,
|
|
491
582
|
ticket,
|
|
492
583
|
});
|
|
493
584
|
|
|
@@ -496,28 +587,39 @@ export default class SuiPackage extends SuiObject {
|
|
|
496
587
|
arguments: [cap, receipt],
|
|
497
588
|
});
|
|
498
589
|
|
|
499
|
-
|
|
590
|
+
const wasAtVersion = this._publishedVersion;
|
|
500
591
|
|
|
501
|
-
const
|
|
592
|
+
const signAndExecuteTransactionResult = await this._suiMaster.signAndExecuteTransaction({
|
|
502
593
|
transaction: tx,
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
594
|
+
include: {
|
|
595
|
+
effects: true,
|
|
596
|
+
objectTypes: true,
|
|
506
597
|
},
|
|
598
|
+
requestType: 'WaitForLocalExecution',
|
|
507
599
|
});
|
|
600
|
+
const success = await this.storeInfoFromPublishResult(signAndExecuteTransactionResult);
|
|
508
601
|
|
|
509
|
-
|
|
602
|
+
if (success && this._publishedVersion > wasAtVersion) {
|
|
603
|
+
this.log('upgraded. New version: '+this._publishedVersion+' at packageId: '+this._id);
|
|
510
604
|
|
|
511
|
-
|
|
512
|
-
this.log('upgraded');
|
|
605
|
+
return true;
|
|
513
606
|
}
|
|
514
607
|
|
|
515
|
-
return
|
|
608
|
+
return false;
|
|
516
609
|
}
|
|
517
610
|
|
|
518
611
|
/**
|
|
519
|
-
* Build
|
|
520
|
-
*
|
|
612
|
+
* Build the local Move project by invoking `sui move build --dump-bytecode-as-base64`
|
|
613
|
+
* and cache the resulting modules, dependencies and digest on the instance
|
|
614
|
+
* (`_builtModules`, `_builtDependencies`, `_builtDigest`). Sets `_isBuilt = true`.
|
|
615
|
+
*
|
|
616
|
+
* Must have a local source `path` set on the package — throws otherwise.
|
|
617
|
+
*
|
|
618
|
+
* @param {Object} [params] - Configuration parameters
|
|
619
|
+
* @param {?string} [params.env] - If set, runs `sui client switch --env <env>` before building
|
|
620
|
+
* @param {?boolean} [params.withUnpublishedDependencies] - Pass `--with-unpublished-dependencies` to the build command
|
|
621
|
+
* @returns {Promise<boolean>} true on success
|
|
622
|
+
* @throws if no local path is set
|
|
521
623
|
*/
|
|
522
624
|
async build(params = {}) {
|
|
523
625
|
this.log('building a package...');
|
|
@@ -554,11 +656,14 @@ export default class SuiPackage extends SuiObject {
|
|
|
554
656
|
}
|
|
555
657
|
|
|
556
658
|
/**
|
|
557
|
-
*
|
|
558
|
-
*
|
|
659
|
+
* Read the local `build/<pkg>/bytecode_modules` directory and return the list of compiled module names.
|
|
660
|
+
* Requires the package to have been built already (via `sui move build` or this instance's `build()`).
|
|
661
|
+
*
|
|
662
|
+
* @returns {Promise<string[]>} list of module names (without the `.mv` suffix)
|
|
663
|
+
* @throws if the local path is not set or the build directory can not be read
|
|
559
664
|
*/
|
|
560
665
|
async getModulesNamesFromBuild() {
|
|
561
|
-
this.log('
|
|
666
|
+
this.log('trying to get modules names from local package path...');
|
|
562
667
|
|
|
563
668
|
try {
|
|
564
669
|
return SuiCliCommands.getModulesNamesFromPackagePath(this._path);
|