@neuraiproject/neurai-assets 1.2.0 → 1.2.2

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.
@@ -4172,7 +4172,7 @@ var NeuraiAssetsBundle = (function (exports) {
4172
4172
  addresses === undefined
4173
4173
  ) {
4174
4174
  network = networkOrParams.network;
4175
- actualAddresses = networkOrParams.addresses;
4175
+ actualAddresses = networkOrParams.walletAddresses || networkOrParams.addresses;
4176
4176
  actualParams = networkOrParams;
4177
4177
  } else {
4178
4178
  network = networkOrParams;
@@ -4376,23 +4376,163 @@ var NeuraiAssetsBundle = (function (exports) {
4376
4376
  }
4377
4377
 
4378
4378
  /**
4379
- * Convert amount to satoshis
4380
- * @param {number} amount - Amount in asset units
4381
- * @param {number} units - Decimal places
4382
- * @returns {number} Amount in satoshis
4379
+ * Convert asset amount to protocol raw units.
4380
+ * Asset raw quantities in transaction payloads are always encoded with
4381
+ * 8 decimal places, regardless of the asset's displayed `units`.
4382
+ *
4383
+ * @param {number} amount - User-facing asset amount
4384
+ * @param {number} units - Asset decimal places (kept for API compatibility)
4385
+ * @returns {number} Amount in protocol raw units
4383
4386
  */
4384
4387
  toSatoshis(amount, units) {
4385
- return Math.round(amount * Math.pow(10, units));
4388
+ return Math.round(amount * 100000000);
4386
4389
  }
4387
4390
 
4388
4391
  /**
4389
- * Convert satoshis to amount
4390
- * @param {number} satoshis - Amount in satoshis
4391
- * @param {number} units - Decimal places
4392
+ * Convert protocol raw units back to a user-facing asset amount.
4393
+ *
4394
+ * @param {number} satoshis - Amount in protocol raw units
4395
+ * @param {number} units - Asset decimal places (kept for API compatibility)
4392
4396
  * @returns {number} Amount in asset units
4393
4397
  */
4394
4398
  fromSatoshis(satoshis, units) {
4395
- return satoshis / Math.pow(10, units);
4399
+ return satoshis / 100000000;
4400
+ }
4401
+
4402
+ /**
4403
+ * Normalize builder inputs to raw transaction inputs
4404
+ * @param {Array} inputs - Builder inputs
4405
+ * @returns {Array<{txid: string, vout: number}>} Raw transaction inputs
4406
+ */
4407
+ toRawTxInputs(inputs) {
4408
+ return (inputs || []).map(input => ({
4409
+ txid: input.txid,
4410
+ vout: input.vout !== undefined ? input.vout : input.outputIndex
4411
+ }));
4412
+ }
4413
+
4414
+ /**
4415
+ * Convert XNA amount to satoshis
4416
+ * @param {number|null|undefined} amount - Amount in XNA
4417
+ * @returns {number|undefined} Amount in satoshis
4418
+ */
4419
+ xnaToSatoshis(amount) {
4420
+ if (amount === undefined || amount === null) {
4421
+ return undefined;
4422
+ }
4423
+
4424
+ return Math.round(amount * 100000000);
4425
+ }
4426
+
4427
+ /**
4428
+ * Build a typed local raw build payload compatible with
4429
+ * @neuraiproject/neurai-create-transaction createFromOperation(...)
4430
+ *
4431
+ * @param {string} operationType - Operation type
4432
+ * @param {Array} inputs - Builder inputs
4433
+ * @param {object|null} burnInfo - Burn metadata
4434
+ * @param {string|null} changeAddress - XNA change address
4435
+ * @param {number|null} changeAmount - XNA change amount in XNA
4436
+ * @param {object} operationParams - Operation-specific params
4437
+ * @returns {{ operationType: string, params: object }} Local raw build
4438
+ */
4439
+ buildLocalRawBuild(
4440
+ operationType,
4441
+ inputs,
4442
+ burnInfo = null,
4443
+ changeAddress = null,
4444
+ changeAmount = null,
4445
+ operationParams = {}
4446
+ ) {
4447
+ const params = {
4448
+ inputs: this.toRawTxInputs(inputs),
4449
+ ...operationParams
4450
+ };
4451
+
4452
+ if (burnInfo && burnInfo.address && burnInfo.amount !== undefined && burnInfo.amount !== null) {
4453
+ params.burnAddress = burnInfo.address;
4454
+ params.burnAmountSats = this.xnaToSatoshis(burnInfo.amount);
4455
+ }
4456
+
4457
+ if (changeAddress && changeAmount !== undefined && changeAmount !== null) {
4458
+ params.xnaChangeAddress = changeAddress;
4459
+ params.xnaChangeSats = this.xnaToSatoshis(changeAmount);
4460
+ }
4461
+
4462
+ return {
4463
+ operationType,
4464
+ params
4465
+ };
4466
+ }
4467
+
4468
+ /**
4469
+ * Normalize ordered outputs into flat entries
4470
+ * @param {Array|object} outputs - Transaction outputs
4471
+ * @returns {Array<{address: string, value: unknown}>} Output entries
4472
+ */
4473
+ getOutputEntries(outputs) {
4474
+ if (Array.isArray(outputs)) {
4475
+ return outputs.map(output => {
4476
+ const [address, value] = Object.entries(output)[0];
4477
+ return { address, value };
4478
+ });
4479
+ }
4480
+
4481
+ if (outputs && typeof outputs === 'object') {
4482
+ return Object.entries(outputs).map(([address, value]) => ({ address, value }));
4483
+ }
4484
+
4485
+ return [];
4486
+ }
4487
+
4488
+ /**
4489
+ * Extract burn metadata from outputs
4490
+ * @param {Array<{address: string, value: unknown}>} entries - Output entries
4491
+ * @param {number} burnAmount - Burn amount in XNA
4492
+ * @returns {{ burnAddress: string|null, burnAmount: number }}
4493
+ */
4494
+ extractBurnMetadata(entries, burnAmount) {
4495
+ if (!burnAmount || burnAmount <= 0) {
4496
+ return {
4497
+ burnAddress: null,
4498
+ burnAmount: 0
4499
+ };
4500
+ }
4501
+
4502
+ const burnEntry = entries.find(({ address, value }) => {
4503
+ return typeof value === 'number' &&
4504
+ value === burnAmount &&
4505
+ this.burnManager.isBurnAddress(address);
4506
+ });
4507
+
4508
+ return {
4509
+ burnAddress: burnEntry ? burnEntry.address : null,
4510
+ burnAmount
4511
+ };
4512
+ }
4513
+
4514
+ /**
4515
+ * Extract XNA change metadata from outputs
4516
+ * @param {Array<{address: string, value: unknown}>} entries - Output entries
4517
+ * @param {string|null} burnAddress - Burn address if present
4518
+ * @returns {{ changeAddress: string|null, changeAmount: number|null }}
4519
+ */
4520
+ extractChangeMetadata(entries, burnAddress = null) {
4521
+ const xnaOutputs = entries.filter(({ address, value }) => {
4522
+ return typeof value === 'number' && address !== burnAddress;
4523
+ });
4524
+
4525
+ if (xnaOutputs.length !== 1) {
4526
+ return {
4527
+ changeAddress: null,
4528
+ changeAmount: null
4529
+ };
4530
+ }
4531
+
4532
+ return {
4533
+ changeAddress: xnaOutputs[0].address,
4534
+ changeAmount: xnaOutputs[0].value
4535
+ };
4396
4536
  }
4397
4537
 
4398
4538
  /**
@@ -4407,13 +4547,26 @@ var NeuraiAssetsBundle = (function (exports) {
4407
4547
  * @returns {object} Formatted result
4408
4548
  */
4409
4549
  formatResult(rawTx, utxos, inputs, outputs, fee, burnAmount, extra = {}) {
4550
+ const outputEntries = this.getOutputEntries(outputs);
4551
+ const burnMetadata = this.extractBurnMetadata(outputEntries, burnAmount);
4552
+ const changeMetadata = this.extractChangeMetadata(outputEntries, burnMetadata.burnAddress);
4553
+
4410
4554
  return {
4411
4555
  rawTx,
4412
4556
  utxos,
4413
4557
  inputs,
4414
4558
  outputs,
4415
4559
  fee,
4416
- burnAmount,
4560
+ burnAmount: burnMetadata.burnAmount,
4561
+ network: this.network,
4562
+ buildStrategy: 'rpc-node',
4563
+ burnAddress: burnMetadata.burnAddress,
4564
+ changeAddress: extra.changeAddress !== undefined
4565
+ ? extra.changeAddress
4566
+ : changeMetadata.changeAddress,
4567
+ changeAmount: extra.changeAmount !== undefined
4568
+ ? extra.changeAmount
4569
+ : changeMetadata.changeAmount,
4417
4570
  ...extra
4418
4571
  };
4419
4572
  }
@@ -4630,7 +4783,23 @@ var NeuraiAssetsBundle = (function (exports) {
4630
4783
  {
4631
4784
  assetName,
4632
4785
  ownerTokenName: assetName + '!',
4633
- operationType: 'ISSUE_ROOT'
4786
+ operationType: 'ISSUE_ROOT',
4787
+ localRawBuild: this.buildLocalRawBuild(
4788
+ 'ISSUE_ROOT',
4789
+ inputs,
4790
+ burnInfo,
4791
+ changeAddress,
4792
+ xnaChange > 0.00000001 ? parseFloat(xnaChange.toFixed(8)) : null,
4793
+ {
4794
+ toAddress,
4795
+ assetName,
4796
+ quantityRaw: this.toSatoshis(quantity, units),
4797
+ units,
4798
+ reissuable,
4799
+ ipfsHash: hasIpfs ? ipfsHash : undefined,
4800
+ ownerTokenAddress: changeAddress
4801
+ }
4802
+ )
4634
4803
  }
4635
4804
  );
4636
4805
  }
@@ -4876,7 +5045,23 @@ var NeuraiAssetsBundle = (function (exports) {
4876
5045
  parentAssetName,
4877
5046
  ownerTokenName: assetName + '!',
4878
5047
  parentOwnerTokenUsed: ownerTokenName,
4879
- operationType: 'ISSUE_SUB'
5048
+ operationType: 'ISSUE_SUB',
5049
+ localRawBuild: this.buildLocalRawBuild(
5050
+ 'ISSUE_SUB',
5051
+ inputs,
5052
+ burnInfo,
5053
+ changeAddress,
5054
+ xnaChange > 0.00000001 ? parseFloat(xnaChange.toFixed(8)) : null,
5055
+ {
5056
+ toAddress,
5057
+ assetName,
5058
+ quantityRaw: this.toSatoshis(quantity, units),
5059
+ units,
5060
+ reissuable,
5061
+ ipfsHash: hasIpfs ? ipfsHash : undefined,
5062
+ parentOwnerAddress: changeAddress
5063
+ }
5064
+ )
4880
5065
  }
4881
5066
  );
4882
5067
  }
@@ -5029,7 +5214,22 @@ var NeuraiAssetsBundle = (function (exports) {
5029
5214
  {
5030
5215
  assetName,
5031
5216
  ownerTokenName: `${assetName}!`,
5032
- operationType: 'ISSUE_DEPIN'
5217
+ operationType: 'ISSUE_DEPIN',
5218
+ localRawBuild: this.buildLocalRawBuild(
5219
+ 'ISSUE_DEPIN',
5220
+ inputs,
5221
+ burnInfo,
5222
+ changeAddress,
5223
+ xnaChange > 0.00000001 ? parseFloat(xnaChange.toFixed(8)) : null,
5224
+ {
5225
+ toAddress,
5226
+ assetName,
5227
+ quantityRaw: this.toSatoshis(quantity, 0),
5228
+ ipfsHash: hasIpfs ? ipfsHash : undefined,
5229
+ ownerTokenAddress: changeAddress,
5230
+ reissuable
5231
+ }
5232
+ )
5033
5233
  }
5034
5234
  );
5035
5235
  }
@@ -5277,7 +5477,23 @@ var NeuraiAssetsBundle = (function (exports) {
5277
5477
  newTotalSupply,
5278
5478
  previousSupply: currentSupply,
5279
5479
  reissuableLocked: reissuable === false,
5280
- operationType: 'REISSUE'
5480
+ operationType: 'REISSUE',
5481
+ localRawBuild: this.buildLocalRawBuild(
5482
+ 'REISSUE',
5483
+ inputs,
5484
+ burnInfo,
5485
+ changeAddress,
5486
+ xnaChange > 0.00000001 ? parseFloat(xnaChange.toFixed(8)) : null,
5487
+ {
5488
+ toAddress,
5489
+ assetName,
5490
+ quantityRaw: this.toSatoshis(quantity, units),
5491
+ units,
5492
+ reissuable: reissuable !== undefined ? reissuable : undefined,
5493
+ ipfsHash: newIpfs || undefined,
5494
+ ownerChangeAddress: isDepinAsset ? toAddress : changeAddress
5495
+ }
5496
+ )
5281
5497
  }
5282
5498
  );
5283
5499
  }
@@ -5534,7 +5750,21 @@ var NeuraiAssetsBundle = (function (exports) {
5534
5750
  createdNFTs,
5535
5751
  nftCount,
5536
5752
  ownerTokenUsed: ownerTokenName,
5537
- operationType: 'ISSUE_UNIQUE'
5753
+ operationType: 'ISSUE_UNIQUE',
5754
+ localRawBuild: this.buildLocalRawBuild(
5755
+ 'ISSUE_UNIQUE',
5756
+ inputs,
5757
+ burnInfo,
5758
+ changeAddress,
5759
+ xnaChange > 0.00000001 ? parseFloat(xnaChange.toFixed(8)) : null,
5760
+ {
5761
+ toAddress,
5762
+ rootName,
5763
+ assetTags,
5764
+ ipfsHashes: ipfsHashes.length > 0 ? ipfsHashes : undefined,
5765
+ ownerTokenAddress: changeAddress
5766
+ }
5767
+ )
5538
5768
  }
5539
5769
  );
5540
5770
  }
