mainnet-js 1.1.0 → 1.1.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.
@@ -7,7 +7,13 @@ import { DERIVATION_PATHS, DUST_UTXO_THRESHOLD as DUST } from "../constant";
7
7
  import { delay } from "../util/delay";
8
8
  import { OpReturnData, SendResponse } from "./model";
9
9
  import { ElectrumRawTransaction } from "../network/interface";
10
- import { binToHex, hexToBin, utf8ToBin } from "@bitauth/libauth";
10
+ import {
11
+ binToHex,
12
+ binsAreEqual,
13
+ decodeTransaction,
14
+ hexToBin,
15
+ utf8ToBin,
16
+ } from "@bitauth/libauth";
11
17
  import { mine } from "../mine";
12
18
  import ElectrumNetworkProvider from "../network/ElectrumNetworkProvider";
13
19
 
@@ -1114,4 +1120,98 @@ describe(`Wallet extrema behavior regression testing`, () => {
1114
1120
  (await bob.getMaxAmountToSend({ options: { slpSemiAware: false } })).sat
1115
1121
  ).toBeLessThanOrEqual(546);
1116
1122
  });
1123
+
1124
+ test("Should encode unsigned transactions", async () => {
1125
+ const aliceWif = `wif:regtest:${process.env.PRIVATE_WIF!}`;
1126
+ const aliceWallet = await RegTestWallet.fromId(aliceWif);
1127
+ const bobWallet = await RegTestWallet.newRandom();
1128
+ aliceWallet.privateKey = undefined;
1129
+
1130
+ const aliceUtxos = await aliceWallet.getAddressUtxos();
1131
+
1132
+ {
1133
+ const { encodedTransaction, sourceOutputs } =
1134
+ await aliceWallet.encodeTransaction(
1135
+ [
1136
+ {
1137
+ cashaddr: bobWallet.cashaddr!,
1138
+ value: 2000,
1139
+ unit: "satoshis",
1140
+ },
1141
+ ],
1142
+ false,
1143
+ { buildUnsigned: true }
1144
+ );
1145
+ expect(encodedTransaction.length).toBeGreaterThan(0);
1146
+
1147
+ // check transaction was not submitted
1148
+ expect(JSON.stringify(aliceUtxos)).toBe(
1149
+ JSON.stringify(await aliceWallet.getAddressUtxos())
1150
+ );
1151
+
1152
+ const decoded = decodeTransaction(encodedTransaction);
1153
+ if (typeof decoded === "string") {
1154
+ throw decoded;
1155
+ }
1156
+
1157
+ expect(
1158
+ binsAreEqual(decoded.inputs[0].unlockingBytecode, Uint8Array.from([]))
1159
+ ).toBe(true);
1160
+ expect(sourceOutputs.length).toBe(decoded.inputs.length);
1161
+ }
1162
+
1163
+ {
1164
+ const { unsignedTransaction, sourceOutputs } = await aliceWallet.send(
1165
+ [
1166
+ {
1167
+ cashaddr: bobWallet.cashaddr!,
1168
+ value: 2000,
1169
+ unit: "satoshis",
1170
+ },
1171
+ ],
1172
+ { buildUnsigned: true }
1173
+ );
1174
+ const encodedTransaction = hexToBin(unsignedTransaction!);
1175
+ expect(encodedTransaction.length).toBeGreaterThan(0);
1176
+
1177
+ // check transaction was not submitted
1178
+ expect(JSON.stringify(aliceUtxos)).toBe(
1179
+ JSON.stringify(await aliceWallet.getAddressUtxos())
1180
+ );
1181
+
1182
+ const decoded = decodeTransaction(encodedTransaction);
1183
+ if (typeof decoded === "string") {
1184
+ throw decoded;
1185
+ }
1186
+
1187
+ expect(
1188
+ binsAreEqual(decoded.inputs[0].unlockingBytecode, Uint8Array.from([]))
1189
+ ).toBe(true);
1190
+ expect(sourceOutputs!.length).toBe(decoded.inputs.length);
1191
+ }
1192
+
1193
+ {
1194
+ const { unsignedTransaction, sourceOutputs } = await aliceWallet.sendMax(
1195
+ bobWallet.cashaddr!,
1196
+ { buildUnsigned: true }
1197
+ );
1198
+ const encodedTransaction = hexToBin(unsignedTransaction!);
1199
+ expect(encodedTransaction.length).toBeGreaterThan(0);
1200
+
1201
+ // check transaction was not submitted
1202
+ expect(JSON.stringify(aliceUtxos)).toBe(
1203
+ JSON.stringify(await aliceWallet.getAddressUtxos())
1204
+ );
1205
+
1206
+ const decoded = decodeTransaction(encodedTransaction);
1207
+ if (typeof decoded === "string") {
1208
+ throw decoded;
1209
+ }
1210
+
1211
+ expect(
1212
+ binsAreEqual(decoded.inputs[0].unlockingBytecode, Uint8Array.from([]))
1213
+ ).toBe(true);
1214
+ expect(sourceOutputs!.length).toBe(decoded.inputs.length);
1215
+ }
1216
+ });
1117
1217
  });
