move custom wallet sync to services backend

This commit is contained in:
Mononaut 2024-09-27 21:51:32 +00:00
parent 3f8eb3a2cd
commit 54c2d7efe5
No known key found for this signature in database
GPG key ID: A3F058E41374C04E
2 changed files with 19 additions and 26 deletions

View file

@ -9,55 +9,52 @@ interface WalletAddress {
address: string; address: string;
active: boolean; active: boolean;
transactions?: IEsploraApi.AddressTxSummary[]; transactions?: IEsploraApi.AddressTxSummary[];
lastSync: number;
} }
interface WalletConfig { interface Wallet {
url: string;
name: string; name: string;
apiKey: string;
}
interface Wallet extends WalletConfig {
addresses: Record<string, WalletAddress>; addresses: Record<string, WalletAddress>;
lastPoll: number; lastPoll: number;
} }
const POLL_FREQUENCY = 60 * 60 * 1000; // 1 hour const POLL_FREQUENCY = 5 * 60 * 1000; // 5 minutes
class WalletApi { class WalletApi {
private wallets: Record<string, Wallet> = {}; private wallets: Record<string, Wallet> = {};
private syncing = false; private syncing = false;
constructor() { constructor() {
this.wallets = (config.WALLETS.WALLETS as WalletConfig[]).reduce((acc, wallet) => { this.wallets = config.WALLETS.ENABLED ? (config.WALLETS.WALLETS as string[]).reduce((acc, wallet) => {
acc[wallet.name] = { ...wallet, addresses: {}, lastPoll: 0 }; acc[wallet] = { name: wallet, addresses: {}, lastPoll: 0 };
return acc; return acc;
}, {} as Record<string, Wallet>); }, {} as Record<string, Wallet>) : {};
} }
public getWallet(wallet: string): Record<string, WalletAddress> { public getWallet(wallet: string): Record<string, WalletAddress> {
return this.wallets?.[wallet]?.addresses || {}; return this.wallets?.[wallet]?.addresses || {};
} }
// resync wallet addresses from the provided API // resync wallet addresses from the services backend
async $syncWallets(): Promise<void> { async $syncWallets(): Promise<void> {
if (!config.WALLETS.ENABLED) {
return;
}
this.syncing = true; this.syncing = true;
for (const walletKey of Object.keys(this.wallets)) { for (const walletKey of Object.keys(this.wallets)) {
const wallet = this.wallets[walletKey]; const wallet = this.wallets[walletKey];
if (wallet.lastPoll < (Date.now() - POLL_FREQUENCY)) { if (wallet.lastPoll < (Date.now() - POLL_FREQUENCY)) {
try { try {
const response = await axios.get(`${wallet.url}/${wallet.name}`, { headers: { 'Authorization': `${wallet.apiKey}` } }); const response = await axios.get(config.MEMPOOL_SERVICES.API + `/wallets/${wallet.name}`);
const data: { walletBalances: WalletAddress[] } = response.data; const addresses: Record<string, WalletAddress> = response.data;
const addresses = data.walletBalances; const addressList: WalletAddress[] = Object.values(addresses);
const newAddresses: Record<string, boolean> = {};
// sync all current addresses // sync all current addresses
for (const address of addresses) { for (const address of addressList) {
await this.$syncWalletAddress(wallet, address); await this.$syncWalletAddress(wallet, address);
newAddresses[address.address] = true;
} }
// remove old addresses // remove old addresses
for (const address of Object.keys(wallet.addresses)) { for (const address of Object.keys(wallet.addresses)) {
if (!newAddresses[address]) { if (!addresses[address]) {
delete wallet.addresses[address]; delete wallet.addresses[address];
} }
} }
@ -73,16 +70,16 @@ class WalletApi {
// resync address transactions from esplora // resync address transactions from esplora
async $syncWalletAddress(wallet: Wallet, address: WalletAddress): Promise<void> { async $syncWalletAddress(wallet: Wallet, address: WalletAddress): Promise<void> {
// fetch full transaction data if the address is new or still active // fetch full transaction data if the address is new or still active and hasn't been synced in the last hour
const refreshTransactions = !wallet.addresses[address.address] || address.active; const refreshTransactions = !wallet.addresses[address.address] || (address.active && (Date.now() - wallet.addresses[address.address].lastSync) > 60 * 60 * 1000);
if (refreshTransactions) { if (refreshTransactions) {
try { try {
const walletAddress: WalletAddress = { const walletAddress: WalletAddress = {
address: address.address, address: address.address,
active: address.active, active: address.active,
transactions: await bitcoinApi.$getAddressTransactionSummary(address.address), transactions: await bitcoinApi.$getAddressTransactionSummary(address.address),
lastSync: Date.now(),
}; };
logger.debug(`Synced ${walletAddress.transactions?.length || 0} transactions for wallet ${wallet.name} address ${address.address}`);
wallet.addresses[address.address] = walletAddress; wallet.addresses[address.address] = walletAddress;
} catch (e) { } catch (e) {
logger.err(`Error syncing wallet address ${address.address}: ${(e instanceof Error ? e.message : e)}`); logger.err(`Error syncing wallet address ${address.address}: ${(e instanceof Error ? e.message : e)}`);

View file

@ -164,11 +164,7 @@ interface IConfig {
}, },
WALLETS: { WALLETS: {
ENABLED: boolean; ENABLED: boolean;
WALLETS: { WALLETS: string[];
url: string;
name: string;
apiKey: string;
}[];
} }
} }