@@ -5749,11 +5979,13 @@ var NeuraiAssetsBundle = (function (exports) {
5749
5979
  // Last: Issue qualifier operation
5750
5980
  const issueQualifierOutput = OutputFormatter.formatIssueQualifierOutput({
5751
5981
  asset_name: assetName,
5752
- asset_quantity: quantity,
5982
+ asset_quantity: this.toSatoshis(quantity, 0),
5753
5983
  has_ipfs: hasIpfs,
5754
5984
  ipfs_hash: ipfsHash,
5755
5985
  root_change_address: isSub ? changeAddress : undefined,
5756
- change_quantity: isSub ? parentQualifierQuantity : undefined
5986
+ change_quantity: isSub && parentQualifierQuantity !== null
5987
+ ? this.toSatoshis(parentQualifierQuantity, 0)
5988
+ : undefined
5757
5989
  });
5758
5990
 
5759
5991
  outputs.push({ [toAddress]: issueQualifierOutput });
@@ -5779,7 +6011,24 @@ var NeuraiAssetsBundle = (function (exports) {
5779
6011
  qualifierType: isSub ? 'SUB_QUALIFIER' : 'QUALIFIER',
5780
6012
  parentQualifier: isSub ? parsed.parent : null,
5781
6013
  parentQualifierUsed: parentQualifierName,
5782
- operationType: isSub ? 'ISSUE_SUB_QUALIFIER' : 'ISSUE_QUALIFIER'
6014
+ operationType: isSub ? 'ISSUE_SUB_QUALIFIER' : 'ISSUE_QUALIFIER',
6015
+ localRawBuild: this.buildLocalRawBuild(
6016
+ isSub ? 'ISSUE_SUB_QUALIFIER' : 'ISSUE_QUALIFIER',
6017
+ inputs,
6018
+ burnInfo,
6019
+ changeAddress,
6020
+ xnaChange > 0.00000001 ? parseFloat(xnaChange.toFixed(8)) : null,
6021
+ {
6022
+ toAddress,
6023
+ assetName,
6024
+ quantityRaw: this.toSatoshis(quantity, 0),
6025
+ ipfsHash: hasIpfs ? ipfsHash : undefined,
6026
+ rootChangeAddress: isSub ? changeAddress : undefined,
6027
+ changeQuantityRaw: isSub && parentQualifierQuantity !== null
6028
+ ? this.toSatoshis(parentQualifierQuantity, 0)
6029
+ : undefined
6030
+ }
6031
+ )
5783
6032
  }
5784
6033
  );
5785
6034
  }
@@ -6009,7 +6258,24 @@ var NeuraiAssetsBundle = (function (exports) {
6009
6258
  ownerTokenName,
6010
6259
  verifierString,
6011
6260
  requiredQualifiers,
6012
- operationType: 'ISSUE_RESTRICTED'
6261
+ operationType: 'ISSUE_RESTRICTED',
6262
+ localRawBuild: this.buildLocalRawBuild(
6263
+ 'ISSUE_RESTRICTED',
6264
+ inputs,
6265
+ burnInfo,
6266
+ changeAddress,
6267
+ xnaChange > 0.00000001 ? parseFloat(xnaChange.toFixed(8)) : null,
6268
+ {
6269
+ toAddress,
6270
+ assetName,
6271
+ quantityRaw: this.toSatoshis(quantity, units),
6272
+ verifierString,
6273
+ units,
6274
+ reissuable,
6275
+ ipfsHash: hasIpfs ? ipfsHash : undefined,
6276
+ ownerChangeAddress: changeAddress
6277
+ }
6278
+ )
6013
6279
  }
6014
6280
  );
6015
6281
  }
