@node-dlc/chainmon
Version:
Bitcoin on-chain transaction monitoring tool for DLCs
103 lines (90 loc) • 2.79 kB
text/typescript
import { OutPoint, Script, Tx, Value } from '@node-dlc/bitcoin';
import { BitcoindClient } from '@node-dlc/bitcoind';
import { EventEmitter } from 'events';
export class TxWatcher extends EventEmitter {
/**
* Outpoints that are being watched
*/
public watchedOutPoints: Map<string, OutPoint>;
/**
* ScriptPubKeys that are being watched
*/
public watchedScriptPubKeys: Map<string, [Script, Value]>;
private _client: BitcoindClient;
/**
* TxWatcher listens for transactions that match certain patterns
* and events when a transaction is found matching the pattern
*
* @param client
*/
constructor(client: BitcoindClient) {
super();
this._client = client;
this.watchedOutPoints = new Map<string, OutPoint>();
this.watchedScriptPubKeys = new Map<string, [Script, Value]>();
}
/**
* Starts watching for transactions
*/
public start(): void {
this._client.subscribeRawTx();
this._client.on('rawtx', this._onRawTx.bind(this));
}
/**
* Stops watching for transactions
*/
public stop(): void {
// this._client.close();
}
/**
* Watches an outpoint for broadcase in a new transaction
* @param outpoint
*/
public watchOutpoint(outpoint: OutPoint): void {
const key = outpoint.toString();
this.watchedOutPoints.set(key, outpoint);
}
/**
* Watches a scriptpubkey for broadcast in a new transaction
* @param scriptPubKey
* @param value
*/
public watchScriptPubKey(scriptPubKey: Script, value?: Value): void {
const key = scriptPubKey.toString();
this.watchedScriptPubKeys.set(key, [scriptPubKey, value]);
}
////////////////////////////////////////////////////////////////
private _checkOutpoints(tx: Tx) {
for (const vin of tx.inputs) {
const key = vin.outpoint.toString();
const watchedOutpoint = this.watchedOutPoints.get(key);
if (watchedOutpoint) {
this.watchedOutPoints.delete(key);
this.emit('outpointspent', tx, watchedOutpoint);
}
}
}
private _checkScriptPubkeys(tx: Tx) {
for (const vout of tx.outputs) {
const key = vout.scriptPubKey.toString();
const watchedScriptPubKey = this.watchedScriptPubKeys.get(key);
if (watchedScriptPubKey) {
const [, value] = watchedScriptPubKey;
if (!value || (value && vout.value === value)) {
this.watchedScriptPubKeys.delete(key);
this.emit('scriptpubkeyreceived', tx, watchedScriptPubKey);
}
}
}
}
private _onRawTx(buf: Buffer) {
try {
const tx = Tx.fromBuffer(buf);
this.emit('tx', tx);
this._checkOutpoints(tx);
this._checkScriptPubkeys(tx);
} catch (e) {
console.error('Failed to deserialize tx', buf.toString('hex'));
}
}
}