UNPKG

wallet-storage

Version:

BRC100 conforming wallet, wallet storage and wallet signer components

400 lines (399 loc) 20.9 kB
import { CreateActionResult, HexString, KeyDeriver, PrivateKey, PublicKey, SignActionResult, WalletAction, WalletActionInput, WalletActionOutput, WalletCertificate, WalletInterface } from '@bsv/sdk'; import { sdk, StorageProvider, StorageKnex, table, Wallet, Monitor, Services, WalletStorageManager } from '../../src/index.all'; import { Knex } from 'knex'; import { Beef } from '@bsv/sdk'; export interface TuEnv { chain: sdk.Chain; userId: number; identityKey: string; mainTaalApiKey: string; testTaalApiKey: string; devKeys: Record<string, string>; noMySQL: boolean; runSlowTests: boolean; logTests: boolean; } export declare abstract class TestUtilsWalletStorage { static getEnv(chain: sdk.Chain): { chain: sdk.Chain; userId: number; identityKey: string; identityKey2: string | undefined; mainTaalApiKey: string; testTaalApiKey: string; devKeys: Record<string, string>; noMySQL: boolean; runSlowTests: boolean; logTests: boolean; }; static createNoSendP2PKHTestOutpoint(address: string, satoshis: number, noSendChange: string[] | undefined, wallet: WalletInterface): Promise<{ noSendChange: string[]; txid: string; cr: CreateActionResult; sr: SignActionResult; }>; static createNoSendP2PKHTestOutpoints(count: number, address: string, satoshis: number, noSendChange: string[] | undefined, wallet: WalletInterface): Promise<{ noSendChange: string[]; txid: string; cr: CreateActionResult; sr: SignActionResult; }>; static getKeyPair(priv?: string | PrivateKey): TestKeyPair; static getLockP2PKH(address: string): import("@bsv/sdk").LockingScript; static getUnlockP2PKH(priv: PrivateKey, satoshis: number): { sign: (tx: import("@bsv/sdk").Transaction, inputIndex: number) => Promise<import("@bsv/sdk").UnlockingScript>; estimateLength: () => Promise<108>; }; static createWalletOnly(args: { chain?: sdk.Chain; rootKeyHex?: string; active?: sdk.WalletStorageProvider; backups?: sdk.WalletStorageProvider[]; privKeyHex?: string; }): Promise<TestWalletOnly>; static createTestWalletWithStorageClient(args: { rootKeyHex?: string; endpointUrl?: string; chain?: sdk.Chain; }): Promise<TestWalletOnly>; static createKnexTestWalletWithSetup<T>(args: { knex: Knex<any, any[]>; databaseName: string; chain?: sdk.Chain; rootKeyHex?: string; dropAll?: boolean; privKeyHex?: string; insertSetup: (storage: StorageKnex, identityKey: string) => Promise<T>; }): Promise<TestWallet<T>>; /** * Returns path to temporary file in project's './test/data/tmp/' folder. * * Creates any missing folders. * * Optionally tries to delete any existing file. This may fail if the file file is locked * by another process. * * Optionally copies filename (or if filename has no dir component, a file of the same filename from the project's './test/data' folder) to initialize file's contents. * * CAUTION: returned file path will include four random hex digits unless tryToDelete is true. Files must be purged periodically. * * @param filename target filename without path, optionally just extension in which case random name is used * @param tryToDelete true to attempt to delete an existing file at the returned file path. * @param copyToTmp true to copy file of same filename from './test/data' (or elsewhere if filename has path) to tmp folder * @param reuseExisting true to use existing file if found, otherwise a random string is added to filename. * @returns path in './test/data/tmp' folder. */ static newTmpFile(filename?: string, tryToDelete?: boolean, copyToTmp?: boolean, reuseExisting?: boolean): Promise<string>; static copyFile(srcPath: string, dstPath: string): Promise<void>; static existingDataFile(filename: string): Promise<string>; static createLocalSQLite(filename: string): Knex; static createMySQLFromConnection(connection: object): Knex; static createLocalMySQL(database: string): Knex; static createMySQLTestWallet(args: { databaseName: string; chain?: sdk.Chain; rootKeyHex?: string; dropAll?: boolean; }): Promise<TestWallet<{}>>; static createMySQLTestSetup1Wallet(args: { databaseName: string; chain?: sdk.Chain; rootKeyHex?: string; }): Promise<TestWallet<TestSetup1>>; static createSQLiteTestWallet(args: { filePath?: string; databaseName: string; chain?: sdk.Chain; rootKeyHex?: string; dropAll?: boolean; privKeyHex?: string; }): Promise<TestWalletNoSetup>; static createSQLiteTestSetup1Wallet(args: { databaseName: string; chain?: sdk.Chain; rootKeyHex?: string; }): Promise<TestWallet<TestSetup1>>; static createSQLiteTestSetup2Wallet(args: { databaseName: string; chain?: sdk.Chain; rootKeyHex?: string; }): Promise<TestWallet<TestSetup2>>; static createKnexTestWallet(args: { knex: Knex<any, any[]>; databaseName: string; chain?: sdk.Chain; rootKeyHex?: string; dropAll?: boolean; privKeyHex?: string; }): Promise<TestWalletNoSetup>; static createKnexTestSetup1Wallet(args: { knex: Knex<any, any[]>; databaseName: string; chain?: sdk.Chain; rootKeyHex?: string; dropAll?: boolean; }): Promise<TestWallet<TestSetup1>>; static createKnexTestSetup2Wallet(args: { knex: Knex<any, any[]>; databaseName: string; chain?: sdk.Chain; rootKeyHex?: string; dropAll?: boolean; }): Promise<TestWallet<TestSetup2>>; static fileExists(file: string): Promise<boolean>; static createLegacyWalletSQLiteCopy(databaseName: string): Promise<TestWalletNoSetup>; static createLegacyWalletMySQLCopy(databaseName: string): Promise<TestWalletNoSetup>; static createLiveWalletSQLiteWARNING(databaseFullPath?: string): Promise<TestWalletNoSetup>; static createWalletSQLite(databaseFullPath?: string, databaseName?: string): Promise<TestWalletNoSetup>; static legacyRootKeyHex: string; static createLegacyWalletCopy(databaseName: string, walletKnex: Knex<any, any[]>, tryCopyToPath?: string): Promise<TestWalletNoSetup>; static makeSampleCert(subject?: string): { cert: WalletCertificate; subject: string; certifier: PrivateKey; }; static insertTestProvenTx(storage: StorageProvider, txid?: string): Promise<table.ProvenTx>; static insertTestProvenTxReq(storage: StorageProvider, txid?: string, provenTxId?: number, onlyRequired?: boolean): Promise<table.ProvenTxReq>; static insertTestUser(storage: StorageProvider, identityKey?: string): Promise<table.User>; static insertTestCertificate(storage: StorageProvider, u?: table.User): Promise<table.Certificate>; static insertTestCertificateField(storage: StorageProvider, c: table.Certificate, name: string, value: string): Promise<table.CertificateField>; static insertTestOutputBasket(storage: StorageProvider, u?: table.User | number, partial?: Partial<table.OutputBasket>): Promise<table.OutputBasket>; static insertTestTransaction(storage: StorageProvider, u?: table.User, onlyRequired?: boolean, partial?: Partial<table.Transaction>): Promise<{ tx: table.Transaction; user: table.User; }>; static insertTestOutput(storage: StorageProvider, t: table.Transaction, vout: number, satoshis: number, basket?: table.OutputBasket, requiredOnly?: boolean, partial?: Partial<table.Output>): Promise<table.Output>; static insertTestOutputTag(storage: StorageProvider, u: table.User, partial?: Partial<table.OutputTag>): Promise<table.OutputTag>; static insertTestOutputTagMap(storage: StorageProvider, o: table.Output, tag: table.OutputTag): Promise<table.OutputTagMap>; static insertTestTxLabel(storage: StorageProvider, u: table.User, partial?: Partial<table.TxLabel>): Promise<table.TxLabel>; static insertTestTxLabelMap(storage: StorageProvider, tx: table.Transaction, label: table.TxLabel, partial?: Partial<table.TxLabelMap>): Promise<table.TxLabelMap>; static insertTestSyncState(storage: StorageProvider, u: table.User): Promise<table.SyncState>; static insertTestMonitorEvent(storage: StorageProvider): Promise<table.MonitorEvent>; static insertTestCommission(storage: StorageProvider, t: table.Transaction): Promise<table.Commission>; static createTestSetup1(storage: StorageProvider, u1IdentityKey?: string): Promise<TestSetup1>; static createTestSetup2(storage: StorageProvider, u1IdentityKey: string, mockData?: MockData): Promise<TestSetup2>; static mockPostServicesAsSuccess(ctxs: TestWalletOnly[]): void; static mockPostServicesAsError(ctxs: TestWalletOnly[]): void; static mockPostServicesAsCallback(ctxs: TestWalletOnly[], callback: (beef: Beef, txids: string[]) => 'success' | 'error'): void; static mockMerklePathServicesAsCallback(ctxs: TestWalletOnly[], callback: (txid: string) => Promise<sdk.GetMerklePathResult>): void; } export declare abstract class _tu extends TestUtilsWalletStorage { } export interface TestSetup1 { u1: table.User; u1basket1: table.OutputBasket; u1basket2: table.OutputBasket; u1label1: table.TxLabel; u1label2: table.TxLabel; u1tag1: table.OutputTag; u1tag2: table.OutputTag; u1tx1: table.Transaction; u1comm1: table.Commission; u1tx1label1: table.TxLabelMap; u1tx1label2: table.TxLabelMap; u1tx1o0: table.Output; u1o0tag1: table.OutputTagMap; u1o0tag2: table.OutputTagMap; u1tx1o1: table.Output; u1o1tag1: table.OutputTagMap; u1cert1: table.Certificate; u1cert1field1: table.CertificateField; u1cert1field2: table.CertificateField; u1cert2: table.Certificate; u1cert2field1: table.CertificateField; u1cert3: table.Certificate; u1sync1: table.SyncState; u2: table.User; u2basket1: table.OutputBasket; u2label1: table.TxLabel; u2tx1: table.Transaction; u2comm1: table.Commission; u2tx1label1: table.TxLabelMap; u2tx1o0: table.Output; u2tx2: table.Transaction; u2comm2: table.Commission; proven1: table.ProvenTx; req1: table.ProvenTxReq; req2: table.ProvenTxReq; we1: table.MonitorEvent; } export interface MockData { inputs?: WalletActionInput[]; outputs?: WalletActionOutput[]; actions: WalletAction[]; } export interface TestSetup2 { } export interface TestWallet<T> extends TestWalletOnly { activeStorage: StorageKnex; setup?: T; userId: number; rootKey: PrivateKey; identityKey: string; keyDeriver: KeyDeriver; chain: sdk.Chain; storage: WalletStorageManager; services: Services; monitor: Monitor; wallet: Wallet; } export interface TestWalletOnly { rootKey: PrivateKey; identityKey: string; keyDeriver: KeyDeriver; chain: sdk.Chain; storage: WalletStorageManager; services: Services; monitor: Monitor; wallet: Wallet; } export type TestSetup1Wallet = TestWallet<TestSetup1>; export type TestWalletNoSetup = TestWallet<{}>; export declare function expectToThrowWERR<R>(expectedClass: new (...args: any[]) => any, fn: () => Promise<R>): Promise<void>; export type TestKeyPair = { privateKey: PrivateKey; publicKey: PublicKey; address: string; }; /** * Centralized logging function to handle logging based on the `logEnabled` flag. * * @param {string} message - The main message to log. * @param {...any} optionalParams - Additional parameters to log (optional). * @returns {void} This function does not return any value. * * @example * log('Test message', someVariable); * log('Another message with multiple params', param1, param2); */ export declare const log: (message: string, ...optionalParams: any[]) => void; /** * Updates a table dynamically based on key-value pairs in testValues. * @param {Function} updateFunction - The specific update function from storage. * @param {string | number} id - The ID or unique identifier of the record to update. * @param {Object} testValues - An object containing key-value pairs to update. */ export declare const updateTable: (updateFunction: any, id: any, testValues: any) => Promise<void>; /** * Verifies that all key-value pairs in `testValues` match the corresponding keys in `targetObject`. * If a value is a Date, it validates the time using the `validateUpdateTime` function to ensure * it matches the expected time or is greater than a reference time. * * @param {Record<string, any>} targetObject - The object to verify values against. * @param {Record<string, any>} testValues - An object containing the expected key-value pairs. * @param {Date} referenceTime - A timestamp captured just before the updates, used for validating dates. * * @example * const targetObject = { key1: 'value1', created_at: new Date('2024-12-30T23:00:00Z') } * const testValues = { key1: 'value1', created_at: new Date('2024-12-30T23:00:00Z') } * const referenceTime = new Date() * verifyValues(targetObject, testValues, referenceTime) */ export declare const verifyValues: (targetObject: Record<string, any>, testValues: Record<string, any>, referenceTime: Date) => void; /** * Comparison function to validate update time. * Allows the time to match the expected update time or be greater than a reference time. * Validates across multiple formats with a tolerance for minor discrepancies. * @param {Date} actualTime - The `updated_at` time returned from the storage. * @param {Date} expectedTime - The time you tried to set. * @param {Date} referenceTime - A timestamp captured just before the update attempt. * @param {number} toleranceMs - Optional tolerance in milliseconds for discrepancies (default: 10ms). * @param {boolean} [ logEnabled=false ] - A flag to enable or disable logging for this error. * @returns {boolean} - Returns `true` if the validation passes; `false` otherwise. * Logs human-readable details if the validation fails. */ export declare const validateUpdateTime: (actualTime: Date, expectedTime: Date, referenceTime: Date, toleranceMs?: number, logEnabled?: boolean) => boolean; /** * Set whether logging should be enabled or disabled globally. * * @param {boolean} enabled - A flag to enable or disable logging. * `true` enables logging, `false` disables logging. * * @returns {void} This function does not return any value. * * @example * setLogging(true); // Enable logging * setLogging(false); // Disable logging */ export declare const setLogging: (enabled: boolean) => void; /** * Logs the unique constraint error for multiple fields. * * @param {any} error - The error object that contains the error message. * @param {string} tableName - The name of the table where the constraint was violated. * @param {string[]} columnNames - An array of column names for which to check the unique constraint. * @param {boolean} logEnabled - A flag to enable or disable logging. */ export declare const logUniqueConstraintError: (error: any, tableName: string, columnNames: string[], logEnabled?: boolean) => void; /** * Triggers a unique constraint error by attempting to update a row with a value that violates a unique constraint. * * @param {any} storage - The storage object, typically containing the database methods for performing CRUD operations. * @param {string} findMethod - The method name for finding rows in the table (e.g., `findProvenTxReqs`). * @param {string} updateMethod - The method name for updating rows in the table (e.g., `updateProvenTxReq`). * @param {string} tableName - The name of the table being updated. * @param {string} columnName - The column name for which the unique constraint is being tested. * @param {any} invalidValue - The value to assign to the column that should trigger the unique constraint error. This should be an object with the column name(s) as the key(s). * @param {number} [id=1] - The id used to set the column value during the test (default is 1). * @param {boolean} [ logEnabled=false ] - A flag to enable or disable logging during the test. Default is `true` (logging enabled). * * @returns {Promise<boolean>} This function returns true if error thrown otherwise false, it performs an async operation to test the unique constraint error. * * @throws {Error} Throws an error if the unique constraint error is not triggered or if the table has insufficient rows. * * @example await triggerUniqueConstraintError(storage, 'ProvenTxReq', 'proven_tx_reqs', 'provenTxReqId', { provenTxReqId: 42 }, 1, true) */ export declare const triggerUniqueConstraintError: (storage: any, findMethod: string, updateMethod: string, tableName: string, columnName: string, invalidValue: any, id?: number, logEnabled?: boolean) => Promise<boolean>; /** * Tests that the foreign key constraint error is triggered for any table and column. * * @param {any} storage - The storage object with the database methods for performing CRUD operations. * @param {string} findMethod - The method name for finding rows in the table (e.g., `findProvenTxReqs`). * @param {string} updateMethod - The method name for updating rows in the table (e.g., `updateProvenTxReq`). * @param {string} tableName - The name of the table being updated. * @param {string} columnName - The column name being tested for the foreign key constraint. * @param {any} invalidValue - The value to assign to the column that should trigger the foreign key constraint error. This should be an object with the column name as the key. * @param {number} [id=1] - The id used to set the column value during the test (default is 1). * @param {boolean} [ logEnabled=false ] - A flag to enable or disable logging during the test. Default is `true` (logging enabled). * * @returns {Promise<boolean>} This function returns true if error thrown otherwise false, it performs an async operation to test the foreign key constraint error. * * @throws {Error} Throws an error if the foreign key constraint error is not triggered. * * @example await triggerForeignKeyConstraintError(storage, 'findProvenTxReqs', 'updateProvenTxReq', 'proven_tx_reqs', 'provenTxId', { provenTxId: 42 }) */ export declare const triggerForeignKeyConstraintError: (storage: any, findMethod: string, updateMethod: string, tableName: string, columnName: string, invalidValue: any, id?: number, logEnabled?: boolean) => Promise<boolean>; /** * Aborts all transactions with the status `'nosend'` in the storage and verifies success. * * @param {Wallet} wallet - The wallet instance used to abort actions. * @param {StorageKnex} storage - The storage instance to query transactions from. * @returns {Promise<boolean>} - Resolves to `true` if all `'nosend'` transactions were successfully aborted. */ export declare function cleanUnsentTransactionsUsingAbort(wallet: Wallet, storage: StorageKnex): Promise<boolean>; /** * Aborts all transactions with the status `'unsigned'` in the storage and verifies success. * * @param {Wallet} wallet - The wallet instance used to abort actions. * @param {StorageKnex} storage - The storage instance to query transactions from. * @returns {Promise<boolean>} - Resolves to `true` if all `'unsigned'` transactions were successfully aborted. */ export declare function cleanUnsignedTransactionsUsingAbort(wallet: Wallet, storage: StorageKnex): Promise<boolean>; /** * Aborts all transactions with the status `'unprocessed'` in the storage and verifies success. * * @param {Wallet} wallet - The wallet instance used to abort actions. * @param {StorageKnex} storage - The storage instance to query transactions from. * @returns {Promise<boolean>} - Resolves to `true` if all `'unprocessed'` transactions were successfully aborted. */ export declare function cleanUnprocessedTransactionsUsingAbort(wallet: Wallet, storage: StorageKnex): Promise<boolean>; /** * Normalize a date or ISO string to a consistent ISO string format. * @param value - The value to normalize (Date object or ISO string). * @returns ISO string or null if not a date-like value. */ export declare const normalizeDate: (value: any) => string | null; export declare function logTransaction(storage: StorageKnex, txid: HexString): Promise<string>; export declare function logOutput(storage: StorageKnex, output: table.Output): Promise<string>; export declare function logBasket(storage: StorageKnex, basket: table.OutputBasket): string; //# sourceMappingURL=TestUtilsWalletStorage.d.ts.map