@@ -6272,7 +6538,24 @@ var NeuraiAssetsBundle = (function (exports) {
6272
6538
  newVerifier: changeVerifier ? newVerifier : undefined,
6273
6539
  requiredQualifiers,
6274
6540
  reissuableLocked: reissuable === false,
6275
- operationType: 'REISSUE_RESTRICTED'
6541
+ operationType: 'REISSUE_RESTRICTED',
6542
+ localRawBuild: this.buildLocalRawBuild(
6543
+ 'REISSUE_RESTRICTED',
6544
+ inputs,
6545
+ burnInfo,
6546
+ changeAddress,
6547
+ xnaChange > 0.00000001 ? parseFloat(xnaChange.toFixed(8)) : null,
6548
+ {
6549
+ toAddress,
6550
+ assetName,
6551
+ quantityRaw: this.toSatoshis(quantity, assetData.units || 0),
6552
+ units: assetData.units || 0,
6553
+ reissuable: reissuable !== undefined ? reissuable : undefined,
6554
+ ipfsHash: newIpfs || undefined,
6555
+ ownerChangeAddress: this.params.ownerChangeAddress || changeAddress,
6556
+ verifierString: changeVerifier ? newVerifier : undefined
6557
+ }
6558
+ )
6276
6559
  }
6277
6560
  );