package/src/wallet/Wif.ts CHANGED
@@ -849,7 +849,7 @@ export class Wallet extends BaseWallet {
849
849
  options: {},
850
850
  }
851
851
  ): Promise<{ value: number; utxos: UtxoI[] }> {
852
- if (!this.privateKey) {
852
+ if (!this.privateKey && params.options?.buildUnsigned !== true) {
853
853
  throw Error("Couldn't get network or private key for wallet.");
854
854
  }
855
855
  if (!this.cashaddr) {
@@ -907,7 +907,8 @@ export class Wallet extends BaseWallet {
907
907
  const fee = await getFeeAmount({
908
908
  utxos: fundingUtxos,
909
909
  sendRequests: sendRequests,
910
- privateKey: this.privateKey,
910
+ privateKey: this.privateKey ?? Uint8Array.from([]),
911
+ sourceAddress: this.cashaddr!,
911
912
  relayFeePerByteInSatoshi: relayFeePerByteInSatoshi,
912
913
  slpOutputs: [],
913
914
  feePaidBy: feePaidBy,
@@ -953,31 +954,33 @@ export class Wallet extends BaseWallet {
953
954
  | SendRequestArray[],
954
955
  options?: SendRequestOptionsI
955
956
  ): Promise<SendResponse> {
956
- let { encodedTransaction, tokenIds } = await this.encodeTransaction(
957
- requests,
958
- undefined,
959
- options
960
- );
957
+ const { encodedTransaction, tokenIds, sourceOutputs } =
958
+ await this.encodeTransaction(requests, undefined, options);
961
959
 
962
- const awaitTransactionPropagation =
963
- !options ||
964
- options.awaitTransactionPropagation === undefined ||
965
- options.awaitTransactionPropagation;
960
+ const resp = new SendResponse({});
961
+ resp.tokenIds = tokenIds;
966
962
 
967
- const txId = await this.submitTransaction(
968
- encodedTransaction,
969
- awaitTransactionPropagation
970
- );
963
+ if (options?.buildUnsigned !== true) {
964
+ const txId = await this.submitTransaction(
965
+ encodedTransaction,
966
+ options?.awaitTransactionPropagation === undefined ||
967
+ options?.awaitTransactionPropagation === true
968
+ );
971
969
 
972
- let resp = new SendResponse({});
973
- resp.txId = txId;
974
- const queryBalance =
975
- !options || options.queryBalance === undefined || options.queryBalance;
976
- if (queryBalance) {
977
- resp.balance = (await this.getBalance()) as BalanceResponse;
970
+ resp.txId = txId;
971
+ resp.explorerUrl = this.explorerUrl(resp.txId);
972
+
973
+ if (
974
+ options?.queryBalance === undefined ||
975
+ options?.queryBalance === true
976
+ ) {
977
+ resp.balance = (await this.getBalance()) as BalanceResponse;
978
+ }
979
+ } else {
980
+ resp.unsignedTransaction = binToHex(encodedTransaction);
981
+ resp.sourceOutputs = sourceOutputs;
978
982
  }
979
- resp.explorerUrl = this.explorerUrl(resp.txId);
980
- resp.tokenIds = tokenIds;
983
+
981
984
  return resp;
982
985
  }
983
986
 
@@ -993,16 +996,7 @@ export class Wallet extends BaseWallet {
993
996
  cashaddr: string,
994
997
  options?: SendRequestOptionsI
995
998
  ): Promise<SendResponse> {
996
- const txId = await this.sendMaxRaw(cashaddr, options);
997
- const queryBalance =
998
- !options || options.queryBalance === undefined || options.queryBalance;
999
- return {
1000
- txId: txId,
1001
- balance: queryBalance
1002
- ? ((await this.getBalance()) as BalanceResponse)
1003
- : undefined,
1004
- explorerUrl: this.explorerUrl(txId),
1005
- };
999
+ return await this.sendMaxRaw(cashaddr, options);
1006
1000
  }
1007
1001
 
1008
1002
  /**
@@ -1016,11 +1010,13 @@ export class Wallet extends BaseWallet {
1016
1010
  private async sendMaxRaw(
1017
1011
  cashaddr: string,
1018
1012
  options?: SendRequestOptionsI
1019
- ): Promise<string> {
1020
- let { value: maxSpendableAmount, utxos } = await this._getMaxAmountToSend({
1021
- outputCount: 1,
1022
- options: options,
1023
- });
1013
+ ): Promise<SendResponse> {
1014
+ const { value: maxSpendableAmount, utxos } = await this._getMaxAmountToSend(
1015
+ {
1016
+ outputCount: 1,
1017
+ options: options,
1018
+ }
1019
+ );
1024
1020
 
1025
1021
  if (!options) {
1026
1022
  options = {};
@@ -1028,28 +1024,40 @@ export class Wallet extends BaseWallet {
1028
1024
 
1029
1025
  options.utxoIds = utxos;
1030
1026
 
1031
- let sendRequest = new SendRequest({
1027
+ const sendRequest = new SendRequest({
1032
1028
  cashaddr: cashaddr,
1033
1029
  value: maxSpendableAmount,
1034
1030
  unit: "sat",
1035
1031
  });
1036
1032
 
1037
- const { encodedTransaction } = await this.encodeTransaction(
1038
- [sendRequest],
1039
- true,
1040
- options
1041
- );
1042
- const awaitTransactionPropagation =
1043
- !options ||
1044
- options.awaitTransactionPropagation === undefined ||
1045
- options.awaitTransactionPropagation;
1046
-
1047
- const txId = await this.submitTransaction(
1048
- encodedTransaction,
1049
- awaitTransactionPropagation
1050
- );
1033
+ const { encodedTransaction, tokenIds, sourceOutputs } =
1034
+ await this.encodeTransaction([sendRequest], true, options);
1035
+
1036
+ const resp = new SendResponse({});
1037
+ resp.tokenIds = tokenIds;
1038
+
1039
+ if (options?.buildUnsigned !== true) {
1040
+ const txId = await this.submitTransaction(
1041
+ encodedTransaction,
1042
+ options?.awaitTransactionPropagation === undefined ||
1043
+ options?.awaitTransactionPropagation === true
1044
+ );
1045
+
1046
+ resp.txId = txId;
1047
+ resp.explorerUrl = this.explorerUrl(resp.txId);
1051
1048
 
1052
- return txId;
1049
+ if (
1050
+ options?.queryBalance === undefined ||
1051
+ options?.queryBalance === true
1052
+ ) {
1053
+ resp.balance = (await this.getBalance()) as BalanceResponse;
1054
+ }
1055
+ } else {
1056
+ resp.unsignedTransaction = binToHex(encodedTransaction);
1057
+ resp.sourceOutputs = sourceOutputs;
1058
+ }
1059
+
1060
+ return resp;
1053
1061
  }
1054
1062
 
1055
1063
  /**
@@ -1070,7 +1078,7 @@ export class Wallet extends BaseWallet {
1070
1078
  ) {
1071
1079
  let sendRequests = asSendRequestObject(requests);
1072
1080
 
1073
- if (!this.privateKey) {
1081
+ if (!this.privateKey && options?.buildUnsigned !== true) {
1074
1082
  throw new Error(
1075
1083
  `Wallet ${this.name} is missing either a network or private key`
1076
1084
  );
@@ -1124,6 +1132,13 @@ export class Wallet extends BaseWallet {
1124
1132
  utxos = utxos.filter((val) => !val.token);
1125
1133
  }
1126
1134
 
1135
+ // let tokenOp: "send" | "genesis" | "mint" | "burn" | undefined = undefined;
1136
+ // if (options?.ensureUtxos?.every(val => !val.token) && sendRequests.some(val => (val as TokenSendRequest).tokenId)) {
1137
+ // tokenOp = "genesis";
1138
+ // } else if (options?.ensureUtxos?.length === 1 && options?.ensureUtxos?.[0].token?.capability === NFTCapability.minting && ) {
1139
+
1140
+ // }
1141
+
1127
1142
  const addTokenChangeOutputs = (
1128
1143
  inputs: UtxoI[],
1129
1144
  outputs: SendRequestType[]
@@ -1189,7 +1204,8 @@ export class Wallet extends BaseWallet {
1189
1204
  const feeEstimate = await getFeeAmount({
1190
1205
  utxos: utxos,
1191
1206
  sendRequests: sendRequests,
1192
- privateKey: this.privateKey,
1207
+ privateKey: this.privateKey ?? Uint8Array.from([]),
1208
+ sourceAddress: this.cashaddr!,
1193
1209
  relayFeePerByteInSatoshi: relayFeePerByteInSatoshi,
1194
1210
  slpOutputs: [],
1195
1211
  feePaidBy: feePaidBy,
@@ -1201,7 +1217,8 @@ export class Wallet extends BaseWallet {
1201
1217
  bestHeight,
1202
1218
  feePaidBy,
1203
1219
  sendRequests,
1204
- options?.ensureUtxos || []
1220
+ options?.ensureUtxos || [],
1221
+ options?.tokenOperation
1205
1222
  );
1206
1223
  if (fundingUtxos.length === 0) {
1207
1224
  throw Error(
@@ -1211,20 +1228,24 @@ export class Wallet extends BaseWallet {
1211
1228
  const fee = await getFeeAmount({
1212
1229
  utxos: fundingUtxos,
1213
1230
  sendRequests: sendRequests,
1214
- privateKey: this.privateKey,
1231
+ privateKey: this.privateKey ?? Uint8Array.from([]),
1232
+ sourceAddress: this.cashaddr!,
1215
1233
  relayFeePerByteInSatoshi: relayFeePerByteInSatoshi,
1216
1234
  slpOutputs: [],
1217
1235
  feePaidBy: feePaidBy,
1218
1236
  });
1219
- const encodedTransaction = await buildEncodedTransaction(
1220
- fundingUtxos,
1221
- sendRequests,
1222
- this.privateKey,
1223
- fee,
1224
- discardChange,
1225
- [],
1226
- feePaidBy,
1227
- changeAddress
1237
+ const { encodedTransaction, sourceOutputs } = await buildEncodedTransaction(
1238
+ {
1239
+ inputs: fundingUtxos,
1240
+ outputs: sendRequests,
1241
+ signingKey: this.privateKey ?? Uint8Array.from([]),
1242
+ sourceAddress: this.cashaddr!,
1243
+ fee,
1244
+ discardChange,
1245
+ slpOutputs: [],
1246
+ feePaidBy,
1247
+ changeAddress,
1248
+ }
1228
1249
  );
1229
1250
 
1230
1251
  const tokenIds = [
@@ -1236,7 +1257,7 @@ export class Wallet extends BaseWallet {
1236
1257
  .map((val) => (val as TokenSendRequest).tokenId),
1237
1258
  ].filter((value, index, array) => array.indexOf(value) === index);
1238
1259
 
1239
- return { encodedTransaction, tokenIds: tokenIds };
1260
+ return { encodedTransaction, tokenIds, sourceOutputs };
1240
1261
  }
1241
1262
 
1242
1263
  // Submit a raw transaction
@@ -1437,32 +1458,52 @@ export class Wallet extends BaseWallet {
1437
1458
  * @param {string?} genesisRequest.commitment NFT commitment message
1438
1459
  * @param {string?} genesisRequest.cashaddr cash address to send the created token UTXO to; if undefined will default to your address
1439
1460
  * @param {number?} genesisRequest.value satoshi value to send alongside with tokens; if undefined will default to 1000 satoshi
1440
- * @param {SendRequestType} sendRequests single or an array of extra send requests (OP_RETURN, value transfer, etc.) to include in genesis transaction
1461
+ * @param {SendRequestType | SendRequestType[]} sendRequests single or an array of extra send requests (OP_RETURN, value transfer, etc.) to include in genesis transaction
1462
+ * @param {SendRequestOptionsI} options Options of the send requests
1441
1463
  */
1442
1464
  public async tokenGenesis(
1443
1465
  genesisRequest: TokenGenesisRequest,
1444
- sendRequests: SendRequestType | SendRequestType[] = []
1466
+ sendRequests: SendRequestType | SendRequestType[] = [],
1467
+ options?: SendRequestOptionsI
1445
1468
  ): Promise<SendResponse> {
1446
1469
  if (!Array.isArray(sendRequests)) {
1447
1470
  sendRequests = [sendRequests];
1448
1471
  }
1449
- return this.send(
1450
- [
1451
- new TokenSendRequest({
1452
- cashaddr: genesisRequest.cashaddr || this.tokenaddr!,
1453
- amount: genesisRequest.amount,
1454
- value: genesisRequest.value,
1455
- capability: genesisRequest.capability,
1456
- commitment: genesisRequest.commitment,
1457
- tokenId: "",
1458
- }),
1459
- ...(sendRequests as any),
1460
- ],
1461
- {
1462
- checkTokenQuantities: false,
1463
- queryBalance: false,
1464
- }
1465
- );
1472
+
1473
+ let utxos: UtxoI[];
1474
+ if (options && options.utxoIds) {
1475
+ utxos = options.utxoIds.map((utxoId: UtxoI | string) =>
1476
+ typeof utxoId === "string" ? fromUtxoId(utxoId) : utxoId
1477
+ );
1478
+ } else {
1479
+ utxos = await this.getAddressUtxos(this.cashaddr);
1480
+ }
1481
+
1482
+ const genesisInputs = utxos.filter((val) => val.vout === 0);
1483
+ if (genesisInputs.length === 0) {
1484
+ throw new Error(
1485
+ "No suitable inputs with vout=0 available for new token genesis"
1486
+ );
1487
+ }
1488
+
1489
+ const genesisSendRequest = new TokenSendRequest({
1490
+ cashaddr: genesisRequest.cashaddr || this.tokenaddr!,
1491
+ amount: genesisRequest.amount,
1492
+ value: genesisRequest.value || 1000,
1493
+ capability: genesisRequest.capability,
1494
+ commitment: genesisRequest.commitment,
1495
+ tokenId: utxos[0].txid,
1496
+ });
1497
+ // TODO: remove
1498
+ (genesisSendRequest as any)._isGenesis = true;
1499
+ return this.send([genesisSendRequest, ...(sendRequests as any)], {
1500
+ ...options,
1501
+ utxoIds: utxos,
1502
+ ensureUtxos: [utxos[0]],
1503
+ checkTokenQuantities: false,
1504
+ queryBalance: false,
1505
+ tokenOperation: "genesis",
1506
+ });
1466
1507
  }
1467
1508
 
1468
1509
  /**
@@ -1475,12 +1516,18 @@ export class Wallet extends BaseWallet {
1475
1516
  * @param {string?} mintRequest.cashaddr cash address to send the created token UTXO to; if undefined will default to your address
1476
1517
  * @param {number?} mintRequest.value satoshi value to send alongside with tokens; if undefined will default to 1000 satoshi
1477
1518
  * @param {boolean?} deductTokenAmount if minting token contains fungible amount, deduct from it by amount of minted tokens
1519
+ * @param {SendRequestOptionsI} options Options of the send requests
1478
1520
  */
1479
1521
  public async tokenMint(
1480
1522
  tokenId: string,
1481
1523
  mintRequests: TokenMintRequest | Array<TokenMintRequest>,
1482
- deductTokenAmount: boolean = false
1524
+ deductTokenAmount: boolean = false,
1525
+ options?: SendRequestOptionsI
1483
1526
  ): Promise<SendResponse> {
1527
+ if (tokenId?.length !== 64) {
1528
+ throw Error(`Invalid tokenId supplied: ${tokenId}`);
1529
+ }
1530
+
1484
1531
  if (!Array.isArray(mintRequests)) {
1485
1532
  mintRequests = [mintRequests];
1486
1533
  }
@@ -1489,7 +1536,7 @@ export class Wallet extends BaseWallet {
1489
1536
  const nftUtxos = utxos.filter(
1490
1537
  (val) =>
1491
1538
  val.token?.tokenId === tokenId &&
1492
- val.token?.capability != NFTCapability.none
1539
+ val.token?.capability === NFTCapability.minting
1493
1540
  );
1494
1541
  if (!nftUtxos.length) {
1495
1542
  throw new Error(
@@ -1525,8 +1572,11 @@ export class Wallet extends BaseWallet {
1525
1572
  ),
1526
1573
  ],
1527
1574
  {
1575
+ ...options,
1576
+ ensureUtxos: [nftUtxos[0]],
1528
1577
  checkTokenQuantities: false,
1529
1578
  queryBalance: false,
1579
+ tokenOperation: "mint",
1530
1580
  }
1531
1581
  );
1532
1582
  }
@@ -1545,18 +1595,23 @@ export class Wallet extends BaseWallet {
1545
1595
  * @param {number?} burnRequest.amount amount of fungible tokens to burn, optional
1546
1596
  * @param {string?} burnRequest.cashaddr address to return token and satoshi change to
1547
1597
  * @param {string?} message optional message to include in OP_RETURN
1598
+ * @param {SendRequestOptionsI} options Options of the send requests
1548
1599
  */
1549
1600
  public async tokenBurn(
1550
1601
  burnRequest: TokenBurnRequest,
1551
- message?: string
1602
+ message?: string,
1603
+ options?: SendRequestOptionsI
1552
1604
  ): Promise<SendResponse> {
1605
+ if (burnRequest.tokenId?.length !== 64) {
1606
+ throw Error(`Invalid tokenId supplied: ${burnRequest.tokenId}`);
1607
+ }
1608
+
1553
1609
  const utxos = await this.getAddressUtxos(this.cashaddr!);
1554
1610
  const tokenUtxos = utxos.filter(
1555
1611
  (val) =>
1556
1612
  val.token?.tokenId === burnRequest.tokenId &&
1557
1613
  val.token?.capability === burnRequest.capability &&
1558
- val.token?.commitment === burnRequest.commitment &&
1559
- val.token?.capability === burnRequest.capability
1614
+ val.token?.commitment === burnRequest.commitment
1560
1615
  );
1561
1616
 
1562
1617
  if (!tokenUtxos.length) {
@@ -1579,6 +1634,16 @@ export class Wallet extends BaseWallet {
1579
1634
  changeSendRequests = [];
1580
1635
  utxoIds.push(tokenUtxos[0]);
1581
1636
  } else {
1637
+ // add utxos to spend from
1638
+ let available = 0;
1639
+ for (const token of tokenUtxos.filter((val) => val.token?.amount)) {
1640
+ utxoIds.push(token);
1641
+ available += token.token?.amount!;
1642
+ if (available >= fungibleBurnAmount) {
1643
+ break;
1644
+ }
1645
+ }
1646
+
1582
1647
  // if there are FT, reduce their amount
1583
1648
  const newAmount = totalFungibleAmount - fungibleBurnAmount;
1584
1649
  const safeNewAmount = Math.max(0, newAmount);
@@ -1599,6 +1664,16 @@ export class Wallet extends BaseWallet {
1599
1664
  changeSendRequests = [];
1600
1665
  utxoIds.push(tokenUtxos[0]);
1601
1666
  } else {
1667
+ // add utxos to spend from
1668
+ let available = 0;
1669
+ for (const token of tokenUtxos.filter((val) => val.token?.amount)) {
1670
+ utxoIds.push(token);
1671
+ available += token.token?.amount!;
1672
+ if (available >= fungibleBurnAmount) {
1673
+ break;
1674
+ }
1675
+ }
1676
+
1602
1677
  // reduce the FT amount
1603
1678
  const newAmount = totalFungibleAmount - fungibleBurnAmount;
1604
1679
  const safeNewAmount = Math.max(0, newAmount);
@@ -1615,9 +1690,11 @@ export class Wallet extends BaseWallet {
1615
1690
 
1616
1691
  const opReturn = OpReturnData.fromString(message || "");
1617
1692
  return this.send([opReturn, ...changeSendRequests], {
1693
+ ...options,
1618
1694
  checkTokenQuantities: false,
1619
1695
  queryBalance: false,
1620
1696
  ensureUtxos: utxoIds.length > 0 ? utxoIds : undefined,
1697
+ tokenOperation: "burn",
1621
1698
  });
1622
1699
  }
1623
1700
 
@@ -1641,7 +1718,9 @@ export class Wallet extends BaseWallet {
1641
1718
  * @returns {number} fungible token balance
1642
1719
  */
1643
1720
  public async getTokenBalance(tokenId: string): Promise<number> {
1644
- const utxos = await this.getAddressUtxos(this.cashaddr!);
1721
+ const utxos = (await this.getTokenUtxos(tokenId)).filter(
1722
+ (val) => val.token?.amount
1723
+ );
1645
1724
  return sumTokenAmounts(utxos, tokenId);
1646
1725
  }
1647
1726
 
@@ -1653,7 +1732,9 @@ export class Wallet extends BaseWallet {
1653
1732
  * @returns {number} non-fungible token balance
1654
1733
  */
1655
1734
  public async getNftTokenBalance(tokenId: string): Promise<number> {
1656
- const utxos = await this.getTokenUtxos(tokenId);
1735
+ const utxos = (await this.getTokenUtxos(tokenId)).filter(
1736
+ (val) => val.token?.commitment !== undefined
1737
+ );
1657
1738
  return utxos.length;
1658
1739
  }
1659
1740
 
@@ -1661,9 +1742,11 @@ export class Wallet extends BaseWallet {
1661
1742
  * getAllTokenBalances Gets all fungible token balances in this wallet
1662
1743
  * @returns {Object} a map [tokenId => balance] for all tokens in this wallet
1663
1744
  */
1664
- public async getAllTokenBalances(): Promise<Object> {
1745
+ public async getAllTokenBalances(): Promise<{ [tokenId: string]: number }> {
1665
1746
  const result = {};
1666
- const utxos = await this.getTokenUtxos();
1747
+ const utxos = (await this.getTokenUtxos()).filter(
1748
+ (val) => val.token?.amount
1749
+ );
1667
1750
  for (const utxo of utxos) {
1668
1751
  if (!result[utxo.token!.tokenId]) {
1669
1752
  result[utxo.token!.tokenId] = 0;
@@ -1677,9 +1760,13 @@ export class Wallet extends BaseWallet {
1677
1760
  * getAllNftTokenBalances Gets all non-fungible token (NFT) balances in this wallet
1678
1761
  * @returns {Object} a map [tokenId => balance] for all NFTs in this wallet
1679
1762
  */
1680
- public async getAllNftTokenBalances(): Promise<Object> {
1763
+ public async getAllNftTokenBalances(): Promise<{
1764
+ [tokenId: string]: number;
1765
+ }> {
1681
1766
  const result = {};
1682
- const utxos = await this.getTokenUtxos();
1767
+ const utxos = (await this.getTokenUtxos()).filter(
1768
+ (val) => val.token?.commitment !== undefined
1769
+ );
1683
1770
  for (const utxo of utxos) {
1684
1771
  if (!result[utxo.token!.tokenId]) {
1685
1772
  result[utxo.token!.tokenId] = 0;
@@ -54,7 +54,9 @@ export interface SendRequestOptionsI {
54
54
  awaitTransactionPropagation?: boolean;
55
55
  feePaidBy?: FeePaidByEnum;
56
56
  checkTokenQuantities?: boolean; // true
57
+ tokenOperation?: "send" | "genesis" | "mint" | "burn"; // undefined. internal use only
57
58
  ensureUtxos?: UtxoI[]; // ensure these inputs will be consumed in the transaction
59
+ buildUnsigned?: boolean; // false
58
60
  }
59
61
 
60
62
  export interface MnemonicI {
@@ -4,6 +4,8 @@ import { UnitEnum } from "../enum.js";
4
4
  import { NFTCapability, UtxoI } from "../interface.js";
5
5
  import { DELIMITER } from "../constant.js";
6
6
  import {
7
+ Input,
8
+ Output,
7
9
  binToNumberUint16LE,
8
10
  binToUtf8,
9
11
  hexToBin,
@@ -312,11 +314,15 @@ export class OpReturnData {
312
314
 
313
315
  export type SendRequestArray = Array<string | number | UnitEnum | Buffer>;
314
316
 
317
+ export type SourceOutput = Input & Output;
318
+
315
319
  export class SendResponse {
316
320
  txId?: string;
317
321
  balance?: BalanceResponse;
318
322
  explorerUrl?: string;
319
323
  tokenIds?: string[];
324
+ unsignedTransaction?: string; // unsigned transaction hex
325
+ sourceOutputs?: SourceOutput[]; // source outputs for signing unsigned transactions
320
326
 
321
327
  constructor({
322
328
  txId,