@bsv/wallet-toolbox 1.2.42 → 1.2.44

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.
Files changed (40) hide show
  1. package/docs/client.md +9 -0
  2. package/docs/wallet.md +9 -0
  3. package/out/src/WalletPermissionsManager.d.ts +2 -0
  4. package/out/src/WalletPermissionsManager.d.ts.map +1 -1
  5. package/out/src/WalletPermissionsManager.js +61 -31
  6. package/out/src/WalletPermissionsManager.js.map +1 -1
  7. package/out/src/__tests/WalletPermissionsManager.checks.test.js +6 -1
  8. package/out/src/__tests/WalletPermissionsManager.checks.test.js.map +1 -1
  9. package/out/src/__tests/WalletPermissionsManager.encryption.test.js +40 -1
  10. package/out/src/__tests/WalletPermissionsManager.encryption.test.js.map +1 -1
  11. package/out/src/__tests/WalletPermissionsManager.fixtures.d.ts +1 -0
  12. package/out/src/__tests/WalletPermissionsManager.fixtures.d.ts.map +1 -1
  13. package/out/src/__tests/WalletPermissionsManager.fixtures.js +5 -1
  14. package/out/src/__tests/WalletPermissionsManager.fixtures.js.map +1 -1
  15. package/out/src/__tests/WalletPermissionsManager.flows.test.js +2 -0
  16. package/out/src/__tests/WalletPermissionsManager.flows.test.js.map +1 -1
  17. package/out/src/__tests/WalletPermissionsManager.proxying.test.js +15 -2
  18. package/out/src/__tests/WalletPermissionsManager.proxying.test.js.map +1 -1
  19. package/out/src/__tests/WalletPermissionsManager.tokens.test.js +40 -0
  20. package/out/src/__tests/WalletPermissionsManager.tokens.test.js.map +1 -1
  21. package/out/src/services/__tests/ARC.man.test.d.ts +2 -0
  22. package/out/src/services/__tests/ARC.man.test.d.ts.map +1 -0
  23. package/out/src/services/__tests/{ARC.test.js → ARC.man.test.js} +1 -1
  24. package/out/src/services/__tests/ARC.man.test.js.map +1 -0
  25. package/out/src/services/createDefaultWalletServicesOptions.js +1 -1
  26. package/out/src/services/createDefaultWalletServicesOptions.js.map +1 -1
  27. package/out/tsconfig.all.tsbuildinfo +1 -1
  28. package/package.json +1 -1
  29. package/src/WalletPermissionsManager.ts +66 -34
  30. package/src/__tests/WalletPermissionsManager.checks.test.ts +6 -1
  31. package/src/__tests/WalletPermissionsManager.encryption.test.ts +43 -2
  32. package/src/__tests/WalletPermissionsManager.fixtures.ts +6 -1
  33. package/src/__tests/WalletPermissionsManager.flows.test.ts +2 -0
  34. package/src/__tests/WalletPermissionsManager.proxying.test.ts +16 -2
  35. package/src/__tests/WalletPermissionsManager.tokens.test.ts +40 -1
  36. package/src/services/createDefaultWalletServicesOptions.ts +1 -1
  37. package/out/src/services/__tests/ARC.test.d.ts +0 -2
  38. package/out/src/services/__tests/ARC.test.d.ts.map +0 -1
  39. package/out/src/services/__tests/ARC.test.js.map +0 -1
  40. /package/src/services/__tests/{ARC.test.ts → ARC.man.test.ts} +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bsv/wallet-toolbox",
3
- "version": "1.2.42",
3
+ "version": "1.2.44",
4
4
  "description": "BRC100 conforming wallet, wallet storage and wallet signer components",
5
5
  "main": "./out/src/index.js",
6
6
  "types": "./out/src/index.d.ts",
