@wishknish/knishio-client-ts 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/index.cjs +2670 -1039
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +336 -105
- package/dist/index.d.ts +336 -105
- package/dist/index.iife.js +22097 -20047
- package/dist/index.iife.js.map +1 -1
- package/dist/index.js +2667 -1040
- package/dist/index.js.map +1 -1
- package/package.json +10 -4
- package/src/AuthToken.ts +8 -2
- package/src/KnishIOClient.ts +306 -50
- package/src/constants.ts +5 -3
- package/src/core/Atom.ts +167 -100
- package/src/core/AtomMeta.ts +11 -28
- package/src/core/Meta.ts +18 -15
- package/src/core/Molecule.ts +582 -140
- package/src/core/Wallet.ts +19 -24
- package/src/index.ts +8 -0
- package/src/instance/rules/Rule.ts +128 -19
- package/src/libraries/CheckMolecule.ts +88 -1
- package/src/libraries/crypto.ts +14 -30
- package/src/libraries/strings.ts +26 -25
- package/src/mutation/MutationAppendRequest.ts +52 -0
- package/src/mutation/MutationCreateRule.ts +2 -2
- package/src/mutation/MutationPeering.ts +37 -0
- package/src/mutation/MutationRequestAuthorization.ts +3 -3
- package/src/query/QueryActiveSession.ts +0 -1
- package/src/query/QueryContinuId.ts +8 -0
- package/src/query/QueryMetaTypeViaMolecule.ts +221 -0
- package/src/query/QueryWalletList.ts +2 -2
- package/src/response/ResponseAppendRequest.ts +17 -0
- package/src/response/ResponseBalance.ts +8 -3
- package/src/response/ResponseContinuId.ts +1 -1
- package/src/response/ResponseMetaType.ts +32 -19
- package/src/response/ResponseMetaTypeViaMolecule.ts +224 -0
- package/src/response/ResponsePeering.ts +17 -0
- package/src/response/ResponsePolicy.ts +2 -3
- package/src/response/ResponseProposeMolecule.ts +0 -1
- package/src/response/ResponseRequestAuthorization.ts +32 -2
- package/src/response/ResponseRequestAuthorizationGuest.ts +25 -1
- package/src/response/ResponseWalletList.ts +1 -1
- package/src/types/guards.ts +18 -5
- package/src/types/index.ts +3 -3
package/src/core/Molecule.ts
CHANGED
|
@@ -49,9 +49,11 @@ License: https://github.com/WishKnish/KnishIO-Client-TS/blob/master/LICENSE
|
|
|
49
49
|
import Atom from './Atom'
|
|
50
50
|
import AtomMeta from './AtomMeta'
|
|
51
51
|
import Wallet from './Wallet'
|
|
52
|
+
import Rule from '@/instance/rules/Rule'
|
|
52
53
|
import CheckMolecule from '@/libraries/CheckMolecule'
|
|
53
54
|
import { chunkSubstr, hexToBase64 } from '@/libraries/strings'
|
|
54
|
-
import { generateBundleHash, generateOTSSignature } from '@/libraries/crypto'
|
|
55
|
+
import { generateBundleHash, generateBatchId, generateOTSSignature } from '@/libraries/crypto'
|
|
56
|
+
import versions from '@/versions'
|
|
55
57
|
import {
|
|
56
58
|
AtomsMissingException,
|
|
57
59
|
BalanceInsufficientException,
|
|
@@ -75,7 +77,8 @@ export default class Molecule {
|
|
|
75
77
|
public sourceWallet: Wallet | null
|
|
76
78
|
public remainderWallet: Wallet | null
|
|
77
79
|
public atoms: Atom[]
|
|
78
|
-
public version: string | null
|
|
80
|
+
public version: string | null | undefined
|
|
81
|
+
public parentHashes: string[]
|
|
79
82
|
public local?: number
|
|
80
83
|
|
|
81
84
|
/**
|
|
@@ -105,12 +108,15 @@ export default class Molecule {
|
|
|
105
108
|
this.bundle = bundle
|
|
106
109
|
this.sourceWallet = sourceWallet
|
|
107
110
|
this.atoms = []
|
|
108
|
-
|
|
109
|
-
|
|
111
|
+
this.parentHashes = []
|
|
112
|
+
|
|
113
|
+
const versionRegistry = versions as Record<string | number, any>
|
|
114
|
+
if (version !== null && Object.prototype.hasOwnProperty.call(versionRegistry, version)) {
|
|
110
115
|
this.version = String(version)
|
|
111
|
-
} else {
|
|
112
|
-
this.version = null
|
|
113
116
|
}
|
|
117
|
+
// Only set version if it's a recognized version in the registry (matching JS SDK).
|
|
118
|
+
// When version is not recognized, this.version stays undefined.
|
|
119
|
+
// JSON.stringify omits undefined properties, so the server won't see a version field.
|
|
114
120
|
|
|
115
121
|
// Set the remainder wallet for this transaction
|
|
116
122
|
if (remainderWallet || sourceWallet) {
|
|
@@ -149,7 +155,7 @@ export default class Molecule {
|
|
|
149
155
|
if (!Array.isArray(isotopes)) {
|
|
150
156
|
isotopes = [isotopes]
|
|
151
157
|
}
|
|
152
|
-
return atoms.filter(atom => isotopes.includes(atom.isotope))
|
|
158
|
+
return atoms.filter(atom => atom.isotope !== null && isotopes.includes(atom.isotope))
|
|
153
159
|
}
|
|
154
160
|
|
|
155
161
|
/**
|
|
@@ -176,7 +182,7 @@ export default class Molecule {
|
|
|
176
182
|
|
|
177
183
|
// Set atom's index
|
|
178
184
|
atom.index = this.generateIndex()
|
|
179
|
-
atom.version = this.version
|
|
185
|
+
atom.version = this.version ?? undefined
|
|
180
186
|
|
|
181
187
|
// Add atom
|
|
182
188
|
this.atoms.push(atom)
|
|
@@ -189,19 +195,74 @@ export default class Molecule {
|
|
|
189
195
|
|
|
190
196
|
/**
|
|
191
197
|
* Add user remainder atom for ContinuID
|
|
198
|
+
* Matches JavaScript SDK addContinuIdAtom exactly
|
|
192
199
|
*/
|
|
193
200
|
addContinuIdAtom(): Molecule {
|
|
194
|
-
|
|
195
|
-
|
|
201
|
+
// If remainder wallet is not USER token, create a new USER remainder wallet
|
|
202
|
+
if (!this.remainderWallet || this.remainderWallet.token !== 'USER') {
|
|
203
|
+
this.remainderWallet = Wallet.create({
|
|
204
|
+
secret: this.secret!,
|
|
205
|
+
bundle: this.bundle!
|
|
206
|
+
})
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// ContinuID metadata for chain integrity validation
|
|
210
|
+
const continuIdMeta: Record<string, any> = {}
|
|
211
|
+
|
|
212
|
+
// previousPosition: the source wallet's position being consumed
|
|
213
|
+
if (this.sourceWallet && this.sourceWallet.position) {
|
|
214
|
+
continuIdMeta.previousPosition = this.sourceWallet.position
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// pubkey: ML-KEM public key for encrypted communication
|
|
218
|
+
if (this.remainderWallet.pubkey) {
|
|
219
|
+
continuIdMeta.pubkey = this.remainderWallet.pubkey
|
|
196
220
|
}
|
|
197
221
|
|
|
198
|
-
|
|
222
|
+
// characters: encoding format for the wallet
|
|
223
|
+
if (this.remainderWallet.characters) {
|
|
224
|
+
continuIdMeta.characters = this.remainderWallet.characters
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
this.addAtom(Atom.create({
|
|
199
228
|
isotope: 'I',
|
|
200
|
-
|
|
201
|
-
walletAddress: this.remainderWallet.address! as any,
|
|
202
|
-
token: 'USER',
|
|
229
|
+
wallet: this.remainderWallet!,
|
|
203
230
|
metaType: 'walletBundle',
|
|
204
|
-
metaId: this.remainderWallet
|
|
231
|
+
metaId: this.remainderWallet!.bundle!,
|
|
232
|
+
meta: new AtomMeta(continuIdMeta)
|
|
233
|
+
}))
|
|
234
|
+
return this
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Add a policy R-isotope atom (matching JS SDK)
|
|
239
|
+
*/
|
|
240
|
+
addPolicyAtom({
|
|
241
|
+
metaType,
|
|
242
|
+
metaId,
|
|
243
|
+
meta = {},
|
|
244
|
+
policy = {}
|
|
245
|
+
}: {
|
|
246
|
+
metaType: string
|
|
247
|
+
metaId: string
|
|
248
|
+
meta?: any
|
|
249
|
+
policy?: Record<string, any>
|
|
250
|
+
}): Molecule {
|
|
251
|
+
const atomMeta = new AtomMeta(meta)
|
|
252
|
+
atomMeta.addPolicy(policy)
|
|
253
|
+
|
|
254
|
+
const wallet = Wallet.create({
|
|
255
|
+
secret: this.secret!,
|
|
256
|
+
bundle: this.sourceWallet!.bundle!,
|
|
257
|
+
token: 'USER'
|
|
258
|
+
})
|
|
259
|
+
|
|
260
|
+
this.addAtom(Atom.create({
|
|
261
|
+
wallet,
|
|
262
|
+
isotope: 'R',
|
|
263
|
+
metaType,
|
|
264
|
+
metaId,
|
|
265
|
+
meta: atomMeta
|
|
205
266
|
}))
|
|
206
267
|
return this
|
|
207
268
|
}
|
|
@@ -221,43 +282,31 @@ export default class Molecule {
|
|
|
221
282
|
throw new Error('Source wallet required for value transfer')
|
|
222
283
|
}
|
|
223
284
|
|
|
224
|
-
if (this.sourceWallet.balance - amount < 0) {
|
|
285
|
+
if (Number(this.sourceWallet.balance) - amount < 0) {
|
|
225
286
|
throw new BalanceInsufficientException()
|
|
226
287
|
}
|
|
227
288
|
|
|
228
|
-
// Initializing a new Atom to remove
|
|
229
|
-
this.addAtom(
|
|
289
|
+
// Initializing a new Atom to remove tokens from source (debit full balance)
|
|
290
|
+
this.addAtom(Atom.create({
|
|
230
291
|
isotope: 'V',
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
token: this.sourceWallet.token,
|
|
234
|
-
value: -this.sourceWallet.balance
|
|
292
|
+
wallet: this.sourceWallet,
|
|
293
|
+
value: -Number(this.sourceWallet.balance)
|
|
235
294
|
}))
|
|
236
|
-
|
|
237
295
|
// Initializing a new Atom to add tokens to recipient
|
|
238
|
-
this.addAtom(
|
|
296
|
+
this.addAtom(Atom.create({
|
|
239
297
|
isotope: 'V',
|
|
240
|
-
|
|
241
|
-
walletAddress: recipientWallet.address! as any,
|
|
242
|
-
token: recipientWallet.token,
|
|
298
|
+
wallet: recipientWallet,
|
|
243
299
|
value: amount,
|
|
244
300
|
metaType: 'walletBundle',
|
|
245
301
|
metaId: recipientWallet.bundle!
|
|
246
302
|
}))
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
if (!this.remainderWallet) {
|
|
250
|
-
throw new Error('Remainder wallet required for value transfer')
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
this.addAtom(new Atom({
|
|
303
|
+
// Initializing a remainder atom
|
|
304
|
+
this.addAtom(Atom.create({
|
|
254
305
|
isotope: 'V',
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
token: this.remainderWallet.token,
|
|
258
|
-
value: this.sourceWallet.balance - amount,
|
|
306
|
+
wallet: this.remainderWallet!,
|
|
307
|
+
value: Number(this.sourceWallet.balance) - amount,
|
|
259
308
|
metaType: 'walletBundle',
|
|
260
|
-
metaId: this.remainderWallet
|
|
309
|
+
metaId: this.remainderWallet!.bundle!
|
|
261
310
|
}))
|
|
262
311
|
|
|
263
312
|
return this
|
|
@@ -300,6 +349,21 @@ export default class Molecule {
|
|
|
300
349
|
// Set signing position from the first atom
|
|
301
350
|
let signingPosition = signingAtom.position
|
|
302
351
|
|
|
352
|
+
// Get signing wallet from first atom's metas (matching JS SDK exactly)
|
|
353
|
+
// This handles buffer withdraw reconciliation where a different wallet signs
|
|
354
|
+
const signingWalletMeta = signingAtom.aggregatedMeta ? signingAtom.aggregatedMeta() : null
|
|
355
|
+
const signingWalletJson = signingWalletMeta?.signingWallet as string | undefined
|
|
356
|
+
if (signingWalletJson) {
|
|
357
|
+
try {
|
|
358
|
+
const parsedSigningWallet = JSON.parse(signingWalletJson)
|
|
359
|
+
if (parsedSigningWallet.position) {
|
|
360
|
+
signingPosition = parsedSigningWallet.position
|
|
361
|
+
}
|
|
362
|
+
} catch {
|
|
363
|
+
// Invalid JSON in signingWallet meta, use default position
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
|
|
303
367
|
// Signing position is required
|
|
304
368
|
if (!signingPosition) {
|
|
305
369
|
throw new SignatureMalformedException('Signing wallet must have a position!')
|
|
@@ -448,7 +512,7 @@ export default class Molecule {
|
|
|
448
512
|
secureMode?: boolean
|
|
449
513
|
} = {}): any {
|
|
450
514
|
const {
|
|
451
|
-
includeValidationContext =
|
|
515
|
+
includeValidationContext = false,
|
|
452
516
|
includeOtsFragments = true,
|
|
453
517
|
secureMode = false
|
|
454
518
|
} = options
|
|
@@ -459,30 +523,37 @@ export default class Molecule {
|
|
|
459
523
|
throw new Error('Cannot serialize molecule with secret in secure mode')
|
|
460
524
|
}
|
|
461
525
|
|
|
462
|
-
// Core molecule properties (
|
|
526
|
+
// Core molecule properties (server-compatible fields only)
|
|
463
527
|
const serialized: any = {
|
|
464
528
|
status: this.status,
|
|
465
529
|
molecularHash: this.molecularHash,
|
|
466
530
|
createdAt: this.createdAt,
|
|
467
531
|
cellSlug: this.cellSlug,
|
|
468
|
-
cellSlugOrigin: this.cellSlugOrigin,
|
|
469
|
-
version: this.version,
|
|
470
532
|
bundle: this.bundle,
|
|
471
|
-
|
|
533
|
+
|
|
472
534
|
// Serialized atoms array with optional OTS fragments
|
|
473
|
-
atoms: this.atoms.map(atom => atom.toJSON({
|
|
474
|
-
includeOtsFragments
|
|
535
|
+
atoms: this.atoms.map(atom => atom.toJSON({
|
|
536
|
+
includeOtsFragments
|
|
475
537
|
}))
|
|
476
538
|
}
|
|
477
539
|
|
|
478
|
-
//
|
|
540
|
+
// Parent molecular hashes for DAG linkage (only include when non-empty
|
|
541
|
+
// to maintain backward compatibility with servers that don't support it)
|
|
542
|
+
if (this.parentHashes && this.parentHashes.length > 0) {
|
|
543
|
+
serialized.parentHashes = this.parentHashes
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
// Extended context for Rust validator and local validation
|
|
479
547
|
if (includeValidationContext) {
|
|
548
|
+
serialized.cellSlugOrigin = this.cellSlugOrigin
|
|
549
|
+
serialized.version = this.version
|
|
550
|
+
|
|
480
551
|
if (this.sourceWallet) {
|
|
481
552
|
serialized.sourceWallet = {
|
|
482
553
|
address: this.sourceWallet.address,
|
|
483
554
|
position: this.sourceWallet.position,
|
|
484
555
|
token: this.sourceWallet.token,
|
|
485
|
-
balance: this.sourceWallet.balance || 0,
|
|
556
|
+
balance: this.sourceWallet.balance || '0',
|
|
486
557
|
bundle: this.sourceWallet.bundle,
|
|
487
558
|
batchId: this.sourceWallet.batchId || null,
|
|
488
559
|
characters: this.sourceWallet.characters || 'BASE64',
|
|
@@ -499,7 +570,7 @@ export default class Molecule {
|
|
|
499
570
|
address: this.remainderWallet.address,
|
|
500
571
|
position: this.remainderWallet.position,
|
|
501
572
|
token: this.remainderWallet.token,
|
|
502
|
-
balance: this.remainderWallet.balance || 0,
|
|
573
|
+
balance: this.remainderWallet.balance || '0',
|
|
503
574
|
bundle: this.remainderWallet.bundle,
|
|
504
575
|
batchId: this.remainderWallet.batchId || null,
|
|
505
576
|
characters: this.remainderWallet.characters || 'BASE64',
|
|
@@ -532,6 +603,7 @@ export default class Molecule {
|
|
|
532
603
|
|
|
533
604
|
/**
|
|
534
605
|
* Initialize token creation
|
|
606
|
+
* Matches JavaScript SDK initTokenCreation implementation
|
|
535
607
|
*/
|
|
536
608
|
initTokenCreation({
|
|
537
609
|
recipientWallet,
|
|
@@ -542,32 +614,28 @@ export default class Molecule {
|
|
|
542
614
|
amount: number
|
|
543
615
|
meta: any
|
|
544
616
|
}): Molecule {
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
617
|
+
if (!this.sourceWallet) {
|
|
618
|
+
throw new Error('Source wallet required for token creation')
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
// Build meta using AtomMeta class (matching JavaScript SDK exactly)
|
|
622
|
+
const atomMeta = new AtomMeta(meta)
|
|
623
|
+
atomMeta.setMetaWallet(recipientWallet)
|
|
624
|
+
|
|
625
|
+
// The primary atom tells the ledger that a certain amount of the new token is being issued
|
|
626
|
+
this.addAtom(Atom.create({
|
|
627
|
+
isotope: 'C',
|
|
628
|
+
wallet: this.sourceWallet,
|
|
551
629
|
value: amount,
|
|
552
630
|
metaType: 'token',
|
|
553
631
|
metaId: recipientWallet.token,
|
|
554
|
-
meta:
|
|
632
|
+
meta: atomMeta,
|
|
633
|
+
batchId: recipientWallet.batchId
|
|
555
634
|
}))
|
|
556
|
-
|
|
557
|
-
// Add wallet bundle metadata
|
|
558
|
-
this.addAtom(new Atom({
|
|
559
|
-
isotope: 'M',
|
|
560
|
-
position: recipientWallet.position!,
|
|
561
|
-
walletAddress: recipientWallet.address! as any,
|
|
562
|
-
token: recipientWallet.token,
|
|
563
|
-
metaType: 'walletBundle',
|
|
564
|
-
metaId: recipientWallet.bundle!,
|
|
565
|
-
meta: meta ? [{ key: 'tokenMeta', value: JSON.stringify(meta) }] : []
|
|
566
|
-
}))
|
|
567
|
-
|
|
635
|
+
|
|
568
636
|
// Add ContinuID atom (matching JavaScript SDK)
|
|
569
637
|
this.addContinuIdAtom()
|
|
570
|
-
|
|
638
|
+
|
|
571
639
|
return this
|
|
572
640
|
}
|
|
573
641
|
|
|
@@ -576,7 +644,7 @@ export default class Molecule {
|
|
|
576
644
|
*/
|
|
577
645
|
burnToken({
|
|
578
646
|
amount,
|
|
579
|
-
walletBundle = null
|
|
647
|
+
walletBundle: _walletBundle = null
|
|
580
648
|
}: {
|
|
581
649
|
amount: number
|
|
582
650
|
walletBundle?: string | null
|
|
@@ -585,25 +653,52 @@ export default class Molecule {
|
|
|
585
653
|
throw new Error('Source wallet required for token burning')
|
|
586
654
|
}
|
|
587
655
|
|
|
588
|
-
if (amount
|
|
589
|
-
throw new NegativeAmountException()
|
|
656
|
+
if (amount < 0) {
|
|
657
|
+
throw new NegativeAmountException('Molecule::burnToken() - Amount to burn must be positive!')
|
|
590
658
|
}
|
|
591
|
-
|
|
592
|
-
if (this.sourceWallet.balance - amount < 0) {
|
|
659
|
+
|
|
660
|
+
if (Number(this.sourceWallet.balance) - amount < 0) {
|
|
593
661
|
throw new BalanceInsufficientException()
|
|
594
662
|
}
|
|
595
|
-
|
|
596
|
-
// Burn tokens by removing from source
|
|
597
|
-
this.addAtom(
|
|
663
|
+
|
|
664
|
+
// Burn tokens by removing from source (matching JS SDK)
|
|
665
|
+
this.addAtom(Atom.create({
|
|
598
666
|
isotope: 'V',
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
token: this.sourceWallet.token,
|
|
602
|
-
value: -amount,
|
|
603
|
-
metaType: walletBundle ? 'walletBundle' : null,
|
|
604
|
-
metaId: walletBundle || null
|
|
667
|
+
wallet: this.sourceWallet,
|
|
668
|
+
value: -amount
|
|
605
669
|
}))
|
|
606
|
-
|
|
670
|
+
// Remainder atom (matching JS SDK)
|
|
671
|
+
this.addAtom(Atom.create({
|
|
672
|
+
isotope: 'V',
|
|
673
|
+
wallet: this.remainderWallet!,
|
|
674
|
+
value: Number(this.sourceWallet.balance) - amount,
|
|
675
|
+
metaType: 'walletBundle',
|
|
676
|
+
metaId: this.remainderWallet!.bundle!
|
|
677
|
+
}))
|
|
678
|
+
|
|
679
|
+
return this
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
/**
|
|
683
|
+
* Initialize authorization request
|
|
684
|
+
* Creates U-isotope (authorization) atom for requesting auth token
|
|
685
|
+
* Matches JavaScript SDK Molecule.initAuthorization
|
|
686
|
+
*/
|
|
687
|
+
initAuthorization({ meta }: { meta: Record<string, any> }): Molecule {
|
|
688
|
+
if (!this.sourceWallet) {
|
|
689
|
+
throw new Error('Source wallet required for authorization')
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
// Create U-isotope atom for authorization (matching JS SDK)
|
|
693
|
+
this.addAtom(Atom.create({
|
|
694
|
+
isotope: 'U',
|
|
695
|
+
wallet: this.sourceWallet,
|
|
696
|
+
meta: new AtomMeta(meta)
|
|
697
|
+
}))
|
|
698
|
+
|
|
699
|
+
// Add ContinuID atom (matching JavaScript SDK)
|
|
700
|
+
this.addContinuIdAtom()
|
|
701
|
+
|
|
607
702
|
return this
|
|
608
703
|
}
|
|
609
704
|
|
|
@@ -625,78 +720,171 @@ export default class Molecule {
|
|
|
625
720
|
throw new Error('Source wallet required for meta creation')
|
|
626
721
|
}
|
|
627
722
|
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
// Convert meta to array format
|
|
631
|
-
if (meta) {
|
|
632
|
-
if (Array.isArray(meta)) {
|
|
633
|
-
metaArray.push(...meta)
|
|
634
|
-
} else if (typeof meta === 'object') {
|
|
635
|
-
for (const [key, value] of Object.entries(meta)) {
|
|
636
|
-
metaArray.push({ key, value })
|
|
637
|
-
}
|
|
638
|
-
} else {
|
|
639
|
-
metaArray.push({ key: 'value', value: meta })
|
|
640
|
-
}
|
|
641
|
-
}
|
|
642
|
-
|
|
643
|
-
// Add policy if provided
|
|
644
|
-
if (policy) {
|
|
645
|
-
metaArray.push({ key: 'policy', value: JSON.stringify(policy) })
|
|
646
|
-
}
|
|
647
|
-
|
|
648
|
-
// Create meta atom
|
|
649
|
-
this.addAtom(new Atom({
|
|
723
|
+
// Initializing a new Atom to hold our metadata (matching JS SDK)
|
|
724
|
+
this.addAtom(Atom.create({
|
|
650
725
|
isotope: 'M',
|
|
651
|
-
|
|
652
|
-
walletAddress: this.sourceWallet.address! as any,
|
|
653
|
-
token: this.sourceWallet.token,
|
|
726
|
+
wallet: this.sourceWallet,
|
|
654
727
|
metaType,
|
|
655
728
|
metaId,
|
|
656
|
-
meta:
|
|
729
|
+
meta: new AtomMeta(meta)
|
|
657
730
|
}))
|
|
658
|
-
|
|
659
|
-
//
|
|
731
|
+
|
|
732
|
+
// Only add policy atom if policy is provided and not empty
|
|
733
|
+
if (policy && Object.keys(policy).length > 0) {
|
|
734
|
+
this.addPolicyAtom({
|
|
735
|
+
metaType,
|
|
736
|
+
metaId,
|
|
737
|
+
meta,
|
|
738
|
+
policy
|
|
739
|
+
})
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
// User remainder atom
|
|
660
743
|
this.addContinuIdAtom()
|
|
661
|
-
|
|
744
|
+
|
|
662
745
|
return this
|
|
663
746
|
}
|
|
664
747
|
|
|
665
748
|
/**
|
|
666
749
|
* Initialize wallet creation
|
|
750
|
+
* Uses source wallet for atom properties (matching JavaScript SDK)
|
|
751
|
+
* The wallet being created is stored in metadata
|
|
667
752
|
*/
|
|
668
753
|
initWalletCreation(wallet: Wallet, atomMeta: AtomMeta | null = null): Molecule {
|
|
669
|
-
|
|
670
|
-
|
|
754
|
+
if (!this.sourceWallet) {
|
|
755
|
+
throw new Error('Source wallet required for wallet creation')
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
// Matching JS SDK: use AtomMeta.setMetaWallet() for wallet metadata
|
|
759
|
+
if (!atomMeta) {
|
|
760
|
+
atomMeta = new AtomMeta()
|
|
761
|
+
}
|
|
762
|
+
atomMeta.setMetaWallet(wallet)
|
|
763
|
+
|
|
764
|
+
const creationAtom = Atom.create({
|
|
671
765
|
isotope: 'C',
|
|
672
|
-
|
|
673
|
-
walletAddress: wallet.address! as any,
|
|
674
|
-
token: wallet.token,
|
|
766
|
+
wallet: this.sourceWallet,
|
|
675
767
|
metaType: 'wallet',
|
|
676
768
|
metaId: wallet.address!,
|
|
677
|
-
meta: atomMeta
|
|
769
|
+
meta: atomMeta,
|
|
770
|
+
batchId: wallet.batchId
|
|
678
771
|
})
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
772
|
+
this.addAtom(creationAtom)
|
|
773
|
+
this.addContinuIdAtom()
|
|
774
|
+
|
|
775
|
+
return this
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
/**
|
|
779
|
+
* Creates atoms for rule definition
|
|
780
|
+
* Matches JavaScript SDK Molecule.createRule method
|
|
781
|
+
*
|
|
782
|
+
* @param metaType - The meta type for the rule
|
|
783
|
+
* @param metaId - The meta ID for the rule
|
|
784
|
+
* @param rule - Array of Rule objects or rule data
|
|
785
|
+
* @param policy - Optional policy object
|
|
786
|
+
* @return This molecule instance for chaining
|
|
787
|
+
*/
|
|
788
|
+
createRule({
|
|
789
|
+
metaType,
|
|
790
|
+
metaId,
|
|
791
|
+
rule,
|
|
792
|
+
policy = {}
|
|
793
|
+
}: {
|
|
794
|
+
metaType: string
|
|
795
|
+
metaId: string
|
|
796
|
+
rule: Rule[] | any[] | any // Accept single object or array
|
|
797
|
+
policy?: Record<string, any>
|
|
798
|
+
}): Molecule {
|
|
799
|
+
if (!this.sourceWallet) {
|
|
800
|
+
throw new Error('Source wallet required for createRule')
|
|
693
801
|
}
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
802
|
+
|
|
803
|
+
// Normalize rule to array (accept single object or array)
|
|
804
|
+
const ruleArray = Array.isArray(rule) ? rule : [rule]
|
|
805
|
+
|
|
806
|
+
// Convert rules to objects (matching JavaScript SDK)
|
|
807
|
+
const rules: Record<string, any>[] = []
|
|
808
|
+
for (const r of ruleArray) {
|
|
809
|
+
rules.push(r instanceof Rule ? r : Rule.toObject(r))
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
// Create atom meta with rules
|
|
813
|
+
const atomMeta = new AtomMeta({
|
|
814
|
+
rule: JSON.stringify(rules)
|
|
815
|
+
})
|
|
816
|
+
|
|
817
|
+
// Add policies to meta object only if policy exists and has keys (matching JS SDK)
|
|
818
|
+
if (policy && Object.keys(policy).length > 0) {
|
|
819
|
+
atomMeta.addPolicy(policy)
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
// Create R-isotope atom for rule (matching JS SDK)
|
|
823
|
+
this.addAtom(Atom.create({
|
|
824
|
+
isotope: 'R',
|
|
825
|
+
wallet: this.sourceWallet,
|
|
826
|
+
metaType,
|
|
827
|
+
metaId,
|
|
828
|
+
meta: atomMeta
|
|
829
|
+
}))
|
|
830
|
+
|
|
831
|
+
// Add ContinuID atom
|
|
698
832
|
this.addContinuIdAtom()
|
|
699
|
-
|
|
833
|
+
|
|
834
|
+
return this
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
/**
|
|
838
|
+
* Initializes a token request molecule
|
|
839
|
+
* Matches JavaScript SDK Molecule.initTokenRequest method
|
|
840
|
+
*
|
|
841
|
+
* @param token - Token slug to request
|
|
842
|
+
* @param amount - Amount of tokens to request
|
|
843
|
+
* @param metaType - Meta type (typically 'walletBundle')
|
|
844
|
+
* @param metaId - Meta ID (typically recipient bundle hash)
|
|
845
|
+
* @param meta - Optional additional metadata
|
|
846
|
+
* @param batchId - Optional batch ID
|
|
847
|
+
* @return This molecule instance for chaining
|
|
848
|
+
*/
|
|
849
|
+
initTokenRequest({
|
|
850
|
+
token,
|
|
851
|
+
amount,
|
|
852
|
+
metaType,
|
|
853
|
+
metaId,
|
|
854
|
+
meta = {},
|
|
855
|
+
batchId = null
|
|
856
|
+
}: {
|
|
857
|
+
token: string
|
|
858
|
+
amount: number
|
|
859
|
+
metaType: string
|
|
860
|
+
metaId: string
|
|
861
|
+
meta?: Record<string, any>
|
|
862
|
+
batchId?: string | null
|
|
863
|
+
}): Molecule {
|
|
864
|
+
if (!this.sourceWallet) {
|
|
865
|
+
throw new Error('Source wallet required for initTokenRequest')
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
// Add token and amount to meta (matching JavaScript SDK exactly)
|
|
869
|
+
const metaWithToken = { ...meta, token, amount: String(amount) }
|
|
870
|
+
|
|
871
|
+
// Mark as local molecule
|
|
872
|
+
this.local = 1
|
|
873
|
+
|
|
874
|
+
// Create T-isotope atom for token request (matching JS SDK)
|
|
875
|
+
this.addAtom(Atom.create({
|
|
876
|
+
isotope: 'T',
|
|
877
|
+
wallet: this.sourceWallet,
|
|
878
|
+
value: amount,
|
|
879
|
+
metaType,
|
|
880
|
+
metaId,
|
|
881
|
+
meta: new AtomMeta(metaWithToken),
|
|
882
|
+
batchId
|
|
883
|
+
}))
|
|
884
|
+
|
|
885
|
+
// Add ContinuID atom
|
|
886
|
+
this.addContinuIdAtom()
|
|
887
|
+
|
|
700
888
|
return this
|
|
701
889
|
}
|
|
702
890
|
|
|
@@ -761,6 +949,9 @@ export default class Molecule {
|
|
|
761
949
|
})
|
|
762
950
|
}
|
|
763
951
|
|
|
952
|
+
// Reconstruct parent hashes for DAG linkage
|
|
953
|
+
molecule.parentHashes = Array.isArray(data.parentHashes) ? [...data.parentHashes] : []
|
|
954
|
+
|
|
764
955
|
// Reconstruct validation context if available and requested
|
|
765
956
|
if (includeValidationContext) {
|
|
766
957
|
if (data.sourceWallet) {
|
|
@@ -775,7 +966,7 @@ export default class Molecule {
|
|
|
775
966
|
})
|
|
776
967
|
|
|
777
968
|
// Set additional properties for validation context
|
|
778
|
-
molecule.sourceWallet.balance = data.sourceWallet.balance
|
|
969
|
+
molecule.sourceWallet.balance = String(data.sourceWallet.balance != null ? data.sourceWallet.balance : 0)
|
|
779
970
|
molecule.sourceWallet.address = data.sourceWallet.address as any
|
|
780
971
|
if (data.sourceWallet.pubkey) {
|
|
781
972
|
molecule.sourceWallet.pubkey = data.sourceWallet.pubkey
|
|
@@ -797,7 +988,7 @@ export default class Molecule {
|
|
|
797
988
|
})
|
|
798
989
|
|
|
799
990
|
// Set additional properties for validation context
|
|
800
|
-
molecule.remainderWallet.balance = data.remainderWallet.balance
|
|
991
|
+
molecule.remainderWallet.balance = String(data.remainderWallet.balance != null ? data.remainderWallet.balance : 0)
|
|
801
992
|
molecule.remainderWallet.address = data.remainderWallet.address as any
|
|
802
993
|
if (data.remainderWallet.pubkey) {
|
|
803
994
|
molecule.remainderWallet.pubkey = data.remainderWallet.pubkey
|
|
@@ -821,4 +1012,255 @@ export default class Molecule {
|
|
|
821
1012
|
static jsonToObject(json: string): Molecule {
|
|
822
1013
|
return Molecule.fromJSON(json)
|
|
823
1014
|
}
|
|
1015
|
+
|
|
1016
|
+
// =============================================================================
|
|
1017
|
+
// ISOTOPE INIT METHODS - MATCHING JAVASCRIPT SDK PARITY
|
|
1018
|
+
// =============================================================================
|
|
1019
|
+
|
|
1020
|
+
/**
|
|
1021
|
+
* Initialize a P-type molecule for peer registration
|
|
1022
|
+
* Matches JavaScript SDK Molecule.initPeering implementation exactly
|
|
1023
|
+
*
|
|
1024
|
+
* @param host - The peer host URL to register
|
|
1025
|
+
* @return This molecule instance for chaining
|
|
1026
|
+
*/
|
|
1027
|
+
initPeering({ host }: { host: string }): Molecule {
|
|
1028
|
+
if (!this.sourceWallet) {
|
|
1029
|
+
throw new Error('Source wallet required for peer registration')
|
|
1030
|
+
}
|
|
1031
|
+
|
|
1032
|
+
this.addAtom(Atom.create({
|
|
1033
|
+
isotope: 'P',
|
|
1034
|
+
wallet: this.sourceWallet,
|
|
1035
|
+
metaType: 'walletBundle',
|
|
1036
|
+
metaId: this.bundle!,
|
|
1037
|
+
meta: new AtomMeta({ peerHost: host })
|
|
1038
|
+
}))
|
|
1039
|
+
|
|
1040
|
+
this.addContinuIdAtom()
|
|
1041
|
+
|
|
1042
|
+
return this
|
|
1043
|
+
}
|
|
1044
|
+
|
|
1045
|
+
/**
|
|
1046
|
+
* Initialize an A-type molecule for an append request
|
|
1047
|
+
* Matches JavaScript SDK Molecule.initAppendRequest implementation exactly
|
|
1048
|
+
*
|
|
1049
|
+
* @param metaType - The target MetaType to append to
|
|
1050
|
+
* @param metaId - The target MetaId to append to
|
|
1051
|
+
* @param action - The action to perform
|
|
1052
|
+
* @param meta - Additional metadata
|
|
1053
|
+
* @return This molecule instance for chaining
|
|
1054
|
+
*/
|
|
1055
|
+
initAppendRequest({
|
|
1056
|
+
metaType,
|
|
1057
|
+
metaId,
|
|
1058
|
+
action,
|
|
1059
|
+
meta = {}
|
|
1060
|
+
}: {
|
|
1061
|
+
metaType: string
|
|
1062
|
+
metaId: string
|
|
1063
|
+
action: string
|
|
1064
|
+
meta?: Record<string, any>
|
|
1065
|
+
}): Molecule {
|
|
1066
|
+
if (!this.sourceWallet) {
|
|
1067
|
+
throw new Error('Source wallet required for append request')
|
|
1068
|
+
}
|
|
1069
|
+
|
|
1070
|
+
this.addAtom(Atom.create({
|
|
1071
|
+
isotope: 'A',
|
|
1072
|
+
wallet: this.sourceWallet,
|
|
1073
|
+
metaType,
|
|
1074
|
+
metaId,
|
|
1075
|
+
meta: new AtomMeta({ action, ...meta })
|
|
1076
|
+
}))
|
|
1077
|
+
|
|
1078
|
+
this.addContinuIdAtom()
|
|
1079
|
+
|
|
1080
|
+
return this
|
|
1081
|
+
}
|
|
1082
|
+
|
|
1083
|
+
/**
|
|
1084
|
+
* Initialize a deposit buffer operation (B-isotope)
|
|
1085
|
+
* Matches JavaScript SDK Molecule.initDepositBuffer implementation exactly
|
|
1086
|
+
*
|
|
1087
|
+
* @param amount - Amount to deposit into buffer
|
|
1088
|
+
* @param tradeRates - Trade rates for the buffer wallet
|
|
1089
|
+
* @return This molecule instance for chaining
|
|
1090
|
+
*/
|
|
1091
|
+
initDepositBuffer({
|
|
1092
|
+
amount,
|
|
1093
|
+
tradeRates
|
|
1094
|
+
}: {
|
|
1095
|
+
amount: number
|
|
1096
|
+
tradeRates?: Record<string, any>
|
|
1097
|
+
}): Molecule {
|
|
1098
|
+
if (!this.sourceWallet) {
|
|
1099
|
+
throw new Error('Source wallet required for buffer deposit')
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1102
|
+
if (Number(this.sourceWallet.balance) - amount < 0) {
|
|
1103
|
+
throw new BalanceInsufficientException()
|
|
1104
|
+
}
|
|
1105
|
+
|
|
1106
|
+
// Create a buffer wallet
|
|
1107
|
+
const bufferWallet = Wallet.create({
|
|
1108
|
+
secret: this.secret!,
|
|
1109
|
+
bundle: this.bundle,
|
|
1110
|
+
token: this.sourceWallet.token,
|
|
1111
|
+
batchId: this.sourceWallet.batchId
|
|
1112
|
+
})
|
|
1113
|
+
if (tradeRates) {
|
|
1114
|
+
bufferWallet.tradeRates = tradeRates
|
|
1115
|
+
}
|
|
1116
|
+
|
|
1117
|
+
// Debit full balance from source (V-isotope)
|
|
1118
|
+
this.addAtom(Atom.create({
|
|
1119
|
+
isotope: 'V',
|
|
1120
|
+
wallet: this.sourceWallet,
|
|
1121
|
+
value: -Number(this.sourceWallet.balance)
|
|
1122
|
+
}))
|
|
1123
|
+
|
|
1124
|
+
// Deposit amount to buffer (B-isotope)
|
|
1125
|
+
this.addAtom(Atom.create({
|
|
1126
|
+
isotope: 'B',
|
|
1127
|
+
wallet: bufferWallet,
|
|
1128
|
+
value: amount,
|
|
1129
|
+
metaType: 'walletBundle',
|
|
1130
|
+
metaId: this.sourceWallet.bundle!
|
|
1131
|
+
}))
|
|
1132
|
+
|
|
1133
|
+
// Remainder back to source
|
|
1134
|
+
this.addAtom(Atom.create({
|
|
1135
|
+
isotope: 'V',
|
|
1136
|
+
wallet: this.remainderWallet!,
|
|
1137
|
+
value: Number(this.sourceWallet.balance) - amount,
|
|
1138
|
+
metaType: 'walletBundle',
|
|
1139
|
+
metaId: this.sourceWallet.bundle!
|
|
1140
|
+
}))
|
|
1141
|
+
|
|
1142
|
+
return this
|
|
1143
|
+
}
|
|
1144
|
+
|
|
1145
|
+
/**
|
|
1146
|
+
* Initialize a withdraw buffer operation (B-isotope)
|
|
1147
|
+
* Matches JavaScript SDK Molecule.initWithdrawBuffer implementation exactly
|
|
1148
|
+
*
|
|
1149
|
+
* @param recipients - Map of recipientBundle → amount
|
|
1150
|
+
* @param signingWallet - Optional signing wallet for reconciliation
|
|
1151
|
+
* @return This molecule instance for chaining
|
|
1152
|
+
*/
|
|
1153
|
+
initWithdrawBuffer({
|
|
1154
|
+
recipients,
|
|
1155
|
+
signingWallet = null
|
|
1156
|
+
}: {
|
|
1157
|
+
recipients: Record<string, number>
|
|
1158
|
+
signingWallet?: any | null
|
|
1159
|
+
}): Molecule {
|
|
1160
|
+
if (!this.sourceWallet) {
|
|
1161
|
+
throw new Error('Source wallet required for buffer withdrawal')
|
|
1162
|
+
}
|
|
1163
|
+
|
|
1164
|
+
// Calculate total from all recipients
|
|
1165
|
+
let amount = 0
|
|
1166
|
+
for (const recipientAmount of Object.values(recipients || {})) {
|
|
1167
|
+
amount += recipientAmount
|
|
1168
|
+
}
|
|
1169
|
+
|
|
1170
|
+
if (Number(this.sourceWallet.balance) - amount < 0) {
|
|
1171
|
+
throw new BalanceInsufficientException()
|
|
1172
|
+
}
|
|
1173
|
+
|
|
1174
|
+
// Set a meta signing position for molecule correct reconciliation
|
|
1175
|
+
const firstAtomMeta = new AtomMeta()
|
|
1176
|
+
if (signingWallet) {
|
|
1177
|
+
firstAtomMeta.setSigningWallet(signingWallet)
|
|
1178
|
+
}
|
|
1179
|
+
|
|
1180
|
+
// Debit full balance from source (B-isotope)
|
|
1181
|
+
this.addAtom(Atom.create({
|
|
1182
|
+
isotope: 'B',
|
|
1183
|
+
wallet: this.sourceWallet,
|
|
1184
|
+
value: -Number(this.sourceWallet.balance),
|
|
1185
|
+
meta: firstAtomMeta,
|
|
1186
|
+
metaType: 'walletBundle',
|
|
1187
|
+
metaId: this.sourceWallet.bundle!
|
|
1188
|
+
}))
|
|
1189
|
+
|
|
1190
|
+
// Add recipient V-atoms (matching JS SDK: uses `new Atom()` with explicit token)
|
|
1191
|
+
for (const [recipientBundle, recipientAmount] of Object.entries(recipients || {})) {
|
|
1192
|
+
this.addAtom(new Atom({
|
|
1193
|
+
isotope: 'V',
|
|
1194
|
+
token: this.sourceWallet.token,
|
|
1195
|
+
value: recipientAmount as number,
|
|
1196
|
+
batchId: this.sourceWallet.batchId ? generateBatchId({}) : null,
|
|
1197
|
+
metaType: 'walletBundle',
|
|
1198
|
+
metaId: recipientBundle
|
|
1199
|
+
}))
|
|
1200
|
+
}
|
|
1201
|
+
|
|
1202
|
+
// Remainder back to buffer
|
|
1203
|
+
this.addAtom(Atom.create({
|
|
1204
|
+
isotope: 'B',
|
|
1205
|
+
wallet: this.remainderWallet!,
|
|
1206
|
+
value: Number(this.sourceWallet.balance) - amount,
|
|
1207
|
+
metaType: 'walletBundle',
|
|
1208
|
+
metaId: this.remainderWallet!.bundle!
|
|
1209
|
+
}))
|
|
1210
|
+
|
|
1211
|
+
return this
|
|
1212
|
+
}
|
|
1213
|
+
|
|
1214
|
+
/**
|
|
1215
|
+
* Initialize shadow wallet claim
|
|
1216
|
+
* Matches JavaScript SDK Molecule.initShadowWalletClaim implementation exactly
|
|
1217
|
+
*
|
|
1218
|
+
* @param wallet - The shadow wallet to claim
|
|
1219
|
+
* @return This molecule instance for chaining
|
|
1220
|
+
*/
|
|
1221
|
+
initShadowWalletClaim(wallet: Wallet): Molecule {
|
|
1222
|
+
const atomMeta = new AtomMeta()
|
|
1223
|
+
atomMeta.setShadowWalletClaim(true)
|
|
1224
|
+
return this.initWalletCreation(wallet, atomMeta)
|
|
1225
|
+
}
|
|
1226
|
+
|
|
1227
|
+
/**
|
|
1228
|
+
* Initialize identifier creation
|
|
1229
|
+
* Matches JavaScript SDK Molecule.initIdentifierCreation implementation exactly
|
|
1230
|
+
*
|
|
1231
|
+
* @param type - Identifier type (phone or email)
|
|
1232
|
+
* @param contact - Phone number or email string
|
|
1233
|
+
* @param code - Verification code
|
|
1234
|
+
* @return This molecule instance for chaining
|
|
1235
|
+
*/
|
|
1236
|
+
initIdentifierCreation({
|
|
1237
|
+
type,
|
|
1238
|
+
contact,
|
|
1239
|
+
code
|
|
1240
|
+
}: {
|
|
1241
|
+
type: string
|
|
1242
|
+
contact: string
|
|
1243
|
+
code: string
|
|
1244
|
+
}): Molecule {
|
|
1245
|
+
if (!this.sourceWallet) {
|
|
1246
|
+
throw new Error('Source wallet required for identifier creation')
|
|
1247
|
+
}
|
|
1248
|
+
|
|
1249
|
+
const meta = {
|
|
1250
|
+
code,
|
|
1251
|
+
hash: generateBundleHash(contact.trim(), 'Molecule::initIdentifierCreation')
|
|
1252
|
+
}
|
|
1253
|
+
|
|
1254
|
+
this.addAtom(Atom.create({
|
|
1255
|
+
isotope: 'C',
|
|
1256
|
+
wallet: this.sourceWallet,
|
|
1257
|
+
metaType: 'identifier',
|
|
1258
|
+
metaId: type,
|
|
1259
|
+
meta: new AtomMeta(meta)
|
|
1260
|
+
}))
|
|
1261
|
+
|
|
1262
|
+
this.addContinuIdAtom()
|
|
1263
|
+
|
|
1264
|
+
return this
|
|
1265
|
+
}
|
|
824
1266
|
}
|