@bsv/wallet-toolbox-client
Version:
Client only Wallet Storage
226 lines • 8.65 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.SetupClient = void 0;
const sdk_1 = require("@bsv/sdk");
const StorageIdb_1 = require("./storage/StorageIdb");
const WalletStorageManager_1 = require("./storage/WalletStorageManager");
const Services_1 = require("./services/Services");
const Monitor_1 = require("./monitor/Monitor");
const PrivilegedKeyManager_1 = require("./sdk/PrivilegedKeyManager");
const Wallet_1 = require("./Wallet");
const utilityHelpers_1 = require("./utility/utilityHelpers");
const StorageClient_1 = require("./storage/remoting/StorageClient");
/**
* The 'Setup` class provides static setup functions to construct BRC-100 compatible
* wallets in a variety of configurations.
*
* It serves as a starting point for experimentation and customization.
*/
class SetupClient {
/**
* Create a `Wallet`. Storage can optionally be provided or configured later.
*
* The following components are configured: KeyDeriver, WalletStorageManager, WalletService, WalletStorage.
* Optionally, PrivilegedKeyManager is also configured.
*
* @publicbody
*/
static async createWallet(args) {
const chain = args.chain;
const rootKey = sdk_1.PrivateKey.fromHex(args.rootKeyHex);
const identityKey = rootKey.toPublicKey().toString();
const keyDeriver = new sdk_1.CachedKeyDeriver(rootKey);
const storage = new WalletStorageManager_1.WalletStorageManager(identityKey, args.active, args.backups);
if (storage.canMakeAvailable())
await storage.makeAvailable();
const serviceOptions = Services_1.Services.createDefaultOptions(chain);
serviceOptions.taalApiKey = args.taalApiKey;
const services = new Services_1.Services(serviceOptions);
const monopts = Monitor_1.Monitor.createDefaultWalletMonitorOptions(chain, storage, services);
const monitor = new Monitor_1.Monitor(monopts);
monitor.addDefaultTasks();
const privilegedKeyManager = args.privilegedKeyGetter
? new PrivilegedKeyManager_1.PrivilegedKeyManager(args.privilegedKeyGetter)
: undefined;
const wallet = new Wallet_1.Wallet({
chain,
keyDeriver,
storage,
services,
monitor,
privilegedKeyManager
});
const r = {
rootKey,
identityKey,
keyDeriver,
chain,
storage,
services,
monitor,
wallet
};
return r;
}
/**
* Setup a new `Wallet` without requiring a .env file.
*
* @param args.chain - 'main' or 'test'
* @param args.rootKeyHex - Root private key for wallet's key deriver.
* @param args.storageUrl - Optional. `StorageClient` and `chain` compatible endpoint URL.
* @param args.privilegedKeyGetter - Optional. Method that will return the privileged `PrivateKey`, on demand.
*/
static async createWalletClientNoEnv(args) {
const chain = args.chain;
const endpointUrl = args.storageUrl || `https://${args.chain !== 'main' ? 'staging-' : ''}storage.babbage.systems`;
const rootKey = sdk_1.PrivateKey.fromHex(args.rootKeyHex);
const keyDeriver = new sdk_1.CachedKeyDeriver(rootKey);
const storage = new WalletStorageManager_1.WalletStorageManager(keyDeriver.identityKey);
const services = new Services_1.Services(chain);
const privilegedKeyManager = args.privilegedKeyGetter
? new PrivilegedKeyManager_1.PrivilegedKeyManager(args.privilegedKeyGetter)
: undefined;
const wallet = new Wallet_1.Wallet({
chain,
keyDeriver,
storage,
services,
privilegedKeyManager
});
const client = new StorageClient_1.StorageClient(wallet, endpointUrl);
await storage.addWalletStorageProvider(client);
await storage.makeAvailable();
return wallet;
}
/**
* @publicbody
*/
static async createWalletClient(args) {
const wo = await SetupClient.createWallet(args);
const endpointUrl = args.endpointUrl || `https://${args.chain !== 'main' ? 'staging-' : ''}storage.babbage.systems`;
const client = new StorageClient_1.StorageClient(wo.wallet, endpointUrl);
await wo.storage.addWalletStorageProvider(client);
await wo.storage.makeAvailable();
return {
...wo,
endpointUrl
};
}
/**
* @publicbody
*/
static getKeyPair(priv) {
if (priv === undefined)
priv = sdk_1.PrivateKey.fromRandom();
else if (typeof priv === 'string')
priv = new sdk_1.PrivateKey(priv, 'hex');
const pub = sdk_1.PublicKey.fromPrivateKey(priv);
const address = pub.toAddress();
return { privateKey: priv, publicKey: pub, address };
}
/**
* @publicbody
*/
static getLockP2PKH(address) {
const p2pkh = new sdk_1.P2PKH();
const lock = p2pkh.lock(address);
return lock;
}
/**
* @publicbody
*/
static getUnlockP2PKH(priv, satoshis) {
const p2pkh = new sdk_1.P2PKH();
const lock = SetupClient.getLockP2PKH(SetupClient.getKeyPair(priv).address);
// Prepare to pay with SIGHASH_ALL and without ANYONE_CAN_PAY.
// In otherwords:
// - all outputs must remain in the current order, amount and locking scripts.
// - all inputs must remain from the current outpoints and sequence numbers.
// (unlock scripts are never signed)
const unlock = p2pkh.unlock(priv, 'all', false, satoshis, lock);
return unlock;
}
/**
* @publicbody
*/
static createP2PKHOutputs(outputs) {
const os = [];
const count = outputs.length;
for (let i = 0; i < count; i++) {
const o = outputs[i];
os.push({
basket: o.basket,
tags: o.tags,
satoshis: o.satoshis,
lockingScript: SetupClient.getLockP2PKH(o.address).toHex(),
outputDescription: o.outputDescription || `p2pkh ${i}`
});
}
return os;
}
/**
* @publicbody
*/
static async createP2PKHOutputsAction(wallet, outputs, options) {
const os = SetupClient.createP2PKHOutputs(outputs);
const createArgs = {
description: `createP2PKHOutputs`,
outputs: os,
options: {
...options,
// Don't randomize so we can simplify outpoint creation
randomizeOutputs: false
}
};
const cr = await wallet.createAction(createArgs);
let outpoints;
if (cr.txid) {
outpoints = os.map((o, i) => `${cr.txid}.${i}`);
}
return { cr, outpoints };
}
/**
* @publicbody
*/
static async fundWalletFromP2PKHOutpoints(wallet, outpoints, p2pkhKey, inputBEEF) {
// TODO
}
/**
* Adds `indexedDB` based storage to a `Wallet` configured by `SetupClient.createWalletOnly`
*
* @param args.databaseName Name for this storage. For MySQL, the schema name within the MySQL instance.
* @param args.chain Which chain this wallet is on: 'main' or 'test'. Defaults to 'test'.
* @param args.rootKeyHex
*
* @publicbody
*/
static async createWalletIdb(args) {
const wo = await SetupClient.createWallet(args);
const activeStorage = await SetupClient.createStorageIdb(args);
await wo.storage.addWalletStorageProvider(activeStorage);
const { user, isNew } = await activeStorage.findOrInsertUser(wo.identityKey);
const userId = user.userId;
const r = {
...wo,
activeStorage,
userId
};
return r;
}
/**
* @returns {StorageIdb} - `Knex` based storage provider for a wallet. May be used for either active storage or backup storage.
*/
static async createStorageIdb(args) {
const storage = new StorageIdb_1.StorageIdb({
chain: args.chain,
commissionSatoshis: 0,
commissionPubKeyHex: undefined,
feeModel: { model: 'sat/kb', value: 1 }
});
await storage.migrate(args.databaseName, (0, utilityHelpers_1.randomBytesHex)(33));
await storage.makeAvailable();
return storage;
}
}
exports.SetupClient = SetupClient;
//# sourceMappingURL=SetupClient.js.map