@@ -70,6 +70,9 @@ export interface PermissionToken {
70
70
  /** The transaction ID where this token resides. */
71
71
  txid: string
72
72
 
73
+ /** The current transaction encapsulating the token. */
74
+ tx: number[]
75
+
73
76
  /** The output index within that transaction. */
74
77
  outputIndex: number
75
78
 
@@ -923,15 +926,19 @@ export class WalletPermissionsManager implements WalletInterface {
923
926
  }
924
927
 
925
928
  private async decryptPermissionTokenField(ciphertext: number[]): Promise<number[]> {
926
- const { plaintext } = await this.underlying.decrypt(
927
- {
928
- ciphertext,
929
- protocolID: WalletPermissionsManager.PERM_TOKEN_ENCRYPTION_PROTOCOL,
930
- keyID: '1'
931
- },
932
- this.adminOriginator
933
- )
934
- return plaintext
929
+ try {
930
+ const { plaintext } = await this.underlying.decrypt(
931
+ {
932
+ ciphertext,
933
+ protocolID: WalletPermissionsManager.PERM_TOKEN_ENCRYPTION_PROTOCOL,
934
+ keyID: '1'
935
+ },
936
+ this.adminOriginator
937
+ )
938
+ return plaintext
939
+ } catch (e) {
940
+ return ciphertext
941
+ }
935
942
  }
936
943
 
937
944
  /**
@@ -1001,14 +1008,15 @@ export class WalletPermissionsManager implements WalletInterface {
1001
1008
  `counterparty ${counterparty}`
1002
1009
  ],
1003
1010
  tagQueryMode: 'all',
1004
- include: 'locking scripts'
1011
+ include: 'entire transactions'
1005
1012
  },
1006
1013
  this.adminOriginator
1007
1014
  )
1008
1015
 
1009
1016
  for (const out of result.outputs) {
1010
- const script = LockingScript.fromHex(out.lockingScript!)
1011
- const dec = PushDrop.decode(script)
1017
+ const [txid, outputIndexStr] = out.outpoint.split('.')
1018
+ const tx = Transaction.fromBEEF(result.BEEF!, txid)
1019
+ const dec = PushDrop.decode(tx.outputs[Number(outputIndexStr)].lockingScript)
1012
1020
  if (!dec || !dec.fields || dec.fields.length < 6) continue
1013
1021
  const domainRaw = dec.fields[0]
1014
1022
  const expiryRaw = dec.fields[1]
@@ -1040,9 +1048,10 @@ export class WalletPermissionsManager implements WalletInterface {
1040
1048
  continue
1041
1049
  }
1042
1050
  return {
1051
+ tx: tx.toBEEF(),
1043
1052
  txid: out.outpoint.split('.')[0],
1044
1053
  outputIndex: parseInt(out.outpoint.split('.')[1], 10),
1045
- outputScript: out.lockingScript!,
1054
+ outputScript: tx.outputs[Number(outputIndexStr)].lockingScript.toHex(),
1046
1055
  satoshis: out.satoshis,
1047
1056
  originator,
1048
1057
  privileged,
@@ -1066,13 +1075,15 @@ export class WalletPermissionsManager implements WalletInterface {
1066
1075
  basket: BASKET_MAP.basket,
1067
1076
  tags: [`originator ${originator}`, `basket ${basket}`],
1068
1077
  tagQueryMode: 'all',
1069
- include: 'locking scripts'
1078
+ include: 'entire transactions'
1070
1079
  },
1071
1080
  this.adminOriginator
1072
1081
  )
1073
1082
 
1074
1083
  for (const out of result.outputs) {
1075
- const dec = PushDrop.decode(LockingScript.fromHex(out.lockingScript!))
1084
+ const [txid, outputIndexStr] = out.outpoint.split('.')
1085
+ const tx = Transaction.fromBEEF(result.BEEF!, txid)
1086
+ const dec = PushDrop.decode(tx.outputs[Number(outputIndexStr)].lockingScript)
1076
1087
  if (!dec?.fields || dec.fields.length < 3) continue
1077
1088
  const domainRaw = dec.fields[0]
1078
1089
  const expiryRaw = dec.fields[1]
@@ -1085,9 +1096,10 @@ export class WalletPermissionsManager implements WalletInterface {
1085
1096
  if (!includeExpired && this.isTokenExpired(expiryDecoded)) continue
1086
1097
 
1087
1098
  return {
1099
+ tx: tx.toBEEF(),
1088
1100
  txid: out.outpoint.split('.')[0],
1089
1101
  outputIndex: parseInt(out.outpoint.split('.')[1], 10),
1090
- outputScript: out.lockingScript!,
1102
+ outputScript: tx.outputs[Number(outputIndexStr)].lockingScript.toHex(),
1091
1103
  satoshis: out.satoshis,
1092
1104
  originator,
1093
1105
  basketName: basketDecoded,
@@ -1111,13 +1123,15 @@ export class WalletPermissionsManager implements WalletInterface {
1111
1123
  basket: BASKET_MAP.certificate,
1112
1124
  tags: [`originator ${originator}`, `privileged ${!!privileged}`, `type ${certType}`, `verifier ${verifier}`],
1113
1125
  tagQueryMode: 'all',
1114
- include: 'locking scripts'
1126
+ include: 'entire transactions'
1115
1127
  },
1116
1128
  this.adminOriginator
1117
1129
  )
1118
1130
 
1119
1131
  for (const out of result.outputs) {
1120
- const dec = PushDrop.decode(LockingScript.fromHex(out.lockingScript!))
1132
+ const [txid, outputIndexStr] = out.outpoint.split('.')
1133
+ const tx = Transaction.fromBEEF(result.BEEF!, txid)
1134
+ const dec = PushDrop.decode(tx.outputs[Number(outputIndexStr)].lockingScript)
1121
1135
  if (!dec?.fields || dec.fields.length < 6) continue
1122
1136
  const [domainRaw, expiryRaw, privRaw, typeRaw, fieldsRaw, verifierRaw] = dec.fields
1123
1137
 
@@ -1147,9 +1161,10 @@ export class WalletPermissionsManager implements WalletInterface {
1147
1161
  continue
1148
1162
  }
1149
1163
  return {
1164
+ tx: tx.toBEEF(),
1150
1165
  txid: out.outpoint.split('.')[0],
1151
1166
  outputIndex: parseInt(out.outpoint.split('.')[1], 10),
1152
- outputScript: out.lockingScript!,
1167
+ outputScript: tx.outputs[Number(outputIndexStr)].lockingScript.toHex(),
1153
1168
  satoshis: out.satoshis,
1154
1169
  originator,
1155
1170
  privileged,
@@ -1169,13 +1184,15 @@ export class WalletPermissionsManager implements WalletInterface {
1169
1184
  basket: BASKET_MAP.spending,
1170
1185
  tags: [`originator ${originator}`],
1171
1186
  tagQueryMode: 'all',
1172
- include: 'locking scripts'
1187
+ include: 'entire transactions'
1173
1188
  },
1174
1189
  this.adminOriginator
1175
1190
  )
1176
1191
 
1177
1192
  for (const out of result.outputs) {
1178
- const dec = PushDrop.decode(LockingScript.fromHex(out.lockingScript!))
1193
+ const [txid, outputIndexStr] = out.outpoint.split('.')
1194
+ const tx = Transaction.fromBEEF(result.BEEF!, txid)
1195
+ const dec = PushDrop.decode(tx.outputs[Number(outputIndexStr)].lockingScript)
1179
1196
  if (!dec?.fields || dec.fields.length < 2) continue
1180
1197
  const domainRaw = dec.fields[0]
1181
1198
  const amtRaw = dec.fields[1]
@@ -1186,9 +1203,10 @@ export class WalletPermissionsManager implements WalletInterface {
1186
1203
  const authorizedAmount = parseInt(amtDecodedStr, 10)
1187
1204
 
1188
1205
  return {
1206
+ tx: tx.toBEEF(),
1189
1207
  txid: out.outpoint.split('.')[0],
1190
1208
  outputIndex: parseInt(out.outpoint.split('.')[1], 10),
1191
- outputScript: out.lockingScript!,
1209
+ outputScript: tx.outputs[Number(outputIndexStr)].lockingScript.toHex(),
1192
1210
  satoshis: out.satoshis,
1193
1211
  originator,
1194
1212
  authorizedAmount,
@@ -1313,6 +1331,7 @@ export class WalletPermissionsManager implements WalletInterface {
1313
1331
  const { signableTransaction } = await this.createAction(
1314
1332
  {
1315
1333
  description: `Renew ${r.type} permission`,
1334
+ inputBEEF: oldToken.tx,
1316
1335
  inputs: [
1317
1336
  {
1318
1337
  outpoint: oldOutpoint,
@@ -1447,7 +1466,7 @@ export class WalletPermissionsManager implements WalletInterface {
1447
1466
  basket: basketName,
1448
1467
  tags,
1449
1468
  tagQueryMode: 'all',
1450
- include: 'locking scripts',
1469
+ include: 'entire transactions',
1451
1470
  limit: 100
1452
1471
  },
1453
1472
  this.adminOriginator
@@ -1455,7 +1474,9 @@ export class WalletPermissionsManager implements WalletInterface {
1455
1474
 
1456
1475
  const tokens: PermissionToken[] = []
1457
1476
  for (const out of result.outputs) {
1458
- const dec = PushDrop.decode(LockingScript.fromHex(out.lockingScript!))
1477
+ const [txid, outputIndexStr] = out.outpoint.split('.')
1478
+ const tx = Transaction.fromBEEF(result.BEEF!, txid)
1479
+ const dec = PushDrop.decode(tx.outputs[Number(outputIndexStr)].lockingScript)
1459
1480
  if (!dec?.fields || dec.fields.length < 6) continue
1460
1481
  const [domainRaw, expiryRaw, privRaw, secRaw, protoRaw, cptyRaw] = dec.fields
1461
1482
 
@@ -1467,9 +1488,10 @@ export class WalletPermissionsManager implements WalletInterface {
1467
1488
  const cptyDec = Utils.toUTF8(await this.decryptPermissionTokenField(cptyRaw))
1468
1489
 
1469
1490
  tokens.push({
1491
+ tx: tx.toBEEF(),
1470
1492
  txid: out.outpoint.split('.')[0],
1471
1493
  outputIndex: parseInt(out.outpoint.split('.')[1], 10),
1472
- outputScript: out.lockingScript!,
1494
+ outputScript: tx.outputs[Number(outputIndexStr)].lockingScript.toHex(),
1473
1495
  satoshis: out.satoshis,
1474
1496
  originator: domainDec,
1475
1497
  expiry: expiryDec,
@@ -1519,7 +1541,7 @@ export class WalletPermissionsManager implements WalletInterface {
1519
1541
  basket: basketName,
1520
1542
  tags,
1521
1543
  tagQueryMode: 'all',
1522
- include: 'locking scripts',
1544
+ include: 'entire transactions',
1523
1545
  limit: 10000
1524
1546
  },
1525
1547
  this.adminOriginator
@@ -1527,17 +1549,20 @@ export class WalletPermissionsManager implements WalletInterface {
1527
1549
 
1528
1550
  const tokens: PermissionToken[] = []
1529
1551
  for (const out of result.outputs) {
1530
- const dec = PushDrop.decode(LockingScript.fromHex(out.lockingScript!))
1552
+ const [txid, outputIndexStr] = out.outpoint.split('.')
1553
+ const tx = Transaction.fromBEEF(result.BEEF!, txid)
1554
+ const dec = PushDrop.decode(tx.outputs[Number(outputIndexStr)].lockingScript)
1531
1555
  if (!dec?.fields || dec.fields.length < 3) continue
1532
1556
  const [domainRaw, expiryRaw, basketRaw] = dec.fields
1533
1557
  const domainDecoded = Utils.toUTF8(await this.decryptPermissionTokenField(domainRaw))
1534
1558
  const expiryDecoded = parseInt(Utils.toUTF8(await this.decryptPermissionTokenField(expiryRaw)), 10)
1535
1559
  const basketDecoded = Utils.toUTF8(await this.decryptPermissionTokenField(basketRaw))
1536
1560
  tokens.push({
1561
+ tx: tx.toBEEF(),
1537
1562
  txid: out.outpoint.split('.')[0],
1538
1563
  outputIndex: parseInt(out.outpoint.split('.')[1], 10),
1539
1564
  satoshis: out.satoshis,
1540
- outputScript: out.lockingScript!,
1565
+ outputScript: tx.outputs[Number(outputIndexStr)].lockingScript.toHex(),
1541
1566
  originator: domainDecoded,
1542
1567
  basketName: basketDecoded,
1543
1568
  expiry: expiryDecoded
@@ -1577,7 +1602,7 @@ export class WalletPermissionsManager implements WalletInterface {
1577
1602
  basket: basketName,
1578
1603
  tags,
1579
1604
  tagQueryMode: 'all',
1580
- include: 'locking scripts',
1605
+ include: 'entire transactions',
1581
1606
  limit: 10000
1582
1607
  },
1583
1608
  this.adminOriginator
@@ -1585,17 +1610,20 @@ export class WalletPermissionsManager implements WalletInterface {
1585
1610
 
1586
1611
  const tokens: PermissionToken[] = []
1587
1612
  for (const out of result.outputs) {
1588
- const dec = PushDrop.decode(LockingScript.fromHex(out.lockingScript!))
1613
+ const [txid, outputIndexStr] = out.outpoint.split('.')
1614
+ const tx = Transaction.fromBEEF(result.BEEF!, txid)
1615
+ const dec = PushDrop.decode(tx.outputs[Number(outputIndexStr)].lockingScript)
1589
1616
  if (!dec?.fields || dec.fields.length < 2) continue
1590
1617
  const [domainRaw, amtRaw] = dec.fields
1591
1618
  const domainDecoded = Utils.toUTF8(await this.decryptPermissionTokenField(domainRaw))
1592
1619
  const amtDecodedStr = Utils.toUTF8(await this.decryptPermissionTokenField(amtRaw))
1593
1620
  const authorizedAmount = parseInt(amtDecodedStr, 10)
1594
1621
  tokens.push({
1622
+ tx: tx.toBEEF(),
1595
1623
  txid: out.outpoint.split('.')[0],
1596
1624
  outputIndex: parseInt(out.outpoint.split('.')[1], 10),
1597
1625
  satoshis: out.satoshis,
1598
- outputScript: out.lockingScript!,
1626
+ outputScript: tx.outputs[Number(outputIndexStr)].lockingScript.toHex(),
1599
1627
  originator: domainDecoded,
1600
1628
  authorizedAmount,
1601
1629
  expiry: 0
@@ -1635,7 +1663,7 @@ export class WalletPermissionsManager implements WalletInterface {
1635
1663
  basket: basketName,
1636
1664
  tags,
1637
1665
  tagQueryMode: 'all',
1638
- include: 'locking scripts',
1666
+ include: 'entire transactions',
1639
1667
  limit: 10000
1640
1668
  },
1641
1669
  this.adminOriginator
@@ -1643,7 +1671,9 @@ export class WalletPermissionsManager implements WalletInterface {
1643
1671
 
1644
1672
  const tokens: PermissionToken[] = []
1645
1673
  for (const out of result.outputs) {
1646
- const dec = PushDrop.decode(LockingScript.fromHex(out.lockingScript!))
1674
+ const [txid, outputIndexStr] = out.outpoint.split('.')
1675
+ const tx = Transaction.fromBEEF(result.BEEF!, txid)
1676
+ const dec = PushDrop.decode(tx.outputs[Number(outputIndexStr)].lockingScript)
1647
1677
  if (!dec?.fields || dec.fields.length < 6) continue
1648
1678
  const [domainRaw, expiryRaw, privRaw, typeRaw, fieldsRaw, verifierRaw] = dec.fields
1649
1679
  const domainDecoded = Utils.toUTF8(await this.decryptPermissionTokenField(domainRaw))
@@ -1654,10 +1684,11 @@ export class WalletPermissionsManager implements WalletInterface {
1654
1684
  const fieldsJson = await this.decryptPermissionTokenField(fieldsRaw)
1655
1685
  const allFields = JSON.parse(Utils.toUTF8(fieldsJson)) as string[]
1656
1686
  tokens.push({
1687
+ tx: tx.toBEEF(),
1657
1688
  txid: out.outpoint.split('.')[0],
1658
1689
  outputIndex: parseInt(out.outpoint.split('.')[1], 10),
1659
1690
  satoshis: out.satoshis,
1660
- outputScript: out.lockingScript!,
1691
+ outputScript: tx.outputs[Number(outputIndexStr)].lockingScript.toHex(),
1661
1692
  originator: domainDecoded,
1662
1693
  privileged: privDecoded,
1663
1694
  certType: typeDecoded,
@@ -1705,6 +1736,7 @@ export class WalletPermissionsManager implements WalletInterface {
1705
1736
  const { signableTransaction } = await this.createAction(
1706
1737
  {
1707
1738
  description: `Revoke permission`,
1739
+ inputBEEF: oldToken.tx,
1708
1740
  inputs: [
1709
1741
  {
1710
1742
  outpoint: oldOutpoint,
@@ -186,6 +186,7 @@ describe('WalletPermissionsManager - Permission Checks', () => {
186
186
  // Suppose the user already had a token but it’s expired. We mock `findProtocolToken` so that
187
187
  // it returns an expired token, forcing a renewal request.
188
188
  const expiredToken: PermissionToken = {
189
+ tx: [],
189
190
  txid: 'oldtxid123',
190
191
  outputIndex: 0,
191
192
  outputScript: 'deadbeef',
@@ -366,7 +367,7 @@ describe('WalletPermissionsManager - Permission Checks', () => {
366
367
  expect(underlying.listOutputs).toHaveBeenLastCalledWith(
367
368
  {
368
369
  basket: 'admin basket-access',
369
- include: 'locking scripts',
370
+ include: 'entire transactions',
370
371
  tagQueryMode: 'all',
371
372
  tags: ['originator some-user.com', 'basket user-basket']
372
373
  },
@@ -470,6 +471,7 @@ describe('WalletPermissionsManager - Permission Checks', () => {
470
471
 
471
472
  // Suppose we find an existing token that covers fields: ['name', 'dob', 'nationality']
472
473
  const existingToken: PermissionToken = {
474
+ tx: [],
473
475
  txid: 'aabbcc',
474
476
  outputIndex: 0,
475
477
  outputScript: 'scriptHex',
@@ -541,6 +543,7 @@ describe('WalletPermissionsManager - Permission Checks', () => {
541
543
 
542
544
  // Mock an expired token
543
545
  const expiredCertToken: PermissionToken = {
546
+ tx: [],
544
547
  txid: 'old-expired',
545
548
  outputIndex: 0,
546
549
  outputScript: 'deadbeef',
@@ -666,6 +669,7 @@ describe('WalletPermissionsManager - Permission Checks', () => {
666
669
  // Suppose we find an existing DSAP token with authorizedAmount=500
667
670
  // manager.findSpendingToken() is used internally, so let's mock it
668
671
  const existingSpendingToken: PermissionToken = {
672
+ tx: [],
669
673
  txid: 'dsap-old',
670
674
  outputIndex: 0,
671
675
  outputScript: 'scriptHex',
@@ -711,6 +715,7 @@ describe('WalletPermissionsManager - Permission Checks', () => {
711
715
 
712
716
  // existing DSAP token with authorizedAmount=1000
713
717
  const dsapToken: PermissionToken = {
718
+ tx: [],
714
719
  txid: 'dsap123',
715
720
  outputIndex: 0,
716
721
  outputScript: '9218',
@@ -1,4 +1,4 @@
1
- import { mockUnderlyingWallet, MockedBSV_SDK } from './WalletPermissionsManager.fixtures'
1
+ import { mockUnderlyingWallet, MockedBSV_SDK, MockTransaction } from './WalletPermissionsManager.fixtures'
2
2
  import { WalletPermissionsManager } from '../WalletPermissionsManager'
3
3
  import { jest } from '@jest/globals'
4
4
  import { Utils } from '@bsv/sdk'
@@ -282,6 +282,22 @@ describe('WalletPermissionsManager - Metadata Encryption & Decryption', () => {
282
282
 
283
283
  describe('Integration Test for listOutputs decryption', () => {
284
284
  it('should decrypt customInstructions in listOutputs if encryptWalletMetadata=true', async () => {
285
+ jest.spyOn(MockedBSV_SDK.Transaction, 'fromBEEF').mockImplementation(() => {
286
+ const mockTx = new MockTransaction()
287
+ // Add outputs with lockingScript
288
+ mockTx.outputs = [
289
+ {
290
+ lockingScript: {
291
+ // Ensure this matches what PushDrop.decode expects to work with
292
+ toHex: () => 'some script'
293
+ }
294
+ }
295
+ ]
296
+ // Add the toBEEF method
297
+ mockTx.toBEEF = () => []
298
+ return mockTx
299
+ })
300
+
285
301
  const manager = new WalletPermissionsManager(underlying, 'admin.domain.com', {
286
302
  encryptWalletMetadata: true
287
303
  })
@@ -332,6 +348,31 @@ describe('WalletPermissionsManager - Metadata Encryption & Decryption', () => {
332
348
  })
333
349
 
334
350
  it('should fallback to the original ciphertext if decrypt fails in listOutputs', async () => {
351
+ jest.spyOn(MockedBSV_SDK.Transaction, 'fromBEEF').mockImplementation(() => {
352
+ const mockTx = new MockTransaction()
353
+ // Add outputs with lockingScript
354
+ mockTx.outputs = [
355
+ {
356
+ lockingScript: {
357
+ // Ensure this matches what PushDrop.decode expects to work with
358
+ toHex: () => 'some script'
359
+ }
360
+ }
361
+ ]
362
+ // Add the toBEEF method
363
+ mockTx.toBEEF = () => []
364
+ return mockTx
365
+ })
366
+ // Add this to your test alongside the Transaction.fromBEEF mock
367
+ jest.spyOn(MockedBSV_SDK.PushDrop, 'decode').mockReturnValue({
368
+ fields: [
369
+ // Values that will decrypt to the expected values for domain, expiry, and basket
370
+ Utils.toArray('encoded-domain'),
371
+ Utils.toArray('encoded-expiry'),
372
+ Utils.toArray('encoded-basket')
373
+ ]
374
+ })
375
+
335
376
  const manager = new WalletPermissionsManager(underlying, 'admin.domain.com', {
336
377
  encryptWalletMetadata: true
337
378
  })
@@ -342,7 +383,7 @@ describe('WalletPermissionsManager - Metadata Encryption & Decryption', () => {
342
383
  totalOutputs: 1,
343
384
  outputs: [
344
385
  {
345
- outpoint: 'fakeTxid.1',
386
+ outpoint: 'fakeTxid.0',
346
387
  satoshis: 500,
347
388
  lockingScript: 'OP_RETURN something',
348
389
  basket: 'some-basket',
@@ -33,6 +33,11 @@ export class MockTransaction {
33
33
  getFee(): number {
34
34
  return this.fee
35
35
  }
36
+
37
+ toBEEF(): number[] {
38
+ // Return an empty array for the BEEF representation
39
+ return []
40
+ }
36
41
  }
37
42
 
38
43
  ;(MockTransaction as any).fromAtomicBEEF = jest.fn(() => {
@@ -256,7 +261,7 @@ export function mockUnderlyingWallet(): jest.Mocked<any> {
256
261
  subject: '02aaaaaaaaaa...',
257
262
  serialNumber: 'serial123',
258
263
  certifier: '02ccccccccccc...',
259
- revocationOutpoint: 'some.txid.1',
264
+ revocationOutpoint: 'sometxid.1',
260
265
  signature: 'deadbeef',
261
266
  fields: { name: 'Alice', dob: '1990-01-01' }
262
267
  }),
@@ -339,6 +339,7 @@ describe('WalletPermissionsManager - Permission Request Flow & Active Requests',
339
339
  }
340
340
  // second time => pretend we found a valid token
341
341
  const mockToken: PermissionToken = {
342
+ tx: [],
342
343
  txid: 'abcdef',
343
344
  outputIndex: 0,
344
345
  outputScript: '00',
@@ -400,6 +401,7 @@ describe('WalletPermissionsManager - Permission Request Flow & Active Requests',
400
401
 
401
402
  // We'll mock findProtocolToken to return an expired token
402
403
  const expiredToken: PermissionToken = {
404
+ tx: [],
403
405
  txid: 'expiredTxid123',
404
406
  outputIndex: 0,
405
407
  outputScript: '76a914xxxx...88ac',
@@ -362,11 +362,25 @@ describe('WalletPermissionsManager - Regression & Integration with Underlying Wa
362
362
  * ----------------------------------------------------------------------- */
363
363
 
364
364
  it('should ensure basket listing permission then call listOutputs, decrypting customInstructions', async () => {
365
+ jest.spyOn(MockedBSV_SDK.Transaction, 'fromBEEF').mockImplementation(() => {
366
+ const mockTx = new MockTransaction()
367
+ // Add outputs with lockingScript
368
+ mockTx.outputs = [
369
+ {
370
+ lockingScript: {
371
+ // Ensure this matches what PushDrop.decode expects to work with
372
+ toHex: () => 'mockLockingScriptHex'
373
+ }
374
+ }
375
+ ]
376
+ return mockTx
377
+ })
378
+
365
379
  underlying.listOutputs.mockResolvedValue({
366
380
  totalOutputs: 1,
367
381
  outputs: [
368
382
  {
369
- outpoint: 'zzz.1',
383
+ outpoint: 'zzz.0',
370
384
  satoshis: 100,
371
385
  lockingScript: 'mockscript',
372
386
  customInstructions: 'EncryptedWeird'
@@ -381,7 +395,7 @@ describe('WalletPermissionsManager - Regression & Integration with Underlying Wa
381
395
  [
382
396
  {
383
397
  basket: 'admin basket-access',
384
- include: 'locking scripts',
398
+ include: 'entire transactions',
385
399
  tagQueryMode: 'all',
386
400
  tags: ['originator app.example.com', 'basket user-basket']
387
401
  },
@@ -1,6 +1,7 @@
1
1
  import { describe, it, expect, beforeEach, afterEach, jest } from '@jest/globals'
2
- import { mockUnderlyingWallet, MockedBSV_SDK } from './WalletPermissionsManager.fixtures'
2
+ import { mockUnderlyingWallet, MockedBSV_SDK, MockTransaction } from './WalletPermissionsManager.fixtures'
3
3
  import { WalletPermissionsManager, PermissionRequest, PermissionToken } from '../WalletPermissionsManager'
4
+ import { Utils } from '@bsv/sdk'
4
5
 
5
6
  // Re-mock @bsv/sdk with our fixture classes (MockTransaction, MockLockingScript, etc.)
6
7
  jest.mock('@bsv/sdk', () => MockedBSV_SDK)
@@ -340,6 +341,7 @@ describe('WalletPermissionsManager - On-Chain Token Creation, Renewal & Revocati
340
341
  it('should spend the old token input and create a new protocol token output with updated expiry', async () => {
341
342
  // Suppose the user has an old protocol token:
342
343
  const oldToken: PermissionToken = {
344
+ tx: [],
343
345
  txid: 'oldTokenTX',
344
346
  outputIndex: 2,
345
347
  outputScript: '76a914...ac', // not used by the mock
@@ -399,6 +401,7 @@ describe('WalletPermissionsManager - On-Chain Token Creation, Renewal & Revocati
399
401
 
400
402
  it('should allow updating the authorizedAmount in DSAP renewal', async () => {
401
403
  const oldToken: PermissionToken = {
404
+ tx: [],
402
405
  txid: 'dsap-old-tx',
403
406
  outputIndex: 0,
404
407
  outputScript: 'sample script',
@@ -462,6 +465,7 @@ describe('WalletPermissionsManager - On-Chain Token Creation, Renewal & Revocati
462
465
  it('should create a transaction that consumes (spends) the old token with no new outputs', async () => {
463
466
  // A sample old token
464
467
  const oldToken: PermissionToken = {
468
+ tx: [],
465
469
  txid: 'revocableToken.txid',
466
470
  outputIndex: 1,
467
471
  outputScript: 'fakePushdropScript',
@@ -498,8 +502,43 @@ describe('WalletPermissionsManager - On-Chain Token Creation, Renewal & Revocati
498
502
  })
499
503
 
500
504
  it('should remove the old token from listing after revocation', async () => {
505
+ jest.spyOn(MockedBSV_SDK.Transaction, 'fromBEEF').mockImplementation(() => {
506
+ const mockTx = new MockTransaction()
507
+ // Add outputs with lockingScript
508
+ mockTx.outputs = [
509
+ {
510
+ lockingScript: {
511
+ // Ensure this matches what PushDrop.decode expects to work with
512
+ toHex: () => 'some script'
513
+ }
514
+ }
515
+ ]
516
+ // Add the toBEEF method
517
+ mockTx.toBEEF = () => []
518
+ return mockTx
519
+ })
520
+ // Add this to your test alongside the Transaction.fromBEEF mock
521
+ jest.spyOn(MockedBSV_SDK.PushDrop, 'decode').mockReturnValue({
522
+ fields: [
523
+ // Values that will decrypt to the expected values for domain, expiry, and basket
524
+ Utils.toArray('encoded-domain'),
525
+ Utils.toArray('encoded-expiry'),
526
+ Utils.toArray('encoded-basket')
527
+ ]
528
+ })
529
+
530
+ // You'll also need to mock the decryptPermissionTokenField method
531
+ // to handle these encoded values
532
+ jest.spyOn(manager as any, 'decryptPermissionTokenField').mockImplementation(field => {
533
+ if (field === 'encoded-domain') return new Uint8Array([...Buffer.from('example.com')])
534
+ if (field === 'encoded-expiry') return new Uint8Array([...Buffer.from('1735689600')])
535
+ if (field === 'encoded-basket') return new Uint8Array([...Buffer.from('protocol-permission')])
536
+ return new Uint8Array()
537
+ })
538
+
501
539
  // 1) Setup the underlying wallet to initially return the old token in listOutputs
502
540
  const oldToken: PermissionToken = {
541
+ tx: [],
503
542
  txid: 'aaaa1111',
504
543
  outputIndex: 0,
505
544
  outputScript: 'some script',
@@ -43,6 +43,6 @@ export function createDefaultWalletServicesOptions(chain: sdk.Chain): sdk.Wallet
43
43
  }
44
44
 
45
45
  export function arcDefaultUrl(chain: sdk.Chain): string {
46
- const url = chain === 'main' ? 'https://api.taal.com/arc' : 'https://arc-test.taal.com'
46
+ const url = chain === 'main' ? 'https://arc.taal.com' : 'https://arc-test.taal.com'
47
47
  return url
48
48
  }
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=ARC.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ARC.test.d.ts","sourceRoot":"","sources":["../../../../src/services/__tests/ARC.test.ts"],"names":[],"mappings":""}
@@ -1 +0,0 @@
1
- {"version":3,"file":"ARC.test.js","sourceRoot":"","sources":["../../../../src/services/__tests/ARC.test.ts"],"names":[],"mappings":"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"}