cyberia 3.0.2 → 3.1.3

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.
Files changed (182) hide show
  1. package/{.env.production → .env.example} +20 -2
  2. package/.github/workflows/engine-cyberia.cd.yml +41 -10
  3. package/.github/workflows/engine-cyberia.ci.yml +53 -14
  4. package/.github/workflows/ghpkg.ci.yml +1 -1
  5. package/.github/workflows/gitlab.ci.yml +1 -1
  6. package/.github/workflows/hardhat.ci.yml +82 -0
  7. package/.github/workflows/npmpkg.ci.yml +37 -8
  8. package/.github/workflows/publish.ci.yml +5 -5
  9. package/.github/workflows/publish.cyberia.ci.yml +5 -5
  10. package/.github/workflows/pwa-microservices-template-page.cd.yml +3 -3
  11. package/.github/workflows/pwa-microservices-template-test.ci.yml +1 -1
  12. package/.github/workflows/release.cd.yml +3 -2
  13. package/.vscode/extensions.json +9 -8
  14. package/.vscode/settings.json +3 -2
  15. package/CHANGELOG.md +533 -290
  16. package/CLI-HELP.md +79 -53
  17. package/WHITE-PAPER.md +1540 -0
  18. package/bin/build.js +16 -11
  19. package/bin/cyberia.js +959 -8
  20. package/bin/deploy.js +103 -270
  21. package/bin/file.js +2 -1
  22. package/bin/index.js +959 -8
  23. package/bin/vs.js +3 -3
  24. package/conf.js +277 -77
  25. package/deployment.yaml +218 -4
  26. package/hardhat/.env.example +31 -0
  27. package/hardhat/README.md +531 -0
  28. package/hardhat/WHITE-PAPER.md +1540 -0
  29. package/hardhat/contracts/ObjectLayerToken.sol +391 -0
  30. package/hardhat/deployments/.gitkeep +0 -0
  31. package/hardhat/deployments/hardhat-ObjectLayerToken.json +11 -0
  32. package/hardhat/hardhat.config.js +136 -0
  33. package/hardhat/ignition/modules/ObjectLayerToken.js +21 -0
  34. package/hardhat/networks/besu-object-layer.network.json +138 -0
  35. package/hardhat/package-lock.json +7628 -0
  36. package/hardhat/package.json +45 -0
  37. package/hardhat/scripts/deployObjectLayerToken.js +98 -0
  38. package/hardhat/test/ObjectLayerToken.js +590 -0
  39. package/jsdoc.dd-cyberia.json +59 -0
  40. package/jsdoc.json +20 -13
  41. package/manifests/cronjobs/dd-cron/dd-cron-backup.yaml +1 -1
  42. package/manifests/cronjobs/dd-cron/dd-cron-dns.yaml +1 -1
  43. package/manifests/deployment/dd-cyberia-development/deployment.yaml +490 -0
  44. package/manifests/deployment/dd-cyberia-development/proxy.yaml +261 -0
  45. package/manifests/deployment/dd-cyberia-development/pv-pvc.yaml +132 -0
  46. package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
  47. package/manifests/deployment/dd-test-development/deployment.yaml +52 -52
  48. package/manifests/deployment/dd-test-development/proxy.yaml +4 -4
  49. package/manifests/pv-pvc-dd.yaml +1 -1
  50. package/package.json +60 -50
  51. package/proxy.yaml +128 -9
  52. package/pv-pvc.yaml +132 -0
  53. package/scripts/k3s-node-setup.sh +1 -1
  54. package/scripts/ports-ls.sh +2 -0
  55. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.controller.js +3 -1
  56. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.model.js +1 -2
  57. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.service.js +40 -7
  58. package/src/api/document/document.service.js +1 -1
  59. package/src/api/file/file.controller.js +3 -1
  60. package/src/api/file/file.service.js +28 -5
  61. package/src/api/ipfs/ipfs.service.js +2 -2
  62. package/src/api/object-layer/object-layer.controller.js +6 -2
  63. package/src/api/object-layer/object-layer.model.js +67 -21
  64. package/src/api/object-layer/object-layer.router.js +668 -42
  65. package/src/api/object-layer/object-layer.service.js +10 -16
  66. package/src/api/object-layer-render-frames/object-layer-render-frames.model.js +1 -2
  67. package/src/api/user/user.router.js +10 -5
  68. package/src/api/user/user.service.js +7 -7
  69. package/src/cli/baremetal.js +6 -10
  70. package/src/cli/cloud-init.js +0 -3
  71. package/src/cli/db.js +54 -71
  72. package/src/cli/deploy.js +64 -12
  73. package/src/cli/env.js +5 -5
  74. package/src/cli/fs.js +0 -2
  75. package/src/cli/image.js +0 -3
  76. package/src/cli/index.js +41 -13
  77. package/src/cli/monitor.js +5 -6
  78. package/src/cli/repository.js +329 -46
  79. package/src/cli/run.js +210 -122
  80. package/src/cli/secrets.js +1 -3
  81. package/src/cli/ssh.js +1 -1
  82. package/src/client/Itemledger.index.js +1 -959
  83. package/src/client/Underpost.index.js +36 -0
  84. package/src/client/components/core/AgGrid.js +20 -5
  85. package/src/client/components/core/Alert.js +2 -2
  86. package/src/client/components/core/Content.js +22 -3
  87. package/src/client/components/core/Docs.js +30 -6
  88. package/src/client/components/core/FileExplorer.js +71 -4
  89. package/src/client/components/core/Input.js +1 -1
  90. package/src/client/components/core/Modal.js +22 -6
  91. package/src/client/components/core/PublicProfile.js +3 -3
  92. package/src/client/components/core/RichText.js +1 -2
  93. package/src/client/components/core/Router.js +34 -1
  94. package/src/client/components/core/Worker.js +1 -1
  95. package/src/client/components/cryptokoyn/CssCryptokoyn.js +63 -1
  96. package/src/client/components/cyberia/ObjectLayerEngineModal.js +145 -119
  97. package/src/client/components/cyberia/ObjectLayerEngineViewer.js +64 -6
  98. package/src/client/components/cyberia-portal/CommonCyberiaPortal.js +1 -0
  99. package/src/client/components/cyberia-portal/CssCyberiaPortal.js +44 -2
  100. package/src/client/components/cyberia-portal/LogInCyberiaPortal.js +0 -1
  101. package/src/client/components/cyberia-portal/MenuCyberiaPortal.js +64 -2
  102. package/src/client/components/cyberia-portal/RoutesCyberiaPortal.js +1 -0
  103. package/src/client/components/itemledger/CssItemledger.js +62 -0
  104. package/src/client/components/underpost/CommonUnderpost.js +29 -0
  105. package/src/client/components/underpost/CssUnderpost.js +281 -0
  106. package/src/client/components/underpost/CyberpunkBloggerUnderpost.js +879 -0
  107. package/src/client/components/underpost/DocumentSearchProvider.js +448 -0
  108. package/src/client/components/underpost/ElementsUnderpost.js +38 -0
  109. package/src/client/components/underpost/LabGalleryUnderpost.js +82 -0
  110. package/src/client/components/underpost/LogInUnderpost.js +23 -0
  111. package/src/client/components/underpost/LogOutUnderpost.js +15 -0
  112. package/src/client/components/underpost/MenuUnderpost.js +691 -0
  113. package/src/client/components/underpost/RoutesUnderpost.js +47 -0
  114. package/src/client/components/underpost/SettingsUnderpost.js +16 -0
  115. package/src/client/components/underpost/SignUpUnderpost.js +9 -0
  116. package/src/client/components/underpost/SocketIoUnderpost.js +54 -0
  117. package/src/client/components/underpost/TranslateUnderpost.js +10 -0
  118. package/src/client/public/cryptokoyn/assets/logo/base-icon.png +0 -0
  119. package/src/client/public/cryptokoyn/browserconfig.xml +12 -0
  120. package/src/client/public/cryptokoyn/microdata.json +85 -0
  121. package/src/client/public/cryptokoyn/site.webmanifest +57 -0
  122. package/src/client/public/cryptokoyn/sitemap +3 -3
  123. package/src/client/public/default/sitemap +3 -3
  124. package/src/client/public/itemledger/browserconfig.xml +2 -2
  125. package/src/client/public/itemledger/manifest.webmanifest +4 -4
  126. package/src/client/public/itemledger/microdata.json +71 -0
  127. package/src/client/public/itemledger/sitemap +3 -3
  128. package/src/client/public/itemledger/yandex-browser-manifest.json +2 -2
  129. package/src/client/public/test/sitemap +3 -3
  130. package/src/client/services/object-layer/object-layer.management.js +23 -4
  131. package/src/client/ssr/body/404.js +15 -11
  132. package/src/client/ssr/body/500.js +15 -11
  133. package/src/client/ssr/body/SwaggerDarkMode.js +285 -0
  134. package/src/client/ssr/body/UnderpostDefaultSplashScreen.js +83 -0
  135. package/src/client/ssr/head/PwaItemledger.js +60 -0
  136. package/src/client/ssr/head/UnderpostScripts.js +6 -0
  137. package/src/client/ssr/offline/NoNetworkConnection.js +11 -10
  138. package/src/client/ssr/pages/Test.js +11 -10
  139. package/src/client.build.js +0 -3
  140. package/src/client.dev.js +0 -3
  141. package/src/db/DataBaseProvider.js +17 -2
  142. package/src/db/mariadb/MariaDB.js +14 -9
  143. package/src/db/mongo/MongooseDB.js +17 -1
  144. package/src/index.js +1 -1
  145. package/src/proxy.js +0 -3
  146. package/src/runtime/express/Express.js +15 -9
  147. package/src/runtime/lampp/Lampp.js +6 -13
  148. package/src/server/auth.js +12 -14
  149. package/src/server/backup.js +2 -3
  150. package/src/server/besu-genesis-generator.js +1630 -0
  151. package/src/server/client-build-docs.js +126 -17
  152. package/src/server/client-build-live.js +9 -18
  153. package/src/server/client-build.js +203 -75
  154. package/src/server/client-dev-server.js +14 -13
  155. package/src/server/conf.js +376 -164
  156. package/src/server/cron.js +2 -1
  157. package/src/server/dns.js +28 -12
  158. package/src/server/downloader.js +0 -2
  159. package/src/server/logger.js +27 -9
  160. package/src/server/object-layer.js +92 -16
  161. package/src/server/peer.js +0 -2
  162. package/src/server/process.js +1 -50
  163. package/src/server/proxy.js +4 -8
  164. package/src/server/runtime.js +5 -8
  165. package/src/server/semantic-layer-generator.js +1 -0
  166. package/src/server/ssr.js +0 -3
  167. package/src/server/start.js +19 -12
  168. package/src/server/tls.js +0 -2
  169. package/src/server.js +0 -4
  170. package/.env.development +0 -43
  171. package/.env.test +0 -43
  172. package/hardhat/contracts/CryptoKoyn.sol +0 -59
  173. package/hardhat/contracts/ItemLedger.sol +0 -73
  174. package/hardhat/contracts/Lock.sol +0 -34
  175. package/hardhat/hardhat.config.cjs +0 -45
  176. package/hardhat/ignition/modules/Lock.js +0 -18
  177. package/hardhat/networks/cryptokoyn-itemledger.network.json +0 -29
  178. package/hardhat/scripts/deployCryptokoyn.cjs +0 -25
  179. package/hardhat/scripts/deployItemledger.cjs +0 -25
  180. package/hardhat/test/Lock.js +0 -126
  181. package/hardhat/white-paper.md +0 -581
  182. package/white-paper.md +0 -581
