@wishknish/knishio-client-ts 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (141) hide show
  1. package/LICENSE +674 -0
  2. package/README.md +425 -0
  3. package/dist/index.cjs +9961 -0
  4. package/dist/index.cjs.map +1 -0
  5. package/dist/index.iife.js +32241 -0
  6. package/dist/index.iife.js.map +1 -0
  7. package/dist/index.js +9853 -0
  8. package/dist/index.js.map +1 -0
  9. package/package.json +113 -0
  10. package/src/AuthToken.ts +214 -0
  11. package/src/KnishIOClient.ts +2020 -0
  12. package/src/constants.ts +398 -0
  13. package/src/core/Atom.ts +646 -0
  14. package/src/core/AtomMeta.ts +278 -0
  15. package/src/core/Meta.ts +428 -0
  16. package/src/core/Molecule.ts +825 -0
  17. package/src/core/PolicyMeta.ts +130 -0
  18. package/src/core/TokenUnit.ts +148 -0
  19. package/src/core/Wallet.ts +467 -0
  20. package/src/exception/AtomIndexException.ts +97 -0
  21. package/src/exception/AtomsMissingException.ts +109 -0
  22. package/src/exception/AuthorizationRejectedException.ts +63 -0
  23. package/src/exception/BalanceInsufficientException.ts +58 -0
  24. package/src/exception/BaseException.ts +275 -0
  25. package/src/exception/BatchIdException.ts +58 -0
  26. package/src/exception/CodeException.ts +119 -0
  27. package/src/exception/DecryptionKeyException.ts +65 -0
  28. package/src/exception/InvalidResponseException.ts +112 -0
  29. package/src/exception/MetaMissingException.ts +58 -0
  30. package/src/exception/MolecularHashMismatchException.ts +115 -0
  31. package/src/exception/MolecularHashMissingException.ts +58 -0
  32. package/src/exception/NegativeAmountException.ts +58 -0
  33. package/src/exception/PolicyInvalidException.ts +58 -0
  34. package/src/exception/SignatureMalformedException.ts +58 -0
  35. package/src/exception/SignatureMismatchException.ts +98 -0
  36. package/src/exception/StackableUnitAmountException.ts +65 -0
  37. package/src/exception/StackableUnitDecimalsException.ts +65 -0
  38. package/src/exception/TransferBalanceException.ts +98 -0
  39. package/src/exception/TransferMalformedException.ts +58 -0
  40. package/src/exception/TransferMismatchedException.ts +58 -0
  41. package/src/exception/TransferRemainderException.ts +58 -0
  42. package/src/exception/TransferToSelfException.ts +58 -0
  43. package/src/exception/TransferUnbalancedException.ts +58 -0
  44. package/src/exception/UnauthenticatedException.ts +147 -0
  45. package/src/exception/WalletCredentialException.ts +108 -0
  46. package/src/exception/WalletShadowException.ts +65 -0
  47. package/src/exception/WrongTokenTypeException.ts +58 -0
  48. package/src/exception/index.ts +272 -0
  49. package/src/index.ts +512 -0
  50. package/src/instance/rules/Callback.ts +257 -0
  51. package/src/instance/rules/Condition.ts +96 -0
  52. package/src/instance/rules/Meta.ts +163 -0
  53. package/src/instance/rules/Rule.ts +29 -0
  54. package/src/instance/rules/exception/RuleArgumentException.ts +65 -0
  55. package/src/libraries/CheckMolecule.ts +581 -0
  56. package/src/libraries/Decimal.ts +94 -0
  57. package/src/libraries/Dot.ts +202 -0
  58. package/src/libraries/GraphQLClient.ts +276 -0
  59. package/src/libraries/Hex.ts +155 -0
  60. package/src/libraries/UrqlClientWrapper.ts +336 -0
  61. package/src/libraries/array.ts +91 -0
  62. package/src/libraries/crypto.ts +816 -0
  63. package/src/libraries/strings.ts +458 -0
  64. package/src/mutation/Mutation.ts +103 -0
  65. package/src/mutation/MutationActiveSession.ts +108 -0
  66. package/src/mutation/MutationClaimShadowWallet.ts +91 -0
  67. package/src/mutation/MutationCreateIdentifier.ts +86 -0
  68. package/src/mutation/MutationCreateMeta.ts +92 -0
  69. package/src/mutation/MutationCreateRule.ts +90 -0
  70. package/src/mutation/MutationCreateToken.ts +92 -0
  71. package/src/mutation/MutationCreateWallet.ts +78 -0
  72. package/src/mutation/MutationDepositBufferToken.ts +72 -0
  73. package/src/mutation/MutationLinkIdentifier.ts +87 -0
  74. package/src/mutation/MutationProposeMolecule.ts +147 -0
  75. package/src/mutation/MutationRequestAuthorization.ts +77 -0
  76. package/src/mutation/MutationRequestAuthorizationGuest.ts +85 -0
  77. package/src/mutation/MutationRequestTokens.ts +98 -0
  78. package/src/mutation/MutationTransferTokens.ts +87 -0
  79. package/src/mutation/MutationWithdrawBufferToken.ts +73 -0
  80. package/src/query/Query.ts +187 -0
  81. package/src/query/QueryActiveSession.ts +89 -0
  82. package/src/query/QueryAtom.ts +275 -0
  83. package/src/query/QueryBalance.ts +102 -0
  84. package/src/query/QueryBatch.ts +145 -0
  85. package/src/query/QueryBatchHistory.ts +86 -0
  86. package/src/query/QueryContinuId.ts +91 -0
  87. package/src/query/QueryMetaType.ts +177 -0
  88. package/src/query/QueryMetaTypeViaAtom.ts +199 -0
  89. package/src/query/QueryPolicy.ts +91 -0
  90. package/src/query/QueryToken.ts +90 -0
  91. package/src/query/QueryUserActivity.ts +153 -0
  92. package/src/query/QueryWalletBundle.ts +92 -0
  93. package/src/query/QueryWalletList.ts +106 -0
  94. package/src/response/EnhancedResponse.ts +345 -0
  95. package/src/response/Response.ts +254 -0
  96. package/src/response/ResponseActiveSession.ts +72 -0
  97. package/src/response/ResponseAtom.ts +132 -0
  98. package/src/response/ResponseAuthorizationGuest.ts +119 -0
  99. package/src/response/ResponseBalance.ts +153 -0
  100. package/src/response/ResponseClaimShadowWallet.ts +56 -0
  101. package/src/response/ResponseContinuId.ts +101 -0
  102. package/src/response/ResponseCreateIdentifier.ts +56 -0
  103. package/src/response/ResponseCreateMeta.ts +58 -0
  104. package/src/response/ResponseCreateRule.ts +56 -0
  105. package/src/response/ResponseCreateToken.ts +58 -0
  106. package/src/response/ResponseCreateWallet.ts +58 -0
  107. package/src/response/ResponseLinkIdentifier.ts +87 -0
  108. package/src/response/ResponseMetaBatch.ts +72 -0
  109. package/src/response/ResponseMetaType.ts +108 -0
  110. package/src/response/ResponseMetaTypeViaAtom.ts +108 -0
  111. package/src/response/ResponsePolicy.ts +90 -0
  112. package/src/response/ResponseProposeMolecule.ts +155 -0
  113. package/src/response/ResponseQueryActiveSession.ts +105 -0
  114. package/src/response/ResponseQueryUserActivity.ts +89 -0
  115. package/src/response/ResponseRequestAuthorization.ts +100 -0
  116. package/src/response/ResponseRequestAuthorizationGuest.ts +133 -0
  117. package/src/response/ResponseRequestTokens.ts +58 -0
  118. package/src/response/ResponseTransferTokens.ts +72 -0
  119. package/src/response/ResponseWalletBundle.ts +95 -0
  120. package/src/response/ResponseWalletList.ts +165 -0
  121. package/src/schemas/index.ts +457 -0
  122. package/src/subscribe/ActiveSessionSubscribe.ts +72 -0
  123. package/src/subscribe/ActiveWalletSubscribe.ts +99 -0
  124. package/src/subscribe/CreateMoleculeSubscribe.ts +106 -0
  125. package/src/subscribe/Subscribe.ts +182 -0
  126. package/src/subscribe/WalletStatusSubscribe.ts +70 -0
  127. package/src/subscribe/index.ts +59 -0
  128. package/src/types/assertions.ts +722 -0
  129. package/src/types/client.ts +567 -0
  130. package/src/types/crypto.ts +541 -0
  131. package/src/types/graphql.ts +630 -0
  132. package/src/types/guards.ts +659 -0
  133. package/src/types/index.ts +614 -0
  134. package/src/types/response.ts +133 -0
  135. package/src/types/template-literals.ts +382 -0
  136. package/src/validation/UNIVERSAL_CONFIGURATION_INTERFACES.ts +580 -0
  137. package/src/validation/ValidationService.ts +607 -0
  138. package/src/validation/schemas.ts +447 -0
  139. package/src/versions/HashAtom.ts +170 -0
  140. package/src/versions/Version4.ts +120 -0
  141. package/src/versions/index.ts +80 -0
