Skip to content

Commit

Permalink
Merge pull request #27 from ferritecoin/master
Browse files Browse the repository at this point in the history
v0.1a
  • Loading branch information
koh-gt authored Aug 1, 2024
2 parents ac5cc13 + 7269490 commit 0deef57
Show file tree
Hide file tree
Showing 53 changed files with 350 additions and 132 deletions.
33 changes: 24 additions & 9 deletions backend/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@ Jump to a section in this doc:

## Setup

### 1. Clone Ferritepool Repository
### 1. Clone fecspace Repository

Get the latest Ferritepool code:
Get the latest fecspace code:

```
git clone https://github.com/ferritecoin/fecspace
cd Ferritepool
cd fecspace
```

Check out the latest release:
Expand All @@ -36,8 +36,8 @@ Turn on `txindex`, enable RPC, and set RPC credentials in `ferrite.conf`:
```
txindex=1
server=1
rpcuser=mempool
rpcpassword=mempool
rpcuser=user
rpcpassword=password
```

### 3. Configure Electrum Server
Expand All @@ -54,7 +54,7 @@ Get MariaDB from your operating system's package manager:

```
# Debian, Ubuntu, etc.
apt-get install mariadb-server mariadb-client
sudo apt-get install mariadb-server mariadb-client
# macOS
brew install mariadb
Expand All @@ -64,6 +64,8 @@ mysql.server start
Create a database and grant privileges:

```
sudo mariadb
MariaDB [(none)]> drop database mempool;
Query OK, 0 rows affected (0.00 sec)
Expand All @@ -72,18 +74,31 @@ Query OK, 1 row affected (0.00 sec)
MariaDB [(none)]> grant all privileges on mempool.* to 'mempool'@'%' identified by 'mempool';
Query OK, 0 rows affected (0.00 sec)
exit
```

### 5. Prepare Ferritepool Backend

#### Build

_Make sure to use Node.js 16.10 and npm 7._
```
node -v
```

Install dependencies with `npm` and build the backend:

```
cd backend
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash
export NVM_DIR="$([ -z "${XDG_CONFIG_HOME-}" ] && printf %s "${HOME}/.nvm" || printf %s "${XDG_CONFIG_HOME}/nvm")"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
source ~/.bashrc # reload shell
nvm install 16
nvm use 16
npm install
npm run build
```
Expand All @@ -96,14 +111,14 @@ In the backend folder, make a copy of the sample config file:
cp mempool-config.sample.json mempool-config.json
```

Edit `mempool-config.json` as needed.
Edit `mempool-config.json` as needed.n

In particular, make sure:

- the correct Ferrite Core RPC credentials are specified in `CORE_RPC`
- the correct `BACKEND` is specified in `MEMPOOL`:
- "electrum" if you're using [electrs-ltc](https://github.com/rust-ferrite/electrs-ltc/tree/master) or [cculianu/Fulcrum](https://github.com/cculianu/Fulcrum)
- "esplora" if you're using [electrs-ltc-esplora](https://github.com/rust-ferrite/electrs-ltc/tree/esplora)
~- "electrum" if you're using [electrs-ltc](https://github.com/rust-ferrite/electrs-ltc/tree/master) or [cculianu/Fulcrum](https://github.com/cculianu/Fulcrum)~
- "esplora" if you're using [electrs-fec](https://github.com/ferritecoin/electrs-fec)
- "none" if you're not using any Electrum Server

