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/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