@wishknish/knishio-client-js 0.7.4 → 0.7.6
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/dist/client.cjs.js +90 -28
- package/dist/client.cjs.js.map +1 -1
- package/dist/client.es.mjs +1680 -892
- package/dist/client.es.mjs.map +1 -1
- package/dist/client.iife.js +90 -28
- package/dist/client.iife.js.map +1 -1
- package/package.json +1 -1
- package/src/KnishIOClient.js +74 -13
- package/src/Molecule.js +102 -14
- package/src/Wallet.js +48 -1
- package/src/index.js +233 -9
- package/src/libraries/CheckMolecule.js +211 -5
- package/src/query/QueryContinuId.js +8 -0
- package/src/query/QueryMetaTypeViaMolecule.js +223 -0
- package/src/query/QueryWalletList.js +2 -2
- package/src/response/ResponseContinuId.js +1 -1
- package/src/response/ResponseMetaTypeViaMolecule.js +210 -0
- package/src/response/ResponseRequestAuthorization.js +34 -1
- package/src/response/ResponseRequestAuthorizationGuest.js +32 -1
- package/src/response/ResponseWalletList.js +1 -1
package/src/index.js
CHANGED
|
@@ -46,15 +46,112 @@ Please visit https://github.com/WishKnish/KnishIO-Client-JS for information.
|
|
|
46
46
|
License: https://github.com/WishKnish/KnishIO-Client-JS/blob/master/LICENSE
|
|
47
47
|
*/
|
|
48
48
|
|
|
49
|
+
// =============================================================================
|
|
50
|
+
// CORE CLASSES
|
|
51
|
+
// =============================================================================
|
|
52
|
+
|
|
49
53
|
import Atom from './Atom.js'
|
|
54
|
+
import AtomMeta from './AtomMeta.js'
|
|
50
55
|
import Molecule from './Molecule.js'
|
|
51
56
|
import Wallet from './Wallet.js'
|
|
52
57
|
import Meta from './Meta.js'
|
|
58
|
+
import AuthToken from './AuthToken.js'
|
|
59
|
+
import TokenUnit from './TokenUnit.js'
|
|
60
|
+
import PolicyMeta from './PolicyMeta.js'
|
|
53
61
|
import KnishIOClient from './KnishIOClient.js'
|
|
54
|
-
|
|
62
|
+
|
|
63
|
+
// Validation
|
|
64
|
+
import CheckMolecule from './libraries/CheckMolecule.js'
|
|
65
|
+
|
|
66
|
+
// Utilities
|
|
67
|
+
import Dot from './libraries/Dot.js'
|
|
68
|
+
import Decimal from './libraries/Decimal.js'
|
|
69
|
+
|
|
70
|
+
// =============================================================================
|
|
71
|
+
// BASE CLASSES
|
|
72
|
+
// =============================================================================
|
|
73
|
+
|
|
74
|
+
import Query from './query/Query.js'
|
|
75
|
+
import Mutation from './mutation/Mutation.js'
|
|
76
|
+
import Response from './response/Response.js'
|
|
77
|
+
|
|
78
|
+
// =============================================================================
|
|
79
|
+
// QUERY CLASSES
|
|
80
|
+
// =============================================================================
|
|
81
|
+
|
|
82
|
+
import QueryActiveSession from './query/QueryActiveSession.js'
|
|
83
|
+
import QueryAtom from './query/QueryAtom.js'
|
|
84
|
+
import QueryBalance from './query/QueryBalance.js'
|
|
85
|
+
import QueryBatch from './query/QueryBatch.js'
|
|
86
|
+
import QueryBatchHistory from './query/QueryBatchHistory.js'
|
|
87
|
+
import QueryContinuId from './query/QueryContinuId.js'
|
|
88
|
+
import QueryMetaType from './query/QueryMetaType.js'
|
|
89
|
+
import QueryMetaTypeViaAtom from './query/QueryMetaTypeViaAtom.js'
|
|
90
|
+
import QueryMetaTypeViaMolecule from './query/QueryMetaTypeViaMolecule.js'
|
|
91
|
+
import QueryPolicy from './query/QueryPolicy.js'
|
|
92
|
+
import QueryToken from './query/QueryToken.js'
|
|
93
|
+
import QueryUserActivity from './query/QueryUserActivity.js'
|
|
94
|
+
import QueryWalletBundle from './query/QueryWalletBundle.js'
|
|
95
|
+
import QueryWalletList from './query/QueryWalletList.js'
|
|
96
|
+
|
|
97
|
+
// =============================================================================
|
|
98
|
+
// MUTATION CLASSES
|
|
99
|
+
// =============================================================================
|
|
100
|
+
|
|
101
|
+
import MutationActiveSession from './mutation/MutationActiveSession.js'
|
|
55
102
|
import MutationAppendRequest from './mutation/MutationAppendRequest.js'
|
|
56
|
-
import
|
|
103
|
+
import MutationClaimShadowWallet from './mutation/MutationClaimShadowWallet.js'
|
|
104
|
+
import MutationCreateIdentifier from './mutation/MutationCreateIdentifier.js'
|
|
105
|
+
import MutationCreateMeta from './mutation/MutationCreateMeta.js'
|
|
106
|
+
import MutationCreateRule from './mutation/MutationCreateRule.js'
|
|
107
|
+
import MutationCreateToken from './mutation/MutationCreateToken.js'
|
|
108
|
+
import MutationCreateWallet from './mutation/MutationCreateWallet.js'
|
|
109
|
+
import MutationDepositBufferToken from './mutation/MutationDepositBufferToken.js'
|
|
110
|
+
import MutationLinkIdentifier from './mutation/MutationLinkIdentifier.js'
|
|
111
|
+
import MutationPeering from './mutation/MutationPeering.js'
|
|
112
|
+
import MutationProposeMolecule from './mutation/MutationProposeMolecule.js'
|
|
113
|
+
import MutationRequestAuthorization from './mutation/MutationRequestAuthorization.js'
|
|
114
|
+
import MutationRequestAuthorizationGuest from './mutation/MutationRequestAuthorizationGuest.js'
|
|
115
|
+
import MutationRequestTokens from './mutation/MutationRequestTokens.js'
|
|
116
|
+
import MutationTransferTokens from './mutation/MutationTransferTokens.js'
|
|
117
|
+
import MutationWithdrawBufferToken from './mutation/MutationWithdrawBufferToken.js'
|
|
118
|
+
|
|
119
|
+
// =============================================================================
|
|
120
|
+
// RESPONSE CLASSES
|
|
121
|
+
// =============================================================================
|
|
122
|
+
|
|
123
|
+
import ResponseActiveSession from './response/ResponseActiveSession.js'
|
|
57
124
|
import ResponseAppendRequest from './response/ResponseAppendRequest.js'
|
|
125
|
+
import ResponseAtom from './response/ResponseAtom.js'
|
|
126
|
+
import ResponseAuthorizationGuest from './response/ResponseAuthorizationGuest.js'
|
|
127
|
+
import ResponseBalance from './response/ResponseBalance.js'
|
|
128
|
+
import ResponseClaimShadowWallet from './response/ResponseClaimShadowWallet.js'
|
|
129
|
+
import ResponseContinuId from './response/ResponseContinuId.js'
|
|
130
|
+
import ResponseCreateIdentifier from './response/ResponseCreateIdentifier.js'
|
|
131
|
+
import ResponseCreateMeta from './response/ResponseCreateMeta.js'
|
|
132
|
+
import ResponseCreateRule from './response/ResponseCreateRule.js'
|
|
133
|
+
import ResponseCreateToken from './response/ResponseCreateToken.js'
|
|
134
|
+
import ResponseCreateWallet from './response/ResponseCreateWallet.js'
|
|
135
|
+
import ResponseLinkIdentifier from './response/ResponseLinkIdentifier.js'
|
|
136
|
+
import ResponseMetaType from './response/ResponseMetaType.js'
|
|
137
|
+
import ResponseMetaTypeViaAtom from './response/ResponseMetaTypeViaAtom.js'
|
|
138
|
+
import ResponseMetaTypeViaMolecule from './response/ResponseMetaTypeViaMolecule.js'
|
|
139
|
+
import ResponsePeering from './response/ResponsePeering.js'
|
|
140
|
+
import ResponsePolicy from './response/ResponsePolicy.js'
|
|
141
|
+
import ResponseProposeMolecule from './response/ResponseProposeMolecule.js'
|
|
142
|
+
import ResponseQueryActiveSession from './response/ResponseQueryActiveSession.js'
|
|
143
|
+
import ResponseQueryUserActivity from './response/ResponseQueryUserActivity.js'
|
|
144
|
+
import ResponseRequestAuthorization from './response/ResponseRequestAuthorization.js'
|
|
145
|
+
import ResponseRequestAuthorizationGuest from './response/ResponseRequestAuthorizationGuest.js'
|
|
146
|
+
import ResponseRequestTokens from './response/ResponseRequestTokens.js'
|
|
147
|
+
import ResponseTransferTokens from './response/ResponseTransferTokens.js'
|
|
148
|
+
import ResponseWalletBundle from './response/ResponseWalletBundle.js'
|
|
149
|
+
import ResponseWalletList from './response/ResponseWalletList.js'
|
|
150
|
+
|
|
151
|
+
// =============================================================================
|
|
152
|
+
// LIBRARY FUNCTIONS
|
|
153
|
+
// =============================================================================
|
|
154
|
+
|
|
58
155
|
import {
|
|
59
156
|
base64ToHex,
|
|
60
157
|
bufferToHexString,
|
|
@@ -63,30 +160,149 @@ import {
|
|
|
63
160
|
hexStringToBuffer,
|
|
64
161
|
hexToBase64,
|
|
65
162
|
isHex,
|
|
163
|
+
isNumeric,
|
|
66
164
|
randomString
|
|
67
165
|
} from './libraries/strings.js'
|
|
166
|
+
|
|
68
167
|
import {
|
|
168
|
+
generateBatchId,
|
|
69
169
|
generateBundleHash,
|
|
70
170
|
generateSecret,
|
|
71
171
|
shake256
|
|
72
172
|
} from './libraries/crypto.js'
|
|
73
173
|
|
|
174
|
+
import {
|
|
175
|
+
chunkArray,
|
|
176
|
+
deepCloning,
|
|
177
|
+
diff,
|
|
178
|
+
intersect
|
|
179
|
+
} from './libraries/array.js'
|
|
180
|
+
|
|
181
|
+
// =============================================================================
|
|
182
|
+
// EXCEPTION SYSTEM
|
|
183
|
+
// =============================================================================
|
|
184
|
+
|
|
74
185
|
export {
|
|
186
|
+
AtomIndexException,
|
|
187
|
+
AtomsMissingException,
|
|
188
|
+
AuthorizationRejectedException,
|
|
189
|
+
BalanceInsufficientException,
|
|
190
|
+
BatchIdException,
|
|
191
|
+
CodeException,
|
|
192
|
+
InvalidResponseException,
|
|
193
|
+
MetaMissingException,
|
|
194
|
+
MolecularHashMismatchException,
|
|
195
|
+
MolecularHashMissingException,
|
|
196
|
+
NegativeAmountException,
|
|
197
|
+
PolicyInvalidException,
|
|
198
|
+
SignatureMalformedException,
|
|
199
|
+
SignatureMismatchException,
|
|
200
|
+
StackableUnitAmountException,
|
|
201
|
+
StackableUnitDecimalsException,
|
|
202
|
+
TransferBalanceException,
|
|
203
|
+
TransferMalformedException,
|
|
204
|
+
TransferMismatchedException,
|
|
205
|
+
TransferRemainderException,
|
|
206
|
+
TransferToSelfException,
|
|
207
|
+
TransferUnbalancedException,
|
|
208
|
+
UnauthenticatedException,
|
|
209
|
+
WalletShadowException,
|
|
210
|
+
WrongTokenTypeException
|
|
211
|
+
} from './exception/index.js'
|
|
212
|
+
|
|
213
|
+
// =============================================================================
|
|
214
|
+
// NAMED EXPORTS
|
|
215
|
+
// =============================================================================
|
|
216
|
+
|
|
217
|
+
export {
|
|
218
|
+
// Core classes
|
|
75
219
|
Atom,
|
|
220
|
+
AtomMeta,
|
|
76
221
|
Molecule,
|
|
77
222
|
Wallet,
|
|
78
223
|
Meta,
|
|
224
|
+
AuthToken,
|
|
225
|
+
TokenUnit,
|
|
226
|
+
PolicyMeta,
|
|
79
227
|
KnishIOClient,
|
|
80
228
|
|
|
81
|
-
//
|
|
82
|
-
|
|
229
|
+
// Validation
|
|
230
|
+
CheckMolecule,
|
|
231
|
+
|
|
232
|
+
// Utilities
|
|
233
|
+
Dot,
|
|
234
|
+
Decimal,
|
|
235
|
+
|
|
236
|
+
// Base classes
|
|
237
|
+
Query,
|
|
238
|
+
Mutation,
|
|
239
|
+
Response,
|
|
240
|
+
|
|
241
|
+
// Queries
|
|
242
|
+
QueryActiveSession,
|
|
243
|
+
QueryAtom,
|
|
244
|
+
QueryBalance,
|
|
245
|
+
QueryBatch,
|
|
246
|
+
QueryBatchHistory,
|
|
247
|
+
QueryContinuId,
|
|
248
|
+
QueryMetaType,
|
|
249
|
+
QueryMetaTypeViaAtom,
|
|
250
|
+
QueryMetaTypeViaMolecule,
|
|
251
|
+
QueryPolicy,
|
|
252
|
+
QueryToken,
|
|
253
|
+
QueryUserActivity,
|
|
254
|
+
QueryWalletBundle,
|
|
255
|
+
QueryWalletList,
|
|
256
|
+
|
|
257
|
+
// Mutations
|
|
258
|
+
MutationActiveSession,
|
|
83
259
|
MutationAppendRequest,
|
|
260
|
+
MutationClaimShadowWallet,
|
|
261
|
+
MutationCreateIdentifier,
|
|
262
|
+
MutationCreateMeta,
|
|
263
|
+
MutationCreateRule,
|
|
264
|
+
MutationCreateToken,
|
|
265
|
+
MutationCreateWallet,
|
|
266
|
+
MutationDepositBufferToken,
|
|
267
|
+
MutationLinkIdentifier,
|
|
268
|
+
MutationPeering,
|
|
269
|
+
MutationProposeMolecule,
|
|
270
|
+
MutationRequestAuthorization,
|
|
271
|
+
MutationRequestAuthorizationGuest,
|
|
272
|
+
MutationRequestTokens,
|
|
273
|
+
MutationTransferTokens,
|
|
274
|
+
MutationWithdrawBufferToken,
|
|
84
275
|
|
|
85
|
-
//
|
|
86
|
-
|
|
276
|
+
// Responses
|
|
277
|
+
ResponseActiveSession,
|
|
87
278
|
ResponseAppendRequest,
|
|
279
|
+
ResponseAtom,
|
|
280
|
+
ResponseAuthorizationGuest,
|
|
281
|
+
ResponseBalance,
|
|
282
|
+
ResponseClaimShadowWallet,
|
|
283
|
+
ResponseContinuId,
|
|
284
|
+
ResponseCreateIdentifier,
|
|
285
|
+
ResponseCreateMeta,
|
|
286
|
+
ResponseCreateRule,
|
|
287
|
+
ResponseCreateToken,
|
|
288
|
+
ResponseCreateWallet,
|
|
289
|
+
ResponseLinkIdentifier,
|
|
290
|
+
ResponseMetaType,
|
|
291
|
+
ResponseMetaTypeViaAtom,
|
|
292
|
+
ResponseMetaTypeViaMolecule,
|
|
293
|
+
ResponsePeering,
|
|
294
|
+
ResponsePolicy,
|
|
295
|
+
ResponseProposeMolecule,
|
|
296
|
+
ResponseQueryActiveSession,
|
|
297
|
+
ResponseQueryUserActivity,
|
|
298
|
+
ResponseRequestAuthorization,
|
|
299
|
+
ResponseRequestAuthorizationGuest,
|
|
300
|
+
ResponseRequestTokens,
|
|
301
|
+
ResponseTransferTokens,
|
|
302
|
+
ResponseWalletBundle,
|
|
303
|
+
ResponseWalletList,
|
|
88
304
|
|
|
89
|
-
//
|
|
305
|
+
// String utilities
|
|
90
306
|
chunkSubstr,
|
|
91
307
|
base64ToHex,
|
|
92
308
|
bufferToHexString,
|
|
@@ -94,10 +310,18 @@ export {
|
|
|
94
310
|
hexStringToBuffer,
|
|
95
311
|
hexToBase64,
|
|
96
312
|
isHex,
|
|
313
|
+
isNumeric,
|
|
97
314
|
randomString,
|
|
98
315
|
|
|
99
|
-
//
|
|
316
|
+
// Crypto utilities
|
|
100
317
|
generateSecret,
|
|
101
318
|
generateBundleHash,
|
|
102
|
-
|
|
319
|
+
generateBatchId,
|
|
320
|
+
shake256,
|
|
321
|
+
|
|
322
|
+
// Array utilities
|
|
323
|
+
chunkArray,
|
|
324
|
+
deepCloning,
|
|
325
|
+
diff,
|
|
326
|
+
intersect
|
|
103
327
|
}
|
|
@@ -63,6 +63,7 @@ import WrongTokenTypeException from './../exception/WrongTokenTypeException.js'
|
|
|
63
63
|
import BatchIdException from './../exception/BatchIdException.js'
|
|
64
64
|
import Atom from './../Atom.js'
|
|
65
65
|
import Meta from './../Meta.js'
|
|
66
|
+
import Molecule from './../Molecule.js'
|
|
66
67
|
import Wallet from './../Wallet.js'
|
|
67
68
|
import Rule from '../instance/Rules/Rule.js'
|
|
68
69
|
import {
|
|
@@ -119,6 +120,8 @@ export default class CheckMolecule {
|
|
|
119
120
|
this.isotopeR() &&
|
|
120
121
|
this.isotopeP() &&
|
|
121
122
|
this.isotopeA() &&
|
|
123
|
+
this.isotopeB() &&
|
|
124
|
+
this.isotopeF() &&
|
|
122
125
|
this.isotopeV(senderWallet)
|
|
123
126
|
}
|
|
124
127
|
|
|
@@ -384,6 +387,104 @@ export default class CheckMolecule {
|
|
|
384
387
|
return true
|
|
385
388
|
}
|
|
386
389
|
|
|
390
|
+
/**
|
|
391
|
+
* Validates B-isotope (Buffer/Exchange) atoms
|
|
392
|
+
*
|
|
393
|
+
* @returns {boolean}
|
|
394
|
+
*/
|
|
395
|
+
isotopeB () {
|
|
396
|
+
const isotopeB = this.molecule.getIsotopes('B')
|
|
397
|
+
|
|
398
|
+
if (isotopeB.length === 0) {
|
|
399
|
+
return true
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
for (const atom of isotopeB) {
|
|
403
|
+
// B atoms must reference a wallet bundle
|
|
404
|
+
if (!atom.metaType || atom.metaType !== 'walletBundle') {
|
|
405
|
+
throw new MetaMissingException('Check::isotopeB() - B-isotope atoms must have metaType "walletBundle"!')
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
if (!atom.metaId) {
|
|
409
|
+
throw new MetaMissingException('Check::isotopeB() - B-isotope atoms must have a metaId!')
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
// Value must be parseable as a number
|
|
413
|
+
const value = Number(atom.value)
|
|
414
|
+
if (Number.isNaN(value)) {
|
|
415
|
+
throw new TransferMalformedException('Check::isotopeB() - B-isotope atom value is not a valid number!')
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
// V+B balance conservation: sum of all V and B atom values must equal zero
|
|
420
|
+
const vAtoms = this.molecule.getIsotopes('V')
|
|
421
|
+
if (vAtoms.length > 0) {
|
|
422
|
+
let sum = 0
|
|
423
|
+
for (const atom of [...vAtoms, ...isotopeB]) {
|
|
424
|
+
const value = Number(atom.value)
|
|
425
|
+
if (!Number.isNaN(value)) {
|
|
426
|
+
sum += value
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
if (sum !== 0) {
|
|
430
|
+
throw new TransferUnbalancedException('Check::isotopeB() - V+B atom values do not balance to zero!')
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
return true
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
/**
|
|
438
|
+
* Validates F-isotope (Fusion/NFT) atoms
|
|
439
|
+
*
|
|
440
|
+
* @returns {boolean}
|
|
441
|
+
*/
|
|
442
|
+
isotopeF () {
|
|
443
|
+
const isotopeF = this.molecule.getIsotopes('F')
|
|
444
|
+
|
|
445
|
+
if (isotopeF.length === 0) {
|
|
446
|
+
return true
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
for (const atom of isotopeF) {
|
|
450
|
+
// F atoms must reference a wallet bundle
|
|
451
|
+
if (!atom.metaType || atom.metaType !== 'walletBundle') {
|
|
452
|
+
throw new MetaMissingException('Check::isotopeF() - F-isotope atoms must have metaType "walletBundle"!')
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
if (!atom.metaId) {
|
|
456
|
+
throw new MetaMissingException('Check::isotopeF() - F-isotope atoms must have a metaId!')
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
// Value must be parseable
|
|
460
|
+
const value = Number(atom.value)
|
|
461
|
+
if (Number.isNaN(value)) {
|
|
462
|
+
throw new TransferMalformedException('Check::isotopeF() - F-isotope atom value is not a valid number!')
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
if (value < 0) {
|
|
466
|
+
throw new TransferMalformedException('Check::isotopeF() - F-isotope atom value must not be negative!')
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
// V+F balance conservation: sum of all V and F atom values must equal zero
|
|
471
|
+
const vAtoms = this.molecule.getIsotopes('V')
|
|
472
|
+
if (vAtoms.length > 0) {
|
|
473
|
+
let sum = 0
|
|
474
|
+
for (const atom of [...vAtoms, ...isotopeF]) {
|
|
475
|
+
const value = Number(atom.value)
|
|
476
|
+
if (!Number.isNaN(value)) {
|
|
477
|
+
sum += value
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
if (sum !== 0) {
|
|
481
|
+
throw new TransferUnbalancedException('Check::isotopeF() - V+F atom values do not balance to zero!')
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
return true
|
|
486
|
+
}
|
|
487
|
+
|
|
387
488
|
/**
|
|
388
489
|
*
|
|
389
490
|
* @param senderWallet
|
|
@@ -396,9 +497,14 @@ export default class CheckMolecule {
|
|
|
396
497
|
return true
|
|
397
498
|
}
|
|
398
499
|
|
|
500
|
+
// When B or F atoms are present, cross-isotope conservation is validated
|
|
501
|
+
// by isotopeB()/isotopeF() — skip V-only conservation check
|
|
502
|
+
const hasCrossIsotope = this.molecule.getIsotopes('B').length > 0 ||
|
|
503
|
+
this.molecule.getIsotopes('F').length > 0
|
|
504
|
+
|
|
399
505
|
const firstAtom = this.molecule.atoms[0]
|
|
400
506
|
|
|
401
|
-
if (firstAtom.isotope === 'V' && isotopeV.length === 2) {
|
|
507
|
+
if (!hasCrossIsotope && firstAtom.isotope === 'V' && isotopeV.length === 2) {
|
|
402
508
|
const endAtom = isotopeV[isotopeV.length - 1]
|
|
403
509
|
|
|
404
510
|
if (firstAtom.token !== endAtom.token) {
|
|
@@ -409,6 +515,11 @@ export default class CheckMolecule {
|
|
|
409
515
|
throw new TransferMalformedException()
|
|
410
516
|
}
|
|
411
517
|
|
|
518
|
+
// Conservation check for 2-atom transfers
|
|
519
|
+
if ((Number(firstAtom.value) + Number(endAtom.value)) !== 0) {
|
|
520
|
+
throw new TransferUnbalancedException()
|
|
521
|
+
}
|
|
522
|
+
|
|
412
523
|
return true
|
|
413
524
|
}
|
|
414
525
|
|
|
@@ -454,8 +565,8 @@ export default class CheckMolecule {
|
|
|
454
565
|
}
|
|
455
566
|
}
|
|
456
567
|
|
|
457
|
-
//
|
|
458
|
-
if (sum !== 0) {
|
|
568
|
+
// V-only conservation: all V atoms must sum to zero (skip for B/F cross-isotope)
|
|
569
|
+
if (!hasCrossIsotope && sum !== 0) {
|
|
459
570
|
throw new TransferUnbalancedException()
|
|
460
571
|
}
|
|
461
572
|
|
|
@@ -467,7 +578,7 @@ export default class CheckMolecule {
|
|
|
467
578
|
throw new TypeError('Invalid isotope "V" values')
|
|
468
579
|
}
|
|
469
580
|
|
|
470
|
-
const remainder = senderWallet.balance + value
|
|
581
|
+
const remainder = Number(senderWallet.balance) + value
|
|
471
582
|
|
|
472
583
|
// Is there enough balance to send?
|
|
473
584
|
if (remainder < 0) {
|
|
@@ -475,7 +586,8 @@ export default class CheckMolecule {
|
|
|
475
586
|
}
|
|
476
587
|
|
|
477
588
|
// Does the remainder match what should be there in the source wallet, if provided?
|
|
478
|
-
|
|
589
|
+
// Skip for cross-isotope (B/F) — conservation is validated by isotopeB()/isotopeF()
|
|
590
|
+
if (!hasCrossIsotope && remainder !== sum) {
|
|
479
591
|
throw new TransferRemainderException()
|
|
480
592
|
}
|
|
481
593
|
} else if (value !== 0) {
|
|
@@ -578,4 +690,98 @@ export default class CheckMolecule {
|
|
|
578
690
|
// Looks like we passed all the tests!
|
|
579
691
|
return true
|
|
580
692
|
}
|
|
693
|
+
|
|
694
|
+
/**
|
|
695
|
+
* Converts server-side molecule data (from GraphQL meta query responses)
|
|
696
|
+
* into a Molecule instance suitable for verification via CheckMolecule.
|
|
697
|
+
*
|
|
698
|
+
* Handles field mapping differences between server and client:
|
|
699
|
+
* - tokenSlug → token
|
|
700
|
+
* - metasJson (JSON string) → meta (array of {key, value})
|
|
701
|
+
* - bundleHash → bundle
|
|
702
|
+
*
|
|
703
|
+
* @param {object} serverData - Molecule data from GraphQL response
|
|
704
|
+
* @param {string} serverData.molecularHash
|
|
705
|
+
* @param {string} serverData.bundleHash
|
|
706
|
+
* @param {string|null} serverData.cellSlug
|
|
707
|
+
* @param {string|null} serverData.status
|
|
708
|
+
* @param {string|null} serverData.createdAt
|
|
709
|
+
* @param {array} serverData.atoms - Array of server-format atom objects
|
|
710
|
+
* @return {Molecule}
|
|
711
|
+
*/
|
|
712
|
+
static fromServerData ({
|
|
713
|
+
molecularHash,
|
|
714
|
+
bundleHash,
|
|
715
|
+
cellSlug = null,
|
|
716
|
+
status = null,
|
|
717
|
+
createdAt = null,
|
|
718
|
+
atoms = []
|
|
719
|
+
}) {
|
|
720
|
+
const mappedAtoms = atoms.map(serverAtom => {
|
|
721
|
+
let meta = []
|
|
722
|
+
if (serverAtom.metasJson) {
|
|
723
|
+
try {
|
|
724
|
+
const parsed = JSON.parse(serverAtom.metasJson)
|
|
725
|
+
if (Array.isArray(parsed)) {
|
|
726
|
+
// Already in [{key, value}] format
|
|
727
|
+
meta = parsed
|
|
728
|
+
} else if (parsed && typeof parsed === 'object') {
|
|
729
|
+
// Object format {key1: val1, key2: val2} — convert to [{key, value}] pairs
|
|
730
|
+
meta = Object.entries(parsed).map(([key, value]) => ({ key, value }))
|
|
731
|
+
}
|
|
732
|
+
} catch (e) {
|
|
733
|
+
meta = []
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
return {
|
|
738
|
+
position: serverAtom.position || null,
|
|
739
|
+
walletAddress: serverAtom.walletAddress || null,
|
|
740
|
+
isotope: serverAtom.isotope || null,
|
|
741
|
+
token: serverAtom.tokenSlug || serverAtom.token || null,
|
|
742
|
+
value: serverAtom.value != null ? String(serverAtom.value) : null,
|
|
743
|
+
batchId: serverAtom.batchId || null,
|
|
744
|
+
metaType: serverAtom.metaType || null,
|
|
745
|
+
metaId: serverAtom.metaId || null,
|
|
746
|
+
meta,
|
|
747
|
+
index: serverAtom.index != null ? serverAtom.index : null,
|
|
748
|
+
otsFragment: serverAtom.otsFragment || null,
|
|
749
|
+
createdAt: serverAtom.createdAt || null
|
|
750
|
+
}
|
|
751
|
+
})
|
|
752
|
+
|
|
753
|
+
return Molecule.fromJSON({
|
|
754
|
+
molecularHash,
|
|
755
|
+
bundle: bundleHash,
|
|
756
|
+
cellSlug,
|
|
757
|
+
status,
|
|
758
|
+
createdAt,
|
|
759
|
+
atoms: mappedAtoms
|
|
760
|
+
})
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
/**
|
|
764
|
+
* Verifies a molecule reconstructed from server-side GraphQL data.
|
|
765
|
+
* Returns an object with verification result and any error details.
|
|
766
|
+
*
|
|
767
|
+
* @param {object} moleculeData - Server molecule data (same format as fromServerData)
|
|
768
|
+
* @return {{ molecularHash: string, verified: boolean, error: string|null }}
|
|
769
|
+
*/
|
|
770
|
+
static verifyFromServerData (moleculeData) {
|
|
771
|
+
try {
|
|
772
|
+
const molecule = CheckMolecule.fromServerData(moleculeData)
|
|
773
|
+
new CheckMolecule(molecule).verify()
|
|
774
|
+
return {
|
|
775
|
+
molecularHash: moleculeData.molecularHash,
|
|
776
|
+
verified: true,
|
|
777
|
+
error: null
|
|
778
|
+
}
|
|
779
|
+
} catch (error) {
|
|
780
|
+
return {
|
|
781
|
+
molecularHash: moleculeData.molecularHash || null,
|
|
782
|
+
verified: false,
|
|
783
|
+
error: error.message || String(error)
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
}
|
|
581
787
|
}
|
|
@@ -75,6 +75,14 @@ export default class QueryContinuId extends Query {
|
|
|
75
75
|
}`
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
+
/**
|
|
79
|
+
* Force network-only for ContinuID queries to prevent URQL cache from
|
|
80
|
+
* returning stale wallet positions after mutations advance the ContinuID chain
|
|
81
|
+
*/
|
|
82
|
+
createQueryContext () {
|
|
83
|
+
return { requestPolicy: 'network-only' }
|
|
84
|
+
}
|
|
85
|
+
|
|
78
86
|
/**
|
|
79
87
|
* Returns a Response object
|
|
80
88
|
*
|