@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.
- package/LICENSE +674 -0
- package/README.md +425 -0
- package/dist/index.cjs +9961 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.iife.js +32241 -0
- package/dist/index.iife.js.map +1 -0
- package/dist/index.js +9853 -0
- package/dist/index.js.map +1 -0
- package/package.json +113 -0
- package/src/AuthToken.ts +214 -0
- package/src/KnishIOClient.ts +2020 -0
- package/src/constants.ts +398 -0
- package/src/core/Atom.ts +646 -0
- package/src/core/AtomMeta.ts +278 -0
- package/src/core/Meta.ts +428 -0
- package/src/core/Molecule.ts +825 -0
- package/src/core/PolicyMeta.ts +130 -0
- package/src/core/TokenUnit.ts +148 -0
- package/src/core/Wallet.ts +467 -0
- package/src/exception/AtomIndexException.ts +97 -0
- package/src/exception/AtomsMissingException.ts +109 -0
- package/src/exception/AuthorizationRejectedException.ts +63 -0
- package/src/exception/BalanceInsufficientException.ts +58 -0
- package/src/exception/BaseException.ts +275 -0
- package/src/exception/BatchIdException.ts +58 -0
- package/src/exception/CodeException.ts +119 -0
- package/src/exception/DecryptionKeyException.ts +65 -0
- package/src/exception/InvalidResponseException.ts +112 -0
- package/src/exception/MetaMissingException.ts +58 -0
- package/src/exception/MolecularHashMismatchException.ts +115 -0
- package/src/exception/MolecularHashMissingException.ts +58 -0
- package/src/exception/NegativeAmountException.ts +58 -0
- package/src/exception/PolicyInvalidException.ts +58 -0
- package/src/exception/SignatureMalformedException.ts +58 -0
- package/src/exception/SignatureMismatchException.ts +98 -0
- package/src/exception/StackableUnitAmountException.ts +65 -0
- package/src/exception/StackableUnitDecimalsException.ts +65 -0
- package/src/exception/TransferBalanceException.ts +98 -0
- package/src/exception/TransferMalformedException.ts +58 -0
- package/src/exception/TransferMismatchedException.ts +58 -0
- package/src/exception/TransferRemainderException.ts +58 -0
- package/src/exception/TransferToSelfException.ts +58 -0
- package/src/exception/TransferUnbalancedException.ts +58 -0
- package/src/exception/UnauthenticatedException.ts +147 -0
- package/src/exception/WalletCredentialException.ts +108 -0
- package/src/exception/WalletShadowException.ts +65 -0
- package/src/exception/WrongTokenTypeException.ts +58 -0
- package/src/exception/index.ts +272 -0
- package/src/index.ts +512 -0
- package/src/instance/rules/Callback.ts +257 -0
- package/src/instance/rules/Condition.ts +96 -0
- package/src/instance/rules/Meta.ts +163 -0
- package/src/instance/rules/Rule.ts +29 -0
- package/src/instance/rules/exception/RuleArgumentException.ts +65 -0
- package/src/libraries/CheckMolecule.ts +581 -0
- package/src/libraries/Decimal.ts +94 -0
- package/src/libraries/Dot.ts +202 -0
- package/src/libraries/GraphQLClient.ts +276 -0
- package/src/libraries/Hex.ts +155 -0
- package/src/libraries/UrqlClientWrapper.ts +336 -0
- package/src/libraries/array.ts +91 -0
- package/src/libraries/crypto.ts +816 -0
- package/src/libraries/strings.ts +458 -0
- package/src/mutation/Mutation.ts +103 -0
- package/src/mutation/MutationActiveSession.ts +108 -0
- package/src/mutation/MutationClaimShadowWallet.ts +91 -0
- package/src/mutation/MutationCreateIdentifier.ts +86 -0
- package/src/mutation/MutationCreateMeta.ts +92 -0
- package/src/mutation/MutationCreateRule.ts +90 -0
- package/src/mutation/MutationCreateToken.ts +92 -0
- package/src/mutation/MutationCreateWallet.ts +78 -0
- package/src/mutation/MutationDepositBufferToken.ts +72 -0
- package/src/mutation/MutationLinkIdentifier.ts +87 -0
- package/src/mutation/MutationProposeMolecule.ts +147 -0
- package/src/mutation/MutationRequestAuthorization.ts +77 -0
- package/src/mutation/MutationRequestAuthorizationGuest.ts +85 -0
- package/src/mutation/MutationRequestTokens.ts +98 -0
- package/src/mutation/MutationTransferTokens.ts +87 -0
- package/src/mutation/MutationWithdrawBufferToken.ts +73 -0
- package/src/query/Query.ts +187 -0
- package/src/query/QueryActiveSession.ts +89 -0
- package/src/query/QueryAtom.ts +275 -0
- package/src/query/QueryBalance.ts +102 -0
- package/src/query/QueryBatch.ts +145 -0
- package/src/query/QueryBatchHistory.ts +86 -0
- package/src/query/QueryContinuId.ts +91 -0
- package/src/query/QueryMetaType.ts +177 -0
- package/src/query/QueryMetaTypeViaAtom.ts +199 -0
- package/src/query/QueryPolicy.ts +91 -0
- package/src/query/QueryToken.ts +90 -0
- package/src/query/QueryUserActivity.ts +153 -0
- package/src/query/QueryWalletBundle.ts +92 -0
- package/src/query/QueryWalletList.ts +106 -0
- package/src/response/EnhancedResponse.ts +345 -0
- package/src/response/Response.ts +254 -0
- package/src/response/ResponseActiveSession.ts +72 -0
- package/src/response/ResponseAtom.ts +132 -0
- package/src/response/ResponseAuthorizationGuest.ts +119 -0
- package/src/response/ResponseBalance.ts +153 -0
- package/src/response/ResponseClaimShadowWallet.ts +56 -0
- package/src/response/ResponseContinuId.ts +101 -0
- package/src/response/ResponseCreateIdentifier.ts +56 -0
- package/src/response/ResponseCreateMeta.ts +58 -0
- package/src/response/ResponseCreateRule.ts +56 -0
- package/src/response/ResponseCreateToken.ts +58 -0
- package/src/response/ResponseCreateWallet.ts +58 -0
- package/src/response/ResponseLinkIdentifier.ts +87 -0
- package/src/response/ResponseMetaBatch.ts +72 -0
- package/src/response/ResponseMetaType.ts +108 -0
- package/src/response/ResponseMetaTypeViaAtom.ts +108 -0
- package/src/response/ResponsePolicy.ts +90 -0
- package/src/response/ResponseProposeMolecule.ts +155 -0
- package/src/response/ResponseQueryActiveSession.ts +105 -0
- package/src/response/ResponseQueryUserActivity.ts +89 -0
- package/src/response/ResponseRequestAuthorization.ts +100 -0
- package/src/response/ResponseRequestAuthorizationGuest.ts +133 -0
- package/src/response/ResponseRequestTokens.ts +58 -0
- package/src/response/ResponseTransferTokens.ts +72 -0
- package/src/response/ResponseWalletBundle.ts +95 -0
- package/src/response/ResponseWalletList.ts +165 -0
- package/src/schemas/index.ts +457 -0
- package/src/subscribe/ActiveSessionSubscribe.ts +72 -0
- package/src/subscribe/ActiveWalletSubscribe.ts +99 -0
- package/src/subscribe/CreateMoleculeSubscribe.ts +106 -0
- package/src/subscribe/Subscribe.ts +182 -0
- package/src/subscribe/WalletStatusSubscribe.ts +70 -0
- package/src/subscribe/index.ts +59 -0
- package/src/types/assertions.ts +722 -0
- package/src/types/client.ts +567 -0
- package/src/types/crypto.ts +541 -0
- package/src/types/graphql.ts +630 -0
- package/src/types/guards.ts +659 -0
- package/src/types/index.ts +614 -0
- package/src/types/response.ts +133 -0
- package/src/types/template-literals.ts +382 -0
- package/src/validation/UNIVERSAL_CONFIGURATION_INTERFACES.ts +580 -0
- package/src/validation/ValidationService.ts +607 -0
- package/src/validation/schemas.ts +447 -0
- package/src/versions/HashAtom.ts +170 -0
- package/src/versions/Version4.ts +120 -0
- 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
|
+
}
|