universa-core2 2.0.0-alpha.1
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/LICENSE +8 -0
- package/LICENSE.BSD-3-Clause +30 -0
- package/LICENSE.GPL-2.0 +339 -0
- package/README.md +718 -0
- package/dist/.gitkeep +0 -0
- package/dist/index.cjs +2140 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +611 -0
- package/dist/index.mjs +80 -0
- package/package.json +67 -0
package/README.md
ADDED
|
@@ -0,0 +1,718 @@
|
|
|
1
|
+
# universa-core2
|
|
2
|
+
|
|
3
|
+
The official maintained continuation of the Universa JavaScript SDK. It provides tools for working with Universa networks, contracts, transaction packs, parcels, roles, permissions, and keys.
|
|
4
|
+
|
|
5
|
+
`universa-core2` continues the open-source [`universa-core`](https://www.npmjs.com/package/universa-core) project under a new package name because the modernized SDK may not be completely compatible with applications built against the legacy release. The maintained source is [`sergeych/universa-core2`](https://github.com/sergeych/universa-core2). It is derived from [`UniversaBlockchain/universa-core-js`](https://github.com/UniversaBlockchain/universa-core-js), whose history and attribution are retained in this continuation.
|
|
6
|
+
|
|
7
|
+
> **Alpha status:** the API and packaging may change before the stable 2.0 release. Test existing applications before migrating, and pin the prerelease version where reproducible builds matter.
|
|
8
|
+
|
|
9
|
+
Copyright (c) 2026 Sergey Chernov. Dual-licensed under
|
|
10
|
+
BSD-3-Clause or GPL-2.0; see the included license files.
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
### Node.js
|
|
15
|
+
|
|
16
|
+
Node.js 20 or newer is required. Install the current alpha explicitly:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install universa-core2@alpha
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Or with yarn:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
yarn add universa-core2@alpha
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Import APIs from the new package name:
|
|
29
|
+
|
|
30
|
+
```javascript
|
|
31
|
+
import { Network } from 'universa-core2';
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Migrating from `universa-core`
|
|
35
|
+
|
|
36
|
+
Change the dependency and package imports:
|
|
37
|
+
|
|
38
|
+
```diff
|
|
39
|
+
- import { Network, PrivateKey } from 'universa-core';
|
|
40
|
+
+ import { Network, PrivateKey } from 'universa-core2';
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
The project keeps the familiar SDK API where practical, but this alpha is not promised to be a drop-in replacement. In particular, validate module loading, network connectivity, topology handling, contract serialization, and browser-specific integration in your application. The alpha currently targets modern Node.js; do not assume that the legacy browser bundle workflow is unchanged.
|
|
44
|
+
|
|
45
|
+
## Contract
|
|
46
|
+
### Basic models
|
|
47
|
+
#### KeyRecord
|
|
48
|
+
KeyRecord is PublicKey container extended with extra data
|
|
49
|
+
```js
|
|
50
|
+
import { PublicKey, KeyRecord } from 'universa-core2';
|
|
51
|
+
|
|
52
|
+
const pub: PublicKey;
|
|
53
|
+
const optionalData = { comment: "this is key record", author: "John Doe" };
|
|
54
|
+
const record = KeyRecord.create(pub, optionalData);
|
|
55
|
+
|
|
56
|
+
record.extra.comment === "this is key record"; // true
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Roles
|
|
60
|
+
#### Availability for keys/addresses
|
|
61
|
+
```js
|
|
62
|
+
const isAvailable1 = await role.availableFor({ keys: [publicKey] });
|
|
63
|
+
const isAvailable2 = await role.availableFor({ addresses: [publicKey.shortAddress] });
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
#### Simple Role
|
|
67
|
+
Simple role can be created both with addresses and public keys
|
|
68
|
+
```js
|
|
69
|
+
import {
|
|
70
|
+
PublicKey,
|
|
71
|
+
KeyRecord,
|
|
72
|
+
RoleSimple
|
|
73
|
+
} from 'universa-core2';
|
|
74
|
+
|
|
75
|
+
const pub: PublicKey;
|
|
76
|
+
const pub2: PublicKey;
|
|
77
|
+
const role = new RoleSimple("director", { addresses: [pub.shortAddress, pub2.longAddress] });
|
|
78
|
+
const role = new RoleSimple("assistant", { keys: [pub, pub2] });
|
|
79
|
+
```
|
|
80
|
+
Also, you can create simple role with KeyRecord
|
|
81
|
+
```js
|
|
82
|
+
import {
|
|
83
|
+
PublicKey,
|
|
84
|
+
KeyRecord,
|
|
85
|
+
RoleSimple
|
|
86
|
+
} from 'universa-core2';
|
|
87
|
+
|
|
88
|
+
const pub: PublicKey;
|
|
89
|
+
const record = KeyRecord.create(pub, { description: "main key" });
|
|
90
|
+
const role = new RoleSimple("director", { keyRecords: [record] });
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
#### Role Link
|
|
94
|
+
Create role that links to other role
|
|
95
|
+
```js
|
|
96
|
+
import { RoleLink, RoleSimple } from 'universa-core2';
|
|
97
|
+
|
|
98
|
+
const roleSimple: RoleSimple;
|
|
99
|
+
const link1 = new RoleSimple("director", roleSimple.name);
|
|
100
|
+
const link2 = new RoleLink("assistant", "worker3");
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
#### Role List
|
|
104
|
+
Role List is role that represents logical combination of other roles
|
|
105
|
+
|
|
106
|
+
ANY mode to create role that available for any role in the list
|
|
107
|
+
```js
|
|
108
|
+
import { RoleList, RoleLink, RoleSimple } from 'universa-core2';
|
|
109
|
+
|
|
110
|
+
const link1: RoleLink;
|
|
111
|
+
const link2: RoleLink;
|
|
112
|
+
const simple1: RoleSimple;
|
|
113
|
+
|
|
114
|
+
const list1 = new RoleList("founder", {
|
|
115
|
+
mode: RoleList.MODES.ANY,
|
|
116
|
+
roles: [link1, link2, simple1]
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
// or create list with role names
|
|
120
|
+
const list2 = new RoleList("founder", {
|
|
121
|
+
mode: RoleList.MODES.ANY,
|
|
122
|
+
roleNames: [link1.name, link2.name, simple1.name]
|
|
123
|
+
});
|
|
124
|
+
```
|
|
125
|
+
ALL mode to create role that available only if all roles from list available
|
|
126
|
+
```js
|
|
127
|
+
import { RoleList, RoleLink, RoleSimple } from 'universa-core2';
|
|
128
|
+
|
|
129
|
+
const link1: RoleLink;
|
|
130
|
+
const link2: RoleLink;
|
|
131
|
+
const simple1: RoleSimple;
|
|
132
|
+
|
|
133
|
+
const list1 = new RoleList("founder", {
|
|
134
|
+
mode: RoleList.MODES.ALL,
|
|
135
|
+
roles: [link1, link2, simple1]
|
|
136
|
+
});
|
|
137
|
+
```
|
|
138
|
+
QUORUM mode to make role available if at least quorumSize(number) roles is available
|
|
139
|
+
```js
|
|
140
|
+
import { RoleList, RoleLink, RoleSimple } from 'universa-core2';
|
|
141
|
+
|
|
142
|
+
const link1: RoleLink;
|
|
143
|
+
const link2: RoleLink;
|
|
144
|
+
const simple1: RoleSimple;
|
|
145
|
+
|
|
146
|
+
// list1 is available for any 2 roles from list
|
|
147
|
+
const list1 = new RoleList("founder", {
|
|
148
|
+
mode: RoleList.MODES.QUORUM,
|
|
149
|
+
roles: [link1, link2, simple1],
|
|
150
|
+
quorumSize: 2
|
|
151
|
+
});
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### Permissions
|
|
155
|
+
#### Revoke permission
|
|
156
|
+
Revoke permission grants permission to revoke contract to specific role
|
|
157
|
+
```js
|
|
158
|
+
import { RevokePermission } from 'universa-core2';
|
|
159
|
+
|
|
160
|
+
const role: Role;
|
|
161
|
+
|
|
162
|
+
const revoke = new RevokePermission(role);
|
|
163
|
+
// or with custom permission name
|
|
164
|
+
const revokeAdmin = new RevokePermission(role, "revoke_admin");
|
|
165
|
+
// or with role name
|
|
166
|
+
const revoke2 = RevokePermission.create("owner");
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
#### Change owner permission
|
|
170
|
+
Change owner permission grants permission to change owner of contract
|
|
171
|
+
```js
|
|
172
|
+
import { ChangeOwnerPermission } from 'universa-core2';
|
|
173
|
+
|
|
174
|
+
const admin: Role;
|
|
175
|
+
|
|
176
|
+
const changeOwner = new ChangeOwnerPermission(admin);
|
|
177
|
+
// or with custom permission name
|
|
178
|
+
const changeOwnerByAdmin = new ChangeOwnerPermission(admin, "change_admin");
|
|
179
|
+
// or with role name
|
|
180
|
+
const changeOwner2 = ChangeOwnerPermission.create("admin");
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
#### Change number permission
|
|
184
|
+
Change number permission grants permission to change number value of the specific field in state.data section of contract
|
|
185
|
+
```js
|
|
186
|
+
import { ChangeNumberPermission } from 'universa-core2';
|
|
187
|
+
|
|
188
|
+
const admin: Role;
|
|
189
|
+
|
|
190
|
+
const params = {
|
|
191
|
+
field_name: "amount", // field to change in state data
|
|
192
|
+
min_value: "1", // minimum value of field (string/number)
|
|
193
|
+
max_value: "100", // maximum value of field (string/number)
|
|
194
|
+
min_step: "1", // minimum step of value change per one revision (string/number)
|
|
195
|
+
max_step: "5", // maximum step of value change per one revision (string/number)
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
const changeNumber = new ChangeNumberPermission(admin, params);
|
|
199
|
+
// or with custom permission name
|
|
200
|
+
const changeNumberByAdmin = new ChangeNumberPermission(admin, params, "change_number_admin");
|
|
201
|
+
// or with role name
|
|
202
|
+
const changeNumber2 = ChangeNumberPermission.create("admin", params);
|
|
203
|
+
|
|
204
|
+
console.log(changeNumber.params); // params
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
#### Modify data permission
|
|
208
|
+
Modify data permission grants permission to change multitype value of the specific field in state.data section of contract with fixed set of values
|
|
209
|
+
```js
|
|
210
|
+
import { ModifyDataPermission } from 'universa-core2';
|
|
211
|
+
|
|
212
|
+
const admin: Role;
|
|
213
|
+
|
|
214
|
+
const params = {
|
|
215
|
+
fields: {
|
|
216
|
+
amount: [10, 20], // amount field can contain only values 10 or 20
|
|
217
|
+
textIdentifier: [], // textIdentifier can contain any value
|
|
218
|
+
documentReference: [null, "referenceA", "referenceB"], // can be empty
|
|
219
|
+
acceptedAt: [yesterday, tomorrow] // Date instances
|
|
220
|
+
}
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
const modifyData = new ModifyDataPermission(admin, params);
|
|
224
|
+
// or with custom permission name
|
|
225
|
+
const modifyDataByAdmin = new ModifyDataPermission(admin, params, "modify_data_admin");
|
|
226
|
+
// or with role name
|
|
227
|
+
const modifyData2 = ModifyDataPermission.create("admin", params);
|
|
228
|
+
|
|
229
|
+
console.log(modifyData.params); // params
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
#### Split / join permission
|
|
233
|
+
Split / join permission grants permission to split or join contracts by specific number field when some of contract attribures are the same
|
|
234
|
+
```js
|
|
235
|
+
import { SplitJoinPermission } from 'universa-core2';
|
|
236
|
+
|
|
237
|
+
const admin: Role;
|
|
238
|
+
|
|
239
|
+
const params = {
|
|
240
|
+
field_name: "amount", // number field to split/join
|
|
241
|
+
min_value: "15", // minimum value of amount (string/number)
|
|
242
|
+
min_unit: "5", // minimum unit to split (string/number)
|
|
243
|
+
join_match_fields: ["origin", "unit_currency"] // array of fields, that must be same
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
const splitJoin = new SplitJoinPermission(admin, params);
|
|
247
|
+
// or with custom permission name
|
|
248
|
+
const splitJoinByAdmin = new SplitJoinPermission(admin, params, "split_join_admin");
|
|
249
|
+
// or with role name
|
|
250
|
+
const splitJoin2 = SplitJoinPermission.create("admin", params);
|
|
251
|
+
|
|
252
|
+
console.log(splitJoin.params); // params
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
### Transaction
|
|
256
|
+
Create transactional section with given ID
|
|
257
|
+
```js
|
|
258
|
+
const contract; // Contract instance
|
|
259
|
+
contract.createTransactional("myUniqueId"); // creates empty transactional section with id
|
|
260
|
+
console.log(contract.transactional); // { id: "myUniqueId" }
|
|
261
|
+
```
|
|
262
|
+
Set transactional section to null
|
|
263
|
+
```js
|
|
264
|
+
const contract; // Contract instance
|
|
265
|
+
contract.resetTransactional();
|
|
266
|
+
console.log(contract.transactional); // null
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
### References
|
|
270
|
+
To create definition and state references, use types Reference.TYPE_EXISTING_DEFINITION, Reference.TYPE_EXISTING_STATE
|
|
271
|
+
```js
|
|
272
|
+
import { Reference } from 'universa-core2';
|
|
273
|
+
|
|
274
|
+
// example of where condition
|
|
275
|
+
const name = 'my_reference';
|
|
276
|
+
const type = Reference.TYPE_TRANSACTIONAL; // transactional reference
|
|
277
|
+
const where = { all_of: [ 'ref.id==this.definition.data.my_first_id' ] };
|
|
278
|
+
const refTransactional = new Reference(name, type, where);
|
|
279
|
+
|
|
280
|
+
console.log(refTransactional.name); // 'my_reference'
|
|
281
|
+
console.log(refTransactional.where); // { all_of: [ 'ref.id==this.definition.data.my_first_id' ] }
|
|
282
|
+
console.log(refTransactional.type); // Reference.TYPE_TRANSACTIONAL
|
|
283
|
+
```
|
|
284
|
+
Add reference to contract
|
|
285
|
+
```js
|
|
286
|
+
import { Reference } from 'universa-core2';
|
|
287
|
+
|
|
288
|
+
const contract; // Contract instance
|
|
289
|
+
const name = 'my_reference';
|
|
290
|
+
const type = Reference.TYPE_EXISTING_DEFINITION; // definition reference
|
|
291
|
+
const where = { all_of: [ 'ref.id==this.definition.data.my_first_id' ] };
|
|
292
|
+
const refDefinition = new Reference(name, type, where);
|
|
293
|
+
|
|
294
|
+
contract.addReference(refDefinition); // adds reference to definition.references
|
|
295
|
+
console.log(contract.definition.references); // [Reference]
|
|
296
|
+
```
|
|
297
|
+
Modifying extra parameters
|
|
298
|
+
```js
|
|
299
|
+
import { Reference } from 'universa-core2';
|
|
300
|
+
|
|
301
|
+
const name = 'my_reference';
|
|
302
|
+
const type = Reference.TYPE_EXISTING_STATE; // definition reference
|
|
303
|
+
const where = { all_of: [ 'ref.id==this.definition.data.my_first_id' ] };
|
|
304
|
+
const ref = new Reference(name, type, where);
|
|
305
|
+
|
|
306
|
+
// here's some defaultls
|
|
307
|
+
console.log(ref.fields); // []
|
|
308
|
+
console.log(ref.roles); // []
|
|
309
|
+
console.log(ref.signedBy); // []
|
|
310
|
+
console.log(ref.transactionalId); // ''
|
|
311
|
+
console.log(ref.required); // true
|
|
312
|
+
|
|
313
|
+
// modify values
|
|
314
|
+
ref.required = false;
|
|
315
|
+
ref.transactionalId = 'some_id';
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
## Transaction Pack
|
|
319
|
+
Load transaction pack from binary
|
|
320
|
+
```js
|
|
321
|
+
import { TransactionPack } from 'universa-core2';
|
|
322
|
+
|
|
323
|
+
const tpackBinary; // Uint8Array;
|
|
324
|
+
const tpack = TransactionPack.unpack(tpackBinary);
|
|
325
|
+
|
|
326
|
+
tpack.contract // main contract
|
|
327
|
+
|
|
328
|
+
// Get parent of main contract
|
|
329
|
+
const parent = await tpack.getItem(tpack.contract.parent);
|
|
330
|
+
```
|
|
331
|
+
Sign transaction pack's main contract
|
|
332
|
+
```js
|
|
333
|
+
import { TransactionPack } from 'universa-core2';
|
|
334
|
+
|
|
335
|
+
const tpackBinary; // Uint8Array;
|
|
336
|
+
const tpack = TransactionPack.unpack(tpackBinary);
|
|
337
|
+
|
|
338
|
+
tpack.sign(privateKey); // some PrivateKey instance to sign
|
|
339
|
+
```
|
|
340
|
+
Get tagged contract
|
|
341
|
+
```js
|
|
342
|
+
import { TransactionPack } from 'universa-core2';
|
|
343
|
+
|
|
344
|
+
const tpackBinary; // Uint8Array;
|
|
345
|
+
const tpack = TransactionPack.unpack(tpackBinary);
|
|
346
|
+
|
|
347
|
+
const contract = await tpack.getTag("sometag"); // Contract instance
|
|
348
|
+
```
|
|
349
|
+
Add tag
|
|
350
|
+
```js
|
|
351
|
+
import { TransactionPack } from 'universa-core2';
|
|
352
|
+
|
|
353
|
+
const tpackBinary; // Uint8Array;
|
|
354
|
+
const tpack = TransactionPack.unpack(tpackBinary);
|
|
355
|
+
|
|
356
|
+
await tpack.addTag("mytag", hashId); // some HashId instance
|
|
357
|
+
```
|
|
358
|
+
Add subItem
|
|
359
|
+
```js
|
|
360
|
+
import { TransactionPack } from 'universa-core2';
|
|
361
|
+
|
|
362
|
+
const tpackBinary; // Uint8Array;
|
|
363
|
+
const contractBinary; // Uint8Array, packed Contract instance
|
|
364
|
+
const tpack = TransactionPack.unpack(tpackBinary); // TransactionPack instance
|
|
365
|
+
|
|
366
|
+
await tpack.addSubItem(contractBinary); // some HashId instance
|
|
367
|
+
```
|
|
368
|
+
Add referencedItem
|
|
369
|
+
```js
|
|
370
|
+
import { TransactionPack } from 'universa-core2';
|
|
371
|
+
|
|
372
|
+
const tpackBinary; // Uint8Array;
|
|
373
|
+
const contractBinary; // Uint8Array, packed Contract instance
|
|
374
|
+
const tpack = TransactionPack.unpack(tpackBinary); // TransactionPack instance
|
|
375
|
+
|
|
376
|
+
await tpack.addReferencedItem(contractBinary); // some HashId instance
|
|
377
|
+
```
|
|
378
|
+
Main Contract
|
|
379
|
+
```js
|
|
380
|
+
const main = tpack.contract;
|
|
381
|
+
|
|
382
|
+
main.issuer // issuer role
|
|
383
|
+
main.owner // owner role
|
|
384
|
+
main.creator // creator role
|
|
385
|
+
|
|
386
|
+
main.parent // hash id of parent contract
|
|
387
|
+
main.origin // hash id of origin contract
|
|
388
|
+
|
|
389
|
+
main.definition // definition
|
|
390
|
+
main.state // state
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
## Network
|
|
394
|
+
|
|
395
|
+
### Connecting to network
|
|
396
|
+
|
|
397
|
+
For a custom topology in a modern Node.js application, load its JSON and enable direct node connections when required:
|
|
398
|
+
|
|
399
|
+
```js
|
|
400
|
+
import { readFile } from 'node:fs/promises';
|
|
401
|
+
import { Network, Topology } from 'universa-core2';
|
|
402
|
+
|
|
403
|
+
const topologyData = JSON.parse(
|
|
404
|
+
await readFile(new URL('./universa.json', import.meta.url), 'utf8')
|
|
405
|
+
);
|
|
406
|
+
const topology = await Topology.load(topologyData);
|
|
407
|
+
|
|
408
|
+
// privateKey is a PrivateKey instance owned by this client.
|
|
409
|
+
const network = new Network(privateKey, {
|
|
410
|
+
topology,
|
|
411
|
+
directConnection: true
|
|
412
|
+
});
|
|
413
|
+
|
|
414
|
+
await network.connect();
|
|
415
|
+
const response = await network.command('sping');
|
|
416
|
+
console.log(response);
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
Set `directConnection` to `false` or omit it when the topology's normal network endpoints are appropriate.
|
|
420
|
+
|
|
421
|
+
This alpha deliberately does not bundle a default topology because the current
|
|
422
|
+
production topology has not yet been confirmed. Every `Network` must receive
|
|
423
|
+
either a `topology` or `topologyFile` option.
|
|
424
|
+
|
|
425
|
+
Connect with a topology provided by file path:
|
|
426
|
+
|
|
427
|
+
```js
|
|
428
|
+
import { Network, PrivateKey } from 'universa-core2';
|
|
429
|
+
|
|
430
|
+
const network = new Network(privateKey, {
|
|
431
|
+
topologyFile: "/path/to/universa.json",
|
|
432
|
+
directConnection: true
|
|
433
|
+
});
|
|
434
|
+
await network.connect();
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
### Topology
|
|
438
|
+
|
|
439
|
+
Load topology from a JSON file:
|
|
440
|
+
|
|
441
|
+
```js
|
|
442
|
+
import { readFile } from 'node:fs/promises';
|
|
443
|
+
import { Topology } from 'universa-core2';
|
|
444
|
+
|
|
445
|
+
const packed = JSON.parse(await readFile('/path/to/universa.json', 'utf8'));
|
|
446
|
+
const topology = await Topology.load(packed);
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
Get the validated, updated topology from a connected network:
|
|
450
|
+
|
|
451
|
+
```js
|
|
452
|
+
const { topology } = network; // Updated topology instance
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
Update and pack a topology for storage:
|
|
456
|
+
|
|
457
|
+
```js
|
|
458
|
+
await topology.update(true); // true selects direct node connections
|
|
459
|
+
const packedTopology = topology.pack();
|
|
460
|
+
```
|
|
461
|
+
|
|
462
|
+
### Running commands
|
|
463
|
+
network.command(commandName, parameters) - returns Promise with result
|
|
464
|
+
|
|
465
|
+
The following snippets assume `topology` was loaded as shown above.
|
|
466
|
+
|
|
467
|
+
```js
|
|
468
|
+
import { Network, PrivateKey } from 'universa-core2';
|
|
469
|
+
|
|
470
|
+
// privateKey is PrivateKey instance
|
|
471
|
+
const network = new Network(privateKey, { topology });
|
|
472
|
+
let response;
|
|
473
|
+
|
|
474
|
+
try { await network.connect(); }
|
|
475
|
+
catch (err) { console.log("network connection error: ", err); }
|
|
476
|
+
|
|
477
|
+
try {
|
|
478
|
+
// approvedId is Uint8Array
|
|
479
|
+
response = await network.command("getState", {
|
|
480
|
+
itemId: { __type: "HashId", composite3: approvedId }
|
|
481
|
+
});
|
|
482
|
+
}
|
|
483
|
+
catch (err) { console.log("on network command:", err); }
|
|
484
|
+
```
|
|
485
|
+
|
|
486
|
+
### Check full contract status
|
|
487
|
+
Special command to check contract status over network
|
|
488
|
+
isApproved(contractId, trustLevel: Double) // Promise[Boolean]
|
|
489
|
+
|
|
490
|
+
```js
|
|
491
|
+
import { Network, PrivateKey } from 'universa-core2';
|
|
492
|
+
|
|
493
|
+
// privateKey is PrivateKey instance
|
|
494
|
+
const network = new Network(privateKey, { topology });
|
|
495
|
+
let isApproved; // boolean
|
|
496
|
+
|
|
497
|
+
try { await network.connect(); }
|
|
498
|
+
catch (err) { console.log("network connection error: ", err); }
|
|
499
|
+
|
|
500
|
+
try {
|
|
501
|
+
// approvedId can be Uint8Array or base64 string
|
|
502
|
+
isApproved = await network.isApproved(approvedId, 0.6);
|
|
503
|
+
}
|
|
504
|
+
catch (err) { console.log("on network command:", err); }
|
|
505
|
+
```
|
|
506
|
+
|
|
507
|
+
### Check full contract status (extended info)
|
|
508
|
+
Special command to check contract status over network
|
|
509
|
+
checkContract(contractId: HashId | Uint8Array | string, trustLevel: Double)
|
|
510
|
+
|
|
511
|
+
```js
|
|
512
|
+
import { Network, PrivateKey, NetworkApproval } from 'universa-core2';
|
|
513
|
+
|
|
514
|
+
// privateKey is PrivateKey instance
|
|
515
|
+
const network = new Network(privateKey, { topology });
|
|
516
|
+
let status: NetworkApproval|null;
|
|
517
|
+
|
|
518
|
+
try { await network.connect(); }
|
|
519
|
+
catch (err) { console.log("network connection error: ", err); }
|
|
520
|
+
|
|
521
|
+
try {
|
|
522
|
+
// approvedId can be Uint8Array or base64 string
|
|
523
|
+
status = await network.checkContract(approvedId, 0.6);
|
|
524
|
+
}
|
|
525
|
+
catch (err) { console.log("on network command:", err); }
|
|
526
|
+
```
|
|
527
|
+
|
|
528
|
+
|
|
529
|
+
### Get network current time
|
|
530
|
+
Contract revisions that contain state.createdAt time far in past or future will be declined. To avoid this, it's recommended to use network current time while creating revisions.
|
|
531
|
+
|
|
532
|
+
To load network time and use current timestamp:
|
|
533
|
+
|
|
534
|
+
```js
|
|
535
|
+
import { Network, PrivateKey } from 'universa-core2';
|
|
536
|
+
|
|
537
|
+
const network = new Network(privateKey, { topology });
|
|
538
|
+
|
|
539
|
+
try { await network.connect(); } // network time is loaded
|
|
540
|
+
catch (err) { console.log("network connection error: ", err); }
|
|
541
|
+
|
|
542
|
+
const createdAt = network.now(); // Date (network current time)
|
|
543
|
+
```
|
|
544
|
+
|
|
545
|
+
Also, you can load network time only, without establishing connection:
|
|
546
|
+
|
|
547
|
+
```js
|
|
548
|
+
import { Network, PrivateKey } from 'universa-core2';
|
|
549
|
+
|
|
550
|
+
const network = new Network(privateKey, { topology });
|
|
551
|
+
await network.loadNetworkTime(); // network time is loaded
|
|
552
|
+
const createdAt = network.now(); // Date (network current time)
|
|
553
|
+
```
|
|
554
|
+
|
|
555
|
+
### Calculate transaction pack registration cost
|
|
556
|
+
To make payment you need to request it's costs first:
|
|
557
|
+
```js
|
|
558
|
+
const tpack; // TransactionPack instance
|
|
559
|
+
const costs = await Network.getCost(tpack);
|
|
560
|
+
console.log(costs); // { costInTu: 1, cost: 1, testnetCompatible: true }
|
|
561
|
+
```
|
|
562
|
+
|
|
563
|
+
## Parcel
|
|
564
|
+
Parcel is special object used to register contract with U payment.
|
|
565
|
+
|
|
566
|
+
To create payment
|
|
567
|
+
```js
|
|
568
|
+
import { Network, Parcel } from 'universa-core2';
|
|
569
|
+
|
|
570
|
+
const tpack; // TransactionPack instance to register
|
|
571
|
+
const upack; // TransactionPack instance of you U package contract
|
|
572
|
+
|
|
573
|
+
const costs = await Network.getCost(tpack);
|
|
574
|
+
// Create payment to register in TestNet (paymentTest is TransactionPack instance)
|
|
575
|
+
const paymentTest = await Parcel.createPayment(costs.costInTu, upack, { isTestnet: true });
|
|
576
|
+
// or in MainNet (paymentMain is TransactionPack instance)
|
|
577
|
+
const paymentMain = await Parcel.createPayment(costs.cost, upack, {
|
|
578
|
+
createdAt: network.now() // Network instance with loaded time offset
|
|
579
|
+
});
|
|
580
|
+
|
|
581
|
+
await paymentTest.sign(uKey); // uKey is upack owner's PrivateKey
|
|
582
|
+
|
|
583
|
+
// ALWAYS SAVE DRAFT PAYMENT BEFORE REGISTRATION
|
|
584
|
+
const paymentTestBin = await paymentTest.pack(); // TransactionPack binary
|
|
585
|
+
```
|
|
586
|
+
To create parcel
|
|
587
|
+
```js
|
|
588
|
+
const tpackToRegister; // TransactionPack instance to register
|
|
589
|
+
const tpackToRegisterBin = await tpackToRegister.pack();
|
|
590
|
+
|
|
591
|
+
const parcel = await Parcel.create(paymentBin, tpackToRegisterBin);
|
|
592
|
+
```
|
|
593
|
+
|
|
594
|
+
To register in Network
|
|
595
|
+
```js
|
|
596
|
+
const network; // Network instance, connected
|
|
597
|
+
|
|
598
|
+
const result = await network.registerParcel(parcel);
|
|
599
|
+
console.log(result.payment, result.payload); // shows itemResult for each pack
|
|
600
|
+
```
|
|
601
|
+
|
|
602
|
+
## Compound
|
|
603
|
+
Read compound
|
|
604
|
+
```js
|
|
605
|
+
import Compound from 'universa-core2';
|
|
606
|
+
|
|
607
|
+
const compoundBIN; // packed compound Uint8Array
|
|
608
|
+
const compound = Compound.unpack(compoundBIN);
|
|
609
|
+
```
|
|
610
|
+
|
|
611
|
+
Get tagged contract from compound
|
|
612
|
+
```js
|
|
613
|
+
import Compound from 'universa-core2';
|
|
614
|
+
|
|
615
|
+
const compoundBIN; // packed compound Uint8Array
|
|
616
|
+
const compound = Compound.unpack(compoundBIN);
|
|
617
|
+
const someContractTransactionPack = await compound.getTag('sometag'); // TransactionPack | null
|
|
618
|
+
```
|
|
619
|
+
|
|
620
|
+
Sign compound
|
|
621
|
+
```js
|
|
622
|
+
import Compound from 'universa-core2';
|
|
623
|
+
|
|
624
|
+
const compoundBIN; // packed compound Uint8Array
|
|
625
|
+
const compound = Compound.unpack(compoundBIN);
|
|
626
|
+
|
|
627
|
+
await compound.sign(privateKey); // privateKey: PrivateKey instance
|
|
628
|
+
```
|
|
629
|
+
|
|
630
|
+
Pack compound
|
|
631
|
+
```js
|
|
632
|
+
import Compound from 'universa-core2';
|
|
633
|
+
|
|
634
|
+
const compoundBIN; // packed compound Uint8Array
|
|
635
|
+
const compound = Compound.unpack(compoundBIN);
|
|
636
|
+
|
|
637
|
+
const packed = await compound.pack();
|
|
638
|
+
```
|
|
639
|
+
|
|
640
|
+
## Full example for creating and register your own unit contract
|
|
641
|
+
```js
|
|
642
|
+
const uPack; // U package TransactionPack instance, last revision
|
|
643
|
+
const uKey; // PrivateKey instance, uPack owner's key
|
|
644
|
+
const unitKey; // PrivateKey instance to be owner of your unit contract
|
|
645
|
+
|
|
646
|
+
const network = new Network(uKey, { topology });
|
|
647
|
+
// you can omit this step if you already have connected Network instance
|
|
648
|
+
await network.loadNetworkTime();
|
|
649
|
+
|
|
650
|
+
// creating issuer role
|
|
651
|
+
const issuer = new RoleSimple('issuer', {
|
|
652
|
+
addresses: [unitKey.publicKey.shortAddress]
|
|
653
|
+
});
|
|
654
|
+
|
|
655
|
+
const splitJoinPermission = SplitJoinPermission.create('owner', {
|
|
656
|
+
'field_name': 'amount',
|
|
657
|
+
'min_value': '0.0',
|
|
658
|
+
'min_unit': '10.0',
|
|
659
|
+
'join_match_fields': ['state.origin']
|
|
660
|
+
});
|
|
661
|
+
|
|
662
|
+
// NOTICE: RevokePermission will be always added by default
|
|
663
|
+
const myContract = Contract.create(issuer, {
|
|
664
|
+
definitionData: {
|
|
665
|
+
'template_name': 'UNIT_CONTRACT',
|
|
666
|
+
'unit_name': 'My First Token',
|
|
667
|
+
'unit_short_name': 'MFT',
|
|
668
|
+
'description': 'This is my first token contract'
|
|
669
|
+
},
|
|
670
|
+
stateData: {
|
|
671
|
+
'amount': '100'
|
|
672
|
+
},
|
|
673
|
+
permissions: [
|
|
674
|
+
ChangeOwnerPermission.create('owner'),
|
|
675
|
+
splitJoinPermission
|
|
676
|
+
],
|
|
677
|
+
expiresAt: '3m',
|
|
678
|
+
createdAt: network.now()
|
|
679
|
+
});
|
|
680
|
+
|
|
681
|
+
await myContract.sign(unitKey);
|
|
682
|
+
|
|
683
|
+
// TransactionPack is ready to register
|
|
684
|
+
const myUnitPack = new TransactionPack(myContract.pack());
|
|
685
|
+
|
|
686
|
+
// getting costs
|
|
687
|
+
const costs = await Network.getCost(myUnitPack);
|
|
688
|
+
|
|
689
|
+
const payment = await Parcel.createPayment(costs.costInTu, uPack, {
|
|
690
|
+
isTestnet: true,
|
|
691
|
+
createdAt: network.now()
|
|
692
|
+
});
|
|
693
|
+
await payment.sign(uKey);
|
|
694
|
+
|
|
695
|
+
// SAVE CONTRACT BINARY BEFORE REGISTRATION
|
|
696
|
+
const myUnitPackBinary = await myUnitPack.pack();
|
|
697
|
+
// SAVE PAYMENT BINARY BEFORE REGISTRATION
|
|
698
|
+
const paymentBinary = await payment.pack();
|
|
699
|
+
|
|
700
|
+
const parcel = await Parcel.create(paymentBinary, myUnitPackBinary);
|
|
701
|
+
|
|
702
|
+
const response = await network.registerParcel(parcel);
|
|
703
|
+
|
|
704
|
+
console.log(response.payment); // itemResult of payment registration
|
|
705
|
+
console.log(response.payload); // itemResult of your unit contract registration
|
|
706
|
+
```
|
|
707
|
+
|
|
708
|
+
## Running tests
|
|
709
|
+
|
|
710
|
+
Run tests
|
|
711
|
+
```bash
|
|
712
|
+
npm test
|
|
713
|
+
```
|
|
714
|
+
|
|
715
|
+
Run coverage
|
|
716
|
+
```bash
|
|
717
|
+
npm run coverage
|
|
718
|
+
```
|
package/dist/.gitkeep
ADDED
|
File without changes
|