### 6. Run Ferritepool Backend
Expand Down
2 changes: 1 addition & 1 deletion backend/src/__tests__/config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ describe('Mempool Backend Config', () => {

expect(config.ELECTRUM).toStrictEqual({ HOST: '127.0.0.1', PORT: 3306, TLS_ENABLED: true });

expect(config.ESPLORA).toStrictEqual({ REST_API_URL: 'http://127.0.0.1:3000', UNIX_SOCKET_PATH: null, RETRY_UNIX_SOCKET_AFTER: 30000 });
expect(config.ESPLORA).toStrictEqual({ REST_API_URL: 'http://127.0.0.1:3010', UNIX_SOCKET_PATH: null, RETRY_UNIX_SOCKET_AFTER: 30000 });

expect(config.CORE_RPC).toStrictEqual({
HOST: '127.0.0.1',
Expand Down
61 changes: 61 additions & 0 deletions backend/src/tasks/price-feeds/xeggex-api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { query } from '../../utils/axios-query';
import priceUpdater, { PriceFeed, PriceHistory } from '../price-updater';

interface CandleData {
time: number;
close: number;
open: number;
high: number;
low: number;
volume: number;
}

interface CandleApiResponse {
bars: CandleData[];
}

class XeggexApi implements PriceFeed {
public name: string = 'Xeggex';
public currencies: string[] = ['USDT'];

public url: string = 'https://api.xeggex.com/api/v2/ticker/FEC_USDT';

constructor() {
}

public async $fetchPrice(currency): Promise<number> {
const response = await query(this.url);
if (response && response['lastPrice']) {
return parseFloat(response['last_price']);
} else {
return -1;
}
}

public async $fetchRecentPrice(currencies: string[], type: 'hour' | 'day'): Promise<PriceHistory> {
const priceHistory: PriceHistory = {};

for (const currency of currencies) {
if (this.currencies.includes(currency) === false) {
continue;
}

const url = `https://api.xeggex.com/api/v2/market/candles?symbol=FEC%2FUSDT&resolution=30&countBack=336&firstDataRequest=1`;
const response = await query(url) as CandleApiResponse;

if (response && response.bars) {
for (const bar of response.bars) {
const time = Math.round(bar.time / 1000);
if (priceHistory[time] === undefined) {
priceHistory[time] = priceUpdater.getEmptyPricesObj();
}
priceHistory[time][currency] = bar.close; // Using the 'close' price
}
}
}

return priceHistory;
}
}

export default XeggexApi;
32 changes: 17 additions & 15 deletions backend/src/tasks/price-updater.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import config from '../config';
import logger from '../logger';
import PricesRepository, { ApiPrice, MAX_PRICES } from '../repositories/PricesRepository';
import BitfinexApi from './price-feeds/bitfinex-api';
import CoinbaseApi from './price-feeds/coinbase-api';
import GeminiApi from './price-feeds/gemini-api';
import KrakenApi from './price-feeds/kraken-api';
//import BitfinexApi from './price-feeds/bitfinex-api';
//import CoinbaseApi from './price-feeds/coinbase-api';
//import GeminiApi from './price-feeds/gemini-api';
//import KrakenApi from './price-feeds/kraken-api';
import XeggexApi from './price-feeds/xeggex-api';

export interface PriceFeed {
name: string;
Expand Down Expand Up @@ -33,10 +34,11 @@ class PriceUpdater {
constructor() {
this.latestPrices = this.getEmptyPricesObj();

this.feeds.push(new KrakenApi());
this.feeds.push(new CoinbaseApi());
this.feeds.push(new BitfinexApi());
this.feeds.push(new GeminiApi());
// this.feeds.push(new KrakenApi());
// this.feeds.push(new CoinbaseApi());
// this.feeds.push(new BitfinexApi());
// this.feeds.push(new GeminiApi());
this.feeds.push(new XeggexApi());
}

public getLatestPrices(): ApiPrice {
Expand Down Expand Up @@ -88,14 +90,14 @@ class PriceUpdater {
await this.$insertHistoricalPrices();
}
} catch (e: any) {
logger.err(`Cannot save LTC prices in db. Reason: ${e instanceof Error ? e.message : e}`, logger.tags.mining);
logger.err(`Cannot save FEC prices in db. Reason: ${e instanceof Error ? e.message : e}`, logger.tags.mining);
}

this.running = false;
}

/**
* Fetch last LTC price from exchanges, average them, and save it in the database once every hour
* Fetch last FEC price from exchanges, average them, and save it in the database once every hour
*/
private async $updatePrice(): Promise<void> {
if (this.lastRun === 0 && config.DATABASE.ENABLED === true) {
Expand All @@ -121,14 +123,14 @@ class PriceUpdater {
if (price > -1 && price < MAX_PRICES[currency]) {
prices.push(price);
}
logger.debug(`${feed.name} LTC/${currency} price: ${price}`, logger.tags.mining);
logger.debug(`${feed.name} FEC/${currency} price: ${price}`, logger.tags.mining);
} catch (e) {
logger.debug(`Could not fetch LTC/${currency} price at ${feed.name}. Reason: ${(e instanceof Error ? e.message : e)}`, logger.tags.mining);
logger.debug(`Could not fetch FEC/${currency} price at ${feed.name}. Reason: ${(e instanceof Error ? e.message : e)}`, logger.tags.mining);
}
}
}
if (prices.length === 1) {
logger.debug(`Only ${prices.length} feed available for LTC/${currency} price`, logger.tags.mining);
logger.debug(`Only ${prices.length} feed available for FEC/${currency} price`, logger.tags.mining);
}

// Compute average price, non weighted
Expand All @@ -140,7 +142,7 @@ class PriceUpdater {
}
}

logger.info(`Latest LTC fiat averaged price: ${JSON.stringify(this.latestPrices)}`);
logger.info(`Latest FEC fiat averaged price: ${JSON.stringify(this.latestPrices)}`);

if (config.DATABASE.ENABLED === true) {
// Save everything in db
Expand Down Expand Up @@ -172,7 +174,7 @@ class PriceUpdater {
*/
private async $insertHistoricalPrices(): Promise<void> {
// Insert Kraken weekly prices
await new KrakenApi().$insertHistoricalPrice();
// await new KrakenApi().$insertHistoricalPrice();

// Insert missing recent hourly prices
await this.$insertMissingRecentPrices('day');
Expand Down
2 changes: 1 addition & 1 deletion frontend/proxy.conf.local-esplora.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ PROXY_CONFIG.push(...[
},
{
context: ['/api/**'],
target: `http://127.0.0.1:3000`,
target: `http://127.0.0.1:3010`,
secure: false,
changeOrigin: true,
proxyTimeout: 30000,
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/app/components/amount/amount.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,6 @@
<span class="symbol"><ng-template [ngIf]="network === 'liquid'">L-</ng-template>
<ng-template [ngIf]="network === 'liquidtestnet'">tL-</ng-template>
<ng-template [ngIf]="network === 'testnet'">t</ng-template>
<ng-template [ngIf]="network === 'signet'">s</ng-template>LTC</span>
<ng-template [ngIf]="network === 'signet'">s</ng-template>FEC</span>
</ng-template>
</ng-template>
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ export class BlockFeeRatesGraphComponent implements OnInit {
let tooltip = `<b style="color: white; margin-left: 2px">${formatterXAxis(this.locale, this.timespan, parseInt(data[0].axisValue, 10))}</b><br>`;

for (const rate of data.reverse()) {
tooltip += `${rate.marker} ${rate.seriesName}: ${rate.data[1]} lits/vByte<br>`;
tooltip += `${rate.marker} ${rate.seriesName}: ${rate.data[1]} atoms/vByte<br>`;
}

if (['24h', '3d'].includes(this.timespan)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ export class BlockFeesGraphComponent implements OnInit {

for (const tick of data) {
if (tick.seriesIndex === 0) {
tooltip += `${tick.marker} ${tick.seriesName}: ${formatNumber(tick.data[1], this.locale, '1.3-3')} LTC<br>`;
tooltip += `${tick.marker} ${tick.seriesName}: ${formatNumber(tick.data[1], this.locale, '1.3-3')} FEC<br>`;
} else if (tick.seriesIndex === 1) {
tooltip += `${tick.marker} ${tick.seriesName}: ${this.fiatCurrencyPipe.transform(tick.data[1], null, this.currency) }<br>`;
}
Expand All @@ -182,7 +182,7 @@ export class BlockFeesGraphComponent implements OnInit {
legend: data.blockFees.length === 0 ? undefined : {
data: [
{
name: 'Fees LTC',
name: 'Fees FEC',
inactiveColor: 'rgb(110, 112, 121)',
textStyle: {
color: 'white',
Expand All @@ -205,7 +205,7 @@ export class BlockFeesGraphComponent implements OnInit {
axisLabel: {
color: 'rgb(110, 112, 121)',
formatter: (val) => {
return `${val} LTC`;
return `${val} FEC`;
}
},
splitLine: {
Expand Down Expand Up @@ -235,7 +235,7 @@ export class BlockFeesGraphComponent implements OnInit {
legendHoverLink: false,
zlevel: 0,
yAxisIndex: 0,
name: 'Fees LTC',
name: 'Fees FEC',
data: data.blockFees,
type: 'line',
smooth: 0.25,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
position: relative;
width: 100%;
padding-bottom: 100%;
background: #1a1a1a; // LTCbrand: block graph background
background: #1b1b1b; // block graph background
display: flex;
justify-content: center;
align-items: center;
Expand All @@ -26,7 +26,7 @@

.loader-wrapper {
position: absolute;
background: #1a1a1a7f;
background: #1b1b1b7f;
left: 0;
right: 0;
top: 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,18 @@
</tr>
<tr>
<td class="td-width" i18n="transaction.fee|Transaction fee">Fee</td>
<td>{{ fee | number }} <span class="symbol" i18n="shared.sat|lit">lit</span> &nbsp; <span class="fiat"><app-fiat [blockConversion]="blockConversion" [value]="fee"></app-fiat></span></td>
<td>{{ fee | number }} <span class="symbol" i18n="shared.sat|atom">atom</span> &nbsp; <span class="fiat"><app-fiat [blockConversion]="blockConversion" [value]="fee"></app-fiat></span></td>
</tr>
<tr>
<td class="td-width" i18n="transaction.fee-rate|Transaction fee rate">Fee rate</td>
<td>
{{ feeRate | feeRounding }} <span class="symbol" i18n="shared.sat-vbyte|lit/vB">lit/vB</span>
{{ feeRate | feeRounding }} <span class="symbol" i18n="shared.sat-vbyte|atom/vB">atom/vB</span>
</td>
</tr>
<tr *ngIf="effectiveRate && effectiveRate !== feeRate">
<td class="td-width" i18n="transaction.effective-fee-rate|Effective transaction fee rate">Effective fee rate</td>
<td>
{{ effectiveRate | feeRounding }} <span class="symbol" i18n="shared.sat-vbyte|lit/vB">lit/vB</span>
{{ effectiveRate | feeRounding }} <span class="symbol" i18n="shared.sat-vbyte|atom/vB">atom/vB</span>
</td>
</tr>
<tr>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ export class BlockRewardsGraphComponent implements OnInit {

for (const tick of data) {
if (tick.seriesIndex === 0) {
tooltip += `${tick.marker} ${tick.seriesName}: ${formatNumber(tick.data[1], this.locale, '1.3-3')} LTC<br>`;
tooltip += `${tick.marker} ${tick.seriesName}: ${formatNumber(tick.data[1], this.locale, '1.3-3')} FEC<br>`;
} else if (tick.seriesIndex === 1) {
tooltip += `${tick.marker} ${tick.seriesName}: ${this.fiatCurrencyPipe.transform(tick.data[1], null, this.currency)}<br>`;
}
Expand All @@ -181,7 +181,7 @@ export class BlockRewardsGraphComponent implements OnInit {
legend: data.blockRewards.length === 0 ? undefined : {
data: [
{
name: 'Rewards LTC',
name: 'Rewards FEC',
inactiveColor: 'rgb(110, 112, 121)',
textStyle: {
color: 'white',
Expand All @@ -204,7 +204,7 @@ export class BlockRewardsGraphComponent implements OnInit {
axisLabel: {
color: 'rgb(110, 112, 121)',
formatter: (val) => {
return `${val} LTC`;
return `${val} FEC`;
}
},
min: (value) => {
Expand Down Expand Up @@ -246,7 +246,7 @@ export class BlockRewardsGraphComponent implements OnInit {
legendHoverLink: false,
zlevel: 0,
yAxisIndex: 0,
name: 'Rewards LTC',
name: 'Rewards FEC',
data: data.blockRewards,
type: 'line',
smooth: 0.25,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ <h2 class="truncate left">{{ blockHash.slice(32) }}</h2>
</tr>
<tr *ngIf="block?.extras?.medianFee != undefined">
<td class="td-width" i18n="block.median-fee">Median fee</td>
<td>~{{ block?.extras?.medianFee | number:'1.0-0' }} <span class="symbol" i18n="shared.sat-vbyte|lit/vB">lit/vB</span></td>
<td>~{{ block?.extras?.medianFee | number:'1.0-0' }} <span class="symbol" i18n="shared.sat-vbyte|atom/vB">atom/vB</span></td>
</tr>
<ng-template [ngIf]="fees !== undefined">
<tr>
Expand Down
Loading

0 comments on commit 0deef57

Please sign in to comment.