@@ -0,0 +1,590 @@
1
+ import { expect } from 'chai';
2
+ import hre from 'hardhat';
3
+
4
+ const { ethers } = hre;
5
+
6
+ describe('ObjectLayerToken (ERC-1155)', function () {
7
+ let token;
8
+ let owner;
9
+ let player1;
10
+ let player2;
11
+ let receiver;
12
+
13
+ const BASE_URI = 'ipfs://';
14
+ const CRYPTOKOYN_ID = 0n;
15
+ const INITIAL_SUPPLY = ethers.parseEther('10000000'); // 10M with 18 decimals
16
+
17
+ beforeEach(async function () {
18
+ [owner, player1, player2, receiver] = await ethers.getSigners();
19
+
20
+ const ObjectLayerToken = await ethers.getContractFactory('ObjectLayerToken');
21
+ token = await ObjectLayerToken.deploy(owner.address, BASE_URI);
22
+ await token.waitForDeployment();
23
+ });
24
+
25
+ // ────────────────────────────────────────────────────────────────────
26
+ // Deployment
27
+ // ────────────────────────────────────────────────────────────────────
28
+
29
+ describe('Deployment', function () {
30
+ it('Should set the correct owner', async function () {
31
+ expect(await token.owner()).to.equal(owner.address);
32
+ });
33
+
34
+ it('Should mint initial CryptoKoyn supply to the owner', async function () {
35
+ const balance = await token.balanceOf(owner.address, CRYPTOKOYN_ID);
36
+ expect(balance).to.equal(INITIAL_SUPPLY);
37
+ });
38
+
39
+ it('Should track total supply for CryptoKoyn', async function () {
40
+ const supply = await token['totalSupply(uint256)'](CRYPTOKOYN_ID);
41
+ expect(supply).to.equal(INITIAL_SUPPLY);
42
+ });
43
+
44
+ it('Should register cryptokoyn as the item ID for token 0', async function () {
45
+ const itemId = await token.getItemId(CRYPTOKOYN_ID);
46
+ expect(itemId).to.equal('cryptokoyn');
47
+ });
48
+
49
+ it('Should return CRYPTOKOYN constant as 0', async function () {
50
+ expect(await token.CRYPTOKOYN()).to.equal(0n);
51
+ });
52
+
53
+ it('Should return INITIAL_CRYPTOKOYN_SUPPLY constant', async function () {
54
+ expect(await token.INITIAL_CRYPTOKOYN_SUPPLY()).to.equal(INITIAL_SUPPLY);
55
+ });
56
+ });
57
+
58
+ // ────────────────────────────────────────────────────────────────────
59
+ // URI
60
+ // ────────────────────────────────────────────────────────────────────
61
+
62
+ describe('URI', function () {
63
+ it('Should return the base URI by default for unregistered token IDs', async function () {
64
+ const tokenUri = await token.uri(999);
65
+ // Default ERC1155 behavior returns the base URI template
66
+ expect(tokenUri).to.equal(BASE_URI);
67
+ });
68
+
69
+ it('Should return per-token CID URI when set', async function () {
70
+ const testCid = 'bafkreia1234567890abcdef';
71
+ await token.setTokenMetadataCID(CRYPTOKOYN_ID, testCid);
72
+
73
+ const tokenUri = await token.uri(CRYPTOKOYN_ID);
74
+ expect(tokenUri).to.equal(`${BASE_URI}${testCid}`);
75
+ });
76
+
77
+ it('Should allow owner to update base URI', async function () {
78
+ const newBase = 'https://meta.cyberiaonline.com/';
79
+ await token.setBaseURI(newBase);
80
+
81
+ const testCid = 'testcid123';
82
+ await token.setTokenMetadataCID(CRYPTOKOYN_ID, testCid);
83
+
84
+ const tokenUri = await token.uri(CRYPTOKOYN_ID);
85
+ expect(tokenUri).to.equal(`${newBase}${testCid}`);
86
+ });
87
+
88
+ it('Should revert setBaseURI from non-owner', async function () {
89
+ await expect(token.connect(player1).setBaseURI('https://evil.com/')).to.be.revertedWithCustomError(
90
+ token,
91
+ 'OwnableUnauthorizedAccount',
92
+ );
93
+ });
94
+
95
+ it('Should revert setTokenMetadataCID from non-owner', async function () {
96
+ await expect(token.connect(player1).setTokenMetadataCID(CRYPTOKOYN_ID, 'evilcid')).to.be.revertedWithCustomError(
97
+ token,
98
+ 'OwnableUnauthorizedAccount',
99
+ );
100
+ });
101
+
102
+ it('Should emit MetadataUpdated and URI events on setTokenMetadataCID', async function () {
103
+ const cid = 'bafkrei_test_meta';
104
+ await expect(token.setTokenMetadataCID(42, cid)).to.emit(token, 'MetadataUpdated').withArgs(42, cid);
105
+ });
106
+ });
107
+
108
+ // ────────────────────────────────────────────────────────────────────
109
+ // Token ID computation
110
+ // ────────────────────────────────────────────────────────────────────
111
+
112
+ describe('computeTokenId', function () {
113
+ it('Should return deterministic token IDs for item identifiers', async function () {
114
+ const id1 = await token.computeTokenId('hatchet');
115
+ const id2 = await token.computeTokenId('hatchet');
116
+ expect(id1).to.equal(id2);
117
+ });
118
+
119
+ it('Should return different token IDs for different item identifiers', async function () {
120
+ const id1 = await token.computeTokenId('hatchet');
121
+ const id2 = await token.computeTokenId('sword');
122
+ expect(id1).to.not.equal(id2);
123
+ });
124
+
125
+ it('Should match off-chain keccak256 computation', async function () {
126
+ const itemId = 'hatchet';
127
+ const expectedId = BigInt(ethers.keccak256(ethers.toUtf8Bytes(`cyberia.object-layer:${itemId}`)));
128
+ const computedId = await token.computeTokenId(itemId);
129
+ expect(computedId).to.equal(expectedId);
130
+ });
131
+ });
132
+
133
+ // ────────────────────────────────────────────────────────────────────
134
+ // Object Layer Registration
135
+ // ────────────────────────────────────────────────────────────────────
136
+
137
+ describe('registerObjectLayer', function () {
138
+ const testItemId = 'hatchet';
139
+ const testMetadataCid = 'bafkreia_hatchet_meta_json';
140
+ const testSupply = 1n; // Unique / non-fungible
141
+
142
+ it('Should register a new object layer and mint tokens', async function () {
143
+ const tx = await token.registerObjectLayer(owner.address, testItemId, testMetadataCid, testSupply, '0x');
144
+
145
+ const tokenId = await token.computeTokenId(testItemId);
146
+
147
+ await expect(tx)
148
+ .to.emit(token, 'ObjectLayerRegistered')
149
+ .withArgs(tokenId, testItemId, testMetadataCid, testSupply);
150
+
151
+ expect(await token.balanceOf(owner.address, tokenId)).to.equal(testSupply);
152
+ expect(await token['totalSupply(uint256)'](tokenId)).to.equal(testSupply);
153
+ });
154
+
155
+ it('Should store item ID and metadata CID on-chain', async function () {
156
+ await token.registerObjectLayer(owner.address, testItemId, testMetadataCid, testSupply, '0x');
157
+
158
+ const tokenId = await token.computeTokenId(testItemId);
159
+ expect(await token.getItemId(tokenId)).to.equal(testItemId);
160
+ expect(await token.getMetadataCID(tokenId)).to.equal(testMetadataCid);
161
+ });
162
+
163
+ it('Should resolve URI via per-token CID after registration', async function () {
164
+ await token.registerObjectLayer(owner.address, testItemId, testMetadataCid, testSupply, '0x');
165
+
166
+ const tokenId = await token.computeTokenId(testItemId);
167
+ expect(await token.uri(tokenId)).to.equal(`${BASE_URI}${testMetadataCid}`);
168
+ });
169
+
170
+ it('Should allow registration with zero supply (metadata-only)', async function () {
171
+ await token.registerObjectLayer(owner.address, testItemId, testMetadataCid, 0n, '0x');
172
+
173
+ const tokenId = await token.computeTokenId(testItemId);
174
+ expect(await token.balanceOf(owner.address, tokenId)).to.equal(0n);
175
+ expect(await token.getItemId(tokenId)).to.equal(testItemId);
176
+ });
177
+
178
+ it('Should allow registration with empty metadata CID', async function () {
179
+ await token.registerObjectLayer(owner.address, testItemId, '', testSupply, '0x');
180
+
181
+ const tokenId = await token.computeTokenId(testItemId);
182
+ expect(await token.getMetadataCID(tokenId)).to.equal('');
183
+ expect(await token.balanceOf(owner.address, tokenId)).to.equal(testSupply);
184
+ });
185
+
186
+ it('Should register fungible (stackable) items with supply > 1', async function () {
187
+ const fungibleSupply = ethers.parseEther('1000000'); // 1M gold ore
188
+ await token.registerObjectLayer(player1.address, 'gold-ore', 'bafkrei_gold', fungibleSupply, '0x');
189
+
190
+ const tokenId = await token.computeTokenId('gold-ore');
191
+ expect(await token.balanceOf(player1.address, tokenId)).to.equal(fungibleSupply);
192
+ expect(await token['totalSupply(uint256)'](tokenId)).to.equal(fungibleSupply);
193
+ });
194
+
195
+ it('Should support getTokenIdByItemId reverse lookup', async function () {
196
+ await token.registerObjectLayer(owner.address, testItemId, testMetadataCid, testSupply, '0x');
197
+
198
+ const tokenId = await token.computeTokenId(testItemId);
199
+ expect(await token.getTokenIdByItemId(testItemId)).to.equal(tokenId);
200
+ });
201
+
202
+ it('Should revert on duplicate item ID collision at the token ID level', async function () {
203
+ await token.registerObjectLayer(owner.address, testItemId, testMetadataCid, testSupply, '0x');
204
+
205
+ await expect(
206
+ token.registerObjectLayer(owner.address, testItemId, testMetadataCid, testSupply, '0x'),
207
+ ).to.be.revertedWith('ObjectLayerToken: item already registered');
208
+ });
209
+
210
+ it('Should revert when called by non-owner', async function () {
211
+ await expect(
212
+ token.connect(player1).registerObjectLayer(player1.address, testItemId, testMetadataCid, testSupply, '0x'),
213
+ ).to.be.revertedWithCustomError(token, 'OwnableUnauthorizedAccount');
214
+ });
215
+ });
216
+
217
+ // ────────────────────────────────────────────────────────────────────
218
+ // Batch Registration
219
+ // ────────────────────────────────────────────────────────────────────
220
+
221
+ describe('batchRegisterObjectLayers', function () {
222
+ const items = ['sword', 'shield', 'potion', 'scroll'];
223
+ const cids = ['bafkrei_sword', 'bafkrei_shield', 'bafkrei_potion', 'bafkrei_scroll'];
224
+ const supplies = [1n, 1n, ethers.parseEther('100'), ethers.parseEther('50')];
225
+
226
+ it('Should batch-register multiple object layers', async function () {
227
+ const tx = await token.batchRegisterObjectLayers(owner.address, items, cids, supplies, '0x');
228
+
229
+ for (let i = 0; i < items.length; i++) {
230
+ const tokenId = await token.computeTokenId(items[i]);
231
+ expect(await token.balanceOf(owner.address, tokenId)).to.equal(supplies[i]);
232
+ expect(await token.getItemId(tokenId)).to.equal(items[i]);
233
+ expect(await token.getMetadataCID(tokenId)).to.equal(cids[i]);
234
+
235
+ await expect(tx).to.emit(token, 'ObjectLayerRegistered').withArgs(tokenId, items[i], cids[i], supplies[i]);
236
+ }
237
+ });
238
+
239
+ it('Should revert on array length mismatch', async function () {
240
+ await expect(
241
+ token.batchRegisterObjectLayers(owner.address, ['a', 'b'], ['cid1'], [1n, 1n], '0x'),
242
+ ).to.be.revertedWith('ObjectLayerToken: array length mismatch');
243
+ });
244
+
245
+ it('Should revert on duplicate within batch (token ID collision)', async function () {
246
+ await expect(
247
+ token.batchRegisterObjectLayers(owner.address, ['dup-item', 'dup-item'], ['cid1', 'cid2'], [1n, 1n], '0x'),
248
+ ).to.be.revertedWith('ObjectLayerToken: item already registered or token ID collision');
249
+ });
250
+
251
+ it('Should revert when called by non-owner', async function () {
252
+ await expect(
253
+ token.connect(player1).batchRegisterObjectLayers(player1.address, items, cids, supplies, '0x'),
254
+ ).to.be.revertedWithCustomError(token, 'OwnableUnauthorizedAccount');
255
+ });
256
+ });
257
+
258
+ // ────────────────────────────────────────────────────────────────────
259
+ // Minting additional supply
260
+ // ────────────────────────────────────────────────────────────────────
261
+
262
+ describe('Minting', function () {
263
+ it('Should mint additional CryptoKoyn supply', async function () {
264
+ const additionalAmount = ethers.parseEther('5000000');
265
+ await token.mint(player1.address, CRYPTOKOYN_ID, additionalAmount, '0x');
266
+
267
+ expect(await token.balanceOf(player1.address, CRYPTOKOYN_ID)).to.equal(additionalAmount);
268
+ expect(await token['totalSupply(uint256)'](CRYPTOKOYN_ID)).to.equal(INITIAL_SUPPLY + additionalAmount);
269
+ });
270
+
271
+ it('Should mint additional supply for registered object layers', async function () {
272
+ await token.registerObjectLayer(owner.address, 'arrow', 'bafkrei_arrow', 100n, '0x');
273
+ const tokenId = await token.computeTokenId('arrow');
274
+
275
+ await token.mint(player1.address, tokenId, 50n, '0x');
276
+ expect(await token.balanceOf(player1.address, tokenId)).to.equal(50n);
277
+ expect(await token['totalSupply(uint256)'](tokenId)).to.equal(150n);
278
+ });
279
+
280
+ it('Should batch-mint multiple token IDs', async function () {
281
+ await token.registerObjectLayer(owner.address, 'wood', '', 0n, '0x');
282
+ await token.registerObjectLayer(owner.address, 'stone', '', 0n, '0x');
283
+
284
+ const woodId = await token.computeTokenId('wood');
285
+ const stoneId = await token.computeTokenId('stone');
286
+
287
+ await token.mintBatch(player1.address, [woodId, stoneId, CRYPTOKOYN_ID], [100n, 200n, 50n], '0x');
288
+
289
+ expect(await token.balanceOf(player1.address, woodId)).to.equal(100n);
290
+ expect(await token.balanceOf(player1.address, stoneId)).to.equal(200n);
291
+ expect(await token.balanceOf(player1.address, CRYPTOKOYN_ID)).to.equal(50n);
292
+ });
293
+
294
+ it('Should revert mint from non-owner', async function () {
295
+ await expect(token.connect(player1).mint(player1.address, CRYPTOKOYN_ID, 1n, '0x')).to.be.revertedWithCustomError(
296
+ token,
297
+ 'OwnableUnauthorizedAccount',
298
+ );
299
+ });
300
+
301
+ it('Should revert mintBatch from non-owner', async function () {
302
+ await expect(
303
+ token.connect(player1).mintBatch(player1.address, [CRYPTOKOYN_ID], [1n], '0x'),
304
+ ).to.be.revertedWithCustomError(token, 'OwnableUnauthorizedAccount');
305
+ });
306
+ });
307
+
308
+ // ────────────────────────────────────────────────────────────────────
309
+ // Transfers (ERC-1155 standard)
310
+ // ────────────────────────────────────────────────────────────────────
311
+
312
+ describe('Transfers', function () {
313
+ it('Should transfer CryptoKoyn between accounts', async function () {
314
+ const amount = ethers.parseEther('1000');
315
+ await token.safeTransferFrom(owner.address, player1.address, CRYPTOKOYN_ID, amount, '0x');
316
+
317
+ expect(await token.balanceOf(player1.address, CRYPTOKOYN_ID)).to.equal(amount);
318
+ expect(await token.balanceOf(owner.address, CRYPTOKOYN_ID)).to.equal(INITIAL_SUPPLY - amount);
319
+ });
320
+
321
+ it('Should transfer registered object layer items', async function () {
322
+ await token.registerObjectLayer(owner.address, 'rare-blade', 'bafkrei_blade', 1n, '0x');
323
+ const tokenId = await token.computeTokenId('rare-blade');
324
+
325
+ await token.safeTransferFrom(owner.address, player1.address, tokenId, 1n, '0x');
326
+
327
+ expect(await token.balanceOf(player1.address, tokenId)).to.equal(1n);
328
+ expect(await token.balanceOf(owner.address, tokenId)).to.equal(0n);
329
+ });
330
+
331
+ it('Should batch-transfer multiple token types', async function () {
332
+ await token.registerObjectLayer(owner.address, 'helm', '', 5n, '0x');
333
+ const helmId = await token.computeTokenId('helm');
334
+
335
+ await token.safeBatchTransferFrom(
336
+ owner.address,
337
+ player1.address,
338
+ [CRYPTOKOYN_ID, helmId],
339
+ [ethers.parseEther('500'), 2n],
340
+ '0x',
341
+ );
342
+
343
+ expect(await token.balanceOf(player1.address, CRYPTOKOYN_ID)).to.equal(ethers.parseEther('500'));
344
+ expect(await token.balanceOf(player1.address, helmId)).to.equal(2n);
345
+ });
346
+
347
+ it('Should support balanceOfBatch queries', async function () {
348
+ await token.registerObjectLayer(player1.address, 'gem', '', 10n, '0x');
349
+ const gemId = await token.computeTokenId('gem');
350
+
351
+ const balances = await token.balanceOfBatch(
352
+ [owner.address, player1.address, player1.address],
353
+ [CRYPTOKOYN_ID, CRYPTOKOYN_ID, gemId],
354
+ );
355
+
356
+ expect(balances[0]).to.equal(INITIAL_SUPPLY);
357
+ expect(balances[1]).to.equal(0n);
358
+ expect(balances[2]).to.equal(10n);
359
+ });
360
+ });
361
+
362
+ // ────────────────────────────────────────────────────────────────────
363
+ // Burning
364
+ // ────────────────────────────────────────────────────────────────────
365
+
366
+ describe('Burning', function () {
367
+ it('Should allow token holders to burn their tokens', async function () {
368
+ const burnAmount = ethers.parseEther('100');
369
+ await token.burn(owner.address, CRYPTOKOYN_ID, burnAmount);
370
+
371
+ expect(await token.balanceOf(owner.address, CRYPTOKOYN_ID)).to.equal(INITIAL_SUPPLY - burnAmount);
372
+ expect(await token['totalSupply(uint256)'](CRYPTOKOYN_ID)).to.equal(INITIAL_SUPPLY - burnAmount);
373
+ });
374
+
375
+ it('Should allow batch burning', async function () {
376
+ await token.registerObjectLayer(owner.address, 'burn-item', '', 10n, '0x');
377
+ const burnItemId = await token.computeTokenId('burn-item');
378
+
379
+ await token.burnBatch(owner.address, [CRYPTOKOYN_ID, burnItemId], [ethers.parseEther('50'), 3n]);
380
+
381
+ expect(await token.balanceOf(owner.address, CRYPTOKOYN_ID)).to.equal(INITIAL_SUPPLY - ethers.parseEther('50'));
382
+ expect(await token.balanceOf(owner.address, burnItemId)).to.equal(7n);
383
+ });
384
+
385
+ it('Should revert burn when called by unauthorized account on others tokens', async function () {
386
+ await token.safeTransferFrom(owner.address, player1.address, CRYPTOKOYN_ID, ethers.parseEther('100'), '0x');
387
+
388
+ // player2 tries to burn player1's tokens without approval
389
+ await expect(
390
+ token.connect(player2).burn(player1.address, CRYPTOKOYN_ID, ethers.parseEther('50')),
391
+ ).to.be.revertedWithCustomError(token, 'ERC1155MissingApprovalForAll');
392
+ });
393
+
394
+ it('Should allow approved operator to burn tokens', async function () {
395
+ await token.safeTransferFrom(owner.address, player1.address, CRYPTOKOYN_ID, ethers.parseEther('100'), '0x');
396
+
397
+ // player1 approves player2
398
+ await token.connect(player1).setApprovalForAll(player2.address, true);
399
+
400
+ // player2 burns on behalf of player1
401
+ await token.connect(player2).burn(player1.address, CRYPTOKOYN_ID, ethers.parseEther('50'));
402
+
403
+ expect(await token.balanceOf(player1.address, CRYPTOKOYN_ID)).to.equal(ethers.parseEther('50'));
404
+ });
405
+ });
406
+
407
+ // ────────────────────────────────────────────────────────────────────
408
+ // Pause / Unpause
409
+ // ────────────────────────────────────────────────────────────────────
410
+
411
+ describe('Pause / Unpause', function () {
412
+ it('Should pause and block transfers', async function () {
413
+ await token.pause();
414
+
415
+ await expect(
416
+ token.safeTransferFrom(owner.address, player1.address, CRYPTOKOYN_ID, 1n, '0x'),
417
+ ).to.be.revertedWithCustomError(token, 'EnforcedPause');
418
+ });
419
+
420
+ it('Should unpause and allow transfers again', async function () {
421
+ await token.pause();
422
+ await token.unpause();
423
+
424
+ await expect(token.safeTransferFrom(owner.address, player1.address, CRYPTOKOYN_ID, 1n, '0x')).to.not.be.reverted;
425
+ });
426
+
427
+ it('Should block minting when paused', async function () {
428
+ await token.pause();
429
+
430
+ await expect(token.mint(player1.address, CRYPTOKOYN_ID, 1n, '0x')).to.be.revertedWithCustomError(
431
+ token,
432
+ 'EnforcedPause',
433
+ );
434
+ });
435
+
436
+ it('Should block registration (which mints) when paused', async function () {
437
+ await token.pause();
438
+
439
+ await expect(token.registerObjectLayer(owner.address, 'paused-item', '', 1n, '0x')).to.be.revertedWithCustomError(
440
+ token,
441
+ 'EnforcedPause',
442
+ );
443
+ });
444
+
445
+ it('Should revert pause from non-owner', async function () {
446
+ await expect(token.connect(player1).pause()).to.be.revertedWithCustomError(token, 'OwnableUnauthorizedAccount');
447
+ });
448
+
449
+ it('Should revert unpause from non-owner', async function () {
450
+ await token.pause();
451
+ await expect(token.connect(player1).unpause()).to.be.revertedWithCustomError(token, 'OwnableUnauthorizedAccount');
452
+ });
453
+ });
454
+
455
+ // ────────────────────────────────────────────────────────────────────
456
+ // Supply tracking (ERC1155Supply)
457
+ // ────────────────────────────────────────────────────────────────────
458
+
459
+ describe('Supply Tracking', function () {
460
+ it('Should track exists() for minted token IDs', async function () {
461
+ const randomId = 9999n;
462
+ expect(await token.exists(randomId)).to.equal(false);
463
+ expect(await token.exists(CRYPTOKOYN_ID)).to.equal(true);
464
+ });
465
+
466
+ it('Should update exists() after registration', async function () {
467
+ const itemId = 'tracking-test';
468
+ const tokenId = await token.computeTokenId(itemId);
469
+
470
+ expect(await token.exists(tokenId)).to.equal(false);
471
+
472
+ await token.registerObjectLayer(owner.address, itemId, '', 1n, '0x');
473
+
474
+ expect(await token.exists(tokenId)).to.equal(true);
475
+ });
476
+
477
+ it('Should update totalSupply after burns', async function () {
478
+ await token.registerObjectLayer(owner.address, 'supply-test', '', 10n, '0x');
479
+ const tokenId = await token.computeTokenId('supply-test');
480
+
481
+ expect(await token['totalSupply(uint256)'](tokenId)).to.equal(10n);
482
+
483
+ await token.burn(owner.address, tokenId, 3n);
484
+
485
+ expect(await token['totalSupply(uint256)'](tokenId)).to.equal(7n);
486
+ });
487
+ });
488
+
489
+ // ────────────────────────────────────────────────────────────────────
490
+ // Object Layer → ERC-1155 integration scenario
491
+ // ────────────────────────────────────────────────────────────────────
492
+
493
+ describe('Object Layer Integration Scenario', function () {
494
+ it('Should simulate full object layer lifecycle: register → mint → transfer → burn', async function () {
495
+ // 1. Game server registers a weapon type
496
+ const weaponItemId = 'legendary-hatchet';
497
+ const weaponCid = 'bafkreia_hatchet_atlas_metadata_cid';
498
+
499
+ await token.registerObjectLayer(
500
+ owner.address, // governance / server wallet
501
+ weaponItemId,
502
+ weaponCid,
503
+ 1n, // unique: supply of 1
504
+ '0x',
505
+ );
506
+
507
+ const weaponTokenId = await token.computeTokenId(weaponItemId);
508
+
509
+ // Verify on-chain state matches off-chain ObjectLayer data
510
+ expect(await token.getItemId(weaponTokenId)).to.equal(weaponItemId);
511
+ expect(await token.getMetadataCID(weaponTokenId)).to.equal(weaponCid);
512
+ expect(await token['totalSupply(uint256)'](weaponTokenId)).to.equal(1n);
513
+ expect(await token.uri(weaponTokenId)).to.equal(`ipfs://${weaponCid}`);
514
+
515
+ // 2. Game server registers a fungible resource
516
+ const resourceItemId = 'gold-ore';
517
+ const resourceCid = 'bafkreia_gold_ore_meta';
518
+ const resourceSupply = ethers.parseEther('1000000');
519
+
520
+ await token.registerObjectLayer(owner.address, resourceItemId, resourceCid, resourceSupply, '0x');
521
+
522
+ const resourceTokenId = await token.computeTokenId(resourceItemId);
523
+
524
+ // 3. Transfer weapon to player (quest reward)
525
+ await token.safeTransferFrom(owner.address, player1.address, weaponTokenId, 1n, '0x');
526
+ expect(await token.balanceOf(player1.address, weaponTokenId)).to.equal(1n);
527
+
528
+ // 4. Transfer gold to player (enemy loot)
529
+ const lootAmount = ethers.parseEther('500');
530
+ await token.safeTransferFrom(owner.address, player1.address, resourceTokenId, lootAmount, '0x');
531
+
532
+ // 5. Player-to-player trade: player1 sends weapon + 100 gold to player2
533
+ await token
534
+ .connect(player1)
535
+ .safeBatchTransferFrom(
536
+ player1.address,
537
+ player2.address,
538
+ [weaponTokenId, resourceTokenId],
539
+ [1n, ethers.parseEther('100')],
540
+ '0x',
541
+ );
542
+
543
+ expect(await token.balanceOf(player2.address, weaponTokenId)).to.equal(1n);
544
+ expect(await token.balanceOf(player2.address, resourceTokenId)).to.equal(ethers.parseEther('100'));
545
+ expect(await token.balanceOf(player1.address, weaponTokenId)).to.equal(0n);
546
+ expect(await token.balanceOf(player1.address, resourceTokenId)).to.equal(ethers.parseEther('400'));
547
+
548
+ // 6. Player2 consumes (burns) gold ore in crafting
549
+ const craftCost = ethers.parseEther('25');
550
+ await token.connect(player2).burn(player2.address, resourceTokenId, craftCost);
551
+
552
+ expect(await token.balanceOf(player2.address, resourceTokenId)).to.equal(ethers.parseEther('75'));
553
+ expect(await token['totalSupply(uint256)'](resourceTokenId)).to.equal(resourceSupply - craftCost);
554
+
555
+ // 7. Verify CryptoKoyn (fungible currency) still works alongside items
556
+ await token.safeTransferFrom(owner.address, player1.address, CRYPTOKOYN_ID, ethers.parseEther('5000'), '0x');
557
+
558
+ const balances = await token.balanceOfBatch(
559
+ [player1.address, player1.address, player1.address, player2.address, player2.address],
560
+ [CRYPTOKOYN_ID, weaponTokenId, resourceTokenId, weaponTokenId, resourceTokenId],
561
+ );
562
+
563
+ expect(balances[0]).to.equal(ethers.parseEther('5000')); // player1 CKY
564
+ expect(balances[1]).to.equal(0n); // player1 weapon (traded away)
565
+ expect(balances[2]).to.equal(ethers.parseEther('400')); // player1 gold
566
+ expect(balances[3]).to.equal(1n); // player2 weapon
567
+ expect(balances[4]).to.equal(ethers.parseEther('75')); // player2 gold (after burn)
568
+ });
569
+
570
+ it('Should simulate governance: pause, update metadata, unpause', async function () {
571
+ await token.registerObjectLayer(owner.address, 'gov-item', 'old-cid', 10n, '0x');
572
+ const tokenId = await token.computeTokenId('gov-item');
573
+
574
+ // Pause for maintenance
575
+ await token.pause();
576
+ await expect(
577
+ token.safeTransferFrom(owner.address, player1.address, tokenId, 1n, '0x'),
578
+ ).to.be.revertedWithCustomError(token, 'EnforcedPause');
579
+
580
+ // Update metadata while paused (setTokenMetadataCID does not transfer, so it works)
581
+ await token.setTokenMetadataCID(tokenId, 'new-upgraded-cid');
582
+ expect(await token.getMetadataCID(tokenId)).to.equal('new-upgraded-cid');
583
+
584
+ // Resume operations
585
+ await token.unpause();
586
+ await token.safeTransferFrom(owner.address, player1.address, tokenId, 1n, '0x');
587
+ expect(await token.balanceOf(player1.address, tokenId)).to.equal(1n);
588
+ });
589
+ });
590
+ });
@@ -0,0 +1,59 @@
1
+ {
2
+ "tags": {
3
+ "allowUnknownTags": true,
4
+ "dictionaries": ["jsdoc"]
5
+ },
6
+ "source": {
7
+ "include": [
8
+ "./src",
9
+ "./package.json",
10
+ "./README.md",
11
+ "./CHANGELOG.md",
12
+ "./hardhat/README.md",
13
+ "./hardhat/WHITE-PAPER.md"
14
+ ],
15
+ "includePattern": ".js$",
16
+ "excludePattern": "(node_modules/|/docs/|hardhat/)"
17
+ },
18
+ "plugins": ["plugins/markdown", "plugins/summarize", "plugins/shout"],
19
+ "opts": {
20
+ "template": "node_modules/clean-jsdoc-theme",
21
+ "readme": "./hardhat/README.md",
22
+ "recurse": true,
23
+ "destination": "./public/www.cyberiaonline.com/docs/",
24
+ "tutorials": "./src/client/public/cyberia/docs/references",
25
+ "encoding": "utf8",
26
+ "verbose": true,
27
+ "theme_opts": {
28
+ "default_theme": "dark",
29
+ "search": true,
30
+ "title": "CYBERIA - Browser MMORPG & Blockchain Documentation",
31
+ "homepageTitle": "Docs",
32
+ "favicon": "./public/www.cyberiaonline.com/",
33
+ "displayModuleHeader": true,
34
+ "includeFilesListInHomepage": true,
35
+ "sections": ["Namespaces", "Tutorials"],
36
+ "meta": [
37
+ {
38
+ "name": "author",
39
+ "content": "CYBERIA - underpostnet"
40
+ },
41
+ {
42
+ "name": "description",
43
+ "content": "CYBERIA Online - Browser MMORPG, Object Layer Engine, ERC-1155 Token Ecosystem & Hardhat Smart Contract Documentation"
44
+ },
45
+ {
46
+ "name": "keywords",
47
+ "content": "cyberia, mmorpg, browser, game, hardhat, solidity, erc-1155, blockchain, besu, documentation, jsdoc, object-layer, token, cryptokoyn"
48
+ }
49
+ ],
50
+ "footer": "<div style='text-align:center;margin:1rem 0;font-size:0.85rem;'>&copy; CYBERIA / underpostnet — <a href='https://github.com/underpostnet/engine' target='_blank'>Engine</a> | <a href='https://www.cyberiaonline.com' target='_blank'>Play</a> | <a href='https://www.npmjs.com/package/cyberia' target='_blank'>npm</a></div>",
51
+ "create_style": ".jsdoc-category-badge{display:inline-block;padding:2px 8px;border-radius:4px;background:#1a1a2e;color:#00d4ff;font-size:0.82em;font-weight:600;margin-bottom:0.4em;border:1px solid #00d4ff}.jsdoc-category{margin-bottom:0.5em}#sidebar-classes,#sidebar-classes+.sidebar-section-children-container{display:none !important}",
52
+ "add_scripts": ""
53
+ }
54
+ },
55
+ "markdown": {
56
+ "hardwrap": false,
57
+ "idInHeadings": true
58
+ }
59
+ }