Files
xo-stack/packages/stack/src/wallet/base-wallet.ts
T
2025-02-03 11:40:38 +00:00

149 lines
4.6 KiB
TypeScript

import {
type InputTemplateBCH,
type TransactionTemplate,
type WalletAddresses,
type WalletTransactions,
} from './types.js';
import { type BlockchainUTXOs } from '../blockchain';
import { type EventMap, EventEmitter } from '../utils';
import { type TokenBalances, type Address } from '@xocash/primitives';
/**
* Common interface for all wallet types.
*
* @remarks
*
* All function signatures are deliberately asynchronous to accommodate for cases where wallets might be remote.
* For example, we might eventually want to support a multisig service.
* Or we might have to support some other custodial "Apple Pay"-like OS-interface to get accepted onto their app store.
*/
export abstract class BaseWallet<
WalletEvents extends EventMap,
> extends EventEmitter<WalletEvents> {
/**
* Start monitoring this wallet for any transaction activity.
*/
abstract start(): Promise<void>;
/**
* Stop monitoring this wallet for any transaction activity.
*/
abstract stop(): Promise<void>;
/**
* Remove any event listeners from this wallet.
*/
abstract destroy(): Promise<void>;
/**
* Fetch all transactions from the blockchain involving this wallet.
*
* @remarks
*
* We will want to add a query argument so that workers can use this efficiently:
*
* ```ts
* {
* limit?: number;
* offset?: number;
* sort?: () => number;
* filter?: () => boolean;
* }
* ```
*
* This "query" argument should be turned into a generic type as we will want to re-use it for Activities.
*/
abstract getTransactions(): Promise<WalletTransactions>;
/**
* Fetch all unspents from the blockchain belonging to this wallet.
*/
abstract getUnspents(): Promise<BlockchainUTXOs>;
/**
* Fetch all unspents from the blockchain belonging to this wallet.
*
* @remarks
*
* I was considering removing this and just storing unspents as "UTXOSignable"s.
* But that might not be ideal if we want to have Watch-only wallets.
* A better approach might be to have Fetch Unspents return `Array<UTXO | UTXOSignable>`
* Still need to flesh that out.
*
* EDIT: We're going to want to store state for caching anyway...
* May as well just getUnspentDirectives() from the local state instead of fetch.
* Likewise for balances.
*/
abstract getUnspentDirectives(): Promise<Array<InputTemplateBCH>>;
/**
* Get the satoshi balance of this wallet.
*
* @remarks
*
* Consider confirmed/unconfirmed balances (or some other representation).
*
* This becomes important in some instances because services like BitPay require one confirmation.
* This'll also have bearing on how we define our UTXO Selection strategies.
*/
abstract getBalanceSats(): Promise<bigint>;
/**
* Get the token balance of this wallet.
*
* @remarks
*
* Consider confirmed/unconfirmed balances (or some other representation).
*
* This becomes important in some instances because services like BitPay require one confirmation.
* This'll also have bearing on how we define our UTXO Selection strategies.
*/
abstract getBalanceTokens(): Promise<TokenBalances>;
/**
* Get all addresses belonging to this wallet.
*/
abstract getAddresses(): Promise<WalletAddresses>;
/**
* Get the address that this wallet should receive to.
*/
abstract getReceivingAddress(): Promise<Address>;
/**
* Select UTXOs from this wallet to meet the amounts required.
*
* @remarks
*
* TODO: We are going to want to return the Transaction that was compiled.
*
* TODO: This should accept a second argument (probably function) that can filter/sory UTXOs.
* The intent here is to provide a "spending policy". E.g. Only use (or prioritise) UTXOs with 1-conf.
*/
abstract signTransaction(
template: Partial<TransactionTemplate>,
): Promise<Uint8Array>;
/**
* Select UTXOs from this wallet to meet the amounts required and broadcast it to the Blockchain.
*
* @remarks
*
* TODO: We are going to want to return the Transaction that was compiled.
*/
abstract sendTransaction(
template: Partial<TransactionTemplate>,
): Promise<void>;
// TODO: This should be a push-only list.
// Need to understand how Jason's pruning approach works.
// It might make more sense to "key" activities by type:
// This would allow us to filter more effectively each time a new activity is added.
// As it stands, we would have to collate the entire list if it's done by timestamp.
abstract addActivity<T>(activity: T): Promise<void>;
abstract export(): Promise<string>;
}