@@ -0,0 +1,581 @@
1
+ /*
2
+ (
3
+ (/(
4
+ (//(
5
+ (///(
6
+ (/////(
7
+ (//////( )
8
+ (////////( (/)
9
+ (////////( (///)
10
+ (//////////( (////)
11
+ (//////////( (//////)
12
+ (////////////( (///////)
13
+ (/////////////( (/////////)
14
+ (//////////////( (///////////)
15
+ (///////////////( (/////////////)
16
+ (////////////////( (//////////////)
17
+ ((((((((((((((((((( (((((((((((((((
18
+ ((((((((((((((((((( ((((((((((((((
19
+ ((((((((((((((((((( ((((((((((((((
20
+ (((((((((((((((((((( (((((((((((((
21
+ (((((((((((((((((((( ((((((((((((
22
+ ((((((((((((((((((( ((((((((((((
23
+ ((((((((((((((((((( ((((((((((
24
+ ((((((((((((((((((/ (((((((((
25
+ (((((((((((((((((( ((((((((
26
+ ((((((((((((((((( (((((((
27
+ (((((((((((((((((( (((((
28
+ ################# ##
29
+ ################ #
30
+ ################# ##
31
+ %################ ###
32
+ ###############( ####
33
+ ############### ####
34
+ ############### ######
35
+ %#############( (#######
36
+ %############# #########
37
+ ############( ##########
38
+ ########### #############
39
+ ######### ##############
40
+ %######
41
+
42
+ Powered by Knish.IO: Connecting a Decentralized World
43
+
44
+ Please visit https://github.com/WishKnish/KnishIO-Client-TS for information.
45
+
46
+ License: https://github.com/WishKnish/KnishIO-Client-TS/blob/master/LICENSE
47
+ */
48
+
49
+ import {
50
+ AtomIndexException,
51
+ AtomsMissingException,
52
+ MolecularHashMismatchException,
53
+ MolecularHashMissingException,
54
+ PolicyInvalidException,
55
+ SignatureMalformedException,
56
+ SignatureMismatchException,
57
+ TransferBalanceException,
58
+ TransferMalformedException,
59
+ TransferMismatchedException,
60
+ TransferRemainderException,
61
+ TransferToSelfException,
62
+ TransferUnbalancedException,
63
+ MetaMissingException,
64
+ WrongTokenTypeException,
65
+ BatchIdException
66
+ } from '@/exception'
67
+ import Atom from '@/core/Atom'
68
+ import Meta from '@/core/Meta'
69
+ import Wallet from '@/core/Wallet'
70
+ import Rule from '@/instance/rules/Rule'
71
+ import { base64ToHex, chunkSubstr } from '@/libraries/strings'
72
+ import { shake256 } from '@/libraries/crypto'
73
+ import Dot from '@/libraries/Dot'
74
+
75
+ // Type definitions for Molecule structure
76
+ interface MoleculeStructure {
77
+ molecularHash: string | null
78
+ atoms: Atom[]
79
+ status?: string | null
80
+ createdAt?: string
81
+ cellSlug?: string | null
82
+ cellSlugOrigin?: string | null
83
+ bundle?: string | null
84
+
85
+ // Methods that Molecule should have
86
+ getIsotopes(isotope: string): Atom[]
87
+ normalizedHash(): number[]
88
+ }
89
+
90
+ /**
91
+ * CheckMolecule class - Validates molecular integrity and signatures
92
+ * Matches JavaScript SDK CheckMolecule functionality exactly
93
+ */
94
+ export default class CheckMolecule {
95
+ private molecule: MoleculeStructure
96
+
97
+ /**
98
+ * Initialize CheckMolecule with a molecule to validate
99
+ * @param molecule - The molecule to validate
100
+ * @throws MolecularHashMissingException if molecular hash is null
101
+ * @throws AtomsMissingException if no atoms present
102
+ * @throws AtomIndexException if any atom has null index
103
+ */
104
+ constructor(molecule: MoleculeStructure) {
105
+ // No molecular hash?
106
+ if (molecule.molecularHash === null) {
107
+ throw new MolecularHashMissingException()
108
+ }
109
+
110
+ // No atoms?
111
+ if (!molecule.atoms.length) {
112
+ throw new AtomsMissingException()
113
+ }
114
+
115
+ // Check atom indexes
116
+ for (const atom of molecule.atoms) {
117
+ if (atom.index === null) {
118
+ throw new AtomIndexException()
119
+ }
120
+ }
121
+
122
+ this.molecule = molecule
123
+ }
124
+
125
+ /**
126
+ * Perform complete molecular validation
127
+ * @param senderWallet - Optional wallet for balance validation
128
+ * @return True if all validations pass
129
+ */
130
+ verify(senderWallet?: Wallet | null): boolean {
131
+ return this.molecularHash() &&
132
+ this.ots() &&
133
+ this.batchId() &&
134
+ this.continuId() &&
135
+ this.isotopeM() &&
136
+ this.isotopeT() &&
137
+ this.isotopeC() &&
138
+ this.isotopeU() &&
139
+ this.isotopeI() &&
140
+ this.isotopeR() &&
141
+ this.isotopeV(senderWallet || null)
142
+ }
143
+
144
+ /**
145
+ * Validate ContinuID requirement
146
+ * @return True if valid
147
+ * @throws AtomsMissingException if missing required ContinuID atom
148
+ */
149
+ continuId(): boolean {
150
+ const firstAtom = this.molecule.atoms[0]
151
+
152
+ if (firstAtom?.token === 'USER' && this.molecule.getIsotopes('I').length < 1) {
153
+ throw new AtomsMissingException('Check::continuId() - Molecule is missing required ContinuID Atom!')
154
+ }
155
+
156
+ return true
157
+ }
158
+
159
+ /**
160
+ * Validate batch ID consistency
161
+ * @return True if valid
162
+ * @throws BatchIdException if batch ID validation fails
163
+ */
164
+ batchId(): boolean {
165
+ if (this.molecule.atoms.length > 0) {
166
+ const signingAtom = this.molecule.atoms[0]
167
+
168
+ if (signingAtom?.isotope === 'V' && signingAtom.batchId !== null) {
169
+ const atoms = this.molecule.getIsotopes('V')
170
+ const remainderAtom = atoms[atoms.length - 1]
171
+
172
+ if (!remainderAtom || signingAtom.batchId !== remainderAtom.batchId) {
173
+ throw new BatchIdException()
174
+ }
175
+
176
+ for (const atom of atoms) {
177
+ if (atom.batchId === null) {
178
+ throw new BatchIdException()
179
+ }
180
+ }
181
+ }
182
+
183
+ return true
184
+ }
185
+
186
+ throw new BatchIdException()
187
+ }
188
+
189
+ /**
190
+ * Validate isotope I atoms
191
+ * @return True if valid
192
+ * @throws WrongTokenTypeException if token is not USER
193
+ * @throws AtomIndexException if index is 0
194
+ */
195
+ isotopeI(): boolean {
196
+ for (const atom of this.molecule.getIsotopes('I')) {
197
+ if (atom.token !== 'USER') {
198
+ throw new WrongTokenTypeException(`Check::isotopeI() - "${atom.token}" is not a valid Token slug for "${atom.isotope}" isotope Atoms!`)
199
+ }
200
+
201
+ if (atom.index === 0) {
202
+ throw new AtomIndexException(`Check::isotopeI() - Isotope "${atom.isotope}" Atoms must have a non-zero index!`)
203
+ }
204
+ }
205
+
206
+ return true
207
+ }
208
+
209
+ /**
210
+ * Validate isotope U atoms
211
+ * @return True if valid
212
+ * @throws WrongTokenTypeException if token is not AUTH
213
+ * @throws AtomIndexException if index is not 0
214
+ */
215
+ isotopeU(): boolean {
216
+ for (const atom of this.molecule.getIsotopes('U')) {
217
+ if (atom.token !== 'AUTH') {
218
+ throw new WrongTokenTypeException(`Check::isotopeU() - "${atom.token}" is not a valid Token slug for "${atom.isotope}" isotope Atoms!`)
219
+ }
220
+
221
+ if (atom.index !== 0) {
222
+ throw new AtomIndexException(`Check::isotopeU() - Isotope "${atom.isotope}" Atoms must have an index equal to 0!`)
223
+ }
224
+ }
225
+
226
+ return true
227
+ }
228
+
229
+ /**
230
+ * Validate isotope M atoms and their policies
231
+ * @return True if valid
232
+ * @throws MetaMissingException if meta is missing
233
+ * @throws WrongTokenTypeException if token is not USER
234
+ * @throws PolicyInvalidException if policy validation fails
235
+ */
236
+ isotopeM(): boolean {
237
+ const policyArray = ['readPolicy', 'writePolicy']
238
+
239
+ for (const atom of this.molecule.getIsotopes('M')) {
240
+ if (atom.meta.length < 1) {
241
+ throw new MetaMissingException()
242
+ }
243
+
244
+ if (atom.token !== 'USER') {
245
+ throw new WrongTokenTypeException(`Check::isotopeM() - "${atom.token}" is not a valid Token slug for "${atom.isotope}" isotope Atoms!`)
246
+ }
247
+
248
+ const metas = Meta.aggregateMeta(atom.meta)
249
+
250
+ for (const key of policyArray) {
251
+ let policy = metas[key]
252
+
253
+ if (policy) {
254
+ policy = JSON.parse(policy as string) as Record<string, any>
255
+
256
+ for (const [policyName, policyValue] of Object.entries(policy)) {
257
+ if (!policyArray.includes(policyName)) {
258
+ if (!Object.keys(metas).includes(policyName)) {
259
+ throw new PolicyInvalidException(`${policyName} is missing from the meta.`)
260
+ }
261
+
262
+ for (const value of policyValue as any[]) {
263
+ if (!Wallet.isBundleHash(value) && !['all', 'self'].includes(value)) {
264
+ throw new PolicyInvalidException(`${value} does not correspond to the format of the policy.`)
265
+ }
266
+ }
267
+ }
268
+ }
269
+ }
270
+ }
271
+ }
272
+
273
+ return true
274
+ }
275
+
276
+ /**
277
+ * Validate isotope C atoms
278
+ * @return True if valid
279
+ * @throws WrongTokenTypeException if token is not USER
280
+ * @throws AtomIndexException if index is not 0
281
+ */
282
+ isotopeC(): boolean {
283
+ for (const atom of this.molecule.getIsotopes('C')) {
284
+ if (atom.token !== 'USER') {
285
+ throw new WrongTokenTypeException(`Check::isotopeC() - "${atom.token}" is not a valid Token slug for "${atom.isotope}" isotope Atoms!`)
286
+ }
287
+
288
+ if (atom.index !== 0) {
289
+ throw new AtomIndexException(`Check::isotopeC() - Isotope "${atom.isotope}" Atoms must have an index equal to 0!`)
290
+ }
291
+ }
292
+
293
+ return true
294
+ }
295
+
296
+ /**
297
+ * Validate isotope T atoms
298
+ * @return True if valid
299
+ * @throws MetaMissingException if required meta fields are missing
300
+ * @throws WrongTokenTypeException if token is not USER
301
+ * @throws AtomIndexException if index is not 0
302
+ */
303
+ isotopeT(): boolean {
304
+ for (const atom of this.molecule.getIsotopes('T')) {
305
+ const meta = atom.aggregatedMeta()
306
+ const metaType = String(atom.metaType).toLowerCase()
307
+
308
+ if (metaType === 'wallet') {
309
+ for (const key of ['position', 'bundle']) {
310
+ if (!Object.prototype.hasOwnProperty.call(meta, key) || !meta[key]) {
311
+ throw new MetaMissingException(`Check::isotopeT() - Required meta field "${key}" is missing!`)
312
+ }
313
+ }
314
+ }
315
+
316
+ for (const key of ['token']) {
317
+ if (!Object.prototype.hasOwnProperty.call(meta, key) || !meta[key]) {
318
+ throw new MetaMissingException(`Check::isotopeT() - Required meta field "${key}" is missing!`)
319
+ }
320
+ }
321
+
322
+ if (atom.token !== 'USER') {
323
+ throw new WrongTokenTypeException(`Check::isotopeT() - "${atom.token}" is not a valid Token slug for "${atom.isotope}" isotope Atoms!`)
324
+ }
325
+
326
+ if (atom.index !== 0) {
327
+ throw new AtomIndexException(`Check::isotopeT() - Isotope "${atom.isotope}" Atoms must have an index equal to 0!`)
328
+ }
329
+ }
330
+
331
+ return true
332
+ }
333
+
334
+ /**
335
+ * Validate isotope R atoms (rules)
336
+ * @return True if valid
337
+ * @throws MetaMissingException if rule validation fails
338
+ */
339
+ isotopeR(): boolean {
340
+ for (const atom of this.molecule.getIsotopes('R')) {
341
+ const metas = atom.aggregatedMeta()
342
+
343
+ if (metas.policy) {
344
+ const policy = JSON.parse(metas.policy as string)
345
+
346
+ if (!Object.keys(policy).every(i => ['read', 'write'].includes(i))) {
347
+ throw new MetaMissingException('Check::isotopeR() - Mixing rules with politics!')
348
+ }
349
+ }
350
+
351
+ if (metas.rule) {
352
+ const rules = JSON.parse(metas.rule as string)
353
+
354
+ if (!Array.isArray(rules)) {
355
+ throw new MetaMissingException('Check::isotopeR() - Incorrect rule format!')
356
+ }
357
+
358
+ for (const item of rules) {
359
+ Rule.toObject(item)
360
+ }
361
+
362
+ if (rules.length < 1) {
363
+ throw new MetaMissingException('Check::isotopeR() - No rules!')
364
+ }
365
+ }
366
+ }
367
+
368
+ return true
369
+ }
370
+
371
+ /**
372
+ * Validate isotope V atoms (value transfers)
373
+ * @param senderWallet - Optional wallet for balance validation
374
+ * @return True if valid
375
+ * @throws Various transfer exceptions for validation failures
376
+ */
377
+ isotopeV(senderWallet: Wallet | null = null): boolean {
378
+ const isotopeV = this.molecule.getIsotopes('V')
379
+
380
+ if (isotopeV.length === 0) {
381
+ return true
382
+ }
383
+
384
+ const firstAtom = this.molecule.atoms[0]
385
+
386
+ if (!firstAtom) {
387
+ throw new AtomsMissingException('Check::isotopeV() - Missing first atom')
388
+ }
389
+
390
+ if (firstAtom.isotope === 'V' && isotopeV.length === 2) {
391
+ const endAtom = isotopeV[isotopeV.length - 1]
392
+
393
+ if (!endAtom) {
394
+ throw new AtomsMissingException('Check::isotopeV() - Missing end atom')
395
+ }
396
+
397
+ if (firstAtom.token !== endAtom.token) {
398
+ throw new TransferMismatchedException()
399
+ }
400
+
401
+ const endValue = endAtom.value !== null ? Number(endAtom.value) : 0
402
+ if (endValue < 0) {
403
+ throw new TransferMalformedException()
404
+ }
405
+
406
+ return true
407
+ }
408
+
409
+ let sum = 0
410
+ let value = 0
411
+
412
+ for (const index in this.molecule.atoms) {
413
+ if (Object.prototype.hasOwnProperty.call(this.molecule.atoms, index)) {
414
+ const vAtom = this.molecule.atoms[index]
415
+
416
+ // Not V? Next...
417
+ if (!vAtom || vAtom.isotope !== 'V') {
418
+ continue
419
+ }
420
+
421
+ // Making sure we're in integer land
422
+ value = vAtom.value !== null ? Number(vAtom.value) : 0
423
+
424
+ if (Number.isNaN(value)) {
425
+ throw new TypeError('Invalid isotope "V" values')
426
+ }
427
+
428
+ // Making sure all V atoms of the same token
429
+ if (vAtom.token !== firstAtom.token) {
430
+ throw new TransferMismatchedException()
431
+ }
432
+
433
+ // Checking non-primary atoms
434
+ if (Number(index) > 0) {
435
+ // Negative V atom in a non-primary position?
436
+ if (value < 0) {
437
+ throw new TransferMalformedException()
438
+ }
439
+
440
+ // Cannot be sending and receiving from the same address
441
+ if (vAtom.walletAddress === firstAtom.walletAddress) {
442
+ throw new TransferToSelfException()
443
+ }
444
+ }
445
+
446
+ // Adding this Atom's value to the total sum
447
+ sum += value
448
+ }
449
+ }
450
+
451
+ // All atoms must sum to zero for a balanced transaction
452
+ if (sum !== 0) {
453
+ throw new TransferUnbalancedException()
454
+ }
455
+
456
+ // If we're provided with a senderWallet argument, we can perform additional checks
457
+ if (senderWallet) {
458
+ const firstValue = firstAtom.value !== null ? Number(firstAtom.value) : 0
459
+
460
+ if (Number.isNaN(firstValue)) {
461
+ throw new TypeError('Invalid isotope "V" values')
462
+ }
463
+
464
+ const remainder = senderWallet.balance + firstValue
465
+
466
+ // Is there enough balance to send?
467
+ if (remainder < 0) {
468
+ throw new TransferBalanceException()
469
+ }
470
+
471
+ // Does the remainder match what should be there in the source wallet, if provided?
472
+ if (remainder !== sum) {
473
+ throw new TransferRemainderException()
474
+ }
475
+ } else if (sum !== 0) {
476
+ // No senderWallet, but have a remainder?
477
+ throw new TransferRemainderException()
478
+ }
479
+
480
+ // Looks like we passed all the tests!
481
+ return true
482
+ }
483
+
484
+ /**
485
+ * Verify molecular hash matches atom content
486
+ * @return True if valid
487
+ * @throws MolecularHashMismatchException if hash doesn't match
488
+ */
489
+ molecularHash(): boolean {
490
+ if (this.molecule.molecularHash !== Atom.hashAtoms({
491
+ atoms: this.molecule.atoms
492
+ })) {
493
+ throw new MolecularHashMismatchException()
494
+ }
495
+
496
+ // Looks like we passed all the tests!
497
+ return true
498
+ }
499
+
500
+ /**
501
+ * Verify one-time signature (OTS)
502
+ * @return True if valid
503
+ * @throws SignatureMalformedException if signature format is invalid
504
+ * @throws SignatureMismatchException if signature doesn't match
505
+ */
506
+ ots(): boolean {
507
+ // Convert Hm to numeric notation via EnumerateMolecule(Hm)
508
+ const normalizedHash = this.molecule.normalizedHash()
509
+
510
+ // Rebuilding OTS out of all the atoms
511
+ let ots = this.molecule.atoms.map(
512
+ atom => atom.otsFragment || ''
513
+ ).reduce(
514
+ (accumulator, otsFragment) => accumulator + otsFragment
515
+ )
516
+
517
+ // Wrong size? Maybe it's compressed
518
+ if (ots.length !== 2048) {
519
+ // Attempting decompression
520
+ ots = base64ToHex(ots)
521
+
522
+ // Still wrong? That's a failure
523
+ if (ots.length !== 2048) {
524
+ throw new SignatureMalformedException()
525
+ }
526
+ }
527
+
528
+ // Subdivide Kk into 16 segments of 256 bytes (128 characters) each
529
+ const otsChunks = chunkSubstr(ots, 128)
530
+
531
+ let keyFragments = ''
532
+
533
+ for (const index in otsChunks) {
534
+ let workingChunk = otsChunks[index]
535
+ if (!workingChunk) continue
536
+
537
+ const hashValue = normalizedHash[Number(index)] || 0
538
+
539
+ for (let iterationCount = 0, condition = 8 + hashValue; iterationCount < condition; iterationCount++) {
540
+ workingChunk = shake256(workingChunk, 512)
541
+ }
542
+
543
+ keyFragments += workingChunk
544
+ }
545
+
546
+ // Absorb the hashed Kk into the sponge to receive the digest Dk
547
+ const digest = shake256(keyFragments, 8192)
548
+
549
+ // Squeeze the sponge to retrieve a 128 byte (64 character) string that should match the sender's wallet address
550
+ const address = shake256(digest, 256)
551
+
552
+ // Signing atom
553
+ const signingAtom = this.molecule.atoms[0]
554
+
555
+ if (!signingAtom) {
556
+ throw new SignatureMismatchException()
557
+ }
558
+
559
+ // Get a signing address
560
+ let signingAddress = signingAtom.walletAddress
561
+
562
+ // Get signing wallet from first atom's metas
563
+ const signingWallet = Dot.get(signingAtom.aggregatedMeta(), 'signingWallet')
564
+
565
+ // Try to get custom signing address from the metas (local molecule with server secret)
566
+ if (signingWallet) {
567
+ const parsedWallet = JSON.parse(signingWallet as string)
568
+ const walletAddress = Dot.get(parsedWallet, 'address')
569
+ if (walletAddress) {
570
+ signingAddress = walletAddress as string
571
+ }
572
+ }
573
+
574
+ if (address !== signingAddress) {
575
+ throw new SignatureMismatchException()
576
+ }
577
+
578
+ // Looks like we passed all the tests!
579
+ return true
580
+ }
581
+ }
@@ -0,0 +1,94 @@
1
+ /*
2
+ (
3
+ (/(
4
+ (//(
5
+ (///(
6
+ (/////(
7
+ (//////( )
8
+ (////////( (/)
9
+ (////////( (///)
10
+ (//////////( (////)
11
+ (//////////( (//////)
12
+ (////////////( (///////)
13
+ (/////////////( (/////////)
14
+ (//////////////( (///////////)
15
+ (///////////////( (/////////////)
16
+ (////////////////( (//////////////)
17
+ ((((((((((((((((((( (((((((((((((((
18
+ ((((((((((((((((((( ((((((((((((((
19
+ ((((((((((((((((((( ((((((((((((((
20
+ (((((((((((((((((((( (((((((((((((
21
+ (((((((((((((((((((( ((((((((((((
22
+ ((((((((((((((((((( ((((((((((((
23
+ ((((((((((((((((((( ((((((((((
24
+ ((((((((((((((((((/ (((((((((
25
+ (((((((((((((((((( ((((((((
26
+ ((((((((((((((((( (((((((
27
+ (((((((((((((((((( (((((
28
+ ################# ##
29
+ ################ #
30
+ ################# ##
31
+ %################ ###
32
+ ###############( ####
33
+ ############### ####
34
+ ############### ######
35
+ %#############( (#######
36
+ %############# #########
37
+ ############( ##########
38
+ ########### #############
39
+ ######### ##############
40
+ %######
41
+
42
+ Powered by Knish.IO: Connecting a Decentralized World
43
+
44
+ Please visit https://github.com/WishKnish/KnishIO-Client-TS for information.
45
+
46
+ License: https://github.com/WishKnish/KnishIO-Client-TS/blob/master/LICENSE
47
+ */
48
+
49
+ /**
50
+ * High-precision decimal operations for financial calculations
51
+ * Value determined by min SQL decimal precision
52
+ */
53
+
54
+ const MULTIPLIER = 10 ** 18
55
+
56
+ export default class Decimal {
57
+ /**
58
+ * Validates and normalizes a decimal value
59
+ */
60
+ static val(value: number): number {
61
+ if (Math.abs(value * MULTIPLIER) < 1) {
62
+ return 0.0
63
+ }
64
+
65
+ return value
66
+ }
67
+
68
+ /**
69
+ * Compares two decimal values with high precision
70
+ * @param value1 First value to compare
71
+ * @param value2 Second value to compare
72
+ * @param debug Enable debug logging
73
+ * @returns 0 if equal, 1 if value1 > value2, -1 if value1 < value2
74
+ */
75
+ static cmp(value1: number, value2: number, debug: boolean = false): number {
76
+ const val1 = Decimal.val(value1) * MULTIPLIER
77
+ const val2 = Decimal.val(value2) * MULTIPLIER
78
+
79
+ // Equal
80
+ if (Math.abs(val1 - val2) < 1) {
81
+ return 0
82
+ }
83
+
84
+ // Greater or smaller
85
+ return (val1 > val2) ? 1 : -1
86
+ }
87
+
88
+ /**
89
+ * Tests if two decimal values are equal
90
+ */
91
+ static equal(value1: number, value2: number): boolean {
92
+ return (Decimal.cmp(value1, value2) === 0)
93
+ }
94
+ }