@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.
- package/docs/client.md +9 -0
- package/docs/wallet.md +9 -0
- package/out/src/WalletPermissionsManager.d.ts +2 -0
- package/out/src/WalletPermissionsManager.d.ts.map +1 -1
- package/out/src/WalletPermissionsManager.js +61 -31
- package/out/src/WalletPermissionsManager.js.map +1 -1
- package/out/src/__tests/WalletPermissionsManager.checks.test.js +6 -1
- package/out/src/__tests/WalletPermissionsManager.checks.test.js.map +1 -1
- package/out/src/__tests/WalletPermissionsManager.encryption.test.js +40 -1
- package/out/src/__tests/WalletPermissionsManager.encryption.test.js.map +1 -1
- package/out/src/__tests/WalletPermissionsManager.fixtures.d.ts +1 -0
- package/out/src/__tests/WalletPermissionsManager.fixtures.d.ts.map +1 -1
- package/out/src/__tests/WalletPermissionsManager.fixtures.js +5 -1
- package/out/src/__tests/WalletPermissionsManager.fixtures.js.map +1 -1
- package/out/src/__tests/WalletPermissionsManager.flows.test.js +2 -0
- package/out/src/__tests/WalletPermissionsManager.flows.test.js.map +1 -1
- package/out/src/__tests/WalletPermissionsManager.proxying.test.js +15 -2
- package/out/src/__tests/WalletPermissionsManager.proxying.test.js.map +1 -1
- package/out/src/__tests/WalletPermissionsManager.tokens.test.js +40 -0
- package/out/src/__tests/WalletPermissionsManager.tokens.test.js.map +1 -1
- package/out/src/services/__tests/ARC.man.test.d.ts +2 -0
- package/out/src/services/__tests/ARC.man.test.d.ts.map +1 -0
- package/out/src/services/__tests/{ARC.test.js → ARC.man.test.js} +1 -1
- package/out/src/services/__tests/ARC.man.test.js.map +1 -0
- package/out/src/services/createDefaultWalletServicesOptions.js +1 -1
- package/out/src/services/createDefaultWalletServicesOptions.js.map +1 -1
- package/out/tsconfig.all.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/WalletPermissionsManager.ts +66 -34
- package/src/__tests/WalletPermissionsManager.checks.test.ts +6 -1
- package/src/__tests/WalletPermissionsManager.encryption.test.ts +43 -2
- package/src/__tests/WalletPermissionsManager.fixtures.ts +6 -1
- package/src/__tests/WalletPermissionsManager.flows.test.ts +2 -0
- package/src/__tests/WalletPermissionsManager.proxying.test.ts +16 -2
- package/src/__tests/WalletPermissionsManager.tokens.test.ts +40 -1
- package/src/services/createDefaultWalletServicesOptions.ts +1 -1
- package/out/src/services/__tests/ARC.test.d.ts +0 -2
- package/out/src/services/__tests/ARC.test.d.ts.map +0 -1
- package/out/src/services/__tests/ARC.test.js.map +0 -1
- /package/src/services/__tests/{ARC.test.ts → ARC.man.test.ts} +0 -0
package/package.json
CHANGED
|
@@ -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
|
-
|
|
927
|
-
{
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
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: '
|
|
1011
|
+
include: 'entire transactions'
|
|
1005
1012
|
},
|
|
1006
1013
|
this.adminOriginator
|
|
1007
1014
|
)
|
|
1008
1015
|
|
|
1009
1016
|
for (const out of result.outputs) {
|
|
1010
|
-
const
|
|
1011
|
-
const
|
|
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:
|
|
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: '
|
|
1078
|
+
include: 'entire transactions'
|
|
1070
1079
|
},
|
|
1071
1080
|
this.adminOriginator
|
|
1072
1081
|
)
|
|
1073
1082
|
|
|
1074
1083
|
for (const out of result.outputs) {
|
|
1075
|
-
const
|
|
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:
|
|
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: '
|
|
1126
|
+
include: 'entire transactions'
|
|
1115
1127
|
},
|
|
1116
1128
|
this.adminOriginator
|
|
1117
1129
|
)
|
|
1118
1130
|
|
|
1119
1131
|
for (const out of result.outputs) {
|
|
1120
|
-
const
|
|
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:
|
|
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: '
|
|
1187
|
+
include: 'entire transactions'
|
|
1173
1188
|
},
|
|
1174
1189
|
this.adminOriginator
|
|
1175
1190
|
)
|
|
1176
1191
|
|
|
1177
1192
|
for (const out of result.outputs) {
|
|
1178
|
-
const
|
|
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:
|
|
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: '
|
|
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
|
|
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:
|
|
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: '
|
|
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
|
|
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:
|
|
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: '
|
|
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
|
|
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:
|
|
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: '
|
|
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
|
|
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:
|
|
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: '
|
|
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.
|
|
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: '
|
|
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.
|
|
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: '
|
|
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://
|
|
46
|
+
const url = chain === 'main' ? 'https://arc.taal.com' : 'https://arc-test.taal.com'
|
|
47
47
|
return url
|
|
48
48
|
}
|
|
@@ -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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"}
|
|
File without changes
|