Compare commits

...

6 Commits

Author SHA1 Message Date
nymkappa
e3953a6dca
Merge branch 'master' into 5376-merge-attempt 2024-12-09 08:56:55 +01:00
nymkappa
78844f5787
Attempt to merge master into #5376 2024-12-09 08:54:26 +01:00
Mononaut
79e2883ebe
update unfurler and build config 2024-07-26 14:17:55 +00:00
Mononaut
fdbca80920
check in new resources 2024-07-26 14:17:12 +00:00
Mononaut
64baade3b3
custom dashboard wallet widgets 2024-07-26 14:17:12 +00:00
Mononaut
4d06636d83
wallet tracking backend support 2024-07-26 14:17:07 +00:00
6 changed files with 59 additions and 17 deletions

View File

@ -19,8 +19,13 @@ interface WalletAddress {
lastSync: number; lastSync: number;
} }
interface Wallet { interface WalletConfig {
url: string;
name: string; name: string;
apiKey: string;
}
interface Wallet extends WalletConfig {
addresses: Record<string, WalletAddress>; addresses: Record<string, WalletAddress>;
lastPoll: number; lastPoll: number;
} }
@ -32,10 +37,10 @@ class WalletApi {
private syncing = false; private syncing = false;
constructor() { constructor() {
this.wallets = config.WALLETS.ENABLED ? (config.WALLETS.WALLETS as string[]).reduce((acc, wallet) => { this.wallets = (config.WALLETS.WALLETS as WalletConfig[]).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> {
@ -52,16 +57,18 @@ class WalletApi {
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(config.MEMPOOL_SERVICES.API + `/wallets/${wallet.name}`); const response = await axios.get(`${wallet.url}/${wallet.name}`, { headers: { 'Authorization': `${wallet.apiKey}` } });
const addresses: Record<string, WalletAddress> = response.data; const data: { walletBalances: WalletAddress[] } = response.data;
const addressList: WalletAddress[] = Object.values(addresses); const addresses = data.walletBalances;
const newAddresses: Record<string, boolean> = {};
// sync all current addresses // sync all current addresses
for (const address of addressList) { for (const address of addresses) {
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 (!addresses[address]) { if (!newAddresses[address]) {
delete wallet.addresses[address]; delete wallet.addresses[address];
} }
} }
@ -86,10 +93,11 @@ class WalletApi {
const walletAddress: WalletAddress = { const walletAddress: WalletAddress = {
address: address.address, address: address.address,
active: address.active, active: address.active,
transactions: summary, transactions: await bitcoinApi.$getAddressTransactionSummary(address.address),
stats: addressInfo.chain_stats, stats: addressInfo.chain_stats,
lastSync: Date.now(), 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)}`);
@ -142,7 +150,17 @@ class WalletApi {
wallet.addresses[address].transactions?.push(txSummary); wallet.addresses[address].transactions?.push(txSummary);
} }
if (anyMatch) { if (anyMatch) {
walletTransactions[walletKey].push(tx); for (const address of Object.keys({ ...funded, ...spent })) {
if (!walletTransactions[walletKey][address]) {
walletTransactions[walletKey][address] = [];
}
walletTransactions[walletKey][address].push({
txid: tx.txid,
value: (funded[address] ?? 0) - (spent[address] ?? 0),
height: block.height,
time: block.timestamp,
});
}
} }
} }
} }
@ -150,4 +168,4 @@ class WalletApi {
} }
} }
export default new WalletApi(); export default new WalletApi();

View File

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

View File

@ -315,4 +315,4 @@
</ng-template> </ng-template>
<ng-template #loadingbig> <ng-template #loadingbig>
<span class="skeleton-loader skeleton-loader-big" ></span> <span class="skeleton-loader skeleton-loader-big" ></span>
</ng-template> </ng-template>

View File

@ -131,8 +131,8 @@ export NVM_DIR="${HOME}/.nvm"
source "${NVM_DIR}/nvm.sh" source "${NVM_DIR}/nvm.sh"
# what to look for # what to look for
frontends=(mainnet liquid onbtc meta) frontends=(mainnet liquid onbtc bitb meta)
backends=(mainnet testnet testnet4 signet liquid liquidtestnet onbtc) backends=(mainnet testnet testnet4 signet liquid liquidtestnet onbtc bitb)
frontend_repos=() frontend_repos=()
backend_repos=() backend_repos=()

View File

@ -15,7 +15,7 @@ screen -dmS x startx
sleep 3 sleep 3
# start unfurlers for each frontend # start unfurlers for each frontend
for site in mainnet liquid onbtc meta;do for site in mainnet liquid onbtc bitb meta;do
cd "$HOME/${site}/unfurler" && \ cd "$HOME/${site}/unfurler" && \
echo "starting mempool unfurler: ${site}" && \ echo "starting mempool unfurler: ${site}" && \
screen -dmS "unfurler-${site}" sh -c 'while true;do npm run unfurler;sleep 2;done' screen -dmS "unfurler-${site}" sh -c 'while true;do npm run unfurler;sleep 2;done'

View File

@ -282,6 +282,26 @@ export const networks = {
} }
} }
}, },
bitb: {
title: 'BITB | Bitwise Bitcoin ETF',
description: 'BITB provides low-cost access to bitcoin through a professionally managed fund',
fallbackImg: '/resources/bitb/bitb-preview.jpg',
routes: { // only dynamic routes supported
block: routes.block,
address: routes.address,
tx: routes.tx,
mining: {
title: "Mining",
routes: {
pool: routes.mining.routes.pool,
}
},
lightning: {
title: "Lightning",
routes: routes.lightning.routes,
}
}
},
meta: { meta: {
title: 'Metaplanet Inc.', title: 'Metaplanet Inc.',
description: 'Secure the Future with Bitcoin', description: 'Secure the Future with Bitcoin',