@bsv/wallet-toolbox 2.0.0-beta.0 → 2.0.0
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/CHANGELOG.md +21 -0
- package/docs/README.md +1 -0
- package/docs/client.md +409 -267
- package/docs/services.md +15 -3
- package/docs/storage.md +48 -88
- package/docs/wab-shamir.md +311 -0
- package/docs/wallet.md +409 -267
- package/out/src/ShamirWalletManager.d.ts +213 -0
- package/out/src/ShamirWalletManager.d.ts.map +1 -0
- package/out/src/ShamirWalletManager.js +363 -0
- package/out/src/ShamirWalletManager.js.map +1 -0
- package/out/src/Wallet.d.ts +1 -1
- package/out/src/Wallet.d.ts.map +1 -1
- package/out/src/Wallet.js +23 -7
- package/out/src/Wallet.js.map +1 -1
- package/out/src/WalletPermissionsManager.d.ts +84 -1
- package/out/src/WalletPermissionsManager.d.ts.map +1 -1
- package/out/src/WalletPermissionsManager.js +1045 -214
- package/out/src/WalletPermissionsManager.js.map +1 -1
- package/out/src/__tests/ShamirWalletManager.test.d.ts +2 -0
- package/out/src/__tests/ShamirWalletManager.test.d.ts.map +1 -0
- package/out/src/__tests/ShamirWalletManager.test.js +298 -0
- package/out/src/__tests/ShamirWalletManager.test.js.map +1 -0
- package/out/src/__tests/WalletPermissionsManager.callbacks.test.js +134 -0
- package/out/src/__tests/WalletPermissionsManager.callbacks.test.js.map +1 -1
- package/out/src/__tests/WalletPermissionsManager.fixtures.d.ts.map +1 -1
- package/out/src/__tests/WalletPermissionsManager.fixtures.js +9 -0
- package/out/src/__tests/WalletPermissionsManager.fixtures.js.map +1 -1
- package/out/src/__tests/WalletPermissionsManager.flows.test.js +121 -0
- package/out/src/__tests/WalletPermissionsManager.flows.test.js.map +1 -1
- package/out/src/__tests/WalletPermissionsManager.pmodules.test.js +111 -0
- package/out/src/__tests/WalletPermissionsManager.pmodules.test.js.map +1 -1
- package/out/src/entropy/EntropyCollector.d.ts +89 -0
- package/out/src/entropy/EntropyCollector.d.ts.map +1 -0
- package/out/src/entropy/EntropyCollector.js +176 -0
- package/out/src/entropy/EntropyCollector.js.map +1 -0
- package/out/src/entropy/__tests/EntropyCollector.test.d.ts +2 -0
- package/out/src/entropy/__tests/EntropyCollector.test.d.ts.map +1 -0
- package/out/src/entropy/__tests/EntropyCollector.test.js +137 -0
- package/out/src/entropy/__tests/EntropyCollector.test.js.map +1 -0
- package/out/src/index.all.d.ts +2 -0
- package/out/src/index.all.d.ts.map +1 -1
- package/out/src/index.all.js +2 -0
- package/out/src/index.all.js.map +1 -1
- package/out/src/sdk/WalletServices.interfaces.d.ts.map +1 -1
- package/out/src/sdk/WalletStorage.interfaces.d.ts +3 -3
- package/out/src/sdk/WalletStorage.interfaces.d.ts.map +1 -1
- package/out/src/services/__tests/getRawTx.test.js +3 -0
- package/out/src/services/__tests/getRawTx.test.js.map +1 -1
- package/out/src/services/chaintracker/chaintracks/Ingest/BulkIngestorWhatsOnChainCdn.d.ts +1 -1
- package/out/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageBase.d.ts.map +1 -1
- package/out/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageBase.js +4 -1
- package/out/src/services/chaintracker/chaintracks/Storage/ChaintracksStorageBase.js.map +1 -1
- package/out/src/services/chaintracker/chaintracks/__tests/Chaintracks.test.js +3 -1
- package/out/src/services/chaintracker/chaintracks/__tests/Chaintracks.test.js.map +1 -1
- package/out/src/services/chaintracker/chaintracks/util/blockHeaderUtilities.d.ts.map +1 -1
- package/out/src/services/chaintracker/chaintracks/util/blockHeaderUtilities.js +1 -2
- package/out/src/services/chaintracker/chaintracks/util/blockHeaderUtilities.js.map +1 -1
- package/out/src/services/chaintracker/chaintracks/util/validBulkHeaderFilesByFileHash.d.ts.map +1 -1
- package/out/src/services/chaintracker/chaintracks/util/validBulkHeaderFilesByFileHash.js +12 -0
- package/out/src/services/chaintracker/chaintracks/util/validBulkHeaderFilesByFileHash.js.map +1 -1
- package/out/src/storage/StorageProvider.d.ts +16 -2
- package/out/src/storage/StorageProvider.d.ts.map +1 -1
- package/out/src/storage/StorageProvider.js +33 -4
- package/out/src/storage/StorageProvider.js.map +1 -1
- package/out/src/storage/methods/ListOutputsSpecOp.d.ts +15 -1
- package/out/src/storage/methods/ListOutputsSpecOp.d.ts.map +1 -1
- package/out/src/storage/methods/ListOutputsSpecOp.js +52 -2
- package/out/src/storage/methods/ListOutputsSpecOp.js.map +1 -1
- package/out/src/storage/methods/__test/offsetKey.test.js +266 -100
- package/out/src/storage/methods/__test/offsetKey.test.js.map +1 -1
- package/out/src/storage/methods/getBeefForTransaction.js +1 -1
- package/out/src/storage/methods/getBeefForTransaction.js.map +1 -1
- package/out/src/storage/methods/internalizeAction.d.ts.map +1 -1
- package/out/src/storage/methods/internalizeAction.js +2 -2
- package/out/src/storage/methods/internalizeAction.js.map +1 -1
- package/out/src/storage/methods/listOutputsIdb.d.ts.map +1 -1
- package/out/src/storage/methods/listOutputsIdb.js +10 -17
- package/out/src/storage/methods/listOutputsIdb.js.map +1 -1
- package/out/src/storage/methods/listOutputsKnex.d.ts.map +1 -1
- package/out/src/storage/methods/listOutputsKnex.js +44 -26
- package/out/src/storage/methods/listOutputsKnex.js.map +1 -1
- package/out/src/storage/schema/entities/__tests/ProvenTxTests.test.js +4 -0
- package/out/src/storage/schema/entities/__tests/ProvenTxTests.test.js.map +1 -1
- package/out/src/wab-client/WABClient.d.ts +65 -0
- package/out/src/wab-client/WABClient.d.ts.map +1 -1
- package/out/src/wab-client/WABClient.js +107 -0
- package/out/src/wab-client/WABClient.js.map +1 -1
- package/package.json +8 -4
- package/out/src/sdk/validationHelpers.d.ts +0 -303
- package/out/src/sdk/validationHelpers.d.ts.map +0 -1
- package/out/src/sdk/validationHelpers.js +0 -632
- package/out/src/sdk/validationHelpers.js.map +0 -1
- package/out/src/utility/ReaderUint8Array.d.ts +0 -28
- package/out/src/utility/ReaderUint8Array.d.ts.map +0 -1
- package/out/src/utility/ReaderUint8Array.js +0 -166
- package/out/src/utility/ReaderUint8Array.js.map +0 -1
package/docs/services.md
CHANGED
|
@@ -610,7 +610,7 @@ enableCache: boolean
|
|
|
610
610
|
|
|
611
611
|
###### Property idleWait
|
|
612
612
|
|
|
613
|
-
Maximum
|
|
613
|
+
Maximum msecs of "normal" pause with no new data arriving.
|
|
614
614
|
|
|
615
615
|
```ts
|
|
616
616
|
idleWait: number | undefined
|
|
@@ -5222,7 +5222,7 @@ Deserialize a BaseBlockHeader from an 80 byte buffer
|
|
|
5222
5222
|
|
|
5223
5223
|
```ts
|
|
5224
5224
|
export function deserializeBaseBlockHeader(buffer: number[] | Uint8Array, offset = 0): BaseBlockHeader {
|
|
5225
|
-
const reader = ReaderUint8Array.makeReader(buffer, offset);
|
|
5225
|
+
const reader = Utils.ReaderUint8Array.makeReader(buffer, offset);
|
|
5226
5226
|
const header: BaseBlockHeader = {
|
|
5227
5227
|
version: reader.readUInt32LE(),
|
|
5228
5228
|
previousHash: asString(reader.read(32).reverse()),
|
|
@@ -5235,7 +5235,7 @@ export function deserializeBaseBlockHeader(buffer: number[] | Uint8Array, offset
|
|
|
5235
5235
|
}
|
|
5236
5236
|
```
|
|
5237
5237
|
|
|
5238
|
-
See also: [BaseBlockHeader](./client.md#interface-baseblockheader), [
|
|
5238
|
+
See also: [BaseBlockHeader](./client.md#interface-baseblockheader), [asString](./client.md#function-asstring), [readUInt32LE](./services.md#function-readuint32le)
|
|
5239
5239
|
|
|
5240
5240
|
Links: [API](#api), [Interfaces](#interfaces), [Classes](#classes), [Functions](#functions), [Types](#types), [Variables](#variables)
|
|
5241
5241
|
|
|
@@ -6364,6 +6364,18 @@ validBulkHeaderFiles: BulkHeaderFileInfo[] = [
|
|
|
6364
6364
|
prevHash: "00000000000000000e7dcc27c06ee353bd37260b2e7e664314c204f0324a5087",
|
|
6365
6365
|
sourceUrl: "https://cdn.projectbabbage.com/blockheaders",
|
|
6366
6366
|
validated: true
|
|
6367
|
+
},
|
|
6368
|
+
{
|
|
6369
|
+
chain: "main",
|
|
6370
|
+
count: 31772,
|
|
6371
|
+
fileHash: "NuVsRUrI5QnjILbYy4LS3A/Udl6PH/m8Y9uVguEsekM=",
|
|
6372
|
+
fileName: "mainNet_9.headers",
|
|
6373
|
+
firstHeight: 900000,
|
|
6374
|
+
lastChainWork: "0000000000000000000000000000000000000000016ab16bb9b31430588788d3",
|
|
6375
|
+
lastHash: "0000000000000000024a2f1caef4b0ffdc1a036b09f9ed7f48b538f619f32ef2",
|
|
6376
|
+
prevChainWork: "000000000000000000000000000000000000000001664db1f2d50327928007e0",
|
|
6377
|
+
prevHash: "00000000000000000e7dcc27c06ee353bd37260b2e7e664314c204f0324a5087",
|
|
6378
|
+
sourceUrl: "https://cdn.projectbabbage.com/blockheaders"
|
|
6367
6379
|
}
|
|
6368
6380
|
]
|
|
6369
6381
|
```
|
package/docs/storage.md
CHANGED
|
@@ -334,6 +334,7 @@ export interface ListOutputsSpecOp {
|
|
|
334
334
|
ignoreLimit?: boolean;
|
|
335
335
|
includeOutputScripts?: boolean;
|
|
336
336
|
includeSpent?: boolean;
|
|
337
|
+
totalOutputsIsSumOfSatoshis?: boolean;
|
|
337
338
|
resultFromTags?: (s: StorageProvider, auth: AuthId, vargs: Validation.ValidListOutputsArgs, specOpTags: string[]) => Promise<ListOutputsResult>;
|
|
338
339
|
resultFromOutputs?: (s: StorageProvider, auth: AuthId, vargs: Validation.ValidListOutputsArgs, specOpTags: string[], outputs: TableOutput[]) => Promise<ListOutputsResult>;
|
|
339
340
|
filterOutputs?: (s: StorageProvider, auth: AuthId, vargs: Validation.ValidListOutputsArgs, specOpTags: string[], outputs: TableOutput[]) => Promise<TableOutput[]>;
|
|
@@ -362,6 +363,14 @@ or an explicit array of tags to intercept.
|
|
|
362
363
|
tagsToIntercept?: string[]
|
|
363
364
|
```
|
|
364
365
|
|
|
366
|
+
###### Property totalOutputsIsSumOfSatoshis
|
|
367
|
+
|
|
368
|
+
If true, and supported by storage, maximum performance optimization, computing balance done in the query itself.
|
|
369
|
+
|
|
370
|
+
```ts
|
|
371
|
+
totalOutputsIsSumOfSatoshis?: boolean
|
|
372
|
+
```
|
|
373
|
+
|
|
365
374
|
Links: [API](#api), [Interfaces](#interfaces), [Classes](#classes), [Functions](#functions), [Types](#types), [Variables](#variables)
|
|
366
375
|
|
|
367
376
|
---
|
|
@@ -3949,7 +3958,7 @@ export abstract class StorageProvider extends StorageReaderWriter implements Wal
|
|
|
3949
3958
|
async listCertificates(auth: AuthId, args: Validation.ValidListCertificatesArgs): Promise<ListCertificatesResult>
|
|
3950
3959
|
async verifyKnownValidTransaction(txid: string, trx?: TrxToken): Promise<boolean>
|
|
3951
3960
|
async getValidBeefForKnownTxid(txid: string, mergeToBeef?: Beef, trustSelf?: TrustSelf, knownTxids?: string[], trx?: TrxToken, requiredLevels?: number): Promise<Beef>
|
|
3952
|
-
async getValidBeefForTxid(txid: string, mergeToBeef?: Beef, trustSelf?: TrustSelf, knownTxids?: string[], trx?: TrxToken, requiredLevels?: number): Promise<Beef | undefined>
|
|
3961
|
+
async getValidBeefForTxid(txid: string, mergeToBeef?: Beef, trustSelf?: TrustSelf, knownTxids?: string[], trx?: TrxToken, requiredLevels?: number, chainTracker?: ChainTracker, skipInvalidProofs?: boolean): Promise<Beef | undefined>
|
|
3953
3962
|
async getBeefForTransaction(txid: string, options: StorageGetBeefOptions): Promise<Beef>
|
|
3954
3963
|
async findMonitorEventById(id: number, trx?: TrxToken): Promise<TableMonitorEvent | undefined>
|
|
3955
3964
|
async relinquishCertificate(auth: AuthId, args: RelinquishCertificateArgs): Promise<number>
|
|
@@ -4010,6 +4019,18 @@ async getReqsAndBeefToShareWithWorld(txids: string[], knownTxids: string[], trx?
|
|
|
4010
4019
|
```
|
|
4011
4020
|
See also: [GetReqsAndBeefResult](./storage.md#interface-getreqsandbeefresult), [TrxToken](./client.md#interface-trxtoken)
|
|
4012
4021
|
|
|
4022
|
+
###### Method getValidBeefForKnownTxid
|
|
4023
|
+
|
|
4024
|
+
Pulls data from storage to build a valid beef for a txid.
|
|
4025
|
+
|
|
4026
|
+
Optionally merges the data into an existing beef.
|
|
4027
|
+
Optionally requires a minimum number of proof levels.
|
|
4028
|
+
|
|
4029
|
+
```ts
|
|
4030
|
+
async getValidBeefForKnownTxid(txid: string, mergeToBeef?: Beef, trustSelf?: TrustSelf, knownTxids?: string[], trx?: TrxToken, requiredLevels?: number): Promise<Beef>
|
|
4031
|
+
```
|
|
4032
|
+
See also: [TrxToken](./client.md#interface-trxtoken)
|
|
4033
|
+
|
|
4013
4034
|
###### Method updateProvenTxReqWithNewProvenTx
|
|
4014
4035
|
|
|
4015
4036
|
Handles storage changes when a valid MerklePath and mined block header are found for a ProvenTxReq txid.
|
|
@@ -4583,18 +4604,18 @@ Links: [API](#api), [Interfaces](#interfaces), [Classes](#classes), [Functions](
|
|
|
4583
4604
|
|
|
4584
4605
|
| | | |
|
|
4585
4606
|
| --- | --- | --- |
|
|
4586
|
-
| [attemptToPostReqsToNetwork](#function-attempttopostreqstonetwork) | [
|
|
4587
|
-
| [createAction](#function-createaction) | [
|
|
4588
|
-
| [createStorageServiceChargeScript](#function-createstorageservicechargescript) | [
|
|
4589
|
-
| [createSyncMap](#function-createsyncmap) | [
|
|
4590
|
-
| [determineDBType](#function-determinedbtype) | [
|
|
4591
|
-
| [generateChangeSdk](#function-generatechangesdk) | [
|
|
4592
|
-
| [generateChangeSdkMakeStorage](#function-generatechangesdkmakestorage) | [
|
|
4593
|
-
| [getBeefForTransaction](#function-getbeeffortransaction) | [
|
|
4607
|
+
| [attemptToPostReqsToNetwork](#function-attempttopostreqstonetwork) | [listActions](#function-listactions) | [reviewStatus](#function-reviewstatus) |
|
|
4608
|
+
| [createAction](#function-createaction) | [listActionsIdb](#function-listactionsidb) | [reviewStatusIdb](#function-reviewstatusidb) |
|
|
4609
|
+
| [createStorageServiceChargeScript](#function-createstorageservicechargescript) | [listCertificates](#function-listcertificates) | [setDisableDoubleSpendCheckForTest](#function-setdisabledoublespendcheckfortest) |
|
|
4610
|
+
| [createSyncMap](#function-createsyncmap) | [listOutputs](#function-listoutputs) | [shareReqsWithWorld](#function-sharereqswithworld) |
|
|
4611
|
+
| [determineDBType](#function-determinedbtype) | [listOutputsIdb](#function-listoutputsidb) | [transactionInputSize](#function-transactioninputsize) |
|
|
4612
|
+
| [generateChangeSdk](#function-generatechangesdk) | [lockScriptWithKeyOffsetFromPubKey](#function-lockscriptwithkeyoffsetfrompubkey) | [transactionOutputSize](#function-transactionoutputsize) |
|
|
4613
|
+
| [generateChangeSdkMakeStorage](#function-generatechangesdkmakestorage) | [offsetPrivKey](#function-offsetprivkey) | [transactionSize](#function-transactionsize) |
|
|
4614
|
+
| [getBeefForTransaction](#function-getbeeffortransaction) | [offsetPubKey](#function-offsetpubkey) | [validateGenerateChangeSdkParams](#function-validategeneratechangesdkparams) |
|
|
4615
|
+
| [getListOutputsSpecOp](#function-getlistoutputsspecop) | [processAction](#function-processaction) | [validateGenerateChangeSdkResult](#function-validategeneratechangesdkresult) |
|
|
4594
4616
|
| [getSyncChunk](#function-getsyncchunk) | [purgeData](#function-purgedata) | [validateStorageFeeModel](#function-validatestoragefeemodel) |
|
|
4595
4617
|
| [internalizeAction](#function-internalizeaction) | [purgeDataIdb](#function-purgedataidb) | [varUintSize](#function-varuintsize) |
|
|
4596
4618
|
| [keyOffsetToHashedSecret](#function-keyoffsettohashedsecret) | [redeemServiceCharges](#function-redeemservicecharges) | |
|
|
4597
|
-
| [listActions](#function-listactions) | [reviewStatus](#function-reviewstatus) | |
|
|
4598
4619
|
|
|
4599
4620
|
Links: [API](#api), [Interfaces](#interfaces), [Classes](#classes), [Functions](#functions), [Types](#types), [Variables](#variables)
|
|
4600
4621
|
|
|
@@ -4725,6 +4746,23 @@ Argument Details
|
|
|
4725
4746
|
|
|
4726
4747
|
Links: [API](#api), [Interfaces](#interfaces), [Classes](#classes), [Functions](#functions), [Types](#types), [Variables](#variables)
|
|
4727
4748
|
|
|
4749
|
+
---
|
|
4750
|
+
##### Function: getListOutputsSpecOp
|
|
4751
|
+
|
|
4752
|
+
Check basket and tags arguments passed to listOutputs to determine if they trigger a special operation execution mode.
|
|
4753
|
+
|
|
4754
|
+
```ts
|
|
4755
|
+
export function getListOutputsSpecOp(basket: string, tags: string[]): {
|
|
4756
|
+
specOp: ListOutputsSpecOp | undefined;
|
|
4757
|
+
basket?: string;
|
|
4758
|
+
tags: string[];
|
|
4759
|
+
}
|
|
4760
|
+
```
|
|
4761
|
+
|
|
4762
|
+
See also: [ListOutputsSpecOp](./storage.md#interface-listoutputsspecop)
|
|
4763
|
+
|
|
4764
|
+
Links: [API](#api), [Interfaces](#interfaces), [Classes](#classes), [Functions](#functions), [Types](#types), [Variables](#variables)
|
|
4765
|
+
|
|
4728
4766
|
---
|
|
4729
4767
|
##### Function: getSyncChunk
|
|
4730
4768
|
|
|
@@ -5167,7 +5205,6 @@ Links: [API](#api), [Interfaces](#interfaces), [Classes](#classes), [Functions](
|
|
|
5167
5205
|
|
|
5168
5206
|
| |
|
|
5169
5207
|
| --- |
|
|
5170
|
-
| [getBasketToSpecOp](#variable-getbaskettospecop) |
|
|
5171
5208
|
| [getLabelToSpecOp](#variable-getlabeltospecop) |
|
|
5172
5209
|
| [maxPossibleSatoshis](#variable-maxpossiblesatoshis) |
|
|
5173
5210
|
| [outputColumnsWithoutLockingScript](#variable-outputcolumnswithoutlockingscript) |
|
|
@@ -5177,83 +5214,6 @@ Links: [API](#api), [Interfaces](#interfaces), [Classes](#classes), [Functions](
|
|
|
5177
5214
|
|
|
5178
5215
|
---
|
|
5179
5216
|
|
|
5180
|
-
##### Variable: getBasketToSpecOp
|
|
5181
|
-
|
|
5182
|
-
```ts
|
|
5183
|
-
getBasketToSpecOp: () => Record<string, ListOutputsSpecOp> = () => {
|
|
5184
|
-
return {
|
|
5185
|
-
[specOpWalletBalance]: {
|
|
5186
|
-
name: "totalOutputsIsWalletBalance",
|
|
5187
|
-
useBasket: "default",
|
|
5188
|
-
ignoreLimit: true,
|
|
5189
|
-
resultFromOutputs: async (s: StorageProvider, auth: AuthId, vargs: Validation.ValidListOutputsArgs, specOpTags: string[], outputs: TableOutput[]): Promise<ListOutputsResult> => {
|
|
5190
|
-
let totalOutputs = 0;
|
|
5191
|
-
for (const o of outputs)
|
|
5192
|
-
totalOutputs += o.satoshis;
|
|
5193
|
-
return { totalOutputs, outputs: [] };
|
|
5194
|
-
}
|
|
5195
|
-
},
|
|
5196
|
-
[specOpInvalidChange]: {
|
|
5197
|
-
name: "invalidChangeOutputs",
|
|
5198
|
-
useBasket: "default",
|
|
5199
|
-
ignoreLimit: true,
|
|
5200
|
-
includeOutputScripts: true,
|
|
5201
|
-
includeSpent: false,
|
|
5202
|
-
tagsToIntercept: ["release", "all"],
|
|
5203
|
-
filterOutputs: async (s: StorageProvider, auth: AuthId, vargs: Validation.ValidListOutputsArgs, specOpTags: string[], outputs: TableOutput[]): Promise<TableOutput[]> => {
|
|
5204
|
-
const filteredOutputs: TableOutput[] = [];
|
|
5205
|
-
const services = s.getServices();
|
|
5206
|
-
for (const o of outputs) {
|
|
5207
|
-
if (!o.basketId)
|
|
5208
|
-
continue;
|
|
5209
|
-
await s.validateOutputScript(o);
|
|
5210
|
-
let ok: boolean | undefined = false;
|
|
5211
|
-
if (o.lockingScript && o.lockingScript.length > 0) {
|
|
5212
|
-
ok = await services.isUtxo(o);
|
|
5213
|
-
}
|
|
5214
|
-
else {
|
|
5215
|
-
ok = undefined;
|
|
5216
|
-
}
|
|
5217
|
-
if (ok === false) {
|
|
5218
|
-
filteredOutputs.push(o);
|
|
5219
|
-
}
|
|
5220
|
-
}
|
|
5221
|
-
if (specOpTags.indexOf("release") >= 0) {
|
|
5222
|
-
for (const o of filteredOutputs) {
|
|
5223
|
-
await s.updateOutput(o.outputId, { spendable: false });
|
|
5224
|
-
o.spendable = false;
|
|
5225
|
-
}
|
|
5226
|
-
}
|
|
5227
|
-
return filteredOutputs;
|
|
5228
|
-
}
|
|
5229
|
-
},
|
|
5230
|
-
[specOpSetWalletChangeParams]: {
|
|
5231
|
-
name: "setWalletChangeParams",
|
|
5232
|
-
tagsParamsCount: 2,
|
|
5233
|
-
resultFromTags: async (s: StorageProvider, auth: AuthId, vargs: Validation.ValidListOutputsArgs, specOpTags: string[]): Promise<ListOutputsResult> => {
|
|
5234
|
-
if (specOpTags.length !== 2)
|
|
5235
|
-
throw new WERR_INVALID_PARAMETER("numberOfDesiredUTXOs and minimumDesiredUTXOValue", "valid");
|
|
5236
|
-
const numberOfDesiredUTXOs: number = verifyInteger(Number(specOpTags[0]));
|
|
5237
|
-
const minimumDesiredUTXOValue: number = verifyInteger(Number(specOpTags[1]));
|
|
5238
|
-
const basket = verifyOne(await s.findOutputBaskets({
|
|
5239
|
-
partial: { userId: verifyId(auth.userId), name: "default" }
|
|
5240
|
-
}));
|
|
5241
|
-
await s.updateOutputBasket(basket.basketId, {
|
|
5242
|
-
numberOfDesiredUTXOs,
|
|
5243
|
-
minimumDesiredUTXOValue
|
|
5244
|
-
});
|
|
5245
|
-
return { totalOutputs: 0, outputs: [] };
|
|
5246
|
-
}
|
|
5247
|
-
}
|
|
5248
|
-
};
|
|
5249
|
-
}
|
|
5250
|
-
```
|
|
5251
|
-
|
|
5252
|
-
See also: [AuthId](./client.md#interface-authid), [ListOutputsSpecOp](./storage.md#interface-listoutputsspecop), [StorageProvider](./storage.md#class-storageprovider), [TableOutput](./storage.md#interface-tableoutput), [WERR_INVALID_PARAMETER](./client.md#class-werr_invalid_parameter), [specOpInvalidChange](./client.md#variable-specopinvalidchange), [specOpSetWalletChangeParams](./client.md#variable-specopsetwalletchangeparams), [specOpWalletBalance](./client.md#variable-specopwalletbalance), [verifyId](./client.md#function-verifyid), [verifyInteger](./client.md#function-verifyinteger), [verifyOne](./client.md#function-verifyone)
|
|
5253
|
-
|
|
5254
|
-
Links: [API](#api), [Interfaces](#interfaces), [Classes](#classes), [Functions](#functions), [Types](#types), [Variables](#variables)
|
|
5255
|
-
|
|
5256
|
-
---
|
|
5257
5217
|
##### Variable: getLabelToSpecOp
|
|
5258
5218
|
|
|
5259
5219
|
```ts
|
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
# WAB Shamir Key Recovery
|
|
2
|
+
|
|
3
|
+
This guide covers the Shamir Secret Sharing key recovery system, which provides secure wallet backup and recovery using a configurable threshold scheme.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
The Shamir system splits your wallet's root private key into multiple shares. A configurable threshold of shares can reconstruct the key:
|
|
8
|
+
|
|
9
|
+
- **Server share**: Stored on WAB server, released only after OTP verification
|
|
10
|
+
- **User shares**: Application decides how to store (print, password manager, hardware device, etc.)
|
|
11
|
+
|
|
12
|
+
**Default configuration (2-of-3):**
|
|
13
|
+
- 3 total shares, 2 required to reconstruct
|
|
14
|
+
- Server holds 1 share, user receives 2 shares
|
|
15
|
+
- Any 2 shares can recover the key
|
|
16
|
+
|
|
17
|
+
**Example configurations:**
|
|
18
|
+
|
|
19
|
+
| Threshold | Total | Server | User Shares | Use Case |
|
|
20
|
+
|-----------|-------|--------|-------------|----------|
|
|
21
|
+
| 2 | 3 | 1 | 2 | Standard (default) |
|
|
22
|
+
| 2 | 4 | 1 | 3 | Extra redundancy |
|
|
23
|
+
| 3 | 5 | 1 | 4 | High security |
|
|
24
|
+
| 3 | 4 | 1 | 3 | Balanced security |
|
|
25
|
+
|
|
26
|
+
**Important constraint:** User must always have at least `threshold` shares so they can recover independently without the server. This prevents the WAB from becoming a custodian of user funds. For example, 2-of-2 is not allowed because the user would only have 1 share and could not recover without server cooperation.
|
|
27
|
+
|
|
28
|
+
The WAB server always stores exactly one share and cannot reconstruct the key alone.
|
|
29
|
+
|
|
30
|
+
## Generating a Secure Key with Entropy Collection
|
|
31
|
+
|
|
32
|
+
For maximum security, keys are generated using mouse movement entropy mixed with the system's cryptographically secure random number generator (CSPRNG).
|
|
33
|
+
|
|
34
|
+
```ts
|
|
35
|
+
import { EntropyCollector } from '@bsv/wallet-toolbox'
|
|
36
|
+
|
|
37
|
+
// Create collector (default: 256 samples)
|
|
38
|
+
const collector = new EntropyCollector({
|
|
39
|
+
targetSamples: 256,
|
|
40
|
+
minSampleInterval: 10 // ms between samples
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
// Option 1: Manual collection from mousemove events
|
|
44
|
+
document.addEventListener('mousemove', (event) => {
|
|
45
|
+
const progress = collector.addMouseSample(event.clientX, event.clientY)
|
|
46
|
+
if (progress) {
|
|
47
|
+
console.log(`Entropy: ${progress.percent}% (${progress.collected}/${progress.target})`)
|
|
48
|
+
}
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
// Check when complete
|
|
52
|
+
if (collector.isComplete()) {
|
|
53
|
+
const entropy = collector.generateEntropy() // 32 bytes
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Option 2: Automatic browser collection with progress callback
|
|
57
|
+
const entropy = await collector.collectFromBrowser(document, (progress) => {
|
|
58
|
+
updateProgressBar(progress.percent)
|
|
59
|
+
})
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
The `generateEntropy()` method:
|
|
63
|
+
1. Extracts raw entropy from mouse positions and timing
|
|
64
|
+
2. Hashes it with SHA-256 to whiten the data
|
|
65
|
+
3. XORs with `crypto.getRandomValues()` output
|
|
66
|
+
4. Final SHA-256 hash ensures uniform distribution
|
|
67
|
+
|
|
68
|
+
## Using ShamirWalletManager
|
|
69
|
+
|
|
70
|
+
The `ShamirWalletManager` class handles the complete wallet lifecycle with Shamir shares.
|
|
71
|
+
|
|
72
|
+
### Configuration
|
|
73
|
+
|
|
74
|
+
```ts
|
|
75
|
+
import { ShamirWalletManager, Setup, PrivateKey, PrivilegedKeyManager } from '@bsv/wallet-toolbox'
|
|
76
|
+
|
|
77
|
+
const manager = new ShamirWalletManager({
|
|
78
|
+
wabServerUrl: 'https://your-wab-server.com',
|
|
79
|
+
authMethodType: 'TwilioPhone', // or 'DevConsole' for development
|
|
80
|
+
|
|
81
|
+
// Optional: customize threshold scheme (defaults to 2-of-3)
|
|
82
|
+
threshold: 2, // shares needed to reconstruct (min: 2)
|
|
83
|
+
totalShares: 3, // total shares generated (min: 3, must be >= threshold + 1)
|
|
84
|
+
|
|
85
|
+
walletBuilder: async (privateKey, privilegedKeyManager) => {
|
|
86
|
+
const { wallet } = await Setup.createWalletSQLite({
|
|
87
|
+
filePath: './wallet.sqlite',
|
|
88
|
+
databaseName: 'myWallet',
|
|
89
|
+
chain: 'main',
|
|
90
|
+
rootKeyHex: privateKey.toHex(),
|
|
91
|
+
privilegedKeyManager
|
|
92
|
+
})
|
|
93
|
+
return wallet
|
|
94
|
+
}
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
// Check configuration
|
|
98
|
+
console.log(`Using ${manager.getThreshold()}-of-${manager.getTotalShares()} scheme`)
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Creating a New Wallet
|
|
102
|
+
|
|
103
|
+
```ts
|
|
104
|
+
// 1. Collect entropy (show user a "move your mouse" UI)
|
|
105
|
+
await manager.collectEntropyFromBrowser(document, (progress) => {
|
|
106
|
+
document.getElementById('progress').textContent = `${progress.percent}%`
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
// 2. Start OTP verification (user receives SMS)
|
|
110
|
+
const wabClient = new WABClient('https://your-wab-server.com')
|
|
111
|
+
await wabClient.startShareAuth('TwilioPhone', userIdHash, {
|
|
112
|
+
phoneNumber: '+1234567890'
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
// 3. User enters OTP code, then create wallet
|
|
116
|
+
const result = await manager.createNewWallet(
|
|
117
|
+
{ phoneNumber: '+1234567890', otp: '123456' },
|
|
118
|
+
async (userShares, threshold, totalShares) => {
|
|
119
|
+
// Application decides how to handle user shares
|
|
120
|
+
// For 2-of-3: userShares has 2 shares
|
|
121
|
+
console.log(`Save these ${userShares.length} shares (${threshold}-of-${totalShares} scheme)`)
|
|
122
|
+
|
|
123
|
+
// Example: first share for printing, second for password manager
|
|
124
|
+
await showPrintableBackup(userShares[0])
|
|
125
|
+
await showCopyableText(userShares[1])
|
|
126
|
+
|
|
127
|
+
return await confirmUserSavedShares()
|
|
128
|
+
}
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
console.log('User ID Hash:', result.userIdHash)
|
|
132
|
+
console.log('User Shares:', result.userShares)
|
|
133
|
+
console.log(`Scheme: ${result.threshold}-of-${result.totalShares}`)
|
|
134
|
+
|
|
135
|
+
// 4. Build and use the wallet
|
|
136
|
+
const wallet = await manager.buildWallet()
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### Recovery with Server Share
|
|
140
|
+
|
|
141
|
+
When the user has enough shares but needs the server share to meet threshold:
|
|
142
|
+
|
|
143
|
+
```ts
|
|
144
|
+
const manager = new ShamirWalletManager({ /* config */ })
|
|
145
|
+
|
|
146
|
+
// User provides their userIdHash
|
|
147
|
+
manager.setUserIdHash(savedUserIdHash)
|
|
148
|
+
|
|
149
|
+
// Start OTP to retrieve server share
|
|
150
|
+
await manager.startOTPVerification({ phoneNumber: '+1234567890' })
|
|
151
|
+
|
|
152
|
+
// Recover with user shares (need threshold-1 shares)
|
|
153
|
+
// For 2-of-3: need 1 user share + server share
|
|
154
|
+
const privateKey = await manager.recoverWithServerShare(
|
|
155
|
+
[userShare1], // Array of user-held shares
|
|
156
|
+
{ phoneNumber: '+1234567890', otp: '123456' }
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
const wallet = await manager.buildWallet()
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### Recovery with User Shares Only (Offline)
|
|
163
|
+
|
|
164
|
+
When the user has enough shares to meet threshold without the server:
|
|
165
|
+
|
|
166
|
+
```ts
|
|
167
|
+
const manager = new ShamirWalletManager({ /* config */ })
|
|
168
|
+
|
|
169
|
+
// Recover using user-held shares (need at least threshold shares)
|
|
170
|
+
// For 2-of-3: need 2 user shares
|
|
171
|
+
const privateKey = await manager.recoverWithUserShares([userShare1, userShare2])
|
|
172
|
+
|
|
173
|
+
const wallet = await manager.buildWallet()
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## Using WABClient Directly
|
|
177
|
+
|
|
178
|
+
For lower-level control, use `WABClient` directly:
|
|
179
|
+
|
|
180
|
+
```ts
|
|
181
|
+
import { WABClient } from '@bsv/wallet-toolbox'
|
|
182
|
+
|
|
183
|
+
const client = new WABClient('https://your-wab-server.com')
|
|
184
|
+
|
|
185
|
+
// Start OTP verification
|
|
186
|
+
await client.startShareAuth('TwilioPhone', userIdHash, {
|
|
187
|
+
phoneNumber: '+1234567890'
|
|
188
|
+
})
|
|
189
|
+
|
|
190
|
+
// Store the server share (after OTP verification)
|
|
191
|
+
const storeResult = await client.storeShare(
|
|
192
|
+
'TwilioPhone',
|
|
193
|
+
{ phoneNumber: '+1234567890', otp: '123456' },
|
|
194
|
+
serverShare, // The share to store (format: x.y.threshold.integrity)
|
|
195
|
+
userIdHash
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
// Retrieve the server share (requires OTP)
|
|
199
|
+
const retrieveResult = await client.retrieveShare(
|
|
200
|
+
'TwilioPhone',
|
|
201
|
+
{ phoneNumber: '+1234567890', otp: '654321' },
|
|
202
|
+
userIdHash
|
|
203
|
+
)
|
|
204
|
+
console.log('Retrieved server share:', retrieveResult.shareB)
|
|
205
|
+
|
|
206
|
+
// Update share (for key rotation)
|
|
207
|
+
await client.updateShare(
|
|
208
|
+
'TwilioPhone',
|
|
209
|
+
{ phoneNumber: '+1234567890', otp: '111222' },
|
|
210
|
+
userIdHash,
|
|
211
|
+
newServerShare
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
// Delete account and stored share
|
|
215
|
+
await client.deleteShamirUser(
|
|
216
|
+
'TwilioPhone',
|
|
217
|
+
{ phoneNumber: '+1234567890', otp: '333444' },
|
|
218
|
+
userIdHash
|
|
219
|
+
)
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
## Key Rotation
|
|
223
|
+
|
|
224
|
+
To rotate keys (generate new shares while maintaining access):
|
|
225
|
+
|
|
226
|
+
```ts
|
|
227
|
+
// Collect fresh entropy
|
|
228
|
+
manager.resetEntropy()
|
|
229
|
+
await manager.collectEntropyFromBrowser(document, onProgress)
|
|
230
|
+
|
|
231
|
+
// Rotate keys (requires OTP verification)
|
|
232
|
+
const newResult = await manager.rotateKeys(
|
|
233
|
+
{ phoneNumber: '+1234567890', otp: '123456' },
|
|
234
|
+
async (userShares, threshold, totalShares) => {
|
|
235
|
+
console.log(`Save these ${userShares.length} NEW shares`)
|
|
236
|
+
// User must save all new shares
|
|
237
|
+
return await confirmUserSavedShares()
|
|
238
|
+
}
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
// Server share is automatically updated
|
|
242
|
+
// User must save new user shares
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
## Account Deletion
|
|
246
|
+
|
|
247
|
+
To delete a Shamir account and its stored share:
|
|
248
|
+
|
|
249
|
+
```ts
|
|
250
|
+
// Requires OTP verification
|
|
251
|
+
await manager.deleteAccount({
|
|
252
|
+
phoneNumber: '+1234567890',
|
|
253
|
+
otp: '123456'
|
|
254
|
+
})
|
|
255
|
+
// WARNING: Server share is permanently deleted
|
|
256
|
+
// User needs enough remaining shares to meet threshold
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
## Share Format
|
|
260
|
+
|
|
261
|
+
Shamir shares use the format: `x.y.threshold.integrity`
|
|
262
|
+
|
|
263
|
+
- **x**: Share index (1, 2, 3, ...)
|
|
264
|
+
- **y**: Share data (Base58 encoded)
|
|
265
|
+
- **threshold**: Number of shares required (e.g., 2)
|
|
266
|
+
- **integrity**: Checksum for validation
|
|
267
|
+
|
|
268
|
+
Example share:
|
|
269
|
+
```
|
|
270
|
+
1.7KvWLhJ3rQ9FnBZxYmUdNpTsR6CwEiAoH8bVfGjDkM2.2.5XyZ
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
## Security Considerations
|
|
274
|
+
|
|
275
|
+
1. **Share Storage**: Store user shares in separate, secure locations
|
|
276
|
+
2. **Threshold Selection**: Higher threshold = more security but less convenience
|
|
277
|
+
3. **OTP Security**: Consider SIM-swap risks with SMS; email may be safer for some users
|
|
278
|
+
4. **Entropy Quality**: Always collect full entropy before key generation
|
|
279
|
+
5. **User ID Hash**: Store separately - it identifies your account but cannot recover keys
|
|
280
|
+
|
|
281
|
+
### Recommended Share Storage by Scheme
|
|
282
|
+
|
|
283
|
+
**2-of-3 (default):**
|
|
284
|
+
- Share 1: Print and store in safe/safety deposit box
|
|
285
|
+
- Share 2: Save in password manager
|
|
286
|
+
|
|
287
|
+
**3-of-5 (high security):**
|
|
288
|
+
- Share 1: Print and store in safe
|
|
289
|
+
- Share 2: Save in password manager
|
|
290
|
+
- Share 3: Store on hardware device (USB)
|
|
291
|
+
- Share 4: Give to trusted family member
|
|
292
|
+
|
|
293
|
+
## Error Handling
|
|
294
|
+
|
|
295
|
+
```ts
|
|
296
|
+
try {
|
|
297
|
+
await manager.recoverWithServerShare(userShares, authPayload)
|
|
298
|
+
} catch (error) {
|
|
299
|
+
if (error.message.includes('Rate limited')) {
|
|
300
|
+
// Too many attempts - wait and retry
|
|
301
|
+
} else if (error.message.includes('OTP verification failed')) {
|
|
302
|
+
// Wrong code - let user retry
|
|
303
|
+
} else if (error.message.includes('integrity check failed')) {
|
|
304
|
+
// Shares don't match - wrong share or corrupted
|
|
305
|
+
} else if (error.message.includes('Need at least')) {
|
|
306
|
+
// Not enough shares provided
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
[Return to Documentation](./README.md)
|