diff --git a/backend/mempool-config.sample.json b/backend/mempool-config.sample.json index fe9122572..e53df38f2 100644 --- a/backend/mempool-config.sample.json +++ b/backend/mempool-config.sample.json @@ -48,12 +48,5 @@ "BISQ_MARKETS": { "ENABLED": false, "DATA_PATH": "/bisq/statsnode-data/btc_mainnet/db" - }, - "SPONSORS": { - "ENABLED": false, - "BTCPAY_URL": "", - "BTCPAY_AUTH": "", - "BTCPAY_WEBHOOK_URL": "", - "TWITTER_BEARER_AUTH": "" } } diff --git a/backend/src/api/donations.ts b/backend/src/api/donations.ts deleted file mode 100644 index 32700baae..000000000 --- a/backend/src/api/donations.ts +++ /dev/null @@ -1,198 +0,0 @@ -import config from '../config'; -import axios from 'axios'; -import { DB } from '../database'; -import logger from '../logger'; - -class Donations { - private notifyDonationStatusCallback: ((invoiceId: string) => void) | undefined; - private options = { - baseURL: config.SPONSORS.BTCPAY_URL, - headers: { - 'Content-Type': 'application/json', - 'Authorization': config.SPONSORS.BTCPAY_AUTH, - }, - timeout: 10000, - }; - - sponsorsCache: any[] = []; - - constructor() {} - - public async $updateCache() { - try { - this.sponsorsCache = await this.$getDonationsFromDatabase('handle, image'); - } catch (e) { - logger.warn('Setting sponsorsCache failed ' + e.message || e); - } - } - - setNotfyDonationStatusCallback(fn: any): void { - this.notifyDonationStatusCallback = fn; - } - - async $createRequest(amount: number, orderId: string): Promise { - logger.notice('New invoice request. Handle: ' + orderId + ' Amount: ' + amount + ' BTC'); - - const postData = { - 'price': amount, - 'orderId': orderId, - 'currency': 'BTC', - 'itemDesc': 'Sponsor mempool.space', - 'notificationUrl': config.SPONSORS.BTCPAY_WEBHOOK_URL, - 'redirectURL': 'https://mempool.space/about', - }; - const response = await axios.post('/invoices', postData, this.options); - return { - id: response.data.data.id, - amount: parseFloat(response.data.data.btcPrice), - addresses: response.data.data.addresses, - }; - } - - async $handleWebhookRequest(data: any): Promise { - if (!data || !data.id) { - return; - } - const response = await this.$getStatus(data.id); - logger.notice(`Received BTCPayServer webhook. Invoice ID: ${data.id} Status: ${response.status} BTC Paid: ${response.btcPaid}`); - if (response.status !== 'complete' && response.status !== 'confirmed' && response.status !== 'paid') { - return; - } - - if (this.notifyDonationStatusCallback) { - this.notifyDonationStatusCallback(data.id); - } - - if (parseFloat(response.btcPaid) < 0.01) { - return; - } - - if (response.orderId !== '') { - try { - const userData = await this.$getTwitterUserData(response.orderId); - const imageUrl = userData.profile_image_url.replace('normal', '200x200'); - const imageBlob = await this.$downloadProfileImageBlob(imageUrl); - - logger.debug('Creating database entry for donation with invoice id: ' + response.id); - await this.$addDonationToDatabase(response.btcPaid, userData.screen_name, userData.id, response.id, imageUrl, imageBlob); - this.$updateCache(); - } catch (e) { - logger.err(`Error fetching twitter data for handle ${response.orderId}: ${e.message}`); - } - } - } - - getSponsorImage(id: string): any | undefined { - const sponsor = this.sponsorsCache.find((s) => s.handle === id); - if (sponsor) { - return sponsor.image; - } - } - - async $getDonationsFromDatabase(fields: string): Promise { - try { - const connection = await DB.pool.getConnection(); - const query = `SELECT ${fields} FROM donations ORDER BY id DESC`; - const [rows] = await connection.query(query); - connection.release(); - return rows; - } catch (e) { - logger.err('$getDonationsFromDatabase() error: ' + e.message || e); - return []; - } - } - - private async $getOldDonations(): Promise { - try { - const connection = await DB.pool.getConnection(); - const query = `SELECT * FROM donations WHERE twitter_id IS NULL AND handle != ''`; - const [rows] = await connection.query(query); - connection.release(); - return rows; - } catch (e) { - logger.err('$getLegacyDonations() error' + e.message || e); - return []; - } - } - - private async $getStatus(id: string): Promise { - logger.debug('Fetching status for invoice: ' + id); - const response = await axios.get('/invoices/' + id, this.options); - logger.debug('Invoice status received: ' + JSON.stringify(response.data)); - return response.data.data; - } - - private async $addDonationToDatabase(btcPaid: number, handle: string, twitter_id: number | null, - orderId: string, imageUrl: string, image: string): Promise { - try { - const connection = await DB.pool.getConnection(); - const query = `INSERT IGNORE INTO donations(added, amount, handle, twitter_id, order_id, imageUrl, image) VALUES (NOW(), ?, ?, ?, ?, ?, FROM_BASE64(?))`; - const params: (string | number | null)[] = [ - btcPaid, - handle, - twitter_id, - orderId, - imageUrl, - image, - ]; - const [result]: any = await connection.query(query, params); - connection.release(); - } catch (e) { - logger.err('$addDonationToDatabase() error' + e.message || e); - } - } - - private async $updateDonation(id: number, handle: string, twitterId: number, imageUrl: string, image: string): Promise { - try { - const connection = await DB.pool.getConnection(); - const query = `UPDATE donations SET handle = ?, twitter_id = ?, imageUrl = ?, image = FROM_BASE64(?) WHERE id = ?`; - const params: (string | number)[] = [ - handle, - twitterId, - imageUrl, - image, - id, - ]; - const [result]: any = await connection.query(query, params); - connection.release(); - } catch (e) { - logger.err('$updateDonation() error' + e.message || e); - } - } - - private async $getTwitterUserData(handle: string): Promise { - logger.debug('Fetching Twitter API data...'); - const res = await axios.get(`https://api.twitter.com/1.1/users/show.json?screen_name=${handle}`, { - headers: { - Authorization: 'Bearer ' + config.SPONSORS.TWITTER_BEARER_AUTH - }, - timeout: 10000, - }); - logger.debug('Twitter user data fetched:' + JSON.stringify(res.data)); - return res.data; - } - - private async $downloadProfileImageBlob(url: string): Promise { - logger.debug('Fetching image blob...'); - const res = await axios.get(url, { responseType: 'arraybuffer', timeout: 10000 }); - logger.debug('Image downloaded.'); - return Buffer.from(res.data, 'utf8').toString('base64'); - } - - private async refreshSponsors(): Promise { - const oldDonations = await this.$getOldDonations(); - oldDonations.forEach(async (donation: any) => { - logger.debug('Migrating donation for handle: ' + donation.handle); - try { - const twitterData = await this.$getTwitterUserData(donation.handle); - const imageUrl = twitterData.profile_image_url.replace('normal', '200x200'); - const imageBlob = await this.$downloadProfileImageBlob(imageUrl); - await this.$updateDonation(donation.id, twitterData.screen_name, twitterData.id, imageUrl, imageBlob); - } catch (e) { - logger.err('Failed to migrate donation for handle: ' + donation.handle + '. ' + (e.message || e)); - } - }); - } -} - -export default new Donations(); diff --git a/backend/src/config.ts b/backend/src/config.ts index d98b1b1ec..1d46ccfcb 100644 --- a/backend/src/config.ts +++ b/backend/src/config.ts @@ -51,13 +51,6 @@ interface IConfig { ENABLED: boolean; DATA_PATH: string; }; - SPONSORS: { - ENABLED: boolean; - BTCPAY_URL: string; - BTCPAY_AUTH: string; - BTCPAY_WEBHOOK_URL: string; - TWITTER_BEARER_AUTH: string; - }; } const defaults: IConfig = { @@ -111,13 +104,6 @@ const defaults: IConfig = { 'ENABLED': false, 'DATA_PATH': '/bisq/statsnode-data/btc_mainnet/db' }, - 'SPONSORS': { - 'ENABLED': false, - 'BTCPAY_URL': '', - 'BTCPAY_AUTH': '', - 'BTCPAY_WEBHOOK_URL': '', - 'TWITTER_BEARER_AUTH': '' - } }; class Config implements IConfig { @@ -130,7 +116,6 @@ class Config implements IConfig { STATISTICS: IConfig['STATISTICS']; BISQ_BLOCKS: IConfig['BISQ_BLOCKS']; BISQ_MARKETS: IConfig['BISQ_MARKETS']; - SPONSORS: IConfig['SPONSORS']; constructor() { const configs = this.merge(configFile, defaults); @@ -143,7 +128,6 @@ class Config implements IConfig { this.STATISTICS = configs.STATISTICS; this.BISQ_BLOCKS = configs.BISQ_BLOCKS; this.BISQ_MARKETS = configs.BISQ_MARKETS; - this.SPONSORS = configs.SPONSORS; } merge = (...objects: object[]): IConfig => { diff --git a/backend/src/index.ts b/backend/src/index.ts index e78691aed..1013da281 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -1,7 +1,6 @@ import { Express, Request, Response, NextFunction } from 'express'; import * as express from 'express'; import * as http from 'http'; -import * as https from 'https'; import * as WebSocket from 'ws'; import * as cluster from 'cluster'; import axios from 'axios'; @@ -17,7 +16,6 @@ import websocketHandler from './api/websocket-handler'; import fiatConversion from './api/fiat-conversion'; import bisq from './api/bisq/bisq'; import bisqMarkets from './api/bisq/markets'; -import donations from './api/donations'; import logger from './logger'; import backendInfo from './api/backend-info'; import loadingIndicators from './api/loading-indicators'; @@ -25,7 +23,7 @@ import mempool from './api/mempool'; class Server { private wss: WebSocket.Server | undefined; - private server: https.Server | http.Server | undefined; + private server: http.Server | undefined; private app: Express; private currentBackendRetryInterval = 5; @@ -87,10 +85,6 @@ class Server { fiatConversion.startService(); - if (config.SPONSORS.ENABLED) { - donations.$updateCache(); - } - this.setUpHttpApiRoutes(); this.setUpWebsocketHandling(); this.runMainUpdateLoop(); @@ -144,7 +138,6 @@ class Server { statistics.setNewStatisticsEntryCallback(websocketHandler.handleNewStatistic.bind(websocketHandler)); blocks.setNewBlockCallback(websocketHandler.handleNewBlock.bind(websocketHandler)); memPool.setMempoolChangedCallback(websocketHandler.handleMempoolChange.bind(websocketHandler)); - donations.setNotfyDonationStatusCallback(websocketHandler.handleNewDonation.bind(websocketHandler)); fiatConversion.setProgressChangedCallback(websocketHandler.handleNewConversionRates.bind(websocketHandler)); loadingIndicators.setProgressChangedCallback(websocketHandler.handleLoadingChanged.bind(websocketHandler)); } @@ -156,6 +149,24 @@ class Server { .get(config.MEMPOOL.API_URL_PREFIX + 'fees/mempool-blocks', routes.getMempoolBlocks) .get(config.MEMPOOL.API_URL_PREFIX + 'backend-info', routes.getBackendInfo) .get(config.MEMPOOL.API_URL_PREFIX + 'init-data', routes.getInitData) + .get(config.MEMPOOL.API_URL_PREFIX + 'donations', async (req, res) => { + try { + const response = await axios.get('http://localhost:9000/api/v1/donations', { responseType: 'stream', timeout: 10000 }); + response.data.pipe(res); + } catch (e) { + res.status(500).end(); + } + }) + .get(config.MEMPOOL.API_URL_PREFIX + 'donations/images/:id', async (req, res) => { + try { + const response = await axios.get('http://localhost:9000/api/v1/donations/images/' + req.params.id, { + responseType: 'stream', timeout: 10000 + }); + response.data.pipe(res); + } catch (e) { + res.status(500).end(); + } + }) ; if (config.STATISTICS.ENABLED && config.DATABASE.ENABLED) { @@ -195,35 +206,6 @@ class Server { ; } - if (config.SPONSORS.ENABLED) { - this.app - .get(config.MEMPOOL.API_URL_PREFIX + 'donations', routes.getDonations.bind(routes)) - .get(config.MEMPOOL.API_URL_PREFIX + 'donations/images/:id', routes.getSponsorImage.bind(routes)) - .post(config.MEMPOOL.API_URL_PREFIX + 'donations', routes.createDonationRequest.bind(routes)) - .post(config.MEMPOOL.API_URL_PREFIX + 'donations-webhook', routes.donationWebhook.bind(routes)) - ; - } else { - this.app - .get(config.MEMPOOL.API_URL_PREFIX + 'donations', async (req, res) => { - try { - const response = await axios.get('https://mempool.space/api/v1/donations', { responseType: 'stream', timeout: 10000 }); - response.data.pipe(res); - } catch (e) { - res.status(500).end(); - } - }) - .get(config.MEMPOOL.API_URL_PREFIX + 'donations/images/:id', async (req, res) => { - try { - const response = await axios.get('https://mempool.space/api/v1/donations/images/' + req.params.id, { - responseType: 'stream', timeout: 10000 - }); - response.data.pipe(res); - } catch (e) { - res.status(500).end(); - } - }); - } - if (config.MEMPOOL.BACKEND !== 'esplora') { this.app .get(config.MEMPOOL.API_URL_PREFIX + 'mempool', routes.getMempool) diff --git a/backend/src/routes.ts b/backend/src/routes.ts index f451d914d..c03c08b75 100644 --- a/backend/src/routes.ts +++ b/backend/src/routes.ts @@ -8,10 +8,9 @@ import mempool from './api/mempool'; import bisq from './api/bisq/bisq'; import websocketHandler from './api/websocket-handler'; import bisqMarket from './api/bisq/markets-api'; -import { OptimizedStatistic, RequiredSpec, TransactionExtended } from './mempool.interfaces'; +import { RequiredSpec, TransactionExtended } from './mempool.interfaces'; import { MarketsApiError } from './api/bisq/interfaces'; import { IEsploraApi } from './api/bitcoin/esplora-api.interface'; -import donations from './api/donations'; import logger from './logger'; import bitcoinApi from './api/bitcoin/bitcoin-api-factory'; import transactionUtils from './api/transaction-utils'; @@ -99,79 +98,6 @@ class Routes { res.json(backendInfo.getBackendInfo()); } - public async createDonationRequest(req: Request, res: Response) { - const constraints: RequiredSpec = { - 'amount': { - required: true, - types: ['@float'] - }, - 'orderId': { - required: true, - types: ['@string'] - } - }; - - const p = this.parseRequestParameters(req.body, constraints); - if (p.error) { - res.status(400).send(p.error); - return; - } - - if (p.orderId !== '' && !/^(@|)[a-zA-Z0-9_]{1,15}$/.test(p.orderId)) { - res.status(400).send('Invalid Twitter handle'); - return; - } - - if (p.amount < 0.001) { - res.status(400).send('Amount needs to be at least 0.001'); - return; - } - - if (p.amount > 1000) { - res.status(400).send('Amount too large'); - return; - } - - try { - const result = await donations.$createRequest(p.amount, p.orderId); - res.json(result); - } catch (e) { - res.status(500).send(e.message); - } - } - - public async getDonations(req: Request, res: Response) { - try { - const result = await donations.$getDonationsFromDatabase('handle, imageUrl'); - res.json(result); - } catch (e) { - res.status(500).send(e.message); - } - } - - public async getSponsorImage(req: Request, res: Response) { - try { - const result = await donations.getSponsorImage(req.params.id); - if (result) { - res.set('Content-Type', 'image/jpeg'); - res.send(result); - } else { - res.status(404).end(); - } - } catch (e) { - res.status(500).send(e.message); - } - } - - public async donationWebhook(req: Request, res: Response) { - try { - donations.$handleWebhookRequest(req.body); - res.end(); - } catch (e) { - res.status(500).send(e); - } - } - public getBisqStats(req: Request, res: Response) { const result = bisq.getStats(); res.json(result); diff --git a/frontend/proxy.conf.json b/frontend/proxy.conf.json index 5886ff104..d109b50ec 100644 --- a/frontend/proxy.conf.json +++ b/frontend/proxy.conf.json @@ -1,4 +1,8 @@ { + "/api/v1/donations": { + "target": "http://localhost:9000/", + "secure": false + }, "/api/v1": { "target": "http://localhost:8999/", "secure": false diff --git a/frontend/src/app/components/about/about.component.html b/frontend/src/app/components/about/about.component.html index 0c3d37524..d30031ebe 100644 --- a/frontend/src/app/components/about/about.component.html +++ b/frontend/src/app/components/about/about.component.html @@ -173,10 +173,9 @@

Donation confirmed!
Thank you!

-

If you specified a Twitter handle, the profile photo should now be visible on this page when you reload.

-



+


diff --git a/frontend/src/app/components/about/about.component.ts b/frontend/src/app/components/about/about.component.ts index 04681d95a..4e598e693 100644 --- a/frontend/src/app/components/about/about.component.ts +++ b/frontend/src/app/components/about/about.component.ts @@ -1,19 +1,19 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, OnDestroy, OnInit } from '@angular/core'; import { WebsocketService } from '../../services/websocket.service'; import { SeoService } from 'src/app/services/seo.service'; import { StateService } from 'src/app/services/state.service'; -import { Observable } from 'rxjs'; +import { Observable, Subscription } from 'rxjs'; import { FormBuilder, FormGroup, Validators } from '@angular/forms'; import { ApiService } from 'src/app/services/api.service'; import { DomSanitizer, SafeUrl } from '@angular/platform-browser'; -import { map } from 'rxjs/operators'; +import { delay, map, retryWhen, switchMap, tap } from 'rxjs/operators'; @Component({ selector: 'app-about', templateUrl: './about.component.html', styleUrls: ['./about.component.scss'], }) -export class AboutComponent implements OnInit { +export class AboutComponent implements OnInit, OnDestroy { gitCommit$: Observable; donationForm: FormGroup; paymentForm: FormGroup; @@ -22,6 +22,7 @@ export class AboutComponent implements OnInit { donationObj: any; sponsorsEnabled = this.stateService.env.SPONSORS_ENABLED; sponsors = null; + requestSubscription: Subscription | undefined; constructor( private websocketService: WebsocketService, @@ -50,23 +51,37 @@ export class AboutComponent implements OnInit { .subscribe((sponsors) => { this.sponsors = sponsors; }); + } - this.apiService.getDonation$() - this.stateService.donationConfirmed$.subscribe(() => this.donationStatus = 4); + ngOnDestroy() { + if (this.requestSubscription) { + this.requestSubscription.unsubscribe(); + } } submitDonation() { if (this.donationForm.invalid) { return; } - this.apiService.requestDonation$( + this.requestSubscription = this.apiService.requestDonation$( this.donationForm.get('amount').value, this.donationForm.get('handle').value ) - .subscribe((response) => { - this.websocketService.trackDonation(response.id); - this.donationObj = response; - this.donationStatus = 3; + .pipe( + tap((response) => { + this.donationObj = response; + this.donationStatus = 3; + }), + switchMap(() => this.apiService.checkDonation$(this.donationObj.id) + .pipe( + retryWhen((errors) => errors.pipe(delay(2000))) + ) + ) + ).subscribe(() => { + this.donationStatus = 4; + if (this.donationForm.get('handle').value) { + this.sponsors.unshift({ handle: this.donationForm.get('handle').value }); + } }); } diff --git a/frontend/src/app/interfaces/websocket.interface.ts b/frontend/src/app/interfaces/websocket.interface.ts index e96c6e3c2..2a753b91f 100644 --- a/frontend/src/app/interfaces/websocket.interface.ts +++ b/frontend/src/app/interfaces/websocket.interface.ts @@ -15,13 +15,11 @@ export interface WebsocketResponse { tx?: Transaction; rbfTransaction?: Transaction; transactions?: TransactionStripped[]; - donationConfirmed?: boolean; loadingIndicators?: ILoadingIndicators; 'track-tx'?: string; 'track-address'?: string; 'track-asset'?: string; 'watch-mempool'?: boolean; - 'track-donation'?: string; } export interface MempoolBlock { diff --git a/frontend/src/app/services/api.service.ts b/frontend/src/app/services/api.service.ts index 2b2fa6525..b31bb24f3 100644 --- a/frontend/src/app/services/api.service.ts +++ b/frontend/src/app/services/api.service.ts @@ -77,6 +77,10 @@ export class ApiService { return this.httpClient.get(this.apiBaseUrl + this.apiBasePath + '/api/v1/donations'); } + checkDonation$(orderId: string): Observable { + return this.httpClient.get(this.apiBaseUrl + this.apiBasePath + '/api/v1/donations/check?order_id=' + orderId); + } + getInitData$(): Observable { return this.httpClient.get(this.apiBaseUrl + this.apiBasePath + '/api/v1/init-data'); } diff --git a/frontend/src/app/services/state.service.ts b/frontend/src/app/services/state.service.ts index 8b66862fc..be0191e2c 100644 --- a/frontend/src/app/services/state.service.ts +++ b/frontend/src/app/services/state.service.ts @@ -64,7 +64,6 @@ export class StateService { vbytesPerSecond$ = new ReplaySubject(1); lastDifficultyAdjustment$ = new ReplaySubject(1); gitCommit$ = new ReplaySubject(1); - donationConfirmed$ = new Subject(); loadingIndicators$ = new ReplaySubject(1); live2Chart$ = new Subject(); diff --git a/frontend/src/app/services/websocket.service.ts b/frontend/src/app/services/websocket.service.ts index 66bb70b54..7c35e040d 100644 --- a/frontend/src/app/services/websocket.service.ts +++ b/frontend/src/app/services/websocket.service.ts @@ -126,10 +126,6 @@ export class WebsocketService { this.isTrackingTx = true; } - trackDonation(id: string) { - this.websocketSubject.next({ 'track-donation': id }); - } - stopTrackingTransaction() { if (!this.isTrackingTx) { return; @@ -289,9 +285,5 @@ export class WebsocketService { if (response['git-commit']) { this.stateService.gitCommit$.next(response['git-commit']); } - - if (response.donationConfirmed) { - this.stateService.donationConfirmed$.next(true); - } } } diff --git a/frontend/src/locale/messages.xlf b/frontend/src/locale/messages.xlf index e875d4f58..4140d8340 100644 --- a/frontend/src/locale/messages.xlf +++ b/frontend/src/locale/messages.xlf @@ -46,7 +46,7 @@ src/app/components/transactions-list/transactions-list.component.html - 205 + 208 src/app/bisq/bisq-transfers/bisq-transfers.component.html @@ -67,7 +67,7 @@ src/app/components/transactions-list/transactions-list.component.html - 206 + 209 src/app/bisq/bisq-transfers/bisq-transfers.component.html @@ -88,7 +88,7 @@ src/app/components/transactions-list/transactions-list.component.html - 209 + 212 Transaction unconfirmed state transaction.unconfirmed @@ -242,7 +242,7 @@ src/app/components/transactions-list/transactions-list.component.html - 198 + 201 src/app/components/block/block.component.html @@ -468,7 +468,7 @@ nSequence src/app/components/transactions-list/transactions-list.component.html - 92 + 95 transactions-list.nsequence @@ -476,7 +476,7 @@ ScriptSig (ASM) src/app/components/transactions-list/transactions-list.component.html - 71 + 74 ScriptSig (ASM) transactions-list.scriptsig.asm @@ -485,7 +485,7 @@ ScriptSig (HEX) src/app/components/transactions-list/transactions-list.component.html - 75 + 78 ScriptSig (HEX) transactions-list.scriptsig.hex @@ -494,7 +494,7 @@ Witness src/app/components/transactions-list/transactions-list.component.html - 80 + 83 transactions-list.witness @@ -502,7 +502,7 @@ P2SH redeem script src/app/components/transactions-list/transactions-list.component.html - 84 + 87 transactions-list.p2sh-redeem-script @@ -510,7 +510,7 @@ P2WSH witness script src/app/components/transactions-list/transactions-list.component.html - 88 + 91 transactions-list.p2wsh-witness-script @@ -518,7 +518,7 @@ Previous output script src/app/components/transactions-list/transactions-list.component.html - 96 + 99 transactions-list.previous-output-script @@ -526,11 +526,11 @@ Load all src/app/components/transactions-list/transactions-list.component.html - 106 + 109 src/app/components/transactions-list/transactions-list.component.html - 188 + 191 transactions-list.load-all @@ -538,7 +538,7 @@ Peg-out to src/app/components/transactions-list/transactions-list.component.html - 125 + 128 transactions-list.peg-out-to @@ -546,7 +546,7 @@ ScriptPubKey (ASM) src/app/components/transactions-list/transactions-list.component.html - 170 + 173 ScriptPubKey (ASM) transactions-list.scriptpubkey.asm @@ -555,7 +555,7 @@ ScriptPubKey (HEX) src/app/components/transactions-list/transactions-list.component.html - 174 + 177 ScriptPubKey (HEX) transactions-list.scriptpubkey.hex @@ -564,7 +564,7 @@ Type src/app/components/transactions-list/transactions-list.component.html - 166 + 169 src/app/bisq/bisq-transaction-details/bisq-transaction-details.component.html @@ -580,7 +580,7 @@ data src/app/components/transactions-list/transactions-list.component.html - 178 + 181 transactions-list.vout.scriptpubkey-type.data @@ -588,7 +588,7 @@ sat src/app/components/transactions-list/transactions-list.component.html - 198 + 201 sat shared.sat @@ -597,7 +597,7 @@ Confidential src/app/components/transactions-list/transactions-list.component.html - 214 + 217 src/app/components/amount/amount.component.html @@ -605,7 +605,7 @@ src/app/components/address/address.component.html - 132 + 134 src/app/components/asset/asset.component.html @@ -841,11 +841,23 @@ shared.address + + Balance + + src/app/components/address/address.component.html + 30 + + + src/app/bisq/bisq-address/bisq-address.component.html + 28 + + address.balance + Total received src/app/components/address/address.component.html - 20 + 21 src/app/bisq/bisq-address/bisq-address.component.html @@ -857,7 +869,7 @@ Total sent src/app/components/address/address.component.html - 24 + 25 src/app/bisq/bisq-address/bisq-address.component.html @@ -869,23 +881,11 @@ address.total-sent - - Balance - - src/app/components/address/address.component.html - 28 - - - src/app/bisq/bisq-address/bisq-address.component.html - 28 - - address.balance - of transaction src/app/components/address/address.component.html - 48 + 50 X of X Address Transaction @@ -893,7 +893,7 @@ of transactions src/app/components/address/address.component.html - 49 + 51 X of X Address Transactions (Plural) @@ -901,7 +901,7 @@ Error loading address data. src/app/components/address/address.component.html - 113 + 115 address.error.loading-address-data @@ -1020,15 +1020,23 @@ multisig of src/app/components/address-labels/address-labels.component.html - 1 + 5 address-labels.multisig - - Layer Peg-out + + Lightning src/app/components/address-labels/address-labels.component.html - 2 + 11 + + address-labels.upper-layer-peg-out + + + Liquid + + src/app/components/address-labels/address-labels.component.html + 17 address-labels.upper-layer-peg-out @@ -1052,7 +1060,7 @@ src/app/components/about/about.component.ts - 37 + 38 master-page.about @@ -1199,7 +1207,7 @@ Terms of Service src/app/components/about/about.component.html - 206 + 205 src/app/dashboard/dashboard.component.html @@ -1268,14 +1276,6 @@ about.sponsor.thank-you - - If you specified a Twitter handle, the profile photo should now be visible on this page when you reload. - - src/app/components/about/about.component.html - 176 - - about.sponsor.sponsor-completed - Loading graphs... diff --git a/mariadb-structure.sql b/mariadb-structure.sql index d045b3ce3..4d567ed91 100644 --- a/mariadb-structure.sql +++ b/mariadb-structure.sql @@ -84,24 +84,3 @@ ALTER TABLE `transactions` ALTER TABLE `statistics` MODIFY `id` int(11) NOT NULL AUTO_INCREMENT; - - -CREATE TABLE `donations` ( - `id` int(11) NOT NULL, - `added` datetime NOT NULL, - `amount` float NOT NULL, - `handle` varchar(250) NOT NULL, - `order_id` varchar(25) NOT NULL, - `imageUrl` varchar(250) NOT NULL -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -ALTER TABLE `donations` - ADD PRIMARY KEY (`id`); - -ALTER TABLE `donations` - MODIFY `id` int(11) NOT NULL AUTO_INCREMENT; - -ALTER TABLE `donations` ADD UNIQUE(`order_id`); - -ALTER TABLE `donations` ADD `image` MEDIUMBLOB NULL AFTER `imageUrl`; -ALTER TABLE `donations` ADD `twitter_id` VARCHAR(250) NULL AFTER `handle`;