@neuraiproject/neurai-assets 1.5.0 → 1.5.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.
- package/README.md +20 -6
- package/dist/NeuraiAssets.global.js +76 -19
- package/dist/NeuraiAssets.global.js.map +1 -1
- package/dist/browser.js +76 -19
- package/dist/browser.js.map +1 -1
- package/dist/index.cjs +76 -19
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +76 -19
- package/dist/index.js.map +1 -1
- package/index.d.ts +11 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -613,12 +613,26 @@ rejects with `unit must be larger than current unit selection`.
|
|
|
613
613
|
The value read from the chain is still used, to check that the requested
|
|
614
614
|
`quantity` fits the asset's precision.
|
|
615
615
|
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
object has no field for units
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
616
|
+
### Reissue is built locally
|
|
617
|
+
|
|
618
|
+
`createrawtransaction`'s `reissue` object has no field for units, so the node
|
|
619
|
+
fills in `0` and refuses any asset whose units are above zero
|
|
620
|
+
(`unit must be larger than current unit selection`). Since 1.5.0 the two
|
|
621
|
+
reissue operations therefore skip that RPC and build their `rawTx` with
|
|
622
|
+
`createFromOperation`, which can say "keep the current units". They report
|
|
623
|
+
`buildStrategy: 'local-builder'`; every other operation still reports
|
|
624
|
+
`'rpc-node'`.
|
|
625
|
+
|
|
626
|
+
This is why `@neuraiproject/neurai-create-transaction` is a runtime
|
|
627
|
+
**dependency**, not just a dev one.
|
|
628
|
+
|
|
629
|
+
One consequence to know about: on the local path `result.outputs` and `rawTx`
|
|
630
|
+
describe the same operation but not the same output list. The node
|
|
631
|
+
auto-generates the owner-token return while processing a reissue entry, so the
|
|
632
|
+
RPC envelope omits it, while the locally built transaction carries it
|
|
633
|
+
explicitly — three entries in `outputs` against four vouts in `rawTx`. Both are
|
|
634
|
+
valid; parse `rawTx` when you need the outputs the chain will see, and do not
|
|
635
|
+
index `outputs` against its vouts.
|
|
622
636
|
|
|
623
637
|
## Owner Tokens - IMPORTANT
|
|
624
638
|
|
|
@@ -6020,7 +6020,12 @@ var NeuraiAssetsBundle = (function (exports) {
|
|
|
6020
6020
|
return 0;
|
|
6021
6021
|
}
|
|
6022
6022
|
|
|
6023
|
-
|
|
6023
|
+
// One byte per character, matching how the payload encodes the name
|
|
6024
|
+
// (`serializeString` -> `asciiBytes`, which writes a single byte per char).
|
|
6025
|
+
// Node's byte-length helper would be equivalent here, but it hangs off a
|
|
6026
|
+
// global that browsers do not have: using it broke the extension bundle with
|
|
6027
|
+
// "Buffer is not defined", and this library does much of its work there.
|
|
6028
|
+
const nameLength = String(descriptor.assetName).length;
|
|
6024
6029
|
const kind = descriptor.kind || 'transfer';
|
|
6025
6030
|
|
|
6026
6031
|
// marker(3) + type(1) + CompactSize name length(1) + name
|
|
@@ -6304,11 +6309,14 @@ var NeuraiAssetsBundle = (function (exports) {
|
|
|
6304
6309
|
* @throws {InsufficientFundsError} If not enough funds
|
|
6305
6310
|
*/
|
|
6306
6311
|
async selectBaseCurrencyUTXOs(addresses, requiredAmount, buffer = 0.1, options = {}) {
|
|
6307
|
-
//
|
|
6308
|
-
|
|
6309
|
-
|
|
6310
|
-
//
|
|
6311
|
-
const mempool = await
|
|
6312
|
+
// Both reads describe the same addresses and neither feeds the other: the
|
|
6313
|
+
// mempool result only filters the UTXO result afterwards. Awaiting them in
|
|
6314
|
+
// sequence spent one extra network round trip per selection, which on a
|
|
6315
|
+
// remote RPC proxy is most of the time a wallet spends building anything.
|
|
6316
|
+
const [allUTXOs, mempool] = await Promise.all([
|
|
6317
|
+
this.getUTXOs(addresses, null),
|
|
6318
|
+
this.getMempoolEntries(addresses)
|
|
6319
|
+
]);
|
|
6312
6320
|
const unspentUTXOs = this.filterMempoolSpentUTXOs(allUTXOs, mempool);
|
|
6313
6321
|
|
|
6314
6322
|
// Drop outpoints the caller already spends elsewhere in this transaction
|
|
@@ -6374,11 +6382,14 @@ var NeuraiAssetsBundle = (function (exports) {
|
|
|
6374
6382
|
throw new Error('Asset name is required');
|
|
6375
6383
|
}
|
|
6376
6384
|
|
|
6377
|
-
//
|
|
6378
|
-
|
|
6379
|
-
|
|
6380
|
-
//
|
|
6381
|
-
const mempool = await
|
|
6385
|
+
// Both reads describe the same addresses and neither feeds the other: the
|
|
6386
|
+
// mempool result only filters the UTXO result afterwards. Awaiting them in
|
|
6387
|
+
// sequence spent one extra network round trip per selection, which on a
|
|
6388
|
+
// remote RPC proxy is most of the time a wallet spends building anything.
|
|
6389
|
+
const [allUTXOs, mempool] = await Promise.all([
|
|
6390
|
+
this.getUTXOs(addresses, assetName),
|
|
6391
|
+
this.getMempoolEntries(addresses)
|
|
6392
|
+
]);
|
|
6382
6393
|
const unspentUTXOs = this.filterMempoolSpentUTXOs(allUTXOs, mempool);
|
|
6383
6394
|
|
|
6384
6395
|
const excluded = toOutpointSet(options.exclude);
|
|
@@ -6500,8 +6511,10 @@ var NeuraiAssetsBundle = (function (exports) {
|
|
|
6500
6511
|
* @returns {Promise<bigint>} Total balance in 10^8-scaled units
|
|
6501
6512
|
*/
|
|
6502
6513
|
async getBalanceRaw(addresses, assetName = null) {
|
|
6503
|
-
const utxos = await
|
|
6504
|
-
|
|
6514
|
+
const [utxos, mempool] = await Promise.all([
|
|
6515
|
+
this.getUTXOs(addresses, assetName),
|
|
6516
|
+
this.getMempoolEntries(addresses)
|
|
6517
|
+
]);
|
|
6505
6518
|
const availableUTXOs = this.filterMempoolSpentUTXOs(utxos, mempool);
|
|
6506
6519
|
|
|
6507
6520
|
return sumProtocolIntegers(availableUTXOs, 'satoshis', `${assetName || 'XNA'} utxo.satoshis`);
|
|
@@ -7989,6 +8002,44 @@ var NeuraiAssetsBundle = (function (exports) {
|
|
|
7989
8002
|
throw new Error('build must be implemented by subclass');
|
|
7990
8003
|
}
|
|
7991
8004
|
|
|
8005
|
+
/**
|
|
8006
|
+
* Start the fee-rate lookup without waiting for it.
|
|
8007
|
+
*
|
|
8008
|
+
* Every build needs the fee rate, and it depends on nothing the build
|
|
8009
|
+
* computes, so there is no reason for it to wait its turn behind the reads
|
|
8010
|
+
* that come first. Kicking it off early lets it share a round trip with
|
|
8011
|
+
* them; `estimateFee`/`estimateFeeSats` await the same memoised promise, so
|
|
8012
|
+
* the call still happens exactly once and a failure still surfaces there.
|
|
8013
|
+
*
|
|
8014
|
+
* The trailing `catch` only marks the promise as handled while nothing is
|
|
8015
|
+
* awaiting it — it attaches to a derived promise, so the original still
|
|
8016
|
+
* rejects for whoever awaits it later.
|
|
8017
|
+
*
|
|
8018
|
+
* @returns {void}
|
|
8019
|
+
*/
|
|
8020
|
+
warmFeeRate() {
|
|
8021
|
+
if (this._feeRatePromise) {
|
|
8022
|
+
return;
|
|
8023
|
+
}
|
|
8024
|
+
this._feeRatePromise = this.utxoSelector.getFeeRate();
|
|
8025
|
+
this._feeRatePromise.catch(() => {});
|
|
8026
|
+
}
|
|
8027
|
+
|
|
8028
|
+
/**
|
|
8029
|
+
* Start every read a build needs but that depends on nothing the build
|
|
8030
|
+
* computes: the fee rate and the NIP-040 asset marker.
|
|
8031
|
+
*
|
|
8032
|
+
* Both are memoised, so warming them costs no extra call — it only moves
|
|
8033
|
+
* them off the critical path. Every builder that reaches here goes on to
|
|
8034
|
+
* stamp a marker, so neither read is ever speculative.
|
|
8035
|
+
*
|
|
8036
|
+
* @returns {void}
|
|
8037
|
+
*/
|
|
8038
|
+
warmChainReads() {
|
|
8039
|
+
this.warmFeeRate();
|
|
8040
|
+
this.resolveAssetMarker().catch(() => {});
|
|
8041
|
+
}
|
|
8042
|
+
|
|
7992
8043
|
/**
|
|
7993
8044
|
* Estimate transaction fee.
|
|
7994
8045
|
*
|
|
@@ -8002,9 +8053,7 @@ var NeuraiAssetsBundle = (function (exports) {
|
|
|
8002
8053
|
* @returns {Promise<number>} Estimated fee in XNA
|
|
8003
8054
|
*/
|
|
8004
8055
|
async estimateFee(inputs, outputs) {
|
|
8005
|
-
|
|
8006
|
-
this._feeRatePromise = this.utxoSelector.getFeeRate();
|
|
8007
|
-
}
|
|
8056
|
+
this.warmFeeRate();
|
|
8008
8057
|
const feeRate = await this._feeRatePromise;
|
|
8009
8058
|
return this.utxoSelector.estimateFee(inputs, outputs, feeRate);
|
|
8010
8059
|
}
|
|
@@ -8035,9 +8084,7 @@ var NeuraiAssetsBundle = (function (exports) {
|
|
|
8035
8084
|
* @returns {Promise<bigint>} Estimated fee in satoshis
|
|
8036
8085
|
*/
|
|
8037
8086
|
async estimateFeeSats(inputs, outputs) {
|
|
8038
|
-
|
|
8039
|
-
this._feeRatePromise = this.utxoSelector.getFeeRate();
|
|
8040
|
-
}
|
|
8087
|
+
this.warmFeeRate();
|
|
8041
8088
|
const feeRate = await this._feeRatePromise;
|
|
8042
8089
|
return this.utxoSelector.estimateFeeSats(inputs, outputs, feeRate);
|
|
8043
8090
|
}
|
|
@@ -8080,6 +8127,10 @@ var NeuraiAssetsBundle = (function (exports) {
|
|
|
8080
8127
|
initialInputHint = 1
|
|
8081
8128
|
} = options;
|
|
8082
8129
|
|
|
8130
|
+
// Covers the builders that never call assetExists, whose first read is
|
|
8131
|
+
// this one.
|
|
8132
|
+
this.warmChainReads();
|
|
8133
|
+
|
|
8083
8134
|
const addresses = await this._getAddresses();
|
|
8084
8135
|
const excluded = UTXOSelector.toOutpointSet(exclude);
|
|
8085
8136
|
// toOutpointSet returns the caller's Set untouched when it already is one;
|
|
@@ -8709,6 +8760,9 @@ var NeuraiAssetsBundle = (function (exports) {
|
|
|
8709
8760
|
* @returns {Promise<boolean>} True if exists
|
|
8710
8761
|
*/
|
|
8711
8762
|
async assetExists(assetName) {
|
|
8763
|
+
// This is the first read a build performs and its answer gates nothing but
|
|
8764
|
+
// the guard below, so let the build's other chain reads travel alongside it.
|
|
8765
|
+
this.warmChainReads();
|
|
8712
8766
|
try {
|
|
8713
8767
|
const assetData = await this.rpc('getassetdata', [assetName]);
|
|
8714
8768
|
return assetData !== null && assetData !== undefined;
|
|
@@ -8728,6 +8782,9 @@ var NeuraiAssetsBundle = (function (exports) {
|
|
|
8728
8782
|
* @returns {Promise<object|null>} Asset data or null if not found
|
|
8729
8783
|
*/
|
|
8730
8784
|
async getAssetData(assetName) {
|
|
8785
|
+
// This is the first read a build performs and its answer gates nothing but
|
|
8786
|
+
// the guard below, so let the build's other chain reads travel alongside it.
|
|
8787
|
+
this.warmChainReads();
|
|
8731
8788
|
try {
|
|
8732
8789
|
return await this.rpc('getassetdata', [assetName]);
|
|
8733
8790
|
} catch (error) {
|