nexa-wallet-sdk 0.4.2 → 0.5.1
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 +633 -126
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +151 -14
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +637 -130
- package/dist/index.mjs.map +1 -1
- package/dist/index.web.mjs +637 -130
- package/dist/index.web.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -149,7 +149,7 @@ $parcel$export(module.exports, "SighashType", () => $l50U0$libnexats.SighashType
|
|
|
149
149
|
$parcel$export(module.exports, "AccountKeysUtils", () => $4d68f29c39c1a3e4$export$94f569bf4eb0f6f6);
|
|
150
150
|
// @ts-ignore
|
|
151
151
|
var $2dd241e44b9dc3c2$exports = {};
|
|
152
|
-
$2dd241e44b9dc3c2$exports = JSON.parse("{\"name\":\"nexa-wallet-sdk\",\"version\":\"0.
|
|
152
|
+
$2dd241e44b9dc3c2$exports = JSON.parse("{\"name\":\"nexa-wallet-sdk\",\"version\":\"0.5.1\",\"type\":\"module\",\"source\":\"src/index.ts\",\"types\":\"dist/index.d.ts\",\"main\":\"dist/index.cjs\",\"module\":\"dist/index.mjs\",\"browser\":\"dist/index.web.mjs\",\"exports\":{\"types\":\"./dist/index.d.ts\",\"node\":{\"import\":\"./dist/index.mjs\",\"require\":\"./dist/index.cjs\"},\"browser\":\"./dist/index.web.mjs\",\"default\":\"./dist/index.mjs\"},\"scripts\":{\"build\":\"parcel build\",\"lint\":\"eslint .\",\"fix-lint\":\"eslint --fix .\",\"dev\":\"parcel watch\",\"test\":\"vitest run\",\"clean\":\"rm -rf dist .parcel-cache\",\"docs\":\"typedoc\",\"docs:serve\":\"typedoc && npx serve docs -l 8080\",\"docs:mkdocs\":\"typedoc && mkdocs serve\",\"docs:build\":\"typedoc && mkdocs build\",\"docs:setup\":\"./scripts/setup-docs.sh\",\"wallet-cli\":\"node examples/wallet-cli.cjs\"},\"repository\":{\"type\":\"git\",\"url\":\"git+ssh://git@gitlab.com/nexa/wallet-sdk-ts.git\"},\"keywords\":[\"nexa\",\"wallet\",\"web3\",\"crypto\",\"dapp\",\"walletcomms\",\"walletsdk\"],\"contributors\":[{\"name\":\"Dolaned\"},{\"name\":\"Griffith\"},{\"name\":\"Vgrunner\"},{\"name\":\"myendy\"}],\"author\":\"Dolaned\",\"license\":\"MIT\",\"bugs\":{\"url\":\"https://gitlab.com/nexa/wallet-sdk-ts/issues\"},\"homepage\":\"https://gitlab.com/nexa/wallet-sdk-ts#readme\",\"description\":\"Wallet SDK for the Nexa blockchain\",\"devDependencies\":{\"@parcel/packager-ts\":\"^2.15.4\",\"@parcel/transformer-typescript-types\":\"^2.15.4\",\"@types/lodash-es\":\"^4.17.12\",\"@types/node\":\"^22.13.1\",\"eslint\":\"^9.20.1\",\"parcel\":\"^2.15.4\",\"typedoc\":\"^0.28.7\",\"typedoc-plugin-markdown\":\"^4.7.0\",\"typedoc-plugin-rename-defaults\":\"^0.7.3\",\"typescript\":\"^5.8.3\",\"typescript-eslint\":\"^8.24.1\",\"vitest\":\"^3.0.8\"},\"targets\":{\"main\":{\"context\":\"node\",\"outputFormat\":\"commonjs\",\"distDir\":\"dist\",\"isLibrary\":true,\"includeNodeModules\":[\"lodash-es\"]},\"module\":{\"context\":\"node\",\"outputFormat\":\"esmodule\",\"distDir\":\"dist\",\"isLibrary\":true},\"browser\":{\"context\":\"browser\",\"outputFormat\":\"esmodule\",\"distDir\":\"dist\",\"isLibrary\":true}},\"dependencies\":{\"@vgrunner/electrum-cash\":\"^2.0.12\",\"bip39\":\"^3.1.0\",\"js-big-decimal\":\"^2.2.0\",\"libnexa-ts\":\"^1.0.5\",\"lodash-es\":\"^4.17.21\",\"prompt-sync\":\"^4.2.0\",\"wallet-comms-sdk\":\"^0.6.1\"},\"files\":[\"dist\"],\"directories\":{\"test\":\"tests\"},\"@parcel/resolver-default\":{\"packageExports\":true}}");
|
|
153
153
|
|
|
154
154
|
|
|
155
155
|
|
|
@@ -651,6 +651,11 @@ function $bc5ca2c06b1affa3$export$254a5c7330bbfd41(token) {
|
|
|
651
651
|
if ((0, $l50U0$libnexats.CommonUtils).isHexa(token)) return token;
|
|
652
652
|
return $bc5ca2c06b1affa3$export$23010fd5dda8dec1(token).toString('hex');
|
|
653
653
|
}
|
|
654
|
+
function $bc5ca2c06b1affa3$export$f12d707d2b261fb6(txIdem, outputIndex) {
|
|
655
|
+
const writer = new (0, $l50U0$libnexats.BufferWriter)(undefined);
|
|
656
|
+
const outpoint = writer.write(Buffer.from(txIdem, 'hex').reverse()).writeUInt32LE(outputIndex).toBuffer();
|
|
657
|
+
return (0, $l50U0$libnexats.Hash).sha256(outpoint).reverse().toString('hex');
|
|
658
|
+
}
|
|
654
659
|
|
|
655
660
|
|
|
656
661
|
var $0d59d2bcffd646c5$export$dcc1fb6ad5308e56 = /*#__PURE__*/ function(TxTokenType) {
|
|
@@ -1291,7 +1296,6 @@ var $90290c84737dbb50$export$2e2bcd8739ae039 = $90290c84737dbb50$var$isString;
|
|
|
1291
1296
|
|
|
1292
1297
|
|
|
1293
1298
|
|
|
1294
|
-
|
|
1295
1299
|
class $4d68f29c39c1a3e4$export$94f569bf4eb0f6f6 {
|
|
1296
1300
|
static getAllKeys(keys) {
|
|
1297
1301
|
return keys.receiveKeys.concat(keys.changeKeys);
|
|
@@ -1358,7 +1362,7 @@ function $22e282633cad8f97$export$e240c810a53c3a0c(perms) {
|
|
|
1358
1362
|
|
|
1359
1363
|
|
|
1360
1364
|
/** Maximum number of inputs/outputs allowed in a single transaction */ const $b4a043612f1c4089$var$MAX_INPUTS_OUTPUTS = 250;
|
|
1361
|
-
async function $b4a043612f1c4089$export$afd979971a55acfc(txBuilder, keys, totalTxValue, options) {
|
|
1365
|
+
async function $b4a043612f1c4089$export$afd979971a55acfc(txBuilder, keys, totalTxValue, options, spentOutpoints) {
|
|
1362
1366
|
let rKeys = keys.receiveKeys.filter((k)=>BigInt(k.balance) > 0n);
|
|
1363
1367
|
let cKeys = keys.changeKeys.filter((k)=>BigInt(k.balance) > 0n);
|
|
1364
1368
|
let allKeys = rKeys.concat(cKeys);
|
|
@@ -1368,6 +1372,8 @@ async function $b4a043612f1c4089$export$afd979971a55acfc(txBuilder, keys, totalT
|
|
|
1368
1372
|
for (let key of allKeys){
|
|
1369
1373
|
let utxos = await (0, $b5bfd17fdf06d231$export$eaa49f0478d81b9d).getNexaUtxos(key.address);
|
|
1370
1374
|
for (let utxo of utxos){
|
|
1375
|
+
// Skip if this outpoint is already spent
|
|
1376
|
+
if (spentOutpoints && spentOutpoints.has(utxo.outpoint_hash)) continue;
|
|
1371
1377
|
let input = {
|
|
1372
1378
|
outpoint: utxo.outpoint_hash,
|
|
1373
1379
|
address: key.address,
|
|
@@ -1375,6 +1381,8 @@ async function $b4a043612f1c4089$export$afd979971a55acfc(txBuilder, keys, totalT
|
|
|
1375
1381
|
templateData: options.templateData
|
|
1376
1382
|
};
|
|
1377
1383
|
txBuilder.from(input);
|
|
1384
|
+
// Add to spent outpoints set
|
|
1385
|
+
if (spentOutpoints) spentOutpoints.add(utxo.outpoint_hash);
|
|
1378
1386
|
if (!usedKeys.has(key.address)) usedKeys.set(key.address, key.key.privateKey);
|
|
1379
1387
|
if (options.isConsolidate) {
|
|
1380
1388
|
txBuilder.change(options.toChange ?? keys.receiveKeys[keys.receiveKeys.length - 1].address);
|
|
@@ -1418,7 +1426,7 @@ async function $b4a043612f1c4089$export$afd979971a55acfc(txBuilder, keys, totalT
|
|
|
1418
1426
|
};
|
|
1419
1427
|
throw new Error(JSON.stringify(err));
|
|
1420
1428
|
}
|
|
1421
|
-
async function $b4a043612f1c4089$export$931e37acdaa22dcf(txBuilder, keys, token, outTokenAmount) {
|
|
1429
|
+
async function $b4a043612f1c4089$export$931e37acdaa22dcf(txBuilder, keys, token, outTokenAmount, spentOutpoints) {
|
|
1422
1430
|
let tokenHex = (0, $bc5ca2c06b1affa3$export$254a5c7330bbfd41)(token);
|
|
1423
1431
|
let rKeys = keys.receiveKeys.filter((k)=>Object.keys(k.tokensBalance).includes(tokenHex));
|
|
1424
1432
|
let cKeys = keys.changeKeys.filter((k)=>Object.keys(k.tokensBalance).includes(tokenHex));
|
|
@@ -1430,6 +1438,8 @@ async function $b4a043612f1c4089$export$931e37acdaa22dcf(txBuilder, keys, token,
|
|
|
1430
1438
|
let utxos = await (0, $b5bfd17fdf06d231$export$eaa49f0478d81b9d).getTokenUtxos(key.address, token);
|
|
1431
1439
|
for (let utxo of utxos){
|
|
1432
1440
|
if (utxo.token_amount < 0) continue;
|
|
1441
|
+
// Skip if this outpoint is already spent
|
|
1442
|
+
if (spentOutpoints && spentOutpoints.has(utxo.outpoint_hash)) continue;
|
|
1433
1443
|
txBuilder.from({
|
|
1434
1444
|
outpoint: utxo.outpoint_hash,
|
|
1435
1445
|
address: key.address,
|
|
@@ -1437,6 +1447,8 @@ async function $b4a043612f1c4089$export$931e37acdaa22dcf(txBuilder, keys, token,
|
|
|
1437
1447
|
groupId: utxo.group,
|
|
1438
1448
|
groupAmount: BigInt(utxo.token_amount)
|
|
1439
1449
|
});
|
|
1450
|
+
// Add to spent outpoints set
|
|
1451
|
+
if (spentOutpoints) spentOutpoints.add(utxo.outpoint_hash);
|
|
1440
1452
|
inTokenAmount = inTokenAmount + BigInt(utxo.token_amount);
|
|
1441
1453
|
if (!usedKeys.has(key.address)) usedKeys.set(key.address, key.key.privateKey);
|
|
1442
1454
|
if (inTokenAmount > (0, $bc5ca2c06b1affa3$export$8ba128bc85947a2a)) throw new Error("Token inputs exceeded max amount. Consider sending in small chunks");
|
|
@@ -1452,7 +1464,7 @@ async function $b4a043612f1c4089$export$931e37acdaa22dcf(txBuilder, keys, token,
|
|
|
1452
1464
|
}
|
|
1453
1465
|
throw new Error("Not enough token balance");
|
|
1454
1466
|
}
|
|
1455
|
-
async function $b4a043612f1c4089$export$d7f2b844e1d59768(txBuilder, keys, opReturnData, network) {
|
|
1467
|
+
async function $b4a043612f1c4089$export$d7f2b844e1d59768(txBuilder, keys, opReturnData, network, spentOutpoints) {
|
|
1456
1468
|
// TODO validate opreturn data
|
|
1457
1469
|
const allKeys = (0, $4d68f29c39c1a3e4$export$94f569bf4eb0f6f6).getAllKeys(keys);
|
|
1458
1470
|
let outpoint = '';
|
|
@@ -1461,11 +1473,15 @@ async function $b4a043612f1c4089$export$d7f2b844e1d59768(txBuilder, keys, opRetu
|
|
|
1461
1473
|
for (let key of allKeys){
|
|
1462
1474
|
let utxos = await (0, $b5bfd17fdf06d231$export$eaa49f0478d81b9d).getNexaUtxos(key.address);
|
|
1463
1475
|
for (let utxo of utxos){
|
|
1476
|
+
// Skip if this outpoint is already spent
|
|
1477
|
+
if (spentOutpoints && spentOutpoints.has(utxo.outpoint_hash)) continue;
|
|
1464
1478
|
txBuilder.from({
|
|
1465
1479
|
outpoint: utxo.outpoint_hash,
|
|
1466
1480
|
address: key.address,
|
|
1467
1481
|
satoshis: utxo.value
|
|
1468
1482
|
});
|
|
1483
|
+
// Add to spent outpoints set
|
|
1484
|
+
if (spentOutpoints) spentOutpoints.add(utxo.outpoint_hash);
|
|
1469
1485
|
if ((0, $bc5ca2c06b1affa3$export$c8733ae29fb53302)(outpoint)) {
|
|
1470
1486
|
outpoint = utxo.outpoint_hash;
|
|
1471
1487
|
let id = (0, $l50U0$libnexats.GroupToken).findGroupId(outpoint, Buffer.from(opReturnData, 'hex'), (0, $l50U0$libnexats.GroupToken).authFlags.ACTIVE_FLAG_BITS);
|
|
@@ -1494,17 +1510,21 @@ async function $b4a043612f1c4089$export$48a48877d6df17e9(txBuilder, keys, outpoi
|
|
|
1494
1510
|
addrKey.key.privateKey
|
|
1495
1511
|
];
|
|
1496
1512
|
}
|
|
1497
|
-
async function $b4a043612f1c4089$export$1dfa5d829fc95097(txBuilder, keys, token, perm, subgroup = '', subgroupAddr = '', quantity) {
|
|
1513
|
+
async function $b4a043612f1c4089$export$1dfa5d829fc95097(txBuilder, keys, token, perm, subgroup = '', subgroupAddr = '', quantity, spentOutpoints) {
|
|
1498
1514
|
let allKeys = (0, $4d68f29c39c1a3e4$export$94f569bf4eb0f6f6).getAllKeys(keys);
|
|
1499
1515
|
for (let key of allKeys){
|
|
1500
1516
|
let utxos = await (0, $b5bfd17fdf06d231$export$eaa49f0478d81b9d).getTokenUtxos(key.address, token);
|
|
1501
1517
|
for (let utxo of utxos){
|
|
1502
1518
|
if (!(0, $22e282633cad8f97$export$7f7cffd29bf2d96d)(utxo.token_amount, perm)) continue;
|
|
1519
|
+
// Skip if this outpoint is already spent
|
|
1520
|
+
if (spentOutpoints && spentOutpoints.has(utxo.outpoint_hash)) continue;
|
|
1503
1521
|
txBuilder.from({
|
|
1504
1522
|
outpoint: utxo.outpoint_hash,
|
|
1505
1523
|
address: key.address,
|
|
1506
1524
|
satoshis: utxo.value
|
|
1507
1525
|
});
|
|
1526
|
+
// Add to spent outpoints set
|
|
1527
|
+
if (spentOutpoints) spentOutpoints.add(utxo.outpoint_hash);
|
|
1508
1528
|
if (perm === 'subgroup') {
|
|
1509
1529
|
const subgroupQuantity = quantity ?? (0, $22e282633cad8f97$export$636fb0b03b94ac81)(utxo.token_amount, false);
|
|
1510
1530
|
txBuilder.to(subgroupAddr, (0, $l50U0$libnexats.Transaction).DUST_AMOUNT, subgroup, subgroupQuantity);
|
|
@@ -1521,7 +1541,7 @@ async function $b4a043612f1c4089$export$1dfa5d829fc95097(txBuilder, keys, token,
|
|
|
1521
1541
|
}
|
|
1522
1542
|
throw new Error("The requested authority not found");
|
|
1523
1543
|
}
|
|
1524
|
-
async function $b4a043612f1c4089$export$28a843ca046a6b3f(txBuilder, keys, token, perms, toAddr) {
|
|
1544
|
+
async function $b4a043612f1c4089$export$28a843ca046a6b3f(txBuilder, keys, token, perms, toAddr, spentOutpoints) {
|
|
1525
1545
|
let allKeys = (0, $4d68f29c39c1a3e4$export$94f569bf4eb0f6f6).getAllKeys(keys);
|
|
1526
1546
|
let usedKeys = [];
|
|
1527
1547
|
let reqiredPerms = new Set(perms);
|
|
@@ -1530,6 +1550,8 @@ async function $b4a043612f1c4089$export$28a843ca046a6b3f(txBuilder, keys, token,
|
|
|
1530
1550
|
let utxos = await (0, $b5bfd17fdf06d231$export$eaa49f0478d81b9d).getTokenUtxos(key.address, token);
|
|
1531
1551
|
for (let utxo of utxos){
|
|
1532
1552
|
if (utxo.token_amount > 0) continue;
|
|
1553
|
+
// Skip if this outpoint is already spent
|
|
1554
|
+
if (spentOutpoints && spentOutpoints.has(utxo.outpoint_hash)) continue;
|
|
1533
1555
|
let found = false;
|
|
1534
1556
|
for (let perm of reqiredPerms)if ((0, $22e282633cad8f97$export$7f7cffd29bf2d96d)(utxo.token_amount, perm)) {
|
|
1535
1557
|
reqiredPerms.delete(perm);
|
|
@@ -1542,6 +1564,8 @@ async function $b4a043612f1c4089$export$28a843ca046a6b3f(txBuilder, keys, token,
|
|
|
1542
1564
|
satoshis: utxo.value
|
|
1543
1565
|
});
|
|
1544
1566
|
usedKeys.push(key.key.privateKey);
|
|
1567
|
+
// Add to spent outpoints set
|
|
1568
|
+
if (spentOutpoints) spentOutpoints.add(utxo.outpoint_hash);
|
|
1545
1569
|
// duplicate
|
|
1546
1570
|
const duplicateAddress = toAddr != null ? toAddr : keys.changeKeys.length > 0 ? keys.changeKeys[keys.changeKeys.length - 1].address : keys.receiveKeys[keys.receiveKeys.length - 1].address;
|
|
1547
1571
|
txBuilder.to(duplicateAddress, (0, $l50U0$libnexats.Transaction).DUST_AMOUNT, token, (0, $22e282633cad8f97$export$636fb0b03b94ac81)(utxo.token_amount));
|
|
@@ -1680,6 +1704,7 @@ var $ed110f8656071ee4$export$2e2bcd8739ae039 = $ed110f8656071ee4$var$parseInt;
|
|
|
1680
1704
|
|
|
1681
1705
|
|
|
1682
1706
|
|
|
1707
|
+
|
|
1683
1708
|
class $57b0117fe8233fef$export$bba690fb5c12ba04 {
|
|
1684
1709
|
/**
|
|
1685
1710
|
* Creates a new TransactionCreator instance
|
|
@@ -1689,10 +1714,80 @@ class $57b0117fe8233fef$export$bba690fb5c12ba04 {
|
|
|
1689
1714
|
/** Total value of NEXA being sent in this transaction */ this._totalValue = BigInt(0);
|
|
1690
1715
|
/** Network this transaction will be broadcast on */ this._network = (0, $l50U0$libnexats.Networks).mainnet;
|
|
1691
1716
|
/** Transaction options for customizing behavior */ this._txOptions = {};
|
|
1717
|
+
/** Set of outpoints already spent in this transaction to prevent double-spending */ this._spentOutpoints = new Set();
|
|
1692
1718
|
if (tx instanceof (0, $l50U0$libnexats.TransactionBuilder)) this.transactionBuilder = tx;
|
|
1693
1719
|
this.tokens = new Set();
|
|
1694
1720
|
this.transactionBuilder = new (0, $l50U0$libnexats.TransactionBuilder)();
|
|
1695
1721
|
}
|
|
1722
|
+
/**
|
|
1723
|
+
* Parse transaction from hex string with common logic
|
|
1724
|
+
* @param tx Transaction hex string
|
|
1725
|
+
* @returns This instance for chaining
|
|
1726
|
+
*/ parseTxHex(tx) {
|
|
1727
|
+
// Clear any existing builder operations since we're dealing with a pre-built transaction
|
|
1728
|
+
this.builder = [];
|
|
1729
|
+
// Add the parsing operation to the builder queue
|
|
1730
|
+
this.builder.push(async ()=>{
|
|
1731
|
+
try {
|
|
1732
|
+
const txBuilder = new (0, $l50U0$libnexats.TransactionBuilder)(tx);
|
|
1733
|
+
const newTxBuilder = new (0, $l50U0$libnexats.TransactionBuilder)();
|
|
1734
|
+
const oldInputs = txBuilder.transaction.inputs;
|
|
1735
|
+
// Reconstruct inputs with proper script template data if needed
|
|
1736
|
+
for(let i = 0; i < oldInputs.length; i++){
|
|
1737
|
+
const input = oldInputs[i];
|
|
1738
|
+
const utxo = await (0, $b5bfd17fdf06d231$export$eaa49f0478d81b9d).getUtxo(input.outpoint.toString('hex'));
|
|
1739
|
+
const scriptPubkey = (0, $l50U0$libnexats.Script).fromHex(utxo.scriptpubkey);
|
|
1740
|
+
if (scriptPubkey.isScriptTemplateOut()) {
|
|
1741
|
+
const scriptSig = input.scriptSig;
|
|
1742
|
+
newTxBuilder.transaction.addInput(new (0, $l50U0$libnexats.ScriptTemplateInput)({
|
|
1743
|
+
amount: input.amount,
|
|
1744
|
+
outpoint: input.outpoint.toString('hex'),
|
|
1745
|
+
scriptSig: input.scriptSig,
|
|
1746
|
+
templateData: {
|
|
1747
|
+
templateScript: (0, $l50U0$libnexats.BufferUtils).isHashBuffer(scriptPubkey.getTemplateHash()) ? (0, $l50U0$libnexats.Script).fromBuffer(scriptSig.chunks[0].buf) : (0, $l50U0$libnexats.Script).empty(),
|
|
1748
|
+
constraintScript: (0, $l50U0$libnexats.BufferUtils).isHashBuffer(scriptPubkey.getConstraintHash()) ? (0, $l50U0$libnexats.Script).fromBuffer(scriptSig.chunks[1].buf) : (0, $l50U0$libnexats.Opcode).OP_FALSE
|
|
1749
|
+
},
|
|
1750
|
+
output: {
|
|
1751
|
+
type: input.type,
|
|
1752
|
+
value: utxo.amount,
|
|
1753
|
+
scriptPubKey: utxo.scriptpubkey
|
|
1754
|
+
}
|
|
1755
|
+
}));
|
|
1756
|
+
} else // For non-template inputs, add them normally
|
|
1757
|
+
newTxBuilder.from({
|
|
1758
|
+
outpoint: input.outpoint.toString('hex'),
|
|
1759
|
+
satoshis: input.amount,
|
|
1760
|
+
address: utxo.addresses[0],
|
|
1761
|
+
scriptPubKey: utxo.scriptpubkey
|
|
1762
|
+
});
|
|
1763
|
+
// Hook for subclasses to handle input-specific logic (like key management)
|
|
1764
|
+
await this.handleParsedInput(input, utxo, i);
|
|
1765
|
+
}
|
|
1766
|
+
// Copy the outputs from the original transaction
|
|
1767
|
+
newTxBuilder.transaction.outputs = txBuilder.transaction.outputs;
|
|
1768
|
+
this.transactionBuilder = newTxBuilder;
|
|
1769
|
+
// Hook for subclasses to perform post-processing
|
|
1770
|
+
await this.handleParsingComplete();
|
|
1771
|
+
} catch (error) {
|
|
1772
|
+
console.error('parseTxHex: Error parsing transaction:', error);
|
|
1773
|
+
throw error;
|
|
1774
|
+
}
|
|
1775
|
+
});
|
|
1776
|
+
return this;
|
|
1777
|
+
}
|
|
1778
|
+
/**
|
|
1779
|
+
* Hook for subclasses to handle individual parsed inputs
|
|
1780
|
+
* @param input The original input from the transaction
|
|
1781
|
+
* @param utxo UTXO data for this input
|
|
1782
|
+
* @param index Input index
|
|
1783
|
+
*/ async handleParsedInput(input, utxo, index) {
|
|
1784
|
+
// Default implementation does nothing - subclasses can override
|
|
1785
|
+
}
|
|
1786
|
+
/**
|
|
1787
|
+
* Hook for subclasses to perform post-processing after parsing is complete
|
|
1788
|
+
*/ async handleParsingComplete() {
|
|
1789
|
+
// Default implementation does nothing - subclasses can override
|
|
1790
|
+
}
|
|
1696
1791
|
/**
|
|
1697
1792
|
* Sets the network for this transaction
|
|
1698
1793
|
* @param network Network name or Networkish object
|
|
@@ -1737,6 +1832,17 @@ class $57b0117fe8233fef$export$bba690fb5c12ba04 {
|
|
|
1737
1832
|
/** Sets the total NEXA value being sent */ set totalValue(value) {
|
|
1738
1833
|
this._totalValue = value;
|
|
1739
1834
|
}
|
|
1835
|
+
/** Gets the set of spent outpoints */ get spentOutpoints() {
|
|
1836
|
+
return this._spentOutpoints;
|
|
1837
|
+
}
|
|
1838
|
+
/**
|
|
1839
|
+
* Updates the spent outpoints set with current transaction inputs
|
|
1840
|
+
* @returns Set of outpoint hashes that are already spent
|
|
1841
|
+
*/ updateSpentOutpoints() {
|
|
1842
|
+
this._spentOutpoints.clear();
|
|
1843
|
+
for (const input of this.transactionBuilder.transaction.inputs)this._spentOutpoints.add(input.outpoint.toString('hex'));
|
|
1844
|
+
return this._spentOutpoints;
|
|
1845
|
+
}
|
|
1740
1846
|
/**
|
|
1741
1847
|
* Validates and creates a token action
|
|
1742
1848
|
* @param toAddr Destination address
|
|
@@ -1789,10 +1895,27 @@ class $57b0117fe8233fef$export$bba690fb5c12ba04 {
|
|
|
1789
1895
|
* @param toAddr Destination address
|
|
1790
1896
|
* @param amount Amount of tokens to send
|
|
1791
1897
|
* @param token Token ID
|
|
1898
|
+
* @param dustAmount Optional dust amount for the output (defaults to Transaction.DUST_AMOUNT)
|
|
1792
1899
|
* @returns This instance for chaining
|
|
1793
|
-
*/ sendToToken(toAddr, amount, token) {
|
|
1900
|
+
*/ sendToToken(toAddr, amount, token, dustAmount = (0, $l50U0$libnexats.Transaction).DUST_AMOUNT) {
|
|
1794
1901
|
this.builder.push(async ()=>{
|
|
1795
|
-
|
|
1902
|
+
// Validate destination address
|
|
1903
|
+
if (!(0, $0d59d2bcffd646c5$export$8d986bd2866fe6ab)(toAddr, this.network) && !(0, $0d59d2bcffd646c5$export$8d986bd2866fe6ab)(toAddr, this.network, (0, $l50U0$libnexats.AddressType).PayToPublicKeyHash)) throw new Error('Invalid Address.');
|
|
1904
|
+
// Validate amount ranges
|
|
1905
|
+
if (BigInt(amount) < 1n) throw new Error("The amount is too low.");
|
|
1906
|
+
if (BigInt(amount) > (0, $bc5ca2c06b1affa3$export$8ba128bc85947a2a)) throw new Error("The amount is too high.");
|
|
1907
|
+
// Validate token ID
|
|
1908
|
+
if (!(0, $0d59d2bcffd646c5$export$8d986bd2866fe6ab)(token, this.network, (0, $l50U0$libnexats.AddressType).GroupIdAddress)) throw new Error('Invalid Token ID');
|
|
1909
|
+
// Ensure tokens are sent to script template addresses
|
|
1910
|
+
if ((0, $l50U0$libnexats.Address).getOutputType(toAddr) === 0) throw new Error('Token must be sent to script template address');
|
|
1911
|
+
// Add output to transaction with configurable dust amount
|
|
1912
|
+
this.transactionBuilder.to(toAddr, dustAmount, token, BigInt(amount));
|
|
1913
|
+
// Record the token action
|
|
1914
|
+
this.tokens.add({
|
|
1915
|
+
token: token,
|
|
1916
|
+
amount: BigInt(amount),
|
|
1917
|
+
action: 'send'
|
|
1918
|
+
});
|
|
1796
1919
|
});
|
|
1797
1920
|
return this;
|
|
1798
1921
|
}
|
|
@@ -1941,9 +2064,10 @@ class $57b0117fe8233fef$export$bba690fb5c12ba04 {
|
|
|
1941
2064
|
let opReturn = (0, $l50U0$libnexats.ScriptFactory).buildNFTDescription(zipUrl, zipHash);
|
|
1942
2065
|
this.transactionBuilder.addData(opReturn, true);
|
|
1943
2066
|
// generate subgroup ID
|
|
1944
|
-
const
|
|
2067
|
+
const subGroupBuffer = (0, $l50U0$libnexats.GroupToken).generateSubgroupId(parent, zipHash);
|
|
2068
|
+
const subGroupAddress = new (0, $l50U0$libnexats.Address)(subGroupBuffer, (0, $l50U0$libnexats.Networks).get(this.network) || (0, $l50U0$libnexats.Networks).mainnet, (0, $l50U0$libnexats.AddressType).GroupIdAddress).toString();
|
|
1945
2069
|
this.tokens.add({
|
|
1946
|
-
token:
|
|
2070
|
+
token: subGroupAddress,
|
|
1947
2071
|
parentToken: parent,
|
|
1948
2072
|
amount: BigInt((0, $l50U0$libnexats.Transaction).DUST_AMOUNT),
|
|
1949
2073
|
action: 'subgroup',
|
|
@@ -1967,9 +2091,10 @@ class $57b0117fe8233fef$export$bba690fb5c12ba04 {
|
|
|
1967
2091
|
let opReturn = (0, $l50U0$libnexats.ScriptFactory).buildNFTDescription(zipUrl, zipHash);
|
|
1968
2092
|
this.transactionBuilder.addData(opReturn, true);
|
|
1969
2093
|
// generate subgroup ID
|
|
1970
|
-
const
|
|
2094
|
+
const subGroupBuffer = (0, $l50U0$libnexats.GroupToken).generateSubgroupId(parent, zipHash);
|
|
2095
|
+
const subGroupAddress = new (0, $l50U0$libnexats.Address)(subGroupBuffer, (0, $l50U0$libnexats.Networks).get(this.network) || (0, $l50U0$libnexats.Networks).mainnet, (0, $l50U0$libnexats.AddressType).GroupIdAddress).toString();
|
|
1971
2096
|
this.tokens.add({
|
|
1972
|
-
token:
|
|
2097
|
+
token: subGroupAddress,
|
|
1973
2098
|
parentToken: parent,
|
|
1974
2099
|
amount: BigInt((0, $l50U0$libnexats.Transaction).DUST_AMOUNT),
|
|
1975
2100
|
action: 'subgroup',
|
|
@@ -2034,28 +2159,33 @@ class $e1896e59040fa3c5$export$2e2bcd8739ae039 extends (0, $57b0117fe8233fef$exp
|
|
|
2034
2159
|
return this;
|
|
2035
2160
|
}
|
|
2036
2161
|
parseTxHex(tx) {
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
});
|
|
2053
|
-
return this;
|
|
2162
|
+
// Call parent's parseTxHex which handles the common parsing logic
|
|
2163
|
+
return super.parseTxHex(tx);
|
|
2164
|
+
}
|
|
2165
|
+
/**
|
|
2166
|
+
* Handle wallet-specific logic for each parsed input (find and store private keys)
|
|
2167
|
+
*/ async handleParsedInput(input, utxo, index) {
|
|
2168
|
+
// Find and store the private key for this input
|
|
2169
|
+
const foundKey = this.findPrivateKeyFromAddress(utxo.addresses[0]);
|
|
2170
|
+
if (foundKey) this._keysToSign.push(foundKey.key.privateKey);
|
|
2171
|
+
}
|
|
2172
|
+
/**
|
|
2173
|
+
* Handle wallet-specific post-processing after parsing is complete
|
|
2174
|
+
*/ async handleParsingComplete() {
|
|
2175
|
+
// If no keys found, use the primary account key as fallback
|
|
2176
|
+
if (this._keysToSign.length == 0) this._keysToSign.push(this._account.getPrimaryAddressKey().key.privateKey);
|
|
2054
2177
|
}
|
|
2055
2178
|
parseTxBuffer(tx) {
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2179
|
+
// Clear any existing builder operations since we're dealing with a pre-built transaction
|
|
2180
|
+
this.builder = [];
|
|
2181
|
+
// For buffer, we can parse immediately since it doesn't require async operations
|
|
2182
|
+
this.transactionBuilder = new (0, $l50U0$libnexats.TransactionBuilder)(tx);
|
|
2183
|
+
// Extract all possible keys from the account that might be needed for signing
|
|
2184
|
+
// Since we don't have UTXO data, we'll add all account keys
|
|
2185
|
+
const addresses = this._account.getAddresses();
|
|
2186
|
+
for (const addressKey of addresses)if (!this._keysToSign.includes(addressKey.key.privateKey)) this._keysToSign.push(addressKey.key.privateKey);
|
|
2187
|
+
// If no keys found, use the primary account key as fallback
|
|
2188
|
+
if (this._keysToSign.length == 0) this._keysToSign.push(this._account.getPrimaryAddressKey().key.privateKey);
|
|
2059
2189
|
return this;
|
|
2060
2190
|
}
|
|
2061
2191
|
mint(token, amount) {
|
|
@@ -2078,63 +2208,236 @@ class $e1896e59040fa3c5$export$2e2bcd8739ae039 extends (0, $57b0117fe8233fef$exp
|
|
|
2078
2208
|
let tK = [];
|
|
2079
2209
|
let nK = [];
|
|
2080
2210
|
if (this.tokens.size > 0) for (const tokenAction of this.tokens){
|
|
2081
|
-
if (tokenAction.action == 'mint' || tokenAction.action == 'melt') tK = tK.concat(await (0, $b4a043612f1c4089$export$1dfa5d829fc95097)(this.transactionBuilder, this._account.accountKeys, tokenAction.token, tokenAction.action));
|
|
2082
|
-
else if (tokenAction.action == 'group') tK = tK.concat(await (0, $b4a043612f1c4089$export$d7f2b844e1d59768)(this.transactionBuilder, this._account.accountKeys, tokenAction.extraData?.opReturnData, this.network));
|
|
2083
|
-
else if (tokenAction.action == 'subgroup') tK = tK.concat(await (0, $b4a043612f1c4089$export$1dfa5d829fc95097)(this.transactionBuilder, this._account.accountKeys, tokenAction.parentToken, 'subgroup', tokenAction.token, this._account.accountKeys.receiveKeys.at(-1).address, tokenAction.extraData?.quantity));
|
|
2084
|
-
else if (tokenAction.action == 'renew') tK = tK.concat(await (0, $b4a043612f1c4089$export$28a843ca046a6b3f)(this.transactionBuilder, this._account.accountKeys, tokenAction.token, tokenAction.extraData.perms, tokenAction.extraData.address));
|
|
2211
|
+
if (tokenAction.action == 'mint' || tokenAction.action == 'melt') tK = tK.concat(await (0, $b4a043612f1c4089$export$1dfa5d829fc95097)(this.transactionBuilder, this._account.accountKeys, tokenAction.token, tokenAction.action, undefined, undefined, undefined, this.spentOutpoints));
|
|
2212
|
+
else if (tokenAction.action == 'group') tK = tK.concat(await (0, $b4a043612f1c4089$export$d7f2b844e1d59768)(this.transactionBuilder, this._account.accountKeys, tokenAction.extraData?.opReturnData, this.network, this.spentOutpoints));
|
|
2213
|
+
else if (tokenAction.action == 'subgroup') tK = tK.concat(await (0, $b4a043612f1c4089$export$1dfa5d829fc95097)(this.transactionBuilder, this._account.accountKeys, tokenAction.parentToken, 'subgroup', tokenAction.token, this._account.accountKeys.receiveKeys.at(-1).address, tokenAction.extraData?.quantity, this.spentOutpoints));
|
|
2214
|
+
else if (tokenAction.action == 'renew') tK = tK.concat(await (0, $b4a043612f1c4089$export$28a843ca046a6b3f)(this.transactionBuilder, this._account.accountKeys, tokenAction.token, tokenAction.extraData.perms, tokenAction.extraData.address, this.spentOutpoints));
|
|
2085
2215
|
else if (tokenAction.action == 'delete') tK = tK.concat(await (0, $b4a043612f1c4089$export$48a48877d6df17e9)(this.transactionBuilder, this._account.accountKeys, tokenAction.extraData.outpoint));
|
|
2086
|
-
else tK = tK.concat(await (0, $b4a043612f1c4089$export$931e37acdaa22dcf)(this.transactionBuilder, this._account.accountKeys, tokenAction.token, tokenAction.amount));
|
|
2216
|
+
else tK = tK.concat(await (0, $b4a043612f1c4089$export$931e37acdaa22dcf)(this.transactionBuilder, this._account.accountKeys, tokenAction.token, tokenAction.amount, this.spentOutpoints));
|
|
2087
2217
|
this._keysToSign.concat(tK);
|
|
2088
2218
|
}
|
|
2089
|
-
nK = nK.concat(await (0, $b4a043612f1c4089$export$afd979971a55acfc)(this.transactionBuilder, this._account.accountKeys, this.totalValue, this.txOptions));
|
|
2219
|
+
nK = nK.concat(await (0, $b4a043612f1c4089$export$afd979971a55acfc)(this.transactionBuilder, this._account.accountKeys, this.totalValue, this.txOptions, this.spentOutpoints));
|
|
2090
2220
|
this._keysToSign = tK.concat(nK);
|
|
2091
2221
|
});
|
|
2092
2222
|
return this;
|
|
2093
2223
|
}
|
|
2094
2224
|
sign() {
|
|
2095
2225
|
this.builder.push(async ()=>{
|
|
2096
|
-
|
|
2097
|
-
this.transactionBuilder.
|
|
2226
|
+
// Process each transaction input using placeholder-based signing
|
|
2227
|
+
const inputs = this.transactionBuilder.transaction.inputs;
|
|
2228
|
+
for(let inputIndex = 0; inputIndex < inputs.length; inputIndex++){
|
|
2229
|
+
const input = inputs[inputIndex];
|
|
2230
|
+
// Analyze the scriptSig to determine signing strategy
|
|
2231
|
+
const analysis = this.analyzeScriptSig(input.scriptSig);
|
|
2232
|
+
if (analysis.strategy === 'skip') {
|
|
2233
|
+
console.log(`Skipping input ${inputIndex} - no placeholder found`);
|
|
2234
|
+
continue;
|
|
2235
|
+
}
|
|
2236
|
+
// Determine sighash type from placeholder bytes (or default to SIGHASH_ALL)
|
|
2237
|
+
const sighashType = analysis.sighashType || new (0, $l50U0$libnexats.SighashType)();
|
|
2238
|
+
// Try signing with all available keys until one works
|
|
2239
|
+
let signed = false;
|
|
2240
|
+
const allAddressKeys = this._account.getAddresses();
|
|
2241
|
+
for (const addressKey of allAddressKeys)try {
|
|
2242
|
+
// Sign the input
|
|
2243
|
+
const sig = (0, $l50U0$libnexats.TxSigner).sign(this.transactionBuilder.transaction, inputIndex, sighashType, this.transactionBuilder.transaction.inputs[inputIndex].getSubscript(), addressKey.key.privateKey);
|
|
2244
|
+
// Create signature buffer (Schnorr signature for Nexa)
|
|
2245
|
+
const signatureBuffer = new (0, $l50U0$libnexats.TxSignature)({
|
|
2246
|
+
publicKey: addressKey.key.publicKey,
|
|
2247
|
+
sigType: sighashType,
|
|
2248
|
+
signature: sig,
|
|
2249
|
+
subscript: this.transactionBuilder.transaction.inputs[inputIndex].getSubscript(),
|
|
2250
|
+
inputIndex: inputIndex
|
|
2251
|
+
}).toTxSatisfier();
|
|
2252
|
+
if (analysis.strategy === 'sign_all') this.transactionBuilder.signInput(inputIndex, addressKey.key.privateKey, sighashType);
|
|
2253
|
+
else if (analysis.strategy === 'replace_placeholder' && analysis.placeholderIndex !== undefined) {
|
|
2254
|
+
// Handle script template with mixed satisfier elements
|
|
2255
|
+
if (input instanceof (0, $l50U0$libnexats.ScriptTemplateInput) && analysis.satisfierElements && analysis.satisfierElements.length > 0) {
|
|
2256
|
+
// Reconstruct script template with preserved satisfier elements plus signature
|
|
2257
|
+
const templateInput = input;
|
|
2258
|
+
const allSatisfierElements = [
|
|
2259
|
+
...analysis.satisfierElements
|
|
2260
|
+
];
|
|
2261
|
+
// Insert signature at the correct position (where placeholder was)
|
|
2262
|
+
const relativeIndex = analysis.placeholderIndex - 2; // Adjust for template and constraint chunks
|
|
2263
|
+
allSatisfierElements.splice(relativeIndex, 0, signatureBuffer);
|
|
2264
|
+
this.transactionBuilder.transaction.inputs[inputIndex].scriptSig = this.buildScriptSig(templateInput.templateScript, templateInput.constraintScript, allSatisfierElements);
|
|
2265
|
+
} else if (input instanceof (0, $l50U0$libnexats.ScriptTemplateInput)) {
|
|
2266
|
+
// Script template with only placeholder (no other satisfier elements)
|
|
2267
|
+
const templateInput = input;
|
|
2268
|
+
this.transactionBuilder.transaction.inputs[inputIndex].scriptSig = this.buildScriptSig(templateInput.templateScript, templateInput.constraintScript, [
|
|
2269
|
+
signatureBuffer
|
|
2270
|
+
]);
|
|
2271
|
+
} else // P2PKH script: signature placeholder + public key
|
|
2272
|
+
this.transactionBuilder.transaction.inputs[inputIndex].scriptSig = (0, $l50U0$libnexats.ScriptFactory).buildPublicKeyHashIn(addressKey.key.publicKey, sig);
|
|
2273
|
+
}
|
|
2274
|
+
signed = true;
|
|
2275
|
+
break;
|
|
2276
|
+
} catch (error) {
|
|
2277
|
+
// console.log(`Key for address ${addressKey.address} failed to sign input ${inputIndex}:`, (error as Error).message)
|
|
2278
|
+
}
|
|
2279
|
+
signed;
|
|
2280
|
+
}
|
|
2098
2281
|
});
|
|
2099
2282
|
return this;
|
|
2100
2283
|
}
|
|
2284
|
+
buildSatisfier(elements) {
|
|
2285
|
+
let script = new (0, $l50U0$libnexats.Script)();
|
|
2286
|
+
for (const element of elements)script = script.add(element);
|
|
2287
|
+
return script;
|
|
2288
|
+
}
|
|
2289
|
+
buildScriptSig(template, constraint, satisfierElements) {
|
|
2290
|
+
const satisfierScript = this.buildSatisfier(satisfierElements);
|
|
2291
|
+
return (0, $l50U0$libnexats.ScriptFactory).buildScriptTemplateIn(template, constraint, satisfierScript);
|
|
2292
|
+
}
|
|
2101
2293
|
/**
|
|
2102
|
-
*
|
|
2103
|
-
* @param
|
|
2104
|
-
* @returns
|
|
2105
|
-
*/
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
// If sighashSpec is provided, use selective signing
|
|
2110
|
-
if (sighashSpec) {
|
|
2111
|
-
// Parse sighashSpec and create appropriate SighashType
|
|
2112
|
-
const sighashType = this.parseSighashSpec(sighashSpec);
|
|
2113
|
-
// Sign each input with the specified sighash type
|
|
2114
|
-
for(let i = 0; i < this._keysToSign.length; i++)if (this._keysToSign[i]) this.transactionBuilder.signInput(i, this._keysToSign[i], sighashType);
|
|
2115
|
-
} else // Fall back to default signing if no spec provided
|
|
2116
|
-
this.transactionBuilder.sign(this._keysToSign);
|
|
2117
|
-
});
|
|
2118
|
-
return this;
|
|
2294
|
+
* Check if a buffer is a 64-byte placeholder (all zeros)
|
|
2295
|
+
* @param buf - Buffer to check
|
|
2296
|
+
* @returns true if it's a 64-byte zero placeholder
|
|
2297
|
+
*/ isPlaceholder(buf) {
|
|
2298
|
+
if (!buf || buf.length < 64) return false;
|
|
2299
|
+
const placeholderBytes = Buffer.alloc(64, 0);
|
|
2300
|
+
return buf.subarray(0, 64).equals(placeholderBytes);
|
|
2119
2301
|
}
|
|
2120
2302
|
/**
|
|
2121
|
-
*
|
|
2122
|
-
* @param
|
|
2123
|
-
* @returns SighashType
|
|
2124
|
-
*/
|
|
2125
|
-
//
|
|
2126
|
-
|
|
2127
|
-
//
|
|
2303
|
+
* Extract sighash type from placeholder buffer (bytes after the 64-byte placeholder)
|
|
2304
|
+
* @param buf - Buffer that may contain sighash type after placeholder
|
|
2305
|
+
* @returns SighashType or null if using default SIGHASH_ALL (empty sighash = 0)
|
|
2306
|
+
*/ extractSighashFromPlaceholder(buf) {
|
|
2307
|
+
if (buf.length <= 64) // Empty SigHash - use single byte 0 (sign all inputs and outputs)
|
|
2308
|
+
return (0, $l50U0$libnexats.SighashType).ALL; // Use default SIGHASH_ALL
|
|
2309
|
+
// Parse the sighash bytes starting at offset 64
|
|
2310
|
+
const sighashBytes = buf.subarray(64);
|
|
2311
|
+
if (sighashBytes.length === 0) return (0, $l50U0$libnexats.SighashType).ALL; // Default SIGHASH_ALL
|
|
2312
|
+
// Get the sighashtype flag byte
|
|
2313
|
+
const flagByte = sighashBytes[0];
|
|
2314
|
+
// Upper 4 bits = input type, Lower 4 bits = output type
|
|
2315
|
+
const inputType = flagByte >> 4 & 0x0F;
|
|
2316
|
+
const outputType = flagByte & 0x0F;
|
|
2128
2317
|
const sighashType = new (0, $l50U0$libnexats.SighashType)();
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2318
|
+
let byteIndex = 1;
|
|
2319
|
+
// Parse input type flags
|
|
2320
|
+
switch(inputType){
|
|
2321
|
+
case 0:
|
|
2322
|
+
sighashType.inType = 0; // ALL
|
|
2323
|
+
break;
|
|
2324
|
+
case 1:
|
|
2325
|
+
sighashType.inType = 1; // FIRST_N
|
|
2326
|
+
if (byteIndex < sighashBytes.length) {
|
|
2327
|
+
sighashType.inData = [
|
|
2328
|
+
sighashBytes[byteIndex]
|
|
2329
|
+
];
|
|
2330
|
+
byteIndex++;
|
|
2331
|
+
}
|
|
2332
|
+
break;
|
|
2333
|
+
case 2:
|
|
2334
|
+
sighashType.inType = 2; // THIS
|
|
2335
|
+
break;
|
|
2336
|
+
default:
|
|
2337
|
+
// Unknown input type, default to ALL
|
|
2338
|
+
sighashType.inType = 0;
|
|
2339
|
+
}
|
|
2340
|
+
// Parse output type flags
|
|
2341
|
+
switch(outputType){
|
|
2342
|
+
case 0:
|
|
2343
|
+
sighashType.outType = 0; // ALL
|
|
2344
|
+
break;
|
|
2345
|
+
case 1:
|
|
2346
|
+
sighashType.outType = 1; // FIRST_N
|
|
2347
|
+
if (byteIndex < sighashBytes.length) {
|
|
2348
|
+
sighashType.outData = [
|
|
2349
|
+
sighashBytes[byteIndex]
|
|
2350
|
+
];
|
|
2351
|
+
byteIndex++;
|
|
2352
|
+
}
|
|
2353
|
+
break;
|
|
2354
|
+
case 2:
|
|
2355
|
+
sighashType.outType = 2; // TWO_OUTPUTS (if supported)
|
|
2356
|
+
const outData = [];
|
|
2357
|
+
if (byteIndex < sighashBytes.length) {
|
|
2358
|
+
outData.push(sighashBytes[byteIndex]);
|
|
2359
|
+
byteIndex++;
|
|
2360
|
+
}
|
|
2361
|
+
if (byteIndex < sighashBytes.length) {
|
|
2362
|
+
outData.push(sighashBytes[byteIndex]);
|
|
2363
|
+
byteIndex++;
|
|
2364
|
+
}
|
|
2365
|
+
sighashType.outData = outData;
|
|
2366
|
+
break;
|
|
2367
|
+
default:
|
|
2368
|
+
// Unknown output type, default to ALL
|
|
2369
|
+
sighashType.outType = 0;
|
|
2135
2370
|
}
|
|
2136
|
-
|
|
2137
|
-
|
|
2371
|
+
return sighashType;
|
|
2372
|
+
}
|
|
2373
|
+
/**
|
|
2374
|
+
* Determine signing behavior based on scriptSig content
|
|
2375
|
+
* @param scriptSig - The scriptSig to analyze
|
|
2376
|
+
* @returns Object with signing strategy and sighash type
|
|
2377
|
+
*/ analyzeScriptSig(scriptSig) {
|
|
2378
|
+
const chunks = scriptSig.chunks;
|
|
2379
|
+
// Empty scriptSig - sign with SIGHASH_ALL
|
|
2380
|
+
if (chunks.length === 0) return {
|
|
2381
|
+
strategy: 'sign_all',
|
|
2382
|
+
sighashType: (0, $l50U0$libnexats.SighashType).ALL
|
|
2383
|
+
};
|
|
2384
|
+
// Single chunk
|
|
2385
|
+
if (chunks.length === 1) {
|
|
2386
|
+
const chunk = chunks[0];
|
|
2387
|
+
if (chunk.buf && this.isPlaceholder(chunk.buf)) {
|
|
2388
|
+
// Single placeholder - treat same as empty, sign with SIGHASH_ALL or extract sighash
|
|
2389
|
+
const sighashType = this.extractSighashFromPlaceholder(chunk.buf);
|
|
2390
|
+
return {
|
|
2391
|
+
strategy: 'sign_all',
|
|
2392
|
+
sighashType: sighashType
|
|
2393
|
+
};
|
|
2394
|
+
}
|
|
2395
|
+
// Single non-placeholder chunk - skip signing
|
|
2396
|
+
return {
|
|
2397
|
+
strategy: 'skip',
|
|
2398
|
+
sighashType: null
|
|
2399
|
+
};
|
|
2400
|
+
}
|
|
2401
|
+
// For script templates, check if this follows the 3-part structure: template, constraint, satisfier elements
|
|
2402
|
+
// If chunks.length >= 3, assume it's a script template where chunks[2:] are satisfier elements
|
|
2403
|
+
if (chunks.length >= 3) {
|
|
2404
|
+
// Extract satisfier elements (chunks starting from index 2)
|
|
2405
|
+
const satisfierElements = [];
|
|
2406
|
+
let placeholderIndex;
|
|
2407
|
+
let sighashType = null;
|
|
2408
|
+
for(let i = 2; i < chunks.length; i++){
|
|
2409
|
+
const chunk = chunks[i];
|
|
2410
|
+
if (chunk.buf && this.isPlaceholder(chunk.buf)) {
|
|
2411
|
+
// Found placeholder in satisfier elements
|
|
2412
|
+
placeholderIndex = i;
|
|
2413
|
+
sighashType = this.extractSighashFromPlaceholder(chunk.buf);
|
|
2414
|
+
} else // Non-placeholder satisfier element - preserve it
|
|
2415
|
+
satisfierElements.push(chunk);
|
|
2416
|
+
}
|
|
2417
|
+
if (placeholderIndex !== undefined) return {
|
|
2418
|
+
strategy: 'replace_placeholder',
|
|
2419
|
+
sighashType: sighashType,
|
|
2420
|
+
placeholderIndex: placeholderIndex,
|
|
2421
|
+
satisfierElements: satisfierElements
|
|
2422
|
+
};
|
|
2423
|
+
}
|
|
2424
|
+
// Multiple chunks - look for placeholder (fallback for non-template scripts)
|
|
2425
|
+
for(let i = 0; i < chunks.length; i++){
|
|
2426
|
+
const chunk = chunks[i];
|
|
2427
|
+
if (chunk.buf && this.isPlaceholder(chunk.buf)) {
|
|
2428
|
+
const sighashType = this.extractSighashFromPlaceholder(chunk.buf);
|
|
2429
|
+
return {
|
|
2430
|
+
strategy: 'replace_placeholder',
|
|
2431
|
+
sighashType: sighashType,
|
|
2432
|
+
placeholderIndex: i
|
|
2433
|
+
};
|
|
2434
|
+
}
|
|
2435
|
+
}
|
|
2436
|
+
// Multiple chunks without placeholder - skip signing
|
|
2437
|
+
return {
|
|
2438
|
+
strategy: 'skip',
|
|
2439
|
+
sighashType: null
|
|
2440
|
+
};
|
|
2138
2441
|
}
|
|
2139
2442
|
/**
|
|
2140
2443
|
* Validates that the account has the necessary keys before performing operations
|
|
@@ -2184,10 +2487,14 @@ class $7fcf3b163a95e69a$export$2e2bcd8739ae039 {
|
|
|
2184
2487
|
* Creates a new account of the specified type
|
|
2185
2488
|
* @param accountType Type of account to create (DAPP, VAULT, or DEFAULT)
|
|
2186
2489
|
* @param masterKey Master HD private key for deriving account keys
|
|
2490
|
+
* @param forceNextIndex If true, forces the next sequential index regardless of blockchain usage
|
|
2187
2491
|
* @returns Promise resolving to the created account
|
|
2188
|
-
*/ async createAccount(accountType, masterKey) {
|
|
2189
|
-
|
|
2190
|
-
|
|
2492
|
+
*/ async createAccount(accountType, masterKey, forceNextIndex = false) {
|
|
2493
|
+
let nextIndex;
|
|
2494
|
+
if (forceNextIndex) // Force next sequential index considering both blockchain and store
|
|
2495
|
+
nextIndex = await this.getNextSequentialIndex(accountType, masterKey);
|
|
2496
|
+
else // Get the next available index for this account type (discovery-based)
|
|
2497
|
+
nextIndex = await (0, $0d59d2bcffd646c5$export$ef13479e8d3251d7)(accountType, masterKey);
|
|
2191
2498
|
const accountStoreKey = this.getAccountStoreKey(accountType, nextIndex);
|
|
2192
2499
|
// Check if account already exists
|
|
2193
2500
|
const indexExists = this._accounts.get(String(accountStoreKey));
|
|
@@ -2298,6 +2605,41 @@ class $7fcf3b163a95e69a$export$2e2bcd8739ae039 {
|
|
|
2298
2605
|
}
|
|
2299
2606
|
return accounts;
|
|
2300
2607
|
}
|
|
2608
|
+
/**
|
|
2609
|
+
* Gets the next sequential index for an account type, considering both blockchain
|
|
2610
|
+
* discovery and accounts already in the store
|
|
2611
|
+
* @param accountType The account type to get the next index for
|
|
2612
|
+
* @param masterKey Master HD private key for blockchain discovery
|
|
2613
|
+
* @returns Promise resolving to the next safe sequential index
|
|
2614
|
+
*/ async getNextSequentialIndex(accountType, masterKey) {
|
|
2615
|
+
// First, get the discovery-based index (what exists on blockchain)
|
|
2616
|
+
const discoveryIndex = await (0, $0d59d2bcffd646c5$export$ef13479e8d3251d7)(accountType, masterKey);
|
|
2617
|
+
// Then, check what's the next index based on current store
|
|
2618
|
+
const storeBasedIndex = this.getNextStoreIndex(accountType);
|
|
2619
|
+
// Use whichever is higher to ensure we don't conflict with either
|
|
2620
|
+
return Math.max(discoveryIndex, storeBasedIndex);
|
|
2621
|
+
}
|
|
2622
|
+
/**
|
|
2623
|
+
* Gets the next index based only on accounts currently in the store
|
|
2624
|
+
* @param accountType The account type to check
|
|
2625
|
+
* @returns The next available index in the store
|
|
2626
|
+
*/ getNextStoreIndex(accountType) {
|
|
2627
|
+
const indexes = [];
|
|
2628
|
+
for (const [key, _] of this._accounts)switch(accountType){
|
|
2629
|
+
case (0, $0d59d2bcffd646c5$export$b8ca5fa4899cbfc7).DAPP_ACCOUNT:
|
|
2630
|
+
if (key.startsWith('2.')) indexes.push(parseInt(key.split('.')[1]));
|
|
2631
|
+
break;
|
|
2632
|
+
case (0, $0d59d2bcffd646c5$export$b8ca5fa4899cbfc7).VAULT_ACCOUNT:
|
|
2633
|
+
if (key.startsWith('1.')) indexes.push(parseInt(key.split('.')[1]));
|
|
2634
|
+
break;
|
|
2635
|
+
case (0, $0d59d2bcffd646c5$export$b8ca5fa4899cbfc7).NEXA_ACCOUNT:
|
|
2636
|
+
if (!key.includes('.')) indexes.push(parseInt(key));
|
|
2637
|
+
break;
|
|
2638
|
+
}
|
|
2639
|
+
if (indexes.length === 0) return 0; // First account of this type
|
|
2640
|
+
// Return the next sequential index after the highest existing one
|
|
2641
|
+
return Math.max(...indexes) + 1;
|
|
2642
|
+
}
|
|
2301
2643
|
}
|
|
2302
2644
|
|
|
2303
2645
|
|
|
@@ -2389,6 +2731,7 @@ class $b76d3bd5024ccfc0$export$2e2bcd8739ae039 {
|
|
|
2389
2731
|
* const wallet = new Wallet(undefined, 'testnet');
|
|
2390
2732
|
* ```
|
|
2391
2733
|
*/ constructor(data, network){
|
|
2734
|
+
/** Whether to force sequential account indexing instead of discovery-based indexing */ this._forceSequentialIndexing = false;
|
|
2392
2735
|
this._network = (0, $l50U0$libnexats.Networks).get(network) ?? (0, $l50U0$libnexats.Networks).mainnet;
|
|
2393
2736
|
this._accountStore = new (0, $7fcf3b163a95e69a$export$2e2bcd8739ae039)();
|
|
2394
2737
|
if ((0, $54dde1e65fb8e5b8$export$2e2bcd8739ae039)(data)) {
|
|
@@ -2542,7 +2885,7 @@ class $b76d3bd5024ccfc0$export$2e2bcd8739ae039 {
|
|
|
2542
2885
|
* const dappAccount = await wallet.newAccount('DappAccount');
|
|
2543
2886
|
* ```
|
|
2544
2887
|
*/ async newAccount(accountType) {
|
|
2545
|
-
return await this.accountStore.createAccount(accountType, this.masterKey);
|
|
2888
|
+
return await this.accountStore.createAccount(accountType, this.masterKey, this._forceSequentialIndexing);
|
|
2546
2889
|
}
|
|
2547
2890
|
/**
|
|
2548
2891
|
* Broadcast a signed transaction to the Nexa network
|
|
@@ -2760,6 +3103,47 @@ class $b76d3bd5024ccfc0$export$2e2bcd8739ae039 {
|
|
|
2760
3103
|
*/ get network() {
|
|
2761
3104
|
return this._network;
|
|
2762
3105
|
}
|
|
3106
|
+
/**
|
|
3107
|
+
* Get the current sequential indexing setting
|
|
3108
|
+
*
|
|
3109
|
+
* @returns true if forcing sequential indexing, false if using discovery-based indexing
|
|
3110
|
+
*
|
|
3111
|
+
* @example
|
|
3112
|
+
* ```typescript
|
|
3113
|
+
* const isSequential = wallet.forceSequentialIndexing;
|
|
3114
|
+
* console.log('Sequential indexing:', isSequential);
|
|
3115
|
+
* ```
|
|
3116
|
+
*/ get forceSequentialIndexing() {
|
|
3117
|
+
return this._forceSequentialIndexing;
|
|
3118
|
+
}
|
|
3119
|
+
/**
|
|
3120
|
+
* Set whether to force sequential account indexing
|
|
3121
|
+
*
|
|
3122
|
+
* When enabled, new accounts will use sequential indexes (0, 1, 2, ...) regardless
|
|
3123
|
+
* of blockchain activity. This is useful for multi-user wallets where each user
|
|
3124
|
+
* needs a unique account even if they haven't used it yet.
|
|
3125
|
+
*
|
|
3126
|
+
* When disabled (default), account creation uses discovery-based indexing which
|
|
3127
|
+
* scans the blockchain for existing activity before assigning indexes.
|
|
3128
|
+
*
|
|
3129
|
+
* @param force - true to force sequential indexing, false for discovery-based
|
|
3130
|
+
*
|
|
3131
|
+
* @example
|
|
3132
|
+
* ```typescript
|
|
3133
|
+
* // Enable sequential indexing for multi-user scenarios
|
|
3134
|
+
* wallet.forceSequentialIndexing = true;
|
|
3135
|
+
*
|
|
3136
|
+
* // Create accounts - they'll be 2.0, 2.1, 2.2 regardless of usage
|
|
3137
|
+
* const alice = await wallet.newAccount(AccountType.DAPP_ACCOUNT);
|
|
3138
|
+
* const bob = await wallet.newAccount(AccountType.DAPP_ACCOUNT);
|
|
3139
|
+
* const charlie = await wallet.newAccount(AccountType.DAPP_ACCOUNT);
|
|
3140
|
+
*
|
|
3141
|
+
* // Disable for normal discovery-based indexing
|
|
3142
|
+
* wallet.forceSequentialIndexing = false;
|
|
3143
|
+
* ```
|
|
3144
|
+
*/ set forceSequentialIndexing(force) {
|
|
3145
|
+
this._forceSequentialIndexing = force;
|
|
3146
|
+
}
|
|
2763
3147
|
}
|
|
2764
3148
|
|
|
2765
3149
|
|
|
@@ -2771,13 +3155,15 @@ class $b76d3bd5024ccfc0$export$2e2bcd8739ae039 {
|
|
|
2771
3155
|
|
|
2772
3156
|
|
|
2773
3157
|
const $52632971edbdb934$var$MAX_INPUTS_OUTPUTS = 250;
|
|
2774
|
-
async function $52632971edbdb934$export$20e004915450ed44(txBuilder, addresses, totalTxValue, options) {
|
|
3158
|
+
async function $52632971edbdb934$export$20e004915450ed44(txBuilder, addresses, totalTxValue, options, spentOutpoints) {
|
|
2775
3159
|
if ((0, $bc5ca2c06b1affa3$export$c8733ae29fb53302)(addresses)) throw new Error("Not enough Nexa balance.");
|
|
2776
3160
|
let usedAddresses = new Set();
|
|
2777
3161
|
let origAmount = options.isConsolidate ? 0 : Number(totalTxValue);
|
|
2778
3162
|
for (let item of addresses){
|
|
2779
3163
|
let utxos = await (0, $b5bfd17fdf06d231$export$eaa49f0478d81b9d).getNexaUtxos(item.address);
|
|
2780
3164
|
for (let utxo of utxos){
|
|
3165
|
+
// Skip if this outpoint is already spent
|
|
3166
|
+
if (spentOutpoints && spentOutpoints.has(utxo.outpoint_hash)) continue;
|
|
2781
3167
|
let input = {
|
|
2782
3168
|
outpoint: utxo.outpoint_hash,
|
|
2783
3169
|
address: item.address,
|
|
@@ -2785,6 +3171,8 @@ async function $52632971edbdb934$export$20e004915450ed44(txBuilder, addresses, t
|
|
|
2785
3171
|
templateData: options.templateData
|
|
2786
3172
|
};
|
|
2787
3173
|
txBuilder.from(input);
|
|
3174
|
+
// Add to spent outpoints set
|
|
3175
|
+
if (spentOutpoints) spentOutpoints.add(utxo.outpoint_hash);
|
|
2788
3176
|
if (!usedAddresses.has(item.address)) usedAddresses.add(item.address);
|
|
2789
3177
|
if (options.isConsolidate) {
|
|
2790
3178
|
// need to handle change
|
|
@@ -2828,7 +3216,7 @@ async function $52632971edbdb934$export$20e004915450ed44(txBuilder, addresses, t
|
|
|
2828
3216
|
};
|
|
2829
3217
|
throw new Error(JSON.stringify(err));
|
|
2830
3218
|
}
|
|
2831
|
-
async function $52632971edbdb934$export$49bc96b87058cba4(txBuilder, addresses, token, outTokenAmount) {
|
|
3219
|
+
async function $52632971edbdb934$export$49bc96b87058cba4(txBuilder, addresses, token, outTokenAmount, spentOutpoints) {
|
|
2832
3220
|
if ((0, $bc5ca2c06b1affa3$export$c8733ae29fb53302)(addresses)) throw new Error("Not enough token balance.");
|
|
2833
3221
|
let usedKeys = new Set();
|
|
2834
3222
|
let inTokenAmount = 0n;
|
|
@@ -2836,6 +3224,8 @@ async function $52632971edbdb934$export$49bc96b87058cba4(txBuilder, addresses, t
|
|
|
2836
3224
|
let utxos = await (0, $b5bfd17fdf06d231$export$eaa49f0478d81b9d).getTokenUtxos(item.address, token);
|
|
2837
3225
|
for (let utxo of utxos){
|
|
2838
3226
|
if (utxo.token_amount < 0) continue;
|
|
3227
|
+
// Skip if this outpoint is already spent
|
|
3228
|
+
if (spentOutpoints && spentOutpoints.has(utxo.outpoint_hash)) continue;
|
|
2839
3229
|
txBuilder.from({
|
|
2840
3230
|
outpoint: utxo.outpoint_hash,
|
|
2841
3231
|
address: item.address,
|
|
@@ -2843,6 +3233,8 @@ async function $52632971edbdb934$export$49bc96b87058cba4(txBuilder, addresses, t
|
|
|
2843
3233
|
groupId: utxo.group,
|
|
2844
3234
|
groupAmount: BigInt(utxo.token_amount)
|
|
2845
3235
|
});
|
|
3236
|
+
// Add to spent outpoints set
|
|
3237
|
+
if (spentOutpoints) spentOutpoints.add(utxo.outpoint_hash);
|
|
2846
3238
|
inTokenAmount = inTokenAmount + BigInt(utxo.token_amount);
|
|
2847
3239
|
if (!usedKeys.has(item.address)) usedKeys.add(item.address);
|
|
2848
3240
|
if (inTokenAmount > (0, $bc5ca2c06b1affa3$export$8ba128bc85947a2a)) throw new Error("Token inputs exceeded max amount. Consider sending in small chunks");
|
|
@@ -2857,17 +3249,21 @@ async function $52632971edbdb934$export$49bc96b87058cba4(txBuilder, addresses, t
|
|
|
2857
3249
|
}
|
|
2858
3250
|
throw new Error("Not enough token balance");
|
|
2859
3251
|
}
|
|
2860
|
-
async function $52632971edbdb934$export$74e83de914f372c5(txBuilder, addresses, opReturnData, network) {
|
|
3252
|
+
async function $52632971edbdb934$export$74e83de914f372c5(txBuilder, addresses, opReturnData, network, spentOutpoints) {
|
|
2861
3253
|
let outpoint = '';
|
|
2862
3254
|
let usedKeys = [];
|
|
2863
3255
|
for (let item of addresses){
|
|
2864
3256
|
let utxos = await (0, $b5bfd17fdf06d231$export$eaa49f0478d81b9d).getNexaUtxos(item.address);
|
|
2865
3257
|
for (let utxo of utxos){
|
|
3258
|
+
// Skip if this outpoint is already spent
|
|
3259
|
+
if (spentOutpoints && spentOutpoints.has(utxo.outpoint_hash)) continue;
|
|
2866
3260
|
txBuilder.from({
|
|
2867
3261
|
outpoint: utxo.outpoint_hash,
|
|
2868
3262
|
address: item.address,
|
|
2869
3263
|
satoshis: utxo.value
|
|
2870
3264
|
});
|
|
3265
|
+
// Add to spent outpoints set
|
|
3266
|
+
if (spentOutpoints) spentOutpoints.add(utxo.outpoint_hash);
|
|
2871
3267
|
if ((0, $bc5ca2c06b1affa3$export$c8733ae29fb53302)(outpoint) && !utxo.has_token) {
|
|
2872
3268
|
outpoint = utxo.outpoint_hash;
|
|
2873
3269
|
let id = (0, $l50U0$libnexats.GroupToken).findGroupId(outpoint, Buffer.from(opReturnData, 'hex'), (0, $l50U0$libnexats.GroupToken).authFlags.ACTIVE_FLAG_BITS);
|
|
@@ -2894,16 +3290,20 @@ async function $52632971edbdb934$export$1eb54f2f084fd3c6(txBuilder, addresses, o
|
|
|
2894
3290
|
addrKey.address
|
|
2895
3291
|
];
|
|
2896
3292
|
}
|
|
2897
|
-
async function $52632971edbdb934$export$d7c9c386067a6463(txBuilder, addresses, token, perm, subgroup = '', quantity) {
|
|
3293
|
+
async function $52632971edbdb934$export$d7c9c386067a6463(txBuilder, addresses, token, perm, subgroup = '', quantity, spentOutpoints) {
|
|
2898
3294
|
for (let item of addresses){
|
|
2899
3295
|
let utxos = await (0, $b5bfd17fdf06d231$export$eaa49f0478d81b9d).getTokenUtxos(item.address, token);
|
|
2900
3296
|
for (let utxo of utxos){
|
|
2901
3297
|
if (!(0, $22e282633cad8f97$export$7f7cffd29bf2d96d)(utxo.token_amount, perm)) continue;
|
|
3298
|
+
// Skip if this outpoint is already spent
|
|
3299
|
+
if (spentOutpoints && spentOutpoints.has(utxo.outpoint_hash)) continue;
|
|
2902
3300
|
txBuilder.from({
|
|
2903
3301
|
outpoint: utxo.outpoint_hash,
|
|
2904
3302
|
address: item.address,
|
|
2905
3303
|
satoshis: utxo.value
|
|
2906
3304
|
});
|
|
3305
|
+
// Add to spent outpoints set
|
|
3306
|
+
if (spentOutpoints) spentOutpoints.add(utxo.outpoint_hash);
|
|
2907
3307
|
if (perm === 'subgroup') {
|
|
2908
3308
|
const subgroupQuantity = quantity ?? (0, $22e282633cad8f97$export$636fb0b03b94ac81)(utxo.token_amount, false);
|
|
2909
3309
|
txBuilder.to(item.address, (0, $l50U0$libnexats.Transaction).DUST_AMOUNT, subgroup, subgroupQuantity);
|
|
@@ -2917,7 +3317,7 @@ async function $52632971edbdb934$export$d7c9c386067a6463(txBuilder, addresses, t
|
|
|
2917
3317
|
}
|
|
2918
3318
|
throw new Error("The requested authority not found");
|
|
2919
3319
|
}
|
|
2920
|
-
async function $52632971edbdb934$export$5c44e04d8c04c292(txBuilder, addresses, token, perms, toAddr) {
|
|
3320
|
+
async function $52632971edbdb934$export$5c44e04d8c04c292(txBuilder, addresses, token, perms, toAddr, spentOutpoints) {
|
|
2921
3321
|
let usedAddresses = [];
|
|
2922
3322
|
let reqiredPerms = new Set(perms);
|
|
2923
3323
|
reqiredPerms.add('authorise');
|
|
@@ -2925,6 +3325,8 @@ async function $52632971edbdb934$export$5c44e04d8c04c292(txBuilder, addresses, t
|
|
|
2925
3325
|
let utxos = await (0, $b5bfd17fdf06d231$export$eaa49f0478d81b9d).getTokenUtxos(item.address, token);
|
|
2926
3326
|
for (let utxo of utxos){
|
|
2927
3327
|
if (utxo.token_amount > 0) continue;
|
|
3328
|
+
// Skip if this outpoint is already spent
|
|
3329
|
+
if (spentOutpoints && spentOutpoints.has(utxo.outpoint_hash)) continue;
|
|
2928
3330
|
let found = false;
|
|
2929
3331
|
for (let perm of reqiredPerms)if ((0, $22e282633cad8f97$export$7f7cffd29bf2d96d)(utxo.token_amount, perm)) {
|
|
2930
3332
|
reqiredPerms.delete(perm);
|
|
@@ -2937,6 +3339,8 @@ async function $52632971edbdb934$export$5c44e04d8c04c292(txBuilder, addresses, t
|
|
|
2937
3339
|
satoshis: utxo.value
|
|
2938
3340
|
});
|
|
2939
3341
|
usedAddresses.push(item.address);
|
|
3342
|
+
// Add to spent outpoints set
|
|
3343
|
+
if (spentOutpoints) spentOutpoints.add(utxo.outpoint_hash);
|
|
2940
3344
|
// duplicate
|
|
2941
3345
|
txBuilder.to(toAddr != null ? toAddr : item.address, (0, $l50U0$libnexats.Transaction).DUST_AMOUNT, token, (0, $22e282633cad8f97$export$636fb0b03b94ac81)(utxo.token_amount));
|
|
2942
3346
|
if (reqiredPerms.size === 0) return usedAddresses;
|
|
@@ -2948,7 +3352,6 @@ async function $52632971edbdb934$export$5c44e04d8c04c292(txBuilder, addresses, t
|
|
|
2948
3352
|
|
|
2949
3353
|
|
|
2950
3354
|
|
|
2951
|
-
|
|
2952
3355
|
class $2ce5b75d10954bb1$export$2e2bcd8739ae039 extends (0, $57b0117fe8233fef$export$bba690fb5c12ba04) {
|
|
2953
3356
|
/**
|
|
2954
3357
|
* Creates a new WatchOnlyTransactionCreator
|
|
@@ -3018,22 +3421,22 @@ class $2ce5b75d10954bb1$export$2e2bcd8739ae039 extends (0, $57b0117fe8233fef$exp
|
|
|
3018
3421
|
// Process token operations if any are configured
|
|
3019
3422
|
if (this.tokens.size > 0) for (const tokenAction of this.tokens){
|
|
3020
3423
|
if (tokenAction.action == 'mint' || tokenAction.action == 'melt') // Handle token minting/melting - requires authority
|
|
3021
|
-
tokenAddresses = tokenAddresses.concat(await (0, $52632971edbdb934$export$d7c9c386067a6463)(this.transactionBuilder, this._availableAddresses, tokenAction.token, tokenAction.action));
|
|
3424
|
+
tokenAddresses = tokenAddresses.concat(await (0, $52632971edbdb934$export$d7c9c386067a6463)(this.transactionBuilder, this._availableAddresses, tokenAction.token, tokenAction.action, undefined, undefined, this.spentOutpoints));
|
|
3022
3425
|
else if (tokenAction.action == 'group') // Handle group token creation
|
|
3023
|
-
tokenAddresses = tokenAddresses.concat(await (0, $52632971edbdb934$export$74e83de914f372c5)(this.transactionBuilder, this._availableAddresses, tokenAction.extraData?.opReturnData, this.network));
|
|
3426
|
+
tokenAddresses = tokenAddresses.concat(await (0, $52632971edbdb934$export$74e83de914f372c5)(this.transactionBuilder, this._availableAddresses, tokenAction.extraData?.opReturnData, this.network, this.spentOutpoints));
|
|
3024
3427
|
else if (tokenAction.action == 'subgroup') // Handle subgroup token creation
|
|
3025
|
-
tokenAddresses = tokenAddresses.concat(await (0, $52632971edbdb934$export$d7c9c386067a6463)(this.transactionBuilder, this._availableAddresses, tokenAction.parentToken, tokenAction.action, tokenAction.token, tokenAction.extraData?.quantity));
|
|
3428
|
+
tokenAddresses = tokenAddresses.concat(await (0, $52632971edbdb934$export$d7c9c386067a6463)(this.transactionBuilder, this._availableAddresses, tokenAction.parentToken, tokenAction.action, tokenAction.token, tokenAction.extraData?.quantity, this.spentOutpoints));
|
|
3026
3429
|
else if (tokenAction.action == 'renew') // Handle authority renewal
|
|
3027
|
-
tokenAddresses = tokenAddresses.concat(await (0, $52632971edbdb934$export$5c44e04d8c04c292)(this.transactionBuilder, this._availableAddresses, tokenAction.token, tokenAction.extraData.perms, tokenAction.extraData?.address));
|
|
3430
|
+
tokenAddresses = tokenAddresses.concat(await (0, $52632971edbdb934$export$5c44e04d8c04c292)(this.transactionBuilder, this._availableAddresses, tokenAction.token, tokenAction.extraData.perms, tokenAction.extraData?.address, this.spentOutpoints));
|
|
3028
3431
|
else if (tokenAction.action == 'delete') // Handle authority deletion
|
|
3029
3432
|
tokenAddresses = tokenAddresses.concat(await (0, $52632971edbdb934$export$1eb54f2f084fd3c6)(this.transactionBuilder, this._availableAddresses, tokenAction.extraData.outpoint));
|
|
3030
3433
|
else // Handle regular token transfers
|
|
3031
|
-
tokenAddresses = tokenAddresses.concat(await (0, $52632971edbdb934$export$49bc96b87058cba4)(this.transactionBuilder, this._availableAddresses, tokenAction.token, tokenAction.amount));
|
|
3434
|
+
tokenAddresses = tokenAddresses.concat(await (0, $52632971edbdb934$export$49bc96b87058cba4)(this.transactionBuilder, this._availableAddresses, tokenAction.token, tokenAction.amount, this.spentOutpoints));
|
|
3032
3435
|
// Accumulate addresses that need signing
|
|
3033
3436
|
this._addressesToSignWith.concat(tokenAddresses);
|
|
3034
3437
|
}
|
|
3035
3438
|
// Populate NEXA inputs for transaction fees and change
|
|
3036
|
-
nexaAddresses = nexaAddresses.concat(await (0, $52632971edbdb934$export$20e004915450ed44)(this.transactionBuilder, this._availableAddresses, this.totalValue, this.txOptions));
|
|
3439
|
+
nexaAddresses = nexaAddresses.concat(await (0, $52632971edbdb934$export$20e004915450ed44)(this.transactionBuilder, this._availableAddresses, this.totalValue, this.txOptions, this.spentOutpoints));
|
|
3037
3440
|
// Combine all addresses that need signing
|
|
3038
3441
|
this._addressesToSignWith = tokenAddresses.concat(nexaAddresses);
|
|
3039
3442
|
});
|
|
@@ -3051,27 +3454,21 @@ class $2ce5b75d10954bb1$export$2e2bcd8739ae039 extends (0, $57b0117fe8233fef$exp
|
|
|
3051
3454
|
return this;
|
|
3052
3455
|
}
|
|
3053
3456
|
/**
|
|
3054
|
-
* Parse transaction from hex string
|
|
3457
|
+
* Parse transaction from hex string using enhanced base class implementation
|
|
3055
3458
|
* @param tx Transaction hex string
|
|
3056
3459
|
* @returns This instance for chaining
|
|
3057
|
-
* @throws Error indicating method not implemented
|
|
3058
3460
|
*/ parseTxHex(tx) {
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
|
|
3063
|
-
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
|
|
3068
|
-
|
|
3069
|
-
|
|
3070
|
-
}
|
|
3071
|
-
newTxBuilder.transaction.outputs = txBuilder.transaction.outputs;
|
|
3072
|
-
this.transactionBuilder = newTxBuilder;
|
|
3073
|
-
});
|
|
3074
|
-
return this;
|
|
3461
|
+
// Call parent's parseTxHex which handles script template reconstruction
|
|
3462
|
+
return super.parseTxHex(tx);
|
|
3463
|
+
}
|
|
3464
|
+
/**
|
|
3465
|
+
* Handle watch-only specific logic for each parsed input (track addresses for signing)
|
|
3466
|
+
*/ async handleParsedInput(_input, utxo, _index) {
|
|
3467
|
+
// Track addresses that will need to be signed with external wallet
|
|
3468
|
+
if (utxo.addresses && utxo.addresses.length > 0) {
|
|
3469
|
+
const address = utxo.addresses[0];
|
|
3470
|
+
if (!this._addressesToSignWith.includes(address)) this._addressesToSignWith.push(address);
|
|
3471
|
+
}
|
|
3075
3472
|
}
|
|
3076
3473
|
}
|
|
3077
3474
|
|
|
@@ -3250,6 +3647,39 @@ const $7af6fdca1cf5d9d6$export$618de809a659cb44 = {
|
|
|
3250
3647
|
};
|
|
3251
3648
|
|
|
3252
3649
|
|
|
3650
|
+
/**
|
|
3651
|
+
* Extract all token outputs and amounts from transaction hex
|
|
3652
|
+
* @param txHex - Transaction hex string
|
|
3653
|
+
* @param network - Network to use for token address creation
|
|
3654
|
+
* @returns Array of token outputs with tokenId and amount
|
|
3655
|
+
*/ const $23698d921173fdf9$var$getTokenOutputsFromTx = (txHex, network)=>{
|
|
3656
|
+
const tokenOutputs = [];
|
|
3657
|
+
try {
|
|
3658
|
+
const transaction = new (0, $l50U0$libnexats.Transaction)(txHex);
|
|
3659
|
+
for (const output of transaction.outputs)if (output.type !== 0 && output.scriptPubKey.chunks[0]?.opcodenum >= 32) {
|
|
3660
|
+
const tokenIdHex = output.scriptPubKey.chunks[0].buf?.toString('hex');
|
|
3661
|
+
if (tokenIdHex && output.scriptPubKey.chunks[1]?.buf) {
|
|
3662
|
+
const tokenAddress = (0, $l50U0$libnexats.Address).fromObject({
|
|
3663
|
+
data: tokenIdHex,
|
|
3664
|
+
network: network.toString(),
|
|
3665
|
+
type: (0, $l50U0$libnexats.AddressType).GroupIdAddress
|
|
3666
|
+
});
|
|
3667
|
+
if (tokenAddress !== null) {
|
|
3668
|
+
const tokenAddressStr = tokenAddress.toString();
|
|
3669
|
+
// Extract token amount
|
|
3670
|
+
const tokenAmount = (0, $l50U0$libnexats.BNExtended).fromScriptNumBuffer(output.scriptPubKey.chunks[1].buf, false, 8).toBigInt();
|
|
3671
|
+
tokenOutputs.push({
|
|
3672
|
+
tokenId: tokenAddressStr,
|
|
3673
|
+
amount: tokenAmount.toString()
|
|
3674
|
+
});
|
|
3675
|
+
}
|
|
3676
|
+
}
|
|
3677
|
+
}
|
|
3678
|
+
} catch (error) {
|
|
3679
|
+
console.warn('Failed to extract token data from transaction:', error);
|
|
3680
|
+
}
|
|
3681
|
+
return tokenOutputs;
|
|
3682
|
+
};
|
|
3253
3683
|
class $23698d921173fdf9$export$11e896a2f3ae4119 {
|
|
3254
3684
|
constructor(wallet, approvalCallbacks){
|
|
3255
3685
|
this.provider = null;
|
|
@@ -3389,23 +3819,23 @@ class $23698d921173fdf9$export$11e896a2f3ae4119 {
|
|
|
3389
3819
|
// If parsing fails, keep default "Unknown" values
|
|
3390
3820
|
console.warn('Failed to parse transaction for approval details:', error);
|
|
3391
3821
|
}
|
|
3822
|
+
// Extract token outputs from transaction hex
|
|
3823
|
+
const tokenOutputs = $23698d921173fdf9$var$getTokenOutputsFromTx(request.hex, this.wallet.network);
|
|
3392
3824
|
const approvalDetails = {
|
|
3393
3825
|
dApp: this.connectedDApp,
|
|
3394
3826
|
account: request.account,
|
|
3395
3827
|
transactionHex: request.hex,
|
|
3396
3828
|
broadcast: request.broadcast || false,
|
|
3397
|
-
sighashSpec: request.sighashSpec,
|
|
3398
3829
|
totalAmount: totalAmount,
|
|
3399
|
-
fees: fees
|
|
3830
|
+
fees: fees,
|
|
3831
|
+
tokenOutputs: tokenOutputs.length > 0 ? tokenOutputs : undefined
|
|
3400
3832
|
};
|
|
3401
3833
|
const approved = await this.approvalCallbacks.approveTransaction(approvalDetails);
|
|
3402
3834
|
if (!approved) throw new (0, $l50U0$walletcommssdk.JsonRpcError)((0, $l50U0$walletcommssdk.JsonRpcErrorCode).RequestRejected, 'Transaction signing rejected by user');
|
|
3403
3835
|
}
|
|
3404
3836
|
// Parse and sign the transaction
|
|
3405
3837
|
let txBuilder = this.wallet.newTransaction(account, request.hex);
|
|
3406
|
-
|
|
3407
|
-
if (request.sighashSpec) txBuilder = txBuilder.signWithSpec(request.sighashSpec);
|
|
3408
|
-
else txBuilder = txBuilder.sign();
|
|
3838
|
+
txBuilder = txBuilder.sign();
|
|
3409
3839
|
const tx = await txBuilder.build();
|
|
3410
3840
|
// Broadcast if requested
|
|
3411
3841
|
if (request.broadcast) return await this.wallet.sendTransaction(tx); // Return just the txId string
|
|
@@ -3581,12 +4011,12 @@ class $4d217697e55d958e$export$80793d8292a1630a {
|
|
|
3581
4011
|
*/ async sendTransaction(toAddress, amount, opReturnData, broadcast = true) {
|
|
3582
4012
|
if (!this.watchOnlyWallet || !this.connectedWalletAddress) throw new Error('No wallet connected');
|
|
3583
4013
|
// Create unsigned transaction using WatchOnlyWallet
|
|
3584
|
-
let txBuilder = this.watchOnlyWallet.newTransaction().
|
|
4014
|
+
let txBuilder = this.watchOnlyWallet.newTransaction().sendTo(toAddress, amount);
|
|
3585
4015
|
// Add OP_RETURN data if provided
|
|
3586
4016
|
if (opReturnData) txBuilder = txBuilder.addOpReturn(opReturnData);
|
|
3587
4017
|
// Populate and build unsigned transaction
|
|
3588
4018
|
const unsignedTx = await txBuilder.populate().build();
|
|
3589
|
-
return await this.provider.signTransaction(this.connectedWalletAddress, unsignedTx,
|
|
4019
|
+
return await this.provider.signTransaction(this.connectedWalletAddress, unsignedTx, broadcast);
|
|
3590
4020
|
}
|
|
3591
4021
|
/**
|
|
3592
4022
|
* Send tokens to an address
|
|
@@ -3599,12 +4029,12 @@ class $4d217697e55d958e$export$80793d8292a1630a {
|
|
|
3599
4029
|
*/ async sendTokenTransaction(toAddress, amount, tokenId, opReturnData, broadcast = true) {
|
|
3600
4030
|
if (!this.watchOnlyWallet || !this.connectedWalletAddress) throw new Error('No wallet connected');
|
|
3601
4031
|
// Create unsigned token transaction
|
|
3602
|
-
let txBuilder = this.watchOnlyWallet.newTransaction().
|
|
4032
|
+
let txBuilder = this.watchOnlyWallet.newTransaction().sendToToken(toAddress, amount, tokenId);
|
|
3603
4033
|
// Add OP_RETURN data if provided
|
|
3604
4034
|
if (opReturnData) txBuilder = txBuilder.addOpReturn(opReturnData);
|
|
3605
4035
|
// Populate and build unsigned transaction
|
|
3606
4036
|
const unsignedTx = await txBuilder.populate().build();
|
|
3607
|
-
return await this.provider.signTransaction(this.connectedWalletAddress, unsignedTx,
|
|
4037
|
+
return await this.provider.signTransaction(this.connectedWalletAddress, unsignedTx, broadcast);
|
|
3608
4038
|
}
|
|
3609
4039
|
/**
|
|
3610
4040
|
* Create and mint a new token
|
|
@@ -3618,8 +4048,8 @@ class $4d217697e55d958e$export$80793d8292a1630a {
|
|
|
3618
4048
|
*/ async createToken(name, ticker, decimals, docUrl, docHash, broadcast = true) {
|
|
3619
4049
|
if (!this.watchOnlyWallet || !this.connectedWalletAddress) throw new Error('No wallet connected');
|
|
3620
4050
|
// Create token creation transaction
|
|
3621
|
-
const unsignedTx = await this.watchOnlyWallet.newTransaction().
|
|
3622
|
-
return await this.provider.signTransaction(this.connectedWalletAddress, unsignedTx,
|
|
4051
|
+
const unsignedTx = await this.watchOnlyWallet.newTransaction().token(name, ticker, decimals, docUrl, docHash).populate().build();
|
|
4052
|
+
return await this.provider.signTransaction(this.connectedWalletAddress, unsignedTx, broadcast);
|
|
3623
4053
|
}
|
|
3624
4054
|
/**
|
|
3625
4055
|
* Create and mint a new NFT collection
|
|
@@ -3632,8 +4062,8 @@ class $4d217697e55d958e$export$80793d8292a1630a {
|
|
|
3632
4062
|
*/ async createCollection(name, ticker, docUrl, docHash, broadcast = true) {
|
|
3633
4063
|
if (!this.watchOnlyWallet || !this.connectedWalletAddress) throw new Error('No wallet connected');
|
|
3634
4064
|
// Create collection creation transaction
|
|
3635
|
-
const unsignedTx = await this.watchOnlyWallet.newTransaction().
|
|
3636
|
-
return await this.provider.signTransaction(this.connectedWalletAddress, unsignedTx,
|
|
4065
|
+
const unsignedTx = await this.watchOnlyWallet.newTransaction().collection(name, ticker, docUrl, docHash).populate().build();
|
|
4066
|
+
return await this.provider.signTransaction(this.connectedWalletAddress, unsignedTx, broadcast);
|
|
3637
4067
|
}
|
|
3638
4068
|
/**
|
|
3639
4069
|
* Create and mint an NFT within a collection
|
|
@@ -3645,8 +4075,8 @@ class $4d217697e55d958e$export$80793d8292a1630a {
|
|
|
3645
4075
|
*/ async createNFT(parentCollection, zipUrl, zipHash, broadcast = true) {
|
|
3646
4076
|
if (!this.watchOnlyWallet || !this.connectedWalletAddress) throw new Error('No wallet connected');
|
|
3647
4077
|
// Create NFT creation transaction
|
|
3648
|
-
const unsignedTx = await this.watchOnlyWallet.newTransaction().
|
|
3649
|
-
return await this.provider.signTransaction(this.connectedWalletAddress, unsignedTx,
|
|
4078
|
+
const unsignedTx = await this.watchOnlyWallet.newTransaction().nft(parentCollection, zipUrl, zipHash).populate().build();
|
|
4079
|
+
return await this.provider.signTransaction(this.connectedWalletAddress, unsignedTx, broadcast);
|
|
3650
4080
|
}
|
|
3651
4081
|
/**
|
|
3652
4082
|
* Create and mint an SFT (Semi-Fungible Token) within a collection with specified quantity
|
|
@@ -3659,8 +4089,85 @@ class $4d217697e55d958e$export$80793d8292a1630a {
|
|
|
3659
4089
|
*/ async createSFT(parentCollection, zipUrl, zipHash, quantity, broadcast = true) {
|
|
3660
4090
|
if (!this.watchOnlyWallet || !this.connectedWalletAddress) throw new Error('No wallet connected');
|
|
3661
4091
|
// Create SFT creation transaction
|
|
3662
|
-
const unsignedTx = await this.watchOnlyWallet.newTransaction().
|
|
3663
|
-
return await this.provider.signTransaction(this.connectedWalletAddress, unsignedTx,
|
|
4092
|
+
const unsignedTx = await this.watchOnlyWallet.newTransaction().sft(parentCollection, zipUrl, zipHash, quantity).populate().build();
|
|
4093
|
+
return await this.provider.signTransaction(this.connectedWalletAddress, unsignedTx, broadcast);
|
|
4094
|
+
}
|
|
4095
|
+
/**
|
|
4096
|
+
* Sign an arbitrary unsigned transaction
|
|
4097
|
+
* @param unsignedTx Unsigned transaction hex string
|
|
4098
|
+
* @param sighashSpec Optional sighash specification for selective signing
|
|
4099
|
+
* @param broadcast Whether to broadcast immediately (default false)
|
|
4100
|
+
* @returns Promise resolving to transaction ID (if broadcast) or signed hex
|
|
4101
|
+
*/ async signTransaction(unsignedTx, sighashSpec, broadcast = false) {
|
|
4102
|
+
if (!this.connectedWalletAddress) throw new Error('No wallet connected');
|
|
4103
|
+
return await this.provider.signTransaction(this.connectedWalletAddress, unsignedTx, broadcast);
|
|
4104
|
+
}
|
|
4105
|
+
/**
|
|
4106
|
+
* Build an unsigned transaction without signing
|
|
4107
|
+
* @param toAddress Destination address
|
|
4108
|
+
* @param amount Amount in satoshis (as string)
|
|
4109
|
+
* @param tokenId Optional token ID for token transfers
|
|
4110
|
+
* @param opReturnData Optional OP_RETURN data
|
|
4111
|
+
* @returns Promise resolving to unsigned transaction hex
|
|
4112
|
+
*/ async buildTransaction(toAddress, amount, tokenId, opReturnData) {
|
|
4113
|
+
if (!this.watchOnlyWallet) throw new Error('No wallet connected');
|
|
4114
|
+
let txBuilder = this.watchOnlyWallet.newTransaction();
|
|
4115
|
+
if (tokenId) txBuilder = txBuilder.sendToToken(toAddress, amount, tokenId);
|
|
4116
|
+
else txBuilder = txBuilder.sendTo(toAddress, amount);
|
|
4117
|
+
if (opReturnData) txBuilder = txBuilder.addOpReturn(opReturnData);
|
|
4118
|
+
return await txBuilder.populate().build();
|
|
4119
|
+
}
|
|
4120
|
+
/**
|
|
4121
|
+
* Build an unsigned token creation transaction
|
|
4122
|
+
* @param name Token name
|
|
4123
|
+
* @param ticker Token ticker symbol
|
|
4124
|
+
* @param decimals Number of decimal places
|
|
4125
|
+
* @param docUrl URL to token documentation
|
|
4126
|
+
* @param docHash Hash of token documentation
|
|
4127
|
+
* @returns Promise resolving to unsigned transaction hex
|
|
4128
|
+
*/ async buildTokenCreation(name, ticker, decimals, docUrl, docHash) {
|
|
4129
|
+
if (!this.watchOnlyWallet) throw new Error('No wallet connected');
|
|
4130
|
+
return await this.watchOnlyWallet.newTransaction().token(name, ticker, decimals, docUrl, docHash).populate().build();
|
|
4131
|
+
}
|
|
4132
|
+
/**
|
|
4133
|
+
* Build an unsigned collection creation transaction
|
|
4134
|
+
* @param name Collection name
|
|
4135
|
+
* @param ticker Collection ticker symbol
|
|
4136
|
+
* @param docUrl URL to collection documentation
|
|
4137
|
+
* @param docHash Hash of collection documentation
|
|
4138
|
+
* @returns Promise resolving to unsigned transaction hex
|
|
4139
|
+
*/ async buildCollectionCreation(name, ticker, docUrl, docHash) {
|
|
4140
|
+
if (!this.watchOnlyWallet) throw new Error('No wallet connected');
|
|
4141
|
+
return await this.watchOnlyWallet.newTransaction().collection(name, ticker, docUrl, docHash).populate().build();
|
|
4142
|
+
}
|
|
4143
|
+
/**
|
|
4144
|
+
* Build an unsigned NFT creation transaction
|
|
4145
|
+
* @param parentCollection Parent collection token ID
|
|
4146
|
+
* @param zipUrl URL to NFT content ZIP file
|
|
4147
|
+
* @param zipHash Hash of NFT content ZIP file
|
|
4148
|
+
* @returns Promise resolving to unsigned transaction hex
|
|
4149
|
+
*/ async buildNFTCreation(parentCollection, zipUrl, zipHash) {
|
|
4150
|
+
if (!this.watchOnlyWallet) throw new Error('No wallet connected');
|
|
4151
|
+
return await this.watchOnlyWallet.newTransaction().nft(parentCollection, zipUrl, zipHash).populate().build();
|
|
4152
|
+
}
|
|
4153
|
+
/**
|
|
4154
|
+
* Build an unsigned SFT creation transaction
|
|
4155
|
+
* @param parentCollection Parent collection token ID
|
|
4156
|
+
* @param zipUrl URL to SFT content ZIP file
|
|
4157
|
+
* @param zipHash Hash of SFT content ZIP file
|
|
4158
|
+
* @param quantity Quantity of SFTs to create
|
|
4159
|
+
* @returns Promise resolving to unsigned transaction hex
|
|
4160
|
+
*/ async buildSFTCreation(parentCollection, zipUrl, zipHash, quantity) {
|
|
4161
|
+
if (!this.watchOnlyWallet) throw new Error('No wallet connected');
|
|
4162
|
+
return await this.watchOnlyWallet.newTransaction().sft(parentCollection, zipUrl, zipHash, quantity).populate().build();
|
|
4163
|
+
}
|
|
4164
|
+
/**
|
|
4165
|
+
* Initialize WatchOnlyWallet with multiple addresses
|
|
4166
|
+
* @param addresses Array of addresses to watch
|
|
4167
|
+
*/ initializeWatchOnly(addresses) {
|
|
4168
|
+
this.watchOnlyWallet = new (0, $f4ad400261a08cba$export$2e2bcd8739ae039)(addresses.map((addr)=>({
|
|
4169
|
+
address: addr
|
|
4170
|
+
})), this.currentNetwork);
|
|
3664
4171
|
}
|
|
3665
4172
|
/**
|
|
3666
4173
|
* Create a custom unsigned transaction
|
|
@@ -3671,10 +4178,10 @@ class $4d217697e55d958e$export$80793d8292a1630a {
|
|
|
3671
4178
|
*/ async createCustomTransaction(txBuilder, sighashSpec, broadcast = true) {
|
|
3672
4179
|
if (!this.watchOnlyWallet || !this.connectedWalletAddress) throw new Error('No wallet connected');
|
|
3673
4180
|
// Create custom transaction using provided builder function
|
|
3674
|
-
const builder = this.watchOnlyWallet.newTransaction()
|
|
4181
|
+
const builder = this.watchOnlyWallet.newTransaction();
|
|
3675
4182
|
const configuredBuilder = txBuilder(builder);
|
|
3676
4183
|
const unsignedTx = await configuredBuilder.populate().build();
|
|
3677
|
-
return await this.provider.signTransaction(this.connectedWalletAddress, unsignedTx,
|
|
4184
|
+
return await this.provider.signTransaction(this.connectedWalletAddress, unsignedTx, broadcast);
|
|
3678
4185
|
}
|
|
3679
4186
|
/**
|
|
3680
4187
|
* Sign a message with the connected wallet
|