6278
6561
  }
@@ -6464,12 +6747,12 @@ var NeuraiAssetsBundle = (function (exports) {
6464
6747
  ? OutputFormatter.formatUntagAddressesOutput({
6465
6748
  qualifier: qualifierName,
6466
6749
  addresses: targetAddresses,
6467
- change_quantity: qualifierQuantity
6750
+ change_quantity: this.toSatoshis(qualifierQuantity, 0)
6468
6751
  })
6469
6752
  : OutputFormatter.formatTagAddressesOutput({
6470
6753
  qualifier: qualifierName,
6471
6754
  addresses: targetAddresses,
6472
- change_quantity: qualifierQuantity
6755
+ change_quantity: this.toSatoshis(qualifierQuantity, 0)
6473
6756
  });
6474
6757
 
6475
6758
  outputs.push({ [changeAddress]: operationOutput });
@@ -6495,7 +6778,20 @@ var NeuraiAssetsBundle = (function (exports) {
6495
6778
  qualifierAssetUsed: qualifierName,
6496
6779
  targetAddresses,
6497
6780
  addressCount,
6498
- operationType: isUntag ? 'UNTAG_ADDRESSES' : 'TAG_ADDRESSES'
6781
+ operationType: isUntag ? 'UNTAG_ADDRESSES' : 'TAG_ADDRESSES',
6782
+ localRawBuild: this.buildLocalRawBuild(
6783
+ isUntag ? 'UNTAG_ADDRESSES' : 'TAG_ADDRESSES',
6784
+ inputs,
6785
+ burnInfo,
6786
+ changeAddress,
6787
+ xnaChange > 0.00000001 ? parseFloat(xnaChange.toFixed(8)) : null,
6788
+ {
6789
+ qualifierName,
6790
+ targetAddresses,
6791
+ qualifierChangeAddress: changeAddress,
6792
+ qualifierChangeAmountRaw: this.toSatoshis(qualifierQuantity, 0)
6793
+ }
6794
+ )
6499
6795
  }
6500
6796
  );
6501
6797
  }
@@ -6742,7 +7038,24 @@ var NeuraiAssetsBundle = (function (exports) {
6742
7038
  ownerTokenUsed: ownerTokenName,
6743
7039
  targetAddresses: targetAddresses.length > 0 ? targetAddresses : null,
6744
7040
  addressCount: targetAddresses.length,
6745
- operationType
7041
+ operationType,
7042
+ localRawBuild: this.buildLocalRawBuild(
7043
+ operationType,
7044
+ inputs,
7045
+ null,
7046
+ xnaChange > 0.00000001 ? changeAddress : null,
7047
+ xnaChange > 0.00000001 ? parseFloat(xnaChange.toFixed(8)) : null,
7048
+ operationType === 'FREEZE_ADDRESSES' || operationType === 'UNFREEZE_ADDRESSES'
7049
+ ? {
7050
+ assetName,
7051
+ targetAddresses,
7052
+ ownerChangeAddress: changeAddress
7053
+ }
7054
+ : {
7055
+ assetName,
7056
+ ownerChangeAddress: changeAddress
7057
+ }
7058
+ )
6746
7059
  }
6747
7060
  );
6748
7061
  }
@@ -6919,7 +7232,7 @@ var NeuraiAssetsBundle = (function (exports) {
6919
7232
  return {
6920
7233
  ...params,
6921
7234
  network: this.config.network,
6922
- addresses: this.config.addresses,
7235
+ walletAddresses: this.config.addresses,
6923
7236
  changeAddress: params.changeAddress || this.config.changeAddress,
6924
7237
  toAddress: params.toAddress || this.config.toAddress
6925
7238
  };