@bsv/wallet-toolbox-client
Version:
Client only Wallet Storage
522 lines (521 loc) • 26.2 kB
TypeScript
import { Knex } from 'knex';
import { Beef, CreateActionResult, HexString, KeyDeriverApi, PrivateKey, PublicKey, SignActionResult, Transaction, WalletAction, WalletActionInput, WalletActionOutput, WalletCertificate, WalletInterface } from '@bsv/sdk';
import { Chain } from '../../src/sdk/types';
import { StorageKnex } from '../../src/storage/StorageKnex';
import { Services } from '../../src/services/Services';
import { TrxToken, WalletStorageProvider } from '../../src/sdk/WalletStorage.interfaces';
import { WalletStorageManager } from '../../src/storage/WalletStorageManager';
import { GetMerklePathResult } from '../../src/sdk/WalletServices.interfaces';
import { Monitor } from '../../src/monitor/Monitor';
import { Wallet } from '../../src/Wallet';
import { StorageProvider } from '../../src/storage/StorageProvider';
import { TableProvenTx } from '../../src/storage/schema/tables/TableProvenTx';
import { TableProvenTxReq } from '../../src/storage/schema/tables/TableProvenTxReq';
import { TableUser } from '../../src/storage/schema/tables/TableUser';
import { TableCertificate } from '../../src/storage/schema/tables/TableCertificate';
import { TableCertificateField } from '../../src/storage/schema/tables/TableCertificateField';
import { TableOutputBasket } from '../../src/storage/schema/tables/TableOutputBasket';
import { TableTransaction } from '../../src/storage/schema/tables/TableTransaction';
import { TableOutput } from '../../src/storage/schema/tables/TableOutput';
import { TableOutputTag } from '../../src/storage/schema/tables/TableOutputTag';
import { TableOutputTagMap } from '../../src/storage/schema/tables/TableOutputTagMap';
import { TableTxLabel } from '../../src/storage/schema/tables/TableTxLabel';
import { TableTxLabelMap } from '../../src/storage/schema/tables/TableTxLabelMap';
import { TableSyncState } from '../../src/storage/schema/tables/TableSyncState';
import { TableMonitorEvent } from '../../src/storage/schema/tables/TableMonitorEvent';
import { TableCommission } from '../../src/storage/schema/tables/TableCommission';
export interface TuEnvFlags {
chain: Chain;
runMySQL: boolean;
runSlowTests: boolean;
logTests: boolean;
}
export interface TuEnv extends TuEnvFlags {
chain: Chain;
identityKey: string;
identityKey2: string;
taalApiKey: string;
bitailsApiKey: string;
whatsonchainApiKey: string;
devKeys: Record<string, string>;
/**
* file path to local sqlite file for identityKey
*/
filePath?: string;
/**
* identityKey for automated test wallet on this chain
*/
testIdentityKey?: string;
/**
* file path to local sqlite file for testIdentityKey
*/
testFilePath?: string;
cloudMySQLConnection?: string;
}
export declare abstract class TestUtilsWalletStorage {
/**
* @param chain
* @returns true if .env has truthy idenityKey, idenityKey2 values for chain
*/
static noEnv(chain: Chain): boolean;
/**
* @param chain
* @returns true if .env is not valid for chain or testIdentityKey or testFilePath are undefined or empty.
*/
static noTestEnv(chain: Chain): boolean;
static getEnvFlags(chain: Chain): TuEnvFlags;
static getEnv(chain: Chain): TuEnv;
static createMainReviewSetup(): Promise<{
env: TuEnv;
storage: StorageKnex;
services: Services;
}>;
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: Transaction, inputIndex: number) => Promise<import("@bsv/sdk").UnlockingScript>;
estimateLength: () => Promise<108>;
};
static createWalletOnly(args: {
chain?: Chain;
rootKeyHex?: string;
active?: WalletStorageProvider;
backups?: WalletStorageProvider[];
privKeyHex?: string;
}): Promise<TestWalletOnly>;
/**
* Creates a wallet with both local sqlite and cloud stores, the local store is left active.
*
* Requires a valid .env file with chain matching testIdentityKey and testFilePath properties valid.
* Or `args` with those properties.
*
* Verifies wallet has at least 1000 satoshis in at least 10 change utxos.
*
* @param chain
*
* @returns {TestWalletNoSetup}
*/
static createTestWallet(args: Chain | CreateTestWalletArgs): Promise<TestWalletNoSetup>;
static createTestWalletWithStorageClient(args: {
rootKeyHex?: string;
endpointUrl?: string;
chain?: Chain;
}): Promise<TestWalletOnly>;
static createKnexTestWalletWithSetup<T>(args: {
knex: Knex<any, any[]>;
databaseName: string;
chain?: 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?: Chain;
rootKeyHex?: string;
dropAll?: boolean;
}): Promise<TestWallet<{}>>;
static createMySQLTestSetup1Wallet(args: {
databaseName: string;
chain?: Chain;
rootKeyHex?: string;
}): Promise<TestWallet<TestSetup1>>;
static createMySQLTestSetup2Wallet(args: {
databaseName: string;
mockData: MockData;
chain?: Chain;
rootKeyHex?: string;
}): Promise<TestWallet<TestSetup2>>;
static createSQLiteTestWallet(args: {
filePath?: string;
databaseName: string;
chain?: Chain;
rootKeyHex?: string;
dropAll?: boolean;
privKeyHex?: string;
}): Promise<TestWalletNoSetup>;
static createSQLiteTestSetup1Wallet(args: {
databaseName: string;
chain?: Chain;
rootKeyHex?: string;
}): Promise<TestWallet<TestSetup1>>;
static createSQLiteTestSetup2Wallet(args: {
databaseName: string;
mockData: MockData;
chain?: Chain;
rootKeyHex?: string;
}): Promise<TestWallet<TestSetup2>>;
static createKnexTestWallet(args: {
knex: Knex<any, any[]>;
databaseName: string;
chain?: Chain;
rootKeyHex?: string;
dropAll?: boolean;
privKeyHex?: string;
}): Promise<TestWalletNoSetup>;
static createKnexTestSetup1Wallet(args: {
knex: Knex<any, any[]>;
databaseName: string;
chain?: Chain;
rootKeyHex?: string;
dropAll?: boolean;
}): Promise<TestWallet<TestSetup1>>;
static createKnexTestSetup2Wallet(args: {
knex: Knex<any, any[]>;
databaseName: string;
mockData: MockData;
chain?: 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 wrapProfiling(o: Object, name: string): Record<string, {
count: number;
totalMsecs: number;
}>;
static createIdbLegacyWalletCopy(databaseName: string): Promise<TestWalletProviderNoSetup>;
static makeSampleCert(subject?: string): {
cert: WalletCertificate;
subject: string;
certifier: PrivateKey;
};
static insertTestProvenTx(storage: StorageProvider, txid?: string, trx?: TrxToken): Promise<TableProvenTx>;
static insertTestProvenTxReq(storage: StorageProvider, txid?: string, provenTxId?: number, onlyRequired?: boolean): Promise<TableProvenTxReq>;
static insertTestUser(storage: StorageProvider, identityKey?: string): Promise<TableUser>;
static insertTestCertificate(storage: StorageProvider, u?: TableUser): Promise<TableCertificate>;
static insertTestCertificateField(storage: StorageProvider, c: TableCertificate, name: string, value: string): Promise<TableCertificateField>;
static insertTestOutputBasket(storage: StorageProvider, u?: TableUser | number, partial?: Partial<TableOutputBasket>): Promise<TableOutputBasket>;
static insertTestTransaction(storage: StorageProvider, u?: TableUser, onlyRequired?: boolean, partial?: Partial<TableTransaction>): Promise<{
tx: TableTransaction;
user: TableUser;
}>;
static insertTestOutput(storage: StorageProvider, t: TableTransaction, vout: number, satoshis: number, basket?: TableOutputBasket, requiredOnly?: boolean, partial?: Partial<TableOutput>): Promise<TableOutput>;
static insertTestOutputTag(storage: StorageProvider, u: TableUser, partial?: Partial<TableOutputTag>): Promise<TableOutputTag>;
static insertTestOutputTagMap(storage: StorageProvider, o: TableOutput, tag: TableOutputTag): Promise<TableOutputTagMap>;
static insertTestTxLabel(storage: StorageProvider, u: TableUser, partial?: Partial<TableTxLabel>): Promise<TableTxLabel>;
static insertTestTxLabelMap(storage: StorageProvider, tx: TableTransaction, label: TableTxLabel, partial?: Partial<TableTxLabelMap>): Promise<TableTxLabelMap>;
static insertTestSyncState(storage: StorageProvider, u: TableUser): Promise<TableSyncState>;
static insertTestMonitorEvent(storage: StorageProvider): Promise<TableMonitorEvent>;
static insertTestCommission(storage: StorageProvider, t: TableTransaction): Promise<TableCommission>;
static createTestSetup1(storage: StorageProvider, u1IdentityKey?: string): Promise<TestSetup1>;
static createTestSetup2(storage: StorageProvider, identityKey: 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<GetMerklePathResult>): void;
static createWalletSetupEnv(chain: Chain): Promise<TestWalletOnly>;
/**
* Create a pair of transacitons that cancel out, other than the transaciton fees.
* Both created transactions are left with status 'noSend'.
* This allows the transactions to either be broadcast by an external party,
* or they may be aborted.
*
* `doubleSpendTx` should only be used for double spend testing.
* It attempts to forward the txidDo input, which should already have been reclaimed by txidUndo, to a random private key output.
*
* @param wallet the wallet that will create both transactions, or Chain and createWalletEnv is used to create a wallet.
* @param satoshis amount of new output created and consumed. Defaults to 41.
* @returns { txidDo: string, txidUndo: string, beef: Beef, doubleSpendTx: transaction }
*/
static createNoSendTxPair(wallet: Wallet | Chain, satoshis?: number): Promise<{
txidDo: string;
txidUndo: string;
beef: Beef;
doubleSpendTx: Transaction;
}>;
}
export declare abstract class _tu extends TestUtilsWalletStorage {
}
export interface TestSetup1 {
u1: TableUser;
u1basket1: TableOutputBasket;
u1basket2: TableOutputBasket;
u1label1: TableTxLabel;
u1label2: TableTxLabel;
u1tag1: TableOutputTag;
u1tag2: TableOutputTag;
u1tx1: TableTransaction;
u1comm1: TableCommission;
u1tx1label1: TableTxLabelMap;
u1tx1label2: TableTxLabelMap;
u1tx1o0: TableOutput;
u1o0tag1: TableOutputTagMap;
u1o0tag2: TableOutputTagMap;
u1tx1o1: TableOutput;
u1o1tag1: TableOutputTagMap;
u1cert1: TableCertificate;
u1cert1field1: TableCertificateField;
u1cert1field2: TableCertificateField;
u1cert2: TableCertificate;
u1cert2field1: TableCertificateField;
u1cert3: TableCertificate;
u1sync1: TableSyncState;
u2: TableUser;
u2basket1: TableOutputBasket;
u2label1: TableTxLabel;
u2tx1: TableTransaction;
u2comm1: TableCommission;
u2tx1label1: TableTxLabelMap;
u2tx1o0: TableOutput;
u2tx2: TableTransaction;
u2comm2: TableCommission;
proven1: TableProvenTx;
req1: TableProvenTxReq;
req2: TableProvenTxReq;
we1: TableMonitorEvent;
}
export interface MockData {
inputs?: WalletActionInput[];
outputs?: WalletActionOutput[];
actions: WalletAction[];
}
export interface TestSetup2 extends MockData {
}
export interface TestWalletProvider<T> extends TestWalletOnly {
activeStorage: StorageProvider;
setup?: T;
userId: number;
rootKey: PrivateKey;
identityKey: string;
keyDeriver: KeyDeriverApi;
chain: Chain;
storage: WalletStorageManager;
services: Services;
monitor: Monitor;
wallet: Wallet;
localStorageIdentityKey?: string;
clientStorageIdentityKey?: string;
localBackupStorageIdentityKey?: string;
}
export interface TestWallet<T> extends TestWalletOnly {
activeStorage: StorageKnex;
setup?: T;
userId: number;
rootKey: PrivateKey;
identityKey: string;
keyDeriver: KeyDeriverApi;
chain: Chain;
storage: WalletStorageManager;
services: Services;
monitor: Monitor;
wallet: Wallet;
localStorageIdentityKey?: string;
clientStorageIdentityKey?: string;
localBackupStorageIdentityKey?: string;
}
export interface TestWalletOnly {
rootKey: PrivateKey;
identityKey: string;
keyDeriver: KeyDeriverApi;
chain: Chain;
storage: WalletStorageManager;
services: Services;
monitor: Monitor;
wallet: Wallet;
}
export type TestSetup2Wallet = TestWallet<TestSetup2>;
export type TestSetup1Wallet = TestWallet<TestSetup1>;
export type TestWalletNoSetup = TestWallet<{}>;
export type TestWalletProviderNoSetup = TestWalletProvider<{}>;
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 running in jest "single test" mode,
* or when `logEnabled` is true.
*
* @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 logger: (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, // This remains an object passed in by the caller
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: TableOutput): Promise<string>;
export declare function logInput(storage: StorageKnex, prevOutputTxid: HexString, prevOutputVout: number, indentLevel?: number): Promise<string>;
export declare function logBasket(basket: TableOutputBasket): string;
export interface CreateTestWalletArgs {
chain: Chain;
rootKeyHex: string;
filePath: string;
addLocalBackup?: boolean;
setActiveClient?: boolean;
useMySQLConnectionForClient?: boolean;
}
//# sourceMappingURL=TestUtilsWalletStorage.d.ts.map