Compare commits
185 Commits
v2.3.0-dev
...
v2.3.0-rc6
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
11483852da | ||
|
|
a6fadc840d | ||
|
|
af8c8a2088 | ||
|
|
573cb8f993 | ||
|
|
d70c610741 | ||
|
|
985d19778f | ||
|
|
2cb50c2351 | ||
|
|
359e111ae4 | ||
|
|
548f38292f | ||
|
|
5f2350b763 | ||
|
|
831cd580e0 | ||
|
|
47a6969dc9 | ||
|
|
29581f325f | ||
|
|
fbce72b7fc | ||
|
|
a894fa5bc0 | ||
|
|
9ac3c420eb | ||
|
|
10df6985fc | ||
|
|
27ce863735 | ||
|
|
d840d79aea | ||
|
|
80dfc81900 | ||
|
|
31c911cb59 | ||
|
|
0d4160b232 | ||
|
|
f0022f6af9 | ||
|
|
a16decfb94 | ||
|
|
ea2a2310a0 | ||
|
|
7f17ade65c | ||
|
|
c8d38740cc | ||
|
|
efffd1a929 | ||
|
|
f0c53a4e5b | ||
|
|
a9c1dc3726 | ||
|
|
2944f0b805 | ||
|
|
f494bd6d6a | ||
|
|
ae2cb05dc5 | ||
|
|
4e322fe006 | ||
|
|
5d06d02d64 | ||
|
|
7eabbe30e6 | ||
|
|
c232f6a11d | ||
|
|
04ffa6d7bb | ||
|
|
d46655e5f4 | ||
|
|
1438300763 | ||
|
|
cce49bdb7e | ||
|
|
fc878b696d | ||
|
|
c09fdb656f | ||
|
|
9ac9eb9cc8 | ||
|
|
ff5367b0e7 | ||
|
|
503adc20dc | ||
|
|
2f5cad9d0a | ||
|
|
871329e0fd | ||
|
|
7825b8d732 | ||
|
|
6bfd9da08c | ||
|
|
ce8518ad58 | ||
|
|
865fe488bf | ||
|
|
467cac7d4d | ||
|
|
3a0fb2015a | ||
|
|
bfb5abaa71 | ||
|
|
6cb2625303 | ||
|
|
2d292e27b9 | ||
|
|
9b6d679739 | ||
|
|
8099349dcc | ||
|
|
b1df17d7a3 | ||
|
|
02798db449 | ||
|
|
4b71cb6e28 | ||
|
|
cee52e69f1 | ||
|
|
a4a8fb64b1 | ||
|
|
0e6cc67c0a | ||
|
|
cc621b10ce | ||
|
|
2eaea44182 | ||
|
|
50734bafbf | ||
|
|
745b7d6f65 | ||
|
|
4ca730697c | ||
|
|
dc06a3f62a | ||
|
|
1e78326ee4 | ||
|
|
45542d5f06 | ||
|
|
0106f44129 | ||
|
|
ba895559bf | ||
|
|
513886f6d2 | ||
|
|
09fe7346bc | ||
|
|
4173486f4d | ||
|
|
d809e85dde | ||
|
|
6414f0045e | ||
|
|
39c5393e3b | ||
|
|
d2cd396c75 | ||
|
|
ccbb28c8a0 | ||
|
|
afbced3f4d | ||
|
|
08f2287def | ||
|
|
5175027948 | ||
|
|
d0cda447c0 | ||
|
|
fd288cd106 | ||
|
|
2d0d7df704 | ||
|
|
c41ac34978 | ||
|
|
47307bc755 | ||
|
|
bfe5d3ae49 | ||
|
|
a060816e2c | ||
|
|
898ff5da23 | ||
|
|
d78d2c0eca | ||
|
|
a08e77ff3e | ||
|
|
1e39eb0fa5 | ||
|
|
5de133ae6a | ||
|
|
d27b125848 | ||
|
|
ad36d53bb5 | ||
|
|
24f76f2f37 | ||
|
|
691bdda523 | ||
|
|
81bb31090e | ||
|
|
cc0a0719b6 | ||
|
|
7dca8ae1a0 | ||
|
|
84027d5568 | ||
|
|
4116186c1a | ||
|
|
358301020f | ||
|
|
642022bfd8 | ||
|
|
70f25b6c9c | ||
|
|
c778e84247 | ||
|
|
4de1d017ad | ||
|
|
61851be23a | ||
|
|
5de949eaed | ||
|
|
de6434a5ba | ||
|
|
c8639ec71d | ||
|
|
e1275c62cc | ||
|
|
be45e88056 | ||
|
|
990ab3da5f | ||
|
|
d1d74ebf37 | ||
|
|
6ab79b3c35 | ||
|
|
4f21fc0d87 | ||
|
|
10c4e47091 | ||
|
|
dd49ff0084 | ||
|
|
853314ba58 | ||
|
|
784e2470df | ||
|
|
350b4922da | ||
|
|
40fb1792f4 | ||
|
|
7ce1cc5103 | ||
|
|
71a4e24900 | ||
|
|
a48c2c07b0 | ||
|
|
d89d7efbe6 | ||
|
|
5ea4b043d9 | ||
|
|
dd4710b602 | ||
|
|
832c0cb3cc | ||
|
|
04216e952a | ||
|
|
951d0f0039 | ||
|
|
706f4bbc55 | ||
|
|
3fd96e412b | ||
|
|
766803ded1 | ||
|
|
504f46cad9 | ||
|
|
fd34761a93 | ||
|
|
96e8f45e5b | ||
|
|
195fae670b | ||
|
|
dd767f9468 | ||
|
|
bc8104eeb4 | ||
|
|
2c61eb6227 | ||
|
|
5d360d4156 | ||
|
|
91e30fbc3c | ||
|
|
5b22e2a000 | ||
|
|
533653e54a | ||
|
|
3dc0dc13ad | ||
|
|
e332789afc | ||
|
|
e4a9fd06b4 | ||
|
|
5845f2380e | ||
|
|
c29311d831 | ||
|
|
252db109bc | ||
|
|
b1c9334119 | ||
|
|
ab04247726 | ||
|
|
e94a85b989 | ||
|
|
a4569788f8 | ||
|
|
b455814e90 | ||
|
|
7afd0f3fe7 | ||
|
|
a2a85469cf | ||
|
|
94488a6029 | ||
|
|
8e4829146a | ||
|
|
08f185525c | ||
|
|
d6b00fe39e | ||
|
|
cec3baeaa4 | ||
|
|
6e59733cac | ||
|
|
c5b705ede7 | ||
|
|
2819e24efe | ||
|
|
5f9bc4497a | ||
|
|
086b14e816 | ||
|
|
958bfe6d25 | ||
|
|
e01ab449cf | ||
|
|
9a18019d9d | ||
|
|
5d8c970351 | ||
|
|
89fede9e48 | ||
|
|
f8a54784d0 | ||
|
|
010381aac4 | ||
|
|
1a8fd23b05 | ||
|
|
3ae46e6ba1 | ||
|
|
40f1949654 | ||
|
|
2281116504 |
@@ -1,7 +1,14 @@
|
|||||||
|
---
|
||||||
|
name: 🐛 Bug Report
|
||||||
|
about: Report bugs or other issues to us on GitHub
|
||||||
|
---
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
SUPPORT REQUESTS: This is for reporting bugs in Mempool.
|
SUPPORT REQUESTS:
|
||||||
If you have a support request, please join our Keybase group:
|
This is for reporting bugs in Mempool, not for support requests.
|
||||||
|
If you have a support request, please join our Keybase or Matrix:
|
||||||
https://keybase.io/team/mempool
|
https://keybase.io/team/mempool
|
||||||
|
https://matrix.to/#/#mempool:bitcoin.kyoto
|
||||||
-->
|
-->
|
||||||
|
|
||||||
### Description
|
### Description
|
||||||
@@ -14,11 +21,11 @@
|
|||||||
|
|
||||||
### Steps to reproduce
|
### Steps to reproduce
|
||||||
|
|
||||||
<!--if you can reliably reproduce the bug, list the steps here -->
|
<!-- if you can reliably reproduce the bug, list the steps here -->
|
||||||
|
|
||||||
### Expected behaviour
|
### Expected behaviour
|
||||||
|
|
||||||
<!--description of the expected behavior -->
|
<!-- description of the expected behavior -->
|
||||||
|
|
||||||
### Actual behaviour
|
### Actual behaviour
|
||||||
|
|
||||||
@@ -26,7 +33,7 @@
|
|||||||
|
|
||||||
### Screenshots
|
### Screenshots
|
||||||
|
|
||||||
<!--Screenshots if gui related, drag and drop to add to the issue -->
|
<!-- Screenshots if gui related, drag and drop to add to the issue -->
|
||||||
|
|
||||||
#### Device or machine
|
#### Device or machine
|
||||||
|
|
||||||
28
.github/ISSUE_TEMPLATE/30-feature-request.md
vendored
Normal file
28
.github/ISSUE_TEMPLATE/30-feature-request.md
vendored
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
---
|
||||||
|
name: ✨ Feature Request
|
||||||
|
about: Request a feature or suggest other enhancements 💡
|
||||||
|
---
|
||||||
|
|
||||||
|
<!--
|
||||||
|
SUPPORT REQUESTS:
|
||||||
|
This is for requesting features in Mempool, not for support requests.
|
||||||
|
If you have a support request, please join our Keybase or Matrix:
|
||||||
|
https://keybase.io/team/mempool
|
||||||
|
https://matrix.to/#/#mempool:bitcoin.kyoto
|
||||||
|
-->
|
||||||
|
|
||||||
|
### Description
|
||||||
|
|
||||||
|
<!-- brief description of the feature request -->
|
||||||
|
|
||||||
|
### Problem to be solved
|
||||||
|
|
||||||
|
<!-- description of the the problem you're having -->
|
||||||
|
|
||||||
|
### Proposed solution
|
||||||
|
|
||||||
|
<!-- explain how you think we should solve the problem -->
|
||||||
|
|
||||||
|
#### Additional info
|
||||||
|
|
||||||
|
<!-- Additional information useful for implementing (e.g. docs, links, etc.) -->
|
||||||
8
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
8
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
blank_issues_enabled: false
|
||||||
|
contact_links:
|
||||||
|
- name: 💬 Need help? Chat with us on Matrix
|
||||||
|
url: https://matrix.to/#/#mempool:bitcoin.kyoto
|
||||||
|
about: For support requests or general questions
|
||||||
|
- name: 💬 Need help? Chat with us on Keybase
|
||||||
|
url: https://keybase.io/team/mempool
|
||||||
|
about: For support requests or general questions
|
||||||
@@ -25,8 +25,7 @@ help:
|
|||||||
.PHONY: init
|
.PHONY: init
|
||||||
init:
|
init:
|
||||||
@echo ''
|
@echo ''
|
||||||
mkdir -p $(DATA) $(DATA)/mysql $(DATA)/mysql/db-scripts $(DATA)/mysql/data
|
mkdir -p $(DATA) $(DATA)/mysql $(DATA)/mysql/data
|
||||||
install -v mariadb-structure.sql $(DATA)/mysql/db-scripts
|
|
||||||
#REF: https://github.com/mempool/mempool/blob/master/docker/README.md
|
#REF: https://github.com/mempool/mempool/blob/master/docker/README.md
|
||||||
cat docker/docker-compose.yml > docker-compose.yml
|
cat docker/docker-compose.yml > docker-compose.yml
|
||||||
cat backend/mempool-config.sample.json > backend/mempool-config.json
|
cat backend/mempool-config.sample.json > backend/mempool-config.json
|
||||||
|
|||||||
239
README.md
239
README.md
@@ -14,6 +14,238 @@ Mempool can be self-hosted on a wide variety of your own hardware, ranging from
|
|||||||
4) [Production installation on a powerful FreeBSD server](https://github.com/mempool/mempool/tree/master/production)
|
4) [Production installation on a powerful FreeBSD server](https://github.com/mempool/mempool/tree/master/production)
|
||||||
5) [High Availability cluster using powerful FreeBSD servers](https://github.com/mempool/mempool/tree/master/production#high-availability)
|
5) [High Availability cluster using powerful FreeBSD servers](https://github.com/mempool/mempool/tree/master/production#high-availability)
|
||||||
|
|
||||||
|
# Docker Installation
|
||||||
|
|
||||||
|
The `docker` directory contains the Dockerfiles used to build and release the official images and a `docker-compose.yml` file that is intended for end users to run a Mempool instance with minimal effort.
|
||||||
|
|
||||||
|
## bitcoind only configuration
|
||||||
|
|
||||||
|
To run an instance with the default settings, use the following command:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ docker-compose up
|
||||||
|
```
|
||||||
|
|
||||||
|
The default configuration will allow you to run Mempool using `bitcoind` as the backend, so address lookups will be disabled. It assumes you have added RPC credentials for the `mempool` user with a `mempool` password in your `bitcoin.conf` file:
|
||||||
|
|
||||||
|
```
|
||||||
|
rpcuser=mempool
|
||||||
|
rpcpassword=mempool
|
||||||
|
```
|
||||||
|
|
||||||
|
If you want to use your current credentials, update them in the `docker-compose.yml` file:
|
||||||
|
|
||||||
|
```
|
||||||
|
api:
|
||||||
|
environment:
|
||||||
|
MEMPOOL_BACKEND: "none"
|
||||||
|
RPC_HOST: "172.27.0.1"
|
||||||
|
RPC_PORT: "8332"
|
||||||
|
RPC_USER: "mempool"
|
||||||
|
RPC_PASS: "mempool"
|
||||||
|
```
|
||||||
|
|
||||||
|
Note: the IP in the example above refers to Docker's default gateway IP address so the container can hit the `bitcoind` instance running on the host machine. If your setup is different, update it accordingly.
|
||||||
|
|
||||||
|
You can check if the instance is running by visiting http://localhost - the graphs will be populated as new transactions are detected.
|
||||||
|
|
||||||
|
## bitcoind+romanz/electrs configuration
|
||||||
|
|
||||||
|
In order to run with `romanz/electrs` as the backend, in addition to the settings required for running with `bitcoind` above, you will need to make the following changes to the `docker-compose.yml` file:
|
||||||
|
|
||||||
|
- Under the `api` service, change the value of the `MEMPOOL_BACKEND` key from `none` to `electrum`:
|
||||||
|
|
||||||
|
```
|
||||||
|
api:
|
||||||
|
environment:
|
||||||
|
MEMPOOL_BACKEND: "none"
|
||||||
|
```
|
||||||
|
|
||||||
|
- Under the `api` service, set the `ELECTRUM_HOST` and `ELECTRUM_PORT` keys to your Docker host IP address and set `ELECTRUM_TLS_ENABLED` to `false`:
|
||||||
|
|
||||||
|
```
|
||||||
|
api:
|
||||||
|
environment:
|
||||||
|
ELECTRUM_HOST: "172.27.0.1"
|
||||||
|
ELECTRUM_PORT: "50002"
|
||||||
|
ELECTRUM_TLS: "false"
|
||||||
|
```
|
||||||
|
|
||||||
|
You can update any of the backend settings in the `mempool-config.json` file using the following environment variables to override them.
|
||||||
|
|
||||||
|
JSON:
|
||||||
|
```
|
||||||
|
"MEMPOOL": {
|
||||||
|
"NETWORK": "mainnet",
|
||||||
|
"BACKEND": "electrum",
|
||||||
|
"HTTP_PORT": 8999,
|
||||||
|
"SPAWN_CLUSTER_PROCS": 0,
|
||||||
|
"API_URL_PREFIX": "/api/v1/",
|
||||||
|
"POLL_RATE_MS": 2000,
|
||||||
|
"CACHE_DIR": "./cache",
|
||||||
|
"CLEAR_PROTECTION_MINUTES": 20,
|
||||||
|
"RECOMMENDED_FEE_PERCENTILE": 50,
|
||||||
|
"BLOCK_WEIGHT_UNITS": 4000000,
|
||||||
|
"INITIAL_BLOCKS_AMOUNT": 8,
|
||||||
|
"MEMPOOL_BLOCKS_AMOUNT": 8,
|
||||||
|
"PRICE_FEED_UPDATE_INTERVAL": 3600,
|
||||||
|
"USE_SECOND_NODE_FOR_MINFEE": false,
|
||||||
|
"EXTERNAL_ASSETS": []
|
||||||
|
},
|
||||||
|
```
|
||||||
|
|
||||||
|
docker-compose overrides::
|
||||||
|
```
|
||||||
|
MEMPOOL_NETWORK: ""
|
||||||
|
MEMPOOL_BACKEND: ""
|
||||||
|
MEMPOOL_HTTP_PORT: ""
|
||||||
|
MEMPOOL_SPAWN_CLUSTER_PROCS: ""
|
||||||
|
MEMPOOL_API_URL_PREFIX: ""
|
||||||
|
MEMPOOL_POLL_RATE_MS: ""
|
||||||
|
MEMPOOL_CACHE_DIR: ""
|
||||||
|
MEMPOOL_CLEAR_PROTECTION_MINUTES: ""
|
||||||
|
MEMPOOL_RECOMMENDED_FEE_PERCENTILE: ""
|
||||||
|
MEMPOOL_BLOCK_WEIGHT_UNITS: ""
|
||||||
|
MEMPOOL_INITIAL_BLOCKS_AMOUNT: ""
|
||||||
|
MEMPOOL_MEMPOOL_BLOCKS_AMOUNT: ""
|
||||||
|
MEMPOOL_PRICE_FEED_UPDATE_INTERVAL: ""
|
||||||
|
MEMPOOL_USE_SECOND_NODE_FOR_MINFEE: ""
|
||||||
|
MEMPOOL_EXTERNAL_ASSETS: ""
|
||||||
|
```
|
||||||
|
|
||||||
|
JSON:
|
||||||
|
```
|
||||||
|
"CORE_RPC": {
|
||||||
|
"HOST": "127.0.0.1",
|
||||||
|
"PORT": 8332,
|
||||||
|
"USERNAME": "mempool",
|
||||||
|
"PASSWORD": "mempool"
|
||||||
|
},
|
||||||
|
```
|
||||||
|
docker-compose overrides:
|
||||||
|
```
|
||||||
|
CORE_RPC_HOST: ""
|
||||||
|
CORE_RPC_PORT: ""
|
||||||
|
CORE_RPC_USERNAME: ""
|
||||||
|
CORE_RPC_PASSWORD: ""
|
||||||
|
```
|
||||||
|
|
||||||
|
JSON:
|
||||||
|
```
|
||||||
|
"ELECTRUM": {
|
||||||
|
"HOST": "127.0.0.1",
|
||||||
|
"PORT": 50002,
|
||||||
|
"TLS_ENABLED": true
|
||||||
|
},
|
||||||
|
```
|
||||||
|
|
||||||
|
docker-compose overrides:
|
||||||
|
```
|
||||||
|
ELECTRUM_HOST: ""
|
||||||
|
ELECTRUM_PORT: ""
|
||||||
|
ELECTRUM_TLS: ""
|
||||||
|
```
|
||||||
|
|
||||||
|
JSON:
|
||||||
|
```
|
||||||
|
"ESPLORA": {
|
||||||
|
"REST_API_URL": "http://127.0.0.1:3000"
|
||||||
|
},
|
||||||
|
```
|
||||||
|
docker-compose overrides:
|
||||||
|
```
|
||||||
|
ESPLORA_REST_API_URL: ""
|
||||||
|
```
|
||||||
|
|
||||||
|
JSON:
|
||||||
|
```
|
||||||
|
"SECOND_CORE_RPC": {
|
||||||
|
"HOST": "127.0.0.1",
|
||||||
|
"PORT": 8332,
|
||||||
|
"USERNAME": "mempool",
|
||||||
|
"PASSWORD": "mempool"
|
||||||
|
},
|
||||||
|
```
|
||||||
|
|
||||||
|
docker-compose overrides:
|
||||||
|
```
|
||||||
|
SECOND_CORE_RPC_HOST: ""
|
||||||
|
SECOND_CORE_RPC_PORT: ""
|
||||||
|
SECOND_CORE_RPC_USERNAME: ""
|
||||||
|
SECOND_CORE_RPC_PASSWORD: ""
|
||||||
|
```
|
||||||
|
|
||||||
|
JSON:
|
||||||
|
```
|
||||||
|
"DATABASE": {
|
||||||
|
"ENABLED": true,
|
||||||
|
"HOST": "127.0.0.1",
|
||||||
|
"PORT": 3306,
|
||||||
|
"DATABASE": "mempool",
|
||||||
|
"USERNAME": "mempool",
|
||||||
|
"PASSWORD": "mempool"
|
||||||
|
},
|
||||||
|
```
|
||||||
|
|
||||||
|
docker-compose overrides:
|
||||||
|
```
|
||||||
|
DATABASE_ENABLED: ""
|
||||||
|
DATABASE_HOST: ""
|
||||||
|
DATABASE_PORT: ""
|
||||||
|
DATABASE_DATABASE: ""
|
||||||
|
DATABASE_USERAME: ""
|
||||||
|
DATABASE_PASSWORD: ""
|
||||||
|
```
|
||||||
|
|
||||||
|
JSON:
|
||||||
|
```
|
||||||
|
"SYSLOG": {
|
||||||
|
"ENABLED": true,
|
||||||
|
"HOST": "127.0.0.1",
|
||||||
|
"PORT": 514,
|
||||||
|
"MIN_PRIORITY": "info",
|
||||||
|
"FACILITY": "local7"
|
||||||
|
},
|
||||||
|
```
|
||||||
|
|
||||||
|
docker-compose overrides:
|
||||||
|
```
|
||||||
|
SYSLOG_ENABLED: ""
|
||||||
|
SYSLOG_HOST: ""
|
||||||
|
SYSLOG_PORT: ""
|
||||||
|
SYSLOG_MIN_PRIORITY: ""
|
||||||
|
SYSLOG_FACILITY: ""
|
||||||
|
```
|
||||||
|
|
||||||
|
JSON:
|
||||||
|
```
|
||||||
|
"STATISTICS": {
|
||||||
|
"ENABLED": true,
|
||||||
|
"TX_PER_SECOND_SAMPLE_PERIOD": 150
|
||||||
|
},
|
||||||
|
```
|
||||||
|
|
||||||
|
docker-compose overrides:
|
||||||
|
```
|
||||||
|
STATISTICS_ENABLED: ""
|
||||||
|
STATISTICS_TX_PER_SECOND_SAMPLE_PERIOD: ""
|
||||||
|
```
|
||||||
|
|
||||||
|
JSON:
|
||||||
|
```
|
||||||
|
"BISQ": {
|
||||||
|
"ENABLED": false,
|
||||||
|
"DATA_PATH": "/bisq/statsnode-data/btc_mainnet/db"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
docker-compose overrides:
|
||||||
|
```
|
||||||
|
BISQ_ENABLED: ""
|
||||||
|
BISQ_DATA_PATH: ""
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
# Manual Installation
|
# Manual Installation
|
||||||
|
|
||||||
The following instructions are for a manual installation on Linux or FreeBSD. The file and directory paths may need to be changed to match your OS.
|
The following instructions are for a manual installation on Linux or FreeBSD. The file and directory paths may need to be changed to match your OS.
|
||||||
@@ -69,11 +301,6 @@ Create database and grant privileges:
|
|||||||
Query OK, 0 rows affected (0.00 sec)
|
Query OK, 0 rows affected (0.00 sec)
|
||||||
```
|
```
|
||||||
|
|
||||||
From the mempool repo's top-level folder, import the database structure:
|
|
||||||
```bash
|
|
||||||
mysql -u mempool -p mempool < mariadb-structure.sql
|
|
||||||
```
|
|
||||||
|
|
||||||
## Mempool Backend
|
## Mempool Backend
|
||||||
Install mempool dependencies from npm and build the backend:
|
Install mempool dependencies from npm and build the backend:
|
||||||
|
|
||||||
@@ -163,7 +390,7 @@ Install mempool dependencies from npm and build the frontend static HTML/CSS/JS:
|
|||||||
Install the output into nginx webroot folder:
|
Install the output into nginx webroot folder:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo rsync -av --delete dist/mempool/ /var/www/
|
sudo rsync -av --delete dist/ /var/www/
|
||||||
```
|
```
|
||||||
|
|
||||||
## nginx + certbot
|
## nginx + certbot
|
||||||
|
|||||||
7
backend/.gitignore
vendored
7
backend/.gitignore
vendored
@@ -1,7 +1,10 @@
|
|||||||
# See http://help.github.com/ignore-files/ for more about ignoring files.
|
# See http://help.github.com/ignore-files/ for more about ignoring files.
|
||||||
|
|
||||||
# production config
|
# production config and external assets
|
||||||
mempool-config.json
|
*.json
|
||||||
|
!mempool-config.sample.json
|
||||||
|
|
||||||
|
icons.json
|
||||||
|
|
||||||
# compiled output
|
# compiled output
|
||||||
/dist
|
/dist
|
||||||
|
|||||||
@@ -13,7 +13,8 @@
|
|||||||
"INITIAL_BLOCKS_AMOUNT": 8,
|
"INITIAL_BLOCKS_AMOUNT": 8,
|
||||||
"MEMPOOL_BLOCKS_AMOUNT": 8,
|
"MEMPOOL_BLOCKS_AMOUNT": 8,
|
||||||
"PRICE_FEED_UPDATE_INTERVAL": 3600,
|
"PRICE_FEED_UPDATE_INTERVAL": 3600,
|
||||||
"USE_SECOND_NODE_FOR_MINFEE": false
|
"USE_SECOND_NODE_FOR_MINFEE": false,
|
||||||
|
"EXTERNAL_ASSETS": []
|
||||||
},
|
},
|
||||||
"CORE_RPC": {
|
"CORE_RPC": {
|
||||||
"HOST": "127.0.0.1",
|
"HOST": "127.0.0.1",
|
||||||
|
|||||||
@@ -1,7 +1,14 @@
|
|||||||
import { CpfpInfo, TransactionExtended, TransactionStripped } from '../mempool.interfaces';
|
import { CpfpInfo, TransactionExtended, TransactionStripped } from '../mempool.interfaces';
|
||||||
import config from '../config';
|
import config from '../config';
|
||||||
export class Common {
|
export class Common {
|
||||||
static nativeAssetId = '6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d';
|
static nativeAssetId = config.MEMPOOL.NETWORK === 'liquidtestnet' ?
|
||||||
|
'144c654344aa716d6f3abcc1ca90e5641e4e2a7f633bc09fe3baf64585819a49'
|
||||||
|
: '6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d';
|
||||||
|
static _isLiquid = config.MEMPOOL.NETWORK === 'liquid' || config.MEMPOOL.NETWORK === 'liquidtestnet';
|
||||||
|
|
||||||
|
static isLiquid(): boolean {
|
||||||
|
return this._isLiquid;
|
||||||
|
}
|
||||||
|
|
||||||
static median(numbers: number[]) {
|
static median(numbers: number[]) {
|
||||||
let medianNr = 0;
|
let medianNr = 0;
|
||||||
@@ -107,7 +114,7 @@ export class Common {
|
|||||||
totalFees += tx.bestDescendant.fee;
|
totalFees += tx.bestDescendant.fee;
|
||||||
}
|
}
|
||||||
|
|
||||||
tx.effectiveFeePerVsize = Math.max(config.MEMPOOL.NETWORK === 'liquid' ? 0.1 : 1, totalFees / (totalWeight / 4));
|
tx.effectiveFeePerVsize = Math.max(Common.isLiquid() ? 0.1 : 1, totalFees / (totalWeight / 4));
|
||||||
tx.cpfpChecked = true;
|
tx.cpfpChecked = true;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -1,62 +1,144 @@
|
|||||||
|
import { PoolConnection } from 'mysql2/promise';
|
||||||
import config from '../config';
|
import config from '../config';
|
||||||
import { DB } from '../database';
|
import { DB } from '../database';
|
||||||
import logger from '../logger';
|
import logger from '../logger';
|
||||||
|
|
||||||
|
const sleep = (ms: number) => new Promise( res => setTimeout(res, ms));
|
||||||
|
|
||||||
class DatabaseMigration {
|
class DatabaseMigration {
|
||||||
private static currentVersion = 1;
|
private static currentVersion = 2;
|
||||||
private queryTimeout = 120000;
|
private queryTimeout = 120000;
|
||||||
|
private statisticsAddedIndexed = false;
|
||||||
|
|
||||||
constructor() { }
|
constructor() { }
|
||||||
|
/**
|
||||||
|
* Entry point
|
||||||
|
*/
|
||||||
public async $initializeOrMigrateDatabase(): Promise<void> {
|
public async $initializeOrMigrateDatabase(): Promise<void> {
|
||||||
if (!await this.$checkIfTableExists('statistics')) {
|
logger.info('MIGRATIONS: Running migrations');
|
||||||
await this.$initializeDatabaseTables();
|
|
||||||
|
await this.$printDatabaseVersion();
|
||||||
|
|
||||||
|
// First of all, if the `state` database does not exist, create it so we can track migration version
|
||||||
|
if (!await this.$checkIfTableExists('state')) {
|
||||||
|
logger.info('MIGRATIONS: `state` table does not exist. Creating it.');
|
||||||
|
try {
|
||||||
|
await this.$createMigrationStateTable();
|
||||||
|
} catch (e) {
|
||||||
|
logger.err('MIGRATIONS: Unable to create `state` table, aborting in 10 seconds. ' + e);
|
||||||
|
await sleep(10000);
|
||||||
|
process.exit(-1);
|
||||||
|
}
|
||||||
|
logger.info('MIGRATIONS: `state` table initialized.');
|
||||||
|
}
|
||||||
|
|
||||||
|
let databaseSchemaVersion = 0;
|
||||||
|
try {
|
||||||
|
databaseSchemaVersion = await this.$getSchemaVersionFromDatabase();
|
||||||
|
} catch (e) {
|
||||||
|
logger.err('MIGRATIONS: Unable to get current database migration version, aborting in 10 seconds. ' + e);
|
||||||
|
await sleep(10000);
|
||||||
|
process.exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info('MIGRATIONS: Current state.schema_version ' + databaseSchemaVersion);
|
||||||
|
logger.info('MIGRATIONS: Latest DatabaseMigration.version is ' + DatabaseMigration.currentVersion);
|
||||||
|
if (databaseSchemaVersion >= DatabaseMigration.currentVersion) {
|
||||||
|
logger.info('MIGRATIONS: Nothing to do.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now, create missing tables. Those queries cannot be wrapped into a transaction unfortunately
|
||||||
|
try {
|
||||||
|
await this.$createMissingTablesAndIndexes(databaseSchemaVersion);
|
||||||
|
} catch (e) {
|
||||||
|
logger.err('MIGRATIONS: Unable to create required tables, aborting in 10 seconds. ' + e);
|
||||||
|
await sleep(10000);
|
||||||
|
process.exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (await this.$checkIfTableExists('state')) {
|
|
||||||
const databaseSchemaVersion = await this.$getSchemaVersionFromDatabase();
|
|
||||||
if (DatabaseMigration.currentVersion > databaseSchemaVersion) {
|
if (DatabaseMigration.currentVersion > databaseSchemaVersion) {
|
||||||
|
logger.info('MIGRATIONS: Upgrading datababse schema');
|
||||||
|
try {
|
||||||
await this.$migrateTableSchemaFromVersion(databaseSchemaVersion);
|
await this.$migrateTableSchemaFromVersion(databaseSchemaVersion);
|
||||||
}
|
logger.info(`MIGRATIONS: OK. Database schema have been migrated from version ${databaseSchemaVersion} to ${DatabaseMigration.currentVersion} (latest version)`);
|
||||||
} else {
|
} catch (e) {
|
||||||
await this.$migrateTableSchemaFromVersion(0);
|
logger.err('MIGRATIONS: Unable to migrate database, aborting. ' + e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async $initializeDatabaseTables(): Promise<void> {
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create all missing tables
|
||||||
|
*/
|
||||||
|
private async $createMissingTablesAndIndexes(databaseSchemaVersion: number) {
|
||||||
|
await this.$setStatisticsAddedIndexedFlag(databaseSchemaVersion);
|
||||||
|
|
||||||
const connection = await DB.pool.getConnection();
|
const connection = await DB.pool.getConnection();
|
||||||
for (const query of this.getInitializeTableQueries()) {
|
try {
|
||||||
await connection.query<any>({ sql: query, timeout: this.queryTimeout });
|
await this.$executeQuery(connection, this.getCreateElementsTableQuery(), await this.$checkIfTableExists('elements_pegs'));
|
||||||
|
await this.$executeQuery(connection, this.getCreateStatisticsQuery(), await this.$checkIfTableExists('statistics'));
|
||||||
|
if (databaseSchemaVersion < 2 && this.statisticsAddedIndexed === false) {
|
||||||
|
await this.$executeQuery(connection, `CREATE INDEX added ON statistics (added);`);
|
||||||
}
|
}
|
||||||
connection.release();
|
connection.release();
|
||||||
logger.info(`Initial database tables have been created`);
|
} catch (e) {
|
||||||
}
|
|
||||||
|
|
||||||
private async $migrateTableSchemaFromVersion(version: number): Promise<void> {
|
|
||||||
const connection = await DB.pool.getConnection();
|
|
||||||
for (const query of this.getMigrationQueriesFromVersion(version)) {
|
|
||||||
await connection.query<any>({ sql: query, timeout: this.queryTimeout });
|
|
||||||
}
|
|
||||||
connection.release();
|
connection.release();
|
||||||
await this.$updateToLatestSchemaVersion();
|
throw e;
|
||||||
logger.info(`Database schema have been migrated from version ${version} to ${DatabaseMigration.currentVersion} (latest version)`);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async $getSchemaVersionFromDatabase(): Promise<number> {
|
/**
|
||||||
const connection = await DB.pool.getConnection();
|
* Special case here for the `statistics` table - It appeared that somehow some dbs already had the `added` field indexed
|
||||||
const query = `SELECT number FROM state WHERE name = 'schema_version';`;
|
* while it does not appear in previous schemas. The mariadb command "CREATE INDEX IF NOT EXISTS" is not supported on
|
||||||
const [rows] = await connection.query<any>({ sql: query, timeout: this.queryTimeout });
|
* older mariadb version. Therefore we set a flag here in order to know if the index needs to be created or not before
|
||||||
connection.release();
|
* running the migration process
|
||||||
return rows[0]['number'];
|
*/
|
||||||
|
private async $setStatisticsAddedIndexedFlag(databaseSchemaVersion: number) {
|
||||||
|
if (databaseSchemaVersion >= 2) {
|
||||||
|
this.statisticsAddedIndexed = true;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async $updateToLatestSchemaVersion(): Promise<void> {
|
|
||||||
const connection = await DB.pool.getConnection();
|
const connection = await DB.pool.getConnection();
|
||||||
const query = `UPDATE state SET number = ${DatabaseMigration.currentVersion} WHERE name = 'schema_version'`;
|
|
||||||
const [rows] = await connection.query<any>({ sql: query, timeout: this.queryTimeout });
|
try {
|
||||||
|
// We don't use "CREATE INDEX IF NOT EXISTS" because it is not supported on old mariadb version 5.X
|
||||||
|
const query = `SELECT COUNT(1) hasIndex FROM INFORMATION_SCHEMA.STATISTICS
|
||||||
|
WHERE table_schema=DATABASE() AND table_name='statistics' AND index_name='added';`;
|
||||||
|
const [rows] = await this.$executeQuery(connection, query, true);
|
||||||
|
if (rows[0].hasIndex === 0) {
|
||||||
|
logger.info('MIGRATIONS: `statistics.added` is not indexed');
|
||||||
|
this.statisticsAddedIndexed = false;
|
||||||
|
} else if (rows[0].hasIndex === 1) {
|
||||||
|
logger.info('MIGRATIONS: `statistics.added` is already indexed');
|
||||||
|
this.statisticsAddedIndexed = true;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// Should really never happen but just in case it fails, we just don't execute
|
||||||
|
// any query related to this indexing so it won't fail if the index actually already exists
|
||||||
|
logger.err('MIGRATIONS: Unable to check if `statistics.added` INDEX exist or not.');
|
||||||
|
this.statisticsAddedIndexed = true;
|
||||||
|
}
|
||||||
|
|
||||||
connection.release();
|
connection.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Small query execution wrapper to log all executed queries
|
||||||
|
*/
|
||||||
|
private async $executeQuery(connection: PoolConnection, query: string, silent: boolean = false): Promise<any> {
|
||||||
|
if (!silent) {
|
||||||
|
logger.info('MIGRATIONS: Execute query:\n' + query);
|
||||||
|
}
|
||||||
|
return connection.query<any>({ sql: query, timeout: this.queryTimeout });
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if 'table' exists in the database
|
||||||
|
*/
|
||||||
private async $checkIfTableExists(table: string): Promise<boolean> {
|
private async $checkIfTableExists(table: string): Promise<boolean> {
|
||||||
const connection = await DB.pool.getConnection();
|
const connection = await DB.pool.getConnection();
|
||||||
const query = `SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = '${config.DATABASE.DATABASE}' AND TABLE_NAME = '${table}'`;
|
const query = `SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = '${config.DATABASE.DATABASE}' AND TABLE_NAME = '${table}'`;
|
||||||
@@ -65,11 +147,132 @@ class DatabaseMigration {
|
|||||||
return rows[0]['COUNT(*)'] === 1;
|
return rows[0]['COUNT(*)'] === 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
private getInitializeTableQueries(): string[] {
|
/**
|
||||||
|
* Get current database version
|
||||||
|
*/
|
||||||
|
private async $getSchemaVersionFromDatabase(): Promise<number> {
|
||||||
|
const connection = await DB.pool.getConnection();
|
||||||
|
const query = `SELECT number FROM state WHERE name = 'schema_version';`;
|
||||||
|
const [rows] = await this.$executeQuery(connection, query, true);
|
||||||
|
connection.release();
|
||||||
|
return rows[0]['number'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create the `state` table
|
||||||
|
*/
|
||||||
|
private async $createMigrationStateTable(): Promise<void> {
|
||||||
|
const connection = await DB.pool.getConnection();
|
||||||
|
|
||||||
|
try {
|
||||||
|
const query = `CREATE TABLE IF NOT EXISTS state (
|
||||||
|
name varchar(25) NOT NULL,
|
||||||
|
number int(11) NULL,
|
||||||
|
string varchar(100) NULL,
|
||||||
|
CONSTRAINT name_unique UNIQUE (name)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;`;
|
||||||
|
await this.$executeQuery(connection, query);
|
||||||
|
|
||||||
|
// Set initial values
|
||||||
|
await this.$executeQuery(connection, `INSERT INTO state VALUES('schema_version', 0, NULL);`);
|
||||||
|
await this.$executeQuery(connection, `INSERT INTO state VALUES('last_elements_block', 0, NULL);`);
|
||||||
|
|
||||||
|
connection.release();
|
||||||
|
} catch (e) {
|
||||||
|
connection.release();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We actually execute the migrations queries here
|
||||||
|
*/
|
||||||
|
private async $migrateTableSchemaFromVersion(version: number): Promise<void> {
|
||||||
|
const transactionQueries: string[] = [];
|
||||||
|
for (const query of this.getMigrationQueriesFromVersion(version)) {
|
||||||
|
transactionQueries.push(query);
|
||||||
|
}
|
||||||
|
transactionQueries.push(this.getUpdateToLatestSchemaVersionQuery());
|
||||||
|
|
||||||
|
const connection = await DB.pool.getConnection();
|
||||||
|
try {
|
||||||
|
await this.$executeQuery(connection, 'START TRANSACTION;');
|
||||||
|
await this.$executeQuery(connection, 'SET autocommit = 0;');
|
||||||
|
for (const query of transactionQueries) {
|
||||||
|
await this.$executeQuery(connection, query);
|
||||||
|
}
|
||||||
|
await this.$executeQuery(connection, 'COMMIT;');
|
||||||
|
|
||||||
|
connection.release();
|
||||||
|
} catch (e) {
|
||||||
|
await this.$executeQuery(connection, 'ROLLBACK;');
|
||||||
|
connection.release();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate migration queries based on schema version
|
||||||
|
*/
|
||||||
|
private getMigrationQueriesFromVersion(version: number): string[] {
|
||||||
const queries: string[] = [];
|
const queries: string[] = [];
|
||||||
|
|
||||||
queries.push(`CREATE TABLE IF NOT EXISTS statistics (
|
if (version < 1) {
|
||||||
id int(11) NOT NULL,
|
if (config.MEMPOOL.NETWORK !== 'liquid' && config.MEMPOOL.NETWORK !== 'liquidtestnet') {
|
||||||
|
queries.push(this.getShiftStatisticsQuery());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return queries;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save the schema version in the database
|
||||||
|
*/
|
||||||
|
private getUpdateToLatestSchemaVersionQuery(): string {
|
||||||
|
return `UPDATE state SET number = ${DatabaseMigration.currentVersion} WHERE name = 'schema_version';`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Print current database version
|
||||||
|
*/
|
||||||
|
private async $printDatabaseVersion() {
|
||||||
|
const connection = await DB.pool.getConnection();
|
||||||
|
try {
|
||||||
|
const [rows] = await this.$executeQuery(connection, 'SELECT VERSION() as version;', true);
|
||||||
|
logger.info(`MIGRATIONS: Database engine version '${rows[0].version}'`);
|
||||||
|
} catch (e) {
|
||||||
|
logger.info(`MIGRATIONS: Could not fetch database engine version. ` + e);
|
||||||
|
}
|
||||||
|
connection.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Couple of wrappers to clean the main logic
|
||||||
|
private getShiftStatisticsQuery(): string {
|
||||||
|
return `UPDATE statistics SET
|
||||||
|
vsize_1 = vsize_1 + vsize_2, vsize_2 = vsize_3,
|
||||||
|
vsize_3 = vsize_4, vsize_4 = vsize_5,
|
||||||
|
vsize_5 = vsize_6, vsize_6 = vsize_8,
|
||||||
|
vsize_8 = vsize_10, vsize_10 = vsize_12,
|
||||||
|
vsize_12 = vsize_15, vsize_15 = vsize_20,
|
||||||
|
vsize_20 = vsize_30, vsize_30 = vsize_40,
|
||||||
|
vsize_40 = vsize_50, vsize_50 = vsize_60,
|
||||||
|
vsize_60 = vsize_70, vsize_70 = vsize_80,
|
||||||
|
vsize_80 = vsize_90, vsize_90 = vsize_100,
|
||||||
|
vsize_100 = vsize_125, vsize_125 = vsize_150,
|
||||||
|
vsize_150 = vsize_175, vsize_175 = vsize_200,
|
||||||
|
vsize_200 = vsize_250, vsize_250 = vsize_300,
|
||||||
|
vsize_300 = vsize_350, vsize_350 = vsize_400,
|
||||||
|
vsize_400 = vsize_500, vsize_500 = vsize_600,
|
||||||
|
vsize_600 = vsize_700, vsize_700 = vsize_800,
|
||||||
|
vsize_800 = vsize_900, vsize_900 = vsize_1000,
|
||||||
|
vsize_1000 = vsize_1200, vsize_1200 = vsize_1400,
|
||||||
|
vsize_1400 = vsize_1800, vsize_1800 = vsize_2000, vsize_2000 = 0;`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private getCreateStatisticsQuery(): string {
|
||||||
|
return `CREATE TABLE IF NOT EXISTS statistics (
|
||||||
|
id int(11) NOT NULL AUTO_INCREMENT,
|
||||||
added datetime NOT NULL,
|
added datetime NOT NULL,
|
||||||
unconfirmed_transactions int(11) UNSIGNED NOT NULL,
|
unconfirmed_transactions int(11) UNSIGNED NOT NULL,
|
||||||
tx_per_second float UNSIGNED NOT NULL,
|
tx_per_second float UNSIGNED NOT NULL,
|
||||||
@@ -114,42 +317,13 @@ class DatabaseMigration {
|
|||||||
vsize_1400 int(11) NOT NULL,
|
vsize_1400 int(11) NOT NULL,
|
||||||
vsize_1600 int(11) NOT NULL,
|
vsize_1600 int(11) NOT NULL,
|
||||||
vsize_1800 int(11) NOT NULL,
|
vsize_1800 int(11) NOT NULL,
|
||||||
vsize_2000 int(11) NOT NULL
|
vsize_2000 int(11) NOT NULL,
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;`);
|
CONSTRAINT PRIMARY KEY (id)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;`;
|
||||||
queries.push(`ALTER TABLE statistics ADD PRIMARY KEY (id);`);
|
|
||||||
queries.push(`ALTER TABLE statistics MODIFY id int(11) NOT NULL AUTO_INCREMENT;`);
|
|
||||||
|
|
||||||
return queries;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private getMigrationQueriesFromVersion(version: number): string[] {
|
private getCreateElementsTableQuery(): string {
|
||||||
const queries: string[] = [];
|
return `CREATE TABLE IF NOT EXISTS elements_pegs (
|
||||||
|
|
||||||
if (version < 1) {
|
|
||||||
if (config.MEMPOOL.NETWORK !== 'liquid') {
|
|
||||||
queries.push(`UPDATE statistics SET
|
|
||||||
vsize_1 = vsize_1 + vsize_2, vsize_2 = vsize_3,
|
|
||||||
vsize_3 = vsize_4, vsize_4 = vsize_5,
|
|
||||||
vsize_5 = vsize_6, vsize_6 = vsize_8,
|
|
||||||
vsize_8 = vsize_10, vsize_10 = vsize_12,
|
|
||||||
vsize_12 = vsize_15, vsize_15 = vsize_20,
|
|
||||||
vsize_20 = vsize_30, vsize_30 = vsize_40,
|
|
||||||
vsize_40 = vsize_50, vsize_50 = vsize_60,
|
|
||||||
vsize_60 = vsize_70, vsize_70 = vsize_80,
|
|
||||||
vsize_80 = vsize_90, vsize_90 = vsize_100,
|
|
||||||
vsize_100 = vsize_125, vsize_125 = vsize_150,
|
|
||||||
vsize_150 = vsize_175, vsize_175 = vsize_200,
|
|
||||||
vsize_200 = vsize_250, vsize_250 = vsize_300,
|
|
||||||
vsize_300 = vsize_350, vsize_350 = vsize_400,
|
|
||||||
vsize_400 = vsize_500, vsize_500 = vsize_600,
|
|
||||||
vsize_600 = vsize_700, vsize_700 = vsize_800,
|
|
||||||
vsize_800 = vsize_900, vsize_900 = vsize_1000,
|
|
||||||
vsize_1000 = vsize_1200, vsize_1200 = vsize_1400,
|
|
||||||
vsize_1400 = vsize_1800, vsize_1800 = vsize_2000, vsize_2000 = 0`);
|
|
||||||
}
|
|
||||||
|
|
||||||
queries.push(`CREATE TABLE IF NOT EXISTS elements_pegs (
|
|
||||||
block int(11) NOT NULL,
|
block int(11) NOT NULL,
|
||||||
datetime int(11) NOT NULL,
|
datetime int(11) NOT NULL,
|
||||||
amount bigint(20) NOT NULL,
|
amount bigint(20) NOT NULL,
|
||||||
@@ -159,19 +333,7 @@ class DatabaseMigration {
|
|||||||
bitcointxid varchar(65) NOT NULL,
|
bitcointxid varchar(65) NOT NULL,
|
||||||
bitcoinindex int(11) NOT NULL,
|
bitcoinindex int(11) NOT NULL,
|
||||||
final_tx int(11) NOT NULL
|
final_tx int(11) NOT NULL
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;`);
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;`;
|
||||||
|
|
||||||
queries.push(`CREATE TABLE IF NOT EXISTS state (
|
|
||||||
name varchar(25) NOT NULL,
|
|
||||||
number int(11) NULL,
|
|
||||||
string varchar(100) NULL
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;`);
|
|
||||||
|
|
||||||
queries.push(`INSERT INTO state VALUES('schema_version', 0, NULL);`);
|
|
||||||
queries.push(`INSERT INTO state VALUES('last_elements_block', 0, NULL);`);
|
|
||||||
}
|
|
||||||
|
|
||||||
return queries;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
import config from '../config';
|
import config from '../config';
|
||||||
import { MempoolBlock } from '../mempool.interfaces';
|
import { MempoolBlock } from '../mempool.interfaces';
|
||||||
|
import { Common } from './common';
|
||||||
import mempool from './mempool';
|
import mempool from './mempool';
|
||||||
import projectedBlocks from './mempool-blocks';
|
import projectedBlocks from './mempool-blocks';
|
||||||
|
|
||||||
class FeeApi {
|
class FeeApi {
|
||||||
constructor() { }
|
constructor() { }
|
||||||
|
|
||||||
defaultFee = config.MEMPOOL.NETWORK === 'liquid' ? 0.1 : 1;
|
defaultFee = Common.isLiquid() ? 0.1 : 1;
|
||||||
|
|
||||||
public getRecommendedFee() {
|
public getRecommendedFee() {
|
||||||
const pBlocks = projectedBlocks.getMempoolBlocks();
|
const pBlocks = projectedBlocks.getMempoolBlocks();
|
||||||
|
|||||||
39
backend/src/api/liquid/icons.ts
Normal file
39
backend/src/api/liquid/icons.ts
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
import * as fs from 'fs';
|
||||||
|
import config from '../../config';
|
||||||
|
import logger from '../../logger';
|
||||||
|
|
||||||
|
class Icons {
|
||||||
|
private static FILE_NAME = './icons.json';
|
||||||
|
private iconIds: string[] = [];
|
||||||
|
private icons: { [assetId: string]: string; } = {};
|
||||||
|
|
||||||
|
constructor() {}
|
||||||
|
|
||||||
|
public loadIcons() {
|
||||||
|
if (!fs.existsSync(Icons.FILE_NAME)) {
|
||||||
|
logger.warn(`${Icons.FILE_NAME} does not exist. No Liquid icons loaded.`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const cacheData = fs.readFileSync(Icons.FILE_NAME, 'utf8');
|
||||||
|
this.icons = JSON.parse(cacheData);
|
||||||
|
|
||||||
|
for (const i in this.icons) {
|
||||||
|
this.iconIds.push(i);
|
||||||
|
}
|
||||||
|
logger.debug(`Liquid icons has been loaded.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
public getIconByAssetId(assetId: string): Buffer | undefined {
|
||||||
|
const icon = this.icons[assetId];
|
||||||
|
if (icon) {
|
||||||
|
return Buffer.from(icon, 'base64');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public getAllIconIds() {
|
||||||
|
return this.iconIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default new Icons();
|
||||||
@@ -4,14 +4,12 @@ import logger from '../logger';
|
|||||||
|
|
||||||
import { Statistic, TransactionExtended, OptimizedStatistic } from '../mempool.interfaces';
|
import { Statistic, TransactionExtended, OptimizedStatistic } from '../mempool.interfaces';
|
||||||
import config from '../config';
|
import config from '../config';
|
||||||
|
import { Common } from './common';
|
||||||
|
|
||||||
class Statistics {
|
class Statistics {
|
||||||
protected intervalTimer: NodeJS.Timer | undefined;
|
protected intervalTimer: NodeJS.Timer | undefined;
|
||||||
protected newStatisticsEntryCallback: ((stats: OptimizedStatistic) => void) | undefined;
|
protected newStatisticsEntryCallback: ((stats: OptimizedStatistic) => void) | undefined;
|
||||||
protected queryTimeout = 120000;
|
protected queryTimeout = 120000;
|
||||||
protected cache: { [date: string]: OptimizedStatistic[] } = {
|
|
||||||
'24h': [], '1w': [], '1m': [], '3m': [], '6m': [], '1y': [], '2y': [], '3y': []
|
|
||||||
};
|
|
||||||
|
|
||||||
public setNewStatisticsEntryCallback(fn: (stats: OptimizedStatistic) => void) {
|
public setNewStatisticsEntryCallback(fn: (stats: OptimizedStatistic) => void) {
|
||||||
this.newStatisticsEntryCallback = fn;
|
this.newStatisticsEntryCallback = fn;
|
||||||
@@ -33,25 +31,6 @@ class Statistics {
|
|||||||
this.runStatistics();
|
this.runStatistics();
|
||||||
}, 1 * 60 * 1000);
|
}, 1 * 60 * 1000);
|
||||||
}, difference);
|
}, difference);
|
||||||
|
|
||||||
this.createCache();
|
|
||||||
setInterval(this.createCache.bind(this), 600000);
|
|
||||||
}
|
|
||||||
|
|
||||||
public getCache() {
|
|
||||||
return this.cache;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async createCache() {
|
|
||||||
this.cache['24h'] = await this.$list24H();
|
|
||||||
this.cache['1w'] = await this.$list1W();
|
|
||||||
this.cache['1m'] = await this.$list1M();
|
|
||||||
this.cache['3m'] = await this.$list3M();
|
|
||||||
this.cache['6m'] = await this.$list6M();
|
|
||||||
this.cache['1y'] = await this.$list1Y();
|
|
||||||
this.cache['2y'] = await this.$list2Y();
|
|
||||||
this.cache['3y'] = await this.$list3Y();
|
|
||||||
logger.debug('Statistics cache created');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async runStatistics(): Promise<void> {
|
private async runStatistics(): Promise<void> {
|
||||||
@@ -90,9 +69,9 @@ class Statistics {
|
|||||||
memPoolArray.forEach((transaction) => {
|
memPoolArray.forEach((transaction) => {
|
||||||
for (let i = 0; i < logFees.length; i++) {
|
for (let i = 0; i < logFees.length; i++) {
|
||||||
if (
|
if (
|
||||||
(config.MEMPOOL.NETWORK === 'liquid' && (i === lastItem || transaction.effectiveFeePerVsize * 10 < logFees[i + 1]))
|
(Common.isLiquid() && (i === lastItem || transaction.effectiveFeePerVsize * 10 < logFees[i + 1]))
|
||||||
||
|
||
|
||||||
(config.MEMPOOL.NETWORK !== 'liquid' && (i === lastItem || transaction.effectiveFeePerVsize < logFees[i + 1]))
|
(!Common.isLiquid() && (i === lastItem || transaction.effectiveFeePerVsize < logFees[i + 1]))
|
||||||
) {
|
) {
|
||||||
if (weightVsizeFees[logFees[i]]) {
|
if (weightVsizeFees[logFees[i]]) {
|
||||||
weightVsizeFees[logFees[i]] += transaction.vsize;
|
weightVsizeFees[logFees[i]] += transaction.vsize;
|
||||||
@@ -269,57 +248,57 @@ class Statistics {
|
|||||||
|
|
||||||
private getQueryForDaysAvg(div: number, interval: string) {
|
private getQueryForDaysAvg(div: number, interval: string) {
|
||||||
return `SELECT id, UNIX_TIMESTAMP(added) as added,
|
return `SELECT id, UNIX_TIMESTAMP(added) as added,
|
||||||
CAST(avg(unconfirmed_transactions) as FLOAT) as unconfirmed_transactions,
|
CAST(avg(unconfirmed_transactions) as DOUBLE) as unconfirmed_transactions,
|
||||||
CAST(avg(tx_per_second) as FLOAT) as tx_per_second,
|
CAST(avg(tx_per_second) as DOUBLE) as tx_per_second,
|
||||||
CAST(avg(vbytes_per_second) as FLOAT) as vbytes_per_second,
|
CAST(avg(vbytes_per_second) as DOUBLE) as vbytes_per_second,
|
||||||
CAST(avg(vsize_1) as FLOAT) as vsize_1,
|
CAST(avg(vsize_1) as DOUBLE) as vsize_1,
|
||||||
CAST(avg(vsize_2) as FLOAT) as vsize_2,
|
CAST(avg(vsize_2) as DOUBLE) as vsize_2,
|
||||||
CAST(avg(vsize_3) as FLOAT) as vsize_3,
|
CAST(avg(vsize_3) as DOUBLE) as vsize_3,
|
||||||
CAST(avg(vsize_4) as FLOAT) as vsize_4,
|
CAST(avg(vsize_4) as DOUBLE) as vsize_4,
|
||||||
CAST(avg(vsize_5) as FLOAT) as vsize_5,
|
CAST(avg(vsize_5) as DOUBLE) as vsize_5,
|
||||||
CAST(avg(vsize_6) as FLOAT) as vsize_6,
|
CAST(avg(vsize_6) as DOUBLE) as vsize_6,
|
||||||
CAST(avg(vsize_8) as FLOAT) as vsize_8,
|
CAST(avg(vsize_8) as DOUBLE) as vsize_8,
|
||||||
CAST(avg(vsize_10) as FLOAT) as vsize_10,
|
CAST(avg(vsize_10) as DOUBLE) as vsize_10,
|
||||||
CAST(avg(vsize_12) as FLOAT) as vsize_12,
|
CAST(avg(vsize_12) as DOUBLE) as vsize_12,
|
||||||
CAST(avg(vsize_15) as FLOAT) as vsize_15,
|
CAST(avg(vsize_15) as DOUBLE) as vsize_15,
|
||||||
CAST(avg(vsize_20) as FLOAT) as vsize_20,
|
CAST(avg(vsize_20) as DOUBLE) as vsize_20,
|
||||||
CAST(avg(vsize_30) as FLOAT) as vsize_30,
|
CAST(avg(vsize_30) as DOUBLE) as vsize_30,
|
||||||
CAST(avg(vsize_40) as FLOAT) as vsize_40,
|
CAST(avg(vsize_40) as DOUBLE) as vsize_40,
|
||||||
CAST(avg(vsize_50) as FLOAT) as vsize_50,
|
CAST(avg(vsize_50) as DOUBLE) as vsize_50,
|
||||||
CAST(avg(vsize_60) as FLOAT) as vsize_60,
|
CAST(avg(vsize_60) as DOUBLE) as vsize_60,
|
||||||
CAST(avg(vsize_70) as FLOAT) as vsize_70,
|
CAST(avg(vsize_70) as DOUBLE) as vsize_70,
|
||||||
CAST(avg(vsize_80) as FLOAT) as vsize_80,
|
CAST(avg(vsize_80) as DOUBLE) as vsize_80,
|
||||||
CAST(avg(vsize_90) as FLOAT) as vsize_90,
|
CAST(avg(vsize_90) as DOUBLE) as vsize_90,
|
||||||
CAST(avg(vsize_100) as FLOAT) as vsize_100,
|
CAST(avg(vsize_100) as DOUBLE) as vsize_100,
|
||||||
CAST(avg(vsize_125) as FLOAT) as vsize_125,
|
CAST(avg(vsize_125) as DOUBLE) as vsize_125,
|
||||||
CAST(avg(vsize_150) as FLOAT) as vsize_150,
|
CAST(avg(vsize_150) as DOUBLE) as vsize_150,
|
||||||
CAST(avg(vsize_175) as FLOAT) as vsize_175,
|
CAST(avg(vsize_175) as DOUBLE) as vsize_175,
|
||||||
CAST(avg(vsize_200) as FLOAT) as vsize_200,
|
CAST(avg(vsize_200) as DOUBLE) as vsize_200,
|
||||||
CAST(avg(vsize_250) as FLOAT) as vsize_250,
|
CAST(avg(vsize_250) as DOUBLE) as vsize_250,
|
||||||
CAST(avg(vsize_300) as FLOAT) as vsize_300,
|
CAST(avg(vsize_300) as DOUBLE) as vsize_300,
|
||||||
CAST(avg(vsize_350) as FLOAT) as vsize_350,
|
CAST(avg(vsize_350) as DOUBLE) as vsize_350,
|
||||||
CAST(avg(vsize_400) as FLOAT) as vsize_400,
|
CAST(avg(vsize_400) as DOUBLE) as vsize_400,
|
||||||
CAST(avg(vsize_500) as FLOAT) as vsize_500,
|
CAST(avg(vsize_500) as DOUBLE) as vsize_500,
|
||||||
CAST(avg(vsize_600) as FLOAT) as vsize_600,
|
CAST(avg(vsize_600) as DOUBLE) as vsize_600,
|
||||||
CAST(avg(vsize_700) as FLOAT) as vsize_700,
|
CAST(avg(vsize_700) as DOUBLE) as vsize_700,
|
||||||
CAST(avg(vsize_800) as FLOAT) as vsize_800,
|
CAST(avg(vsize_800) as DOUBLE) as vsize_800,
|
||||||
CAST(avg(vsize_900) as FLOAT) as vsize_900,
|
CAST(avg(vsize_900) as DOUBLE) as vsize_900,
|
||||||
CAST(avg(vsize_1000) as FLOAT) as vsize_1000,
|
CAST(avg(vsize_1000) as DOUBLE) as vsize_1000,
|
||||||
CAST(avg(vsize_1200) as FLOAT) as vsize_1200,
|
CAST(avg(vsize_1200) as DOUBLE) as vsize_1200,
|
||||||
CAST(avg(vsize_1400) as FLOAT) as vsize_1400,
|
CAST(avg(vsize_1400) as DOUBLE) as vsize_1400,
|
||||||
CAST(avg(vsize_1600) as FLOAT) as vsize_1600,
|
CAST(avg(vsize_1600) as DOUBLE) as vsize_1600,
|
||||||
CAST(avg(vsize_1800) as FLOAT) as vsize_1800,
|
CAST(avg(vsize_1800) as DOUBLE) as vsize_1800,
|
||||||
CAST(avg(vsize_2000) as FLOAT) as vsize_2000 \
|
CAST(avg(vsize_2000) as DOUBLE) as vsize_2000 \
|
||||||
FROM statistics \
|
FROM statistics \
|
||||||
WHERE added BETWEEN DATE_SUB(NOW(), INTERVAL ${interval}) AND NOW() \
|
WHERE added BETWEEN DATE_SUB(NOW(), INTERVAL ${interval}) AND NOW() \
|
||||||
GROUP BY UNIX_TIMESTAMP(added) DIV ${div} \
|
GROUP BY UNIX_TIMESTAMP(added) DIV ${div} \
|
||||||
ORDER BY id DESC;`;
|
ORDER BY added DESC;`;
|
||||||
}
|
}
|
||||||
|
|
||||||
private getQueryForDays(div: number, interval: string) {
|
private getQueryForDays(div: number, interval: string) {
|
||||||
return `SELECT id, UNIX_TIMESTAMP(added) as added, unconfirmed_transactions,
|
return `SELECT id, UNIX_TIMESTAMP(added) as added, unconfirmed_transactions,
|
||||||
tx_per_second,
|
tx_per_second,
|
||||||
vbytes_per_second,
|
CAST(avg(vbytes_per_second) as DOUBLE) as vbytes_per_second,
|
||||||
vsize_1,
|
vsize_1,
|
||||||
vsize_2,
|
vsize_2,
|
||||||
vsize_3,
|
vsize_3,
|
||||||
@@ -361,10 +340,10 @@ class Statistics {
|
|||||||
FROM statistics \
|
FROM statistics \
|
||||||
WHERE added BETWEEN DATE_SUB(NOW(), INTERVAL ${interval}) AND NOW() \
|
WHERE added BETWEEN DATE_SUB(NOW(), INTERVAL ${interval}) AND NOW() \
|
||||||
GROUP BY UNIX_TIMESTAMP(added) DIV ${div} \
|
GROUP BY UNIX_TIMESTAMP(added) DIV ${div} \
|
||||||
ORDER BY id DESC;`;
|
ORDER BY added DESC;`;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async $get(id: number): Promise<OptimizedStatistic | undefined> {
|
private async $get(id: number): Promise<OptimizedStatistic | undefined> {
|
||||||
try {
|
try {
|
||||||
const connection = await DB.pool.getConnection();
|
const connection = await DB.pool.getConnection();
|
||||||
const query = `SELECT *, UNIX_TIMESTAMP(added) as added FROM statistics WHERE id = ?`;
|
const query = `SELECT *, UNIX_TIMESTAMP(added) as added FROM statistics WHERE id = ?`;
|
||||||
@@ -381,7 +360,7 @@ class Statistics {
|
|||||||
public async $list2H(): Promise<OptimizedStatistic[]> {
|
public async $list2H(): Promise<OptimizedStatistic[]> {
|
||||||
try {
|
try {
|
||||||
const connection = await DB.pool.getConnection();
|
const connection = await DB.pool.getConnection();
|
||||||
const query = `SELECT *, UNIX_TIMESTAMP(added) as added FROM statistics ORDER BY id DESC LIMIT 120`;
|
const query = `SELECT *, UNIX_TIMESTAMP(added) as added FROM statistics ORDER BY added DESC LIMIT 120`;
|
||||||
const [rows] = await connection.query<any>({ sql: query, timeout: this.queryTimeout });
|
const [rows] = await connection.query<any>({ sql: query, timeout: this.queryTimeout });
|
||||||
connection.release();
|
connection.release();
|
||||||
return this.mapStatisticToOptimizedStatistic(rows);
|
return this.mapStatisticToOptimizedStatistic(rows);
|
||||||
@@ -394,7 +373,7 @@ class Statistics {
|
|||||||
public async $list24H(): Promise<OptimizedStatistic[]> {
|
public async $list24H(): Promise<OptimizedStatistic[]> {
|
||||||
try {
|
try {
|
||||||
const connection = await DB.pool.getConnection();
|
const connection = await DB.pool.getConnection();
|
||||||
const query = this.getQueryForDaysAvg(120, '1 DAY'); // 2m interval
|
const query = `SELECT *, UNIX_TIMESTAMP(added) as added FROM statistics ORDER BY added DESC LIMIT 1440`;
|
||||||
const [rows] = await connection.query<any>({ sql: query, timeout: this.queryTimeout });
|
const [rows] = await connection.query<any>({ sql: query, timeout: this.queryTimeout });
|
||||||
connection.release();
|
connection.release();
|
||||||
return this.mapStatisticToOptimizedStatistic(rows);
|
return this.mapStatisticToOptimizedStatistic(rows);
|
||||||
@@ -407,7 +386,7 @@ class Statistics {
|
|||||||
public async $list1W(): Promise<OptimizedStatistic[]> {
|
public async $list1W(): Promise<OptimizedStatistic[]> {
|
||||||
try {
|
try {
|
||||||
const connection = await DB.pool.getConnection();
|
const connection = await DB.pool.getConnection();
|
||||||
const query = this.getQueryForDaysAvg(600, '1 WEEK'); // 10m interval
|
const query = this.getQueryForDaysAvg(300, '1 WEEK'); // 5m interval
|
||||||
const [rows] = await connection.query<any>({ sql: query, timeout: this.queryTimeout });
|
const [rows] = await connection.query<any>({ sql: query, timeout: this.queryTimeout });
|
||||||
connection.release();
|
connection.release();
|
||||||
return this.mapStatisticToOptimizedStatistic(rows);
|
return this.mapStatisticToOptimizedStatistic(rows);
|
||||||
@@ -420,7 +399,7 @@ class Statistics {
|
|||||||
public async $list1M(): Promise<OptimizedStatistic[]> {
|
public async $list1M(): Promise<OptimizedStatistic[]> {
|
||||||
try {
|
try {
|
||||||
const connection = await DB.pool.getConnection();
|
const connection = await DB.pool.getConnection();
|
||||||
const query = this.getQueryForDaysAvg(3600, '1 MONTH'); // 1h interval
|
const query = this.getQueryForDaysAvg(1800, '1 MONTH'); // 30m interval
|
||||||
const [rows] = await connection.query<any>({ sql: query, timeout: this.queryTimeout });
|
const [rows] = await connection.query<any>({ sql: query, timeout: this.queryTimeout });
|
||||||
connection.release();
|
connection.release();
|
||||||
return this.mapStatisticToOptimizedStatistic(rows);
|
return this.mapStatisticToOptimizedStatistic(rows);
|
||||||
@@ -433,7 +412,7 @@ class Statistics {
|
|||||||
public async $list3M(): Promise<OptimizedStatistic[]> {
|
public async $list3M(): Promise<OptimizedStatistic[]> {
|
||||||
try {
|
try {
|
||||||
const connection = await DB.pool.getConnection();
|
const connection = await DB.pool.getConnection();
|
||||||
const query = this.getQueryForDaysAvg(14400, '3 MONTH'); // 4h interval
|
const query = this.getQueryForDaysAvg(7200, '3 MONTH'); // 2h interval
|
||||||
const [rows] = await connection.query<any>({ sql: query, timeout: this.queryTimeout });
|
const [rows] = await connection.query<any>({ sql: query, timeout: this.queryTimeout });
|
||||||
connection.release();
|
connection.release();
|
||||||
return this.mapStatisticToOptimizedStatistic(rows);
|
return this.mapStatisticToOptimizedStatistic(rows);
|
||||||
@@ -446,7 +425,7 @@ class Statistics {
|
|||||||
public async $list6M(): Promise<OptimizedStatistic[]> {
|
public async $list6M(): Promise<OptimizedStatistic[]> {
|
||||||
try {
|
try {
|
||||||
const connection = await DB.pool.getConnection();
|
const connection = await DB.pool.getConnection();
|
||||||
const query = this.getQueryForDaysAvg(21600, '6 MONTH'); // 6h interval
|
const query = this.getQueryForDaysAvg(10800, '6 MONTH'); // 3h interval
|
||||||
const [rows] = await connection.query<any>({ sql: query, timeout: this.queryTimeout });
|
const [rows] = await connection.query<any>({ sql: query, timeout: this.queryTimeout });
|
||||||
connection.release();
|
connection.release();
|
||||||
return this.mapStatisticToOptimizedStatistic(rows);
|
return this.mapStatisticToOptimizedStatistic(rows);
|
||||||
@@ -459,7 +438,7 @@ class Statistics {
|
|||||||
public async $list1Y(): Promise<OptimizedStatistic[]> {
|
public async $list1Y(): Promise<OptimizedStatistic[]> {
|
||||||
try {
|
try {
|
||||||
const connection = await DB.pool.getConnection();
|
const connection = await DB.pool.getConnection();
|
||||||
const query = this.getQueryForDays(43200, '1 YEAR'); // 12h interval
|
const query = this.getQueryForDays(28800, '1 YEAR'); // 8h interval
|
||||||
const [rows] = await connection.query<any>({ sql: query, timeout: this.queryTimeout });
|
const [rows] = await connection.query<any>({ sql: query, timeout: this.queryTimeout });
|
||||||
connection.release();
|
connection.release();
|
||||||
return this.mapStatisticToOptimizedStatistic(rows);
|
return this.mapStatisticToOptimizedStatistic(rows);
|
||||||
@@ -472,7 +451,7 @@ class Statistics {
|
|||||||
public async $list2Y(): Promise<OptimizedStatistic[]> {
|
public async $list2Y(): Promise<OptimizedStatistic[]> {
|
||||||
try {
|
try {
|
||||||
const connection = await DB.pool.getConnection();
|
const connection = await DB.pool.getConnection();
|
||||||
const query = this.getQueryForDays(86400, "2 YEAR"); // 1d interval
|
const query = this.getQueryForDays(28800, "2 YEAR"); // 8h interval
|
||||||
const [rows] = await connection.query<any>({ sql: query, timeout: this.queryTimeout });
|
const [rows] = await connection.query<any>({ sql: query, timeout: this.queryTimeout });
|
||||||
connection.release();
|
connection.release();
|
||||||
return this.mapStatisticToOptimizedStatistic(rows);
|
return this.mapStatisticToOptimizedStatistic(rows);
|
||||||
@@ -485,7 +464,7 @@ class Statistics {
|
|||||||
public async $list3Y(): Promise<OptimizedStatistic[]> {
|
public async $list3Y(): Promise<OptimizedStatistic[]> {
|
||||||
try {
|
try {
|
||||||
const connection = await DB.pool.getConnection();
|
const connection = await DB.pool.getConnection();
|
||||||
const query = this.getQueryForDays(86400, "3 YEAR"); // 1d interval
|
const query = this.getQueryForDays(43200, "3 YEAR"); // 12h interval
|
||||||
const [rows] = await connection.query<any>({ sql: query, timeout: this.queryTimeout });
|
const [rows] = await connection.query<any>({ sql: query, timeout: this.queryTimeout });
|
||||||
connection.release();
|
connection.release();
|
||||||
return this.mapStatisticToOptimizedStatistic(rows);
|
return this.mapStatisticToOptimizedStatistic(rows);
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import bitcoinApi from './bitcoin/bitcoin-api-factory';
|
|||||||
import { TransactionExtended, TransactionMinerInfo } from '../mempool.interfaces';
|
import { TransactionExtended, TransactionMinerInfo } from '../mempool.interfaces';
|
||||||
import { IEsploraApi } from './bitcoin/esplora-api.interface';
|
import { IEsploraApi } from './bitcoin/esplora-api.interface';
|
||||||
import config from '../config';
|
import config from '../config';
|
||||||
|
import { Common } from './common';
|
||||||
|
|
||||||
class TransactionUtils {
|
class TransactionUtils {
|
||||||
constructor() { }
|
constructor() { }
|
||||||
@@ -31,7 +32,8 @@ class TransactionUtils {
|
|||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
return transaction;
|
return transaction;
|
||||||
}
|
}
|
||||||
const feePerVbytes = Math.max(config.MEMPOOL.NETWORK === 'liquid' ? 0.1 : 1, (transaction.fee || 0) / (transaction.weight / 4));
|
const feePerVbytes = Math.max(Common.isLiquid() ? 0.1 : 1,
|
||||||
|
(transaction.fee || 0) / (transaction.weight / 4));
|
||||||
const transactionExtended: TransactionExtended = Object.assign({
|
const transactionExtended: TransactionExtended = Object.assign({
|
||||||
vsize: Math.round(transaction.weight / 4),
|
vsize: Math.round(transaction.weight / 4),
|
||||||
feePerVsize: feePerVbytes,
|
feePerVsize: feePerVbytes,
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ const configFile = require('../mempool-config.json');
|
|||||||
|
|
||||||
interface IConfig {
|
interface IConfig {
|
||||||
MEMPOOL: {
|
MEMPOOL: {
|
||||||
NETWORK: 'mainnet' | 'testnet' | 'signet' | 'liquid';
|
NETWORK: 'mainnet' | 'testnet' | 'signet' | 'liquid' | 'liquidtestnet';
|
||||||
BACKEND: 'esplora' | 'electrum' | 'none';
|
BACKEND: 'esplora' | 'electrum' | 'none';
|
||||||
HTTP_PORT: number;
|
HTTP_PORT: number;
|
||||||
SPAWN_CLUSTER_PROCS: number;
|
SPAWN_CLUSTER_PROCS: number;
|
||||||
@@ -16,6 +16,7 @@ interface IConfig {
|
|||||||
MEMPOOL_BLOCKS_AMOUNT: number;
|
MEMPOOL_BLOCKS_AMOUNT: number;
|
||||||
PRICE_FEED_UPDATE_INTERVAL: number;
|
PRICE_FEED_UPDATE_INTERVAL: number;
|
||||||
USE_SECOND_NODE_FOR_MINFEE: boolean;
|
USE_SECOND_NODE_FOR_MINFEE: boolean;
|
||||||
|
EXTERNAL_ASSETS: string[];
|
||||||
};
|
};
|
||||||
ESPLORA: {
|
ESPLORA: {
|
||||||
REST_API_URL: string;
|
REST_API_URL: string;
|
||||||
@@ -78,6 +79,7 @@ const defaults: IConfig = {
|
|||||||
'MEMPOOL_BLOCKS_AMOUNT': 8,
|
'MEMPOOL_BLOCKS_AMOUNT': 8,
|
||||||
'PRICE_FEED_UPDATE_INTERVAL': 3600,
|
'PRICE_FEED_UPDATE_INTERVAL': 3600,
|
||||||
'USE_SECOND_NODE_FOR_MINFEE': false,
|
'USE_SECOND_NODE_FOR_MINFEE': false,
|
||||||
|
'EXTERNAL_ASSETS': [],
|
||||||
},
|
},
|
||||||
'ESPLORA': {
|
'ESPLORA': {
|
||||||
'REST_API_URL': 'http://127.0.0.1:3000',
|
'REST_API_URL': 'http://127.0.0.1:3000',
|
||||||
|
|||||||
@@ -22,6 +22,9 @@ import loadingIndicators from './api/loading-indicators';
|
|||||||
import mempool from './api/mempool';
|
import mempool from './api/mempool';
|
||||||
import elementsParser from './api/liquid/elements-parser';
|
import elementsParser from './api/liquid/elements-parser';
|
||||||
import databaseMigration from './api/database-migration';
|
import databaseMigration from './api/database-migration';
|
||||||
|
import syncAssets from './sync-assets';
|
||||||
|
import icons from './api/liquid/icons';
|
||||||
|
import { Common } from './api/common';
|
||||||
|
|
||||||
class Server {
|
class Server {
|
||||||
private wss: WebSocket.Server | undefined;
|
private wss: WebSocket.Server | undefined;
|
||||||
@@ -78,6 +81,7 @@ class Server {
|
|||||||
|
|
||||||
this.setUpWebsocketHandling();
|
this.setUpWebsocketHandling();
|
||||||
|
|
||||||
|
await syncAssets.syncAssets();
|
||||||
diskCache.loadMempoolCache();
|
diskCache.loadMempoolCache();
|
||||||
|
|
||||||
if (config.DATABASE.ENABLED) {
|
if (config.DATABASE.ENABLED) {
|
||||||
@@ -93,6 +97,10 @@ class Server {
|
|||||||
statistics.startStatistics();
|
statistics.startStatistics();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Common.isLiquid()) {
|
||||||
|
icons.loadIcons();
|
||||||
|
}
|
||||||
|
|
||||||
fiatConversion.startService();
|
fiatConversion.startService();
|
||||||
|
|
||||||
this.setUpHttpApiRoutes();
|
this.setUpHttpApiRoutes();
|
||||||
@@ -149,7 +157,7 @@ class Server {
|
|||||||
if (this.wss) {
|
if (this.wss) {
|
||||||
websocketHandler.setWebsocketServer(this.wss);
|
websocketHandler.setWebsocketServer(this.wss);
|
||||||
}
|
}
|
||||||
if (config.MEMPOOL.NETWORK === 'liquid' && config.DATABASE.ENABLED) {
|
if (Common.isLiquid() && config.DATABASE.ENABLED) {
|
||||||
blocks.setNewBlockCallback(async () => {
|
blocks.setNewBlockCallback(async () => {
|
||||||
try {
|
try {
|
||||||
await elementsParser.$parse();
|
await elementsParser.$parse();
|
||||||
@@ -217,15 +225,15 @@ class Server {
|
|||||||
|
|
||||||
if (config.STATISTICS.ENABLED && config.DATABASE.ENABLED) {
|
if (config.STATISTICS.ENABLED && config.DATABASE.ENABLED) {
|
||||||
this.app
|
this.app
|
||||||
.get(config.MEMPOOL.API_URL_PREFIX + 'statistics/2h', routes.get2HStatistics)
|
.get(config.MEMPOOL.API_URL_PREFIX + 'statistics/2h', routes.$getStatisticsByTime.bind(routes, '2h'))
|
||||||
.get(config.MEMPOOL.API_URL_PREFIX + 'statistics/24h', routes.get24HStatistics.bind(routes))
|
.get(config.MEMPOOL.API_URL_PREFIX + 'statistics/24h', routes.$getStatisticsByTime.bind(routes, '24h'))
|
||||||
.get(config.MEMPOOL.API_URL_PREFIX + 'statistics/1w', routes.get1WHStatistics.bind(routes))
|
.get(config.MEMPOOL.API_URL_PREFIX + 'statistics/1w', routes.$getStatisticsByTime.bind(routes, '1w'))
|
||||||
.get(config.MEMPOOL.API_URL_PREFIX + 'statistics/1m', routes.get1MStatistics.bind(routes))
|
.get(config.MEMPOOL.API_URL_PREFIX + 'statistics/1m', routes.$getStatisticsByTime.bind(routes, '1m'))
|
||||||
.get(config.MEMPOOL.API_URL_PREFIX + 'statistics/3m', routes.get3MStatistics.bind(routes))
|
.get(config.MEMPOOL.API_URL_PREFIX + 'statistics/3m', routes.$getStatisticsByTime.bind(routes, '3m'))
|
||||||
.get(config.MEMPOOL.API_URL_PREFIX + 'statistics/6m', routes.get6MStatistics.bind(routes))
|
.get(config.MEMPOOL.API_URL_PREFIX + 'statistics/6m', routes.$getStatisticsByTime.bind(routes, '6m'))
|
||||||
.get(config.MEMPOOL.API_URL_PREFIX + 'statistics/1y', routes.get1YStatistics.bind(routes))
|
.get(config.MEMPOOL.API_URL_PREFIX + 'statistics/1y', routes.$getStatisticsByTime.bind(routes, '1y'))
|
||||||
.get(config.MEMPOOL.API_URL_PREFIX + 'statistics/2y', routes.get2YStatistics.bind(routes))
|
.get(config.MEMPOOL.API_URL_PREFIX + 'statistics/2y', routes.$getStatisticsByTime.bind(routes, '2y'))
|
||||||
.get(config.MEMPOOL.API_URL_PREFIX + 'statistics/3y', routes.get3YStatistics.bind(routes))
|
.get(config.MEMPOOL.API_URL_PREFIX + 'statistics/3y', routes.$getStatisticsByTime.bind(routes, '3y'))
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -276,7 +284,14 @@ class Server {
|
|||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.MEMPOOL.NETWORK === 'liquid' && config.DATABASE.ENABLED) {
|
if (Common.isLiquid()) {
|
||||||
|
this.app
|
||||||
|
.get(config.MEMPOOL.API_URL_PREFIX + 'assets/icons', routes.getAllLiquidIcon)
|
||||||
|
.get(config.MEMPOOL.API_URL_PREFIX + 'asset/:assetId/icon', routes.getLiquidIcon)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Common.isLiquid() && config.DATABASE.ENABLED) {
|
||||||
this.app
|
this.app
|
||||||
.get(config.MEMPOOL.API_URL_PREFIX + 'liquid/pegs/month', routes.$getElementsPegsByMonth)
|
.get(config.MEMPOOL.API_URL_PREFIX + 'liquid/pegs/month', routes.$getElementsPegsByMonth)
|
||||||
;
|
;
|
||||||
|
|||||||
@@ -19,45 +19,55 @@ import loadingIndicators from './api/loading-indicators';
|
|||||||
import { Common } from './api/common';
|
import { Common } from './api/common';
|
||||||
import bitcoinClient from './api/bitcoin/bitcoin-client';
|
import bitcoinClient from './api/bitcoin/bitcoin-client';
|
||||||
import elementsParser from './api/liquid/elements-parser';
|
import elementsParser from './api/liquid/elements-parser';
|
||||||
|
import icons from './api/liquid/icons';
|
||||||
|
|
||||||
class Routes {
|
class Routes {
|
||||||
constructor() {}
|
constructor() {}
|
||||||
|
|
||||||
public async get2HStatistics(req: Request, res: Response) {
|
public async $getStatisticsByTime(time: '2h' | '24h' | '1w' | '1m' | '3m' | '6m' | '1y' | '2y' | '3y', req: Request, res: Response) {
|
||||||
const result = await statistics.$list2H();
|
res.header('Pragma', 'public');
|
||||||
|
res.header('Cache-control', 'public');
|
||||||
|
res.setHeader('Expires', new Date(Date.now() + 1000 * 300).toUTCString());
|
||||||
|
|
||||||
|
try {
|
||||||
|
let result;
|
||||||
|
switch (time as string) {
|
||||||
|
case '2h':
|
||||||
|
result = await statistics.$list2H();
|
||||||
|
res.setHeader('Expires', new Date(Date.now() + 1000 * 30).toUTCString());
|
||||||
|
break;
|
||||||
|
case '24h':
|
||||||
|
result = await statistics.$list24H();
|
||||||
|
res.setHeader('Expires', new Date(Date.now() + 1000 * 60).toUTCString());
|
||||||
|
break;
|
||||||
|
case '1w':
|
||||||
|
result = await statistics.$list1W();
|
||||||
|
break;
|
||||||
|
case '1m':
|
||||||
|
result = await statistics.$list1M();
|
||||||
|
break;
|
||||||
|
case '3m':
|
||||||
|
result = await statistics.$list3M();
|
||||||
|
break;
|
||||||
|
case '6m':
|
||||||
|
result = await statistics.$list6M();
|
||||||
|
break;
|
||||||
|
case '1y':
|
||||||
|
result = await statistics.$list1Y();
|
||||||
|
break;
|
||||||
|
case '2y':
|
||||||
|
result = await statistics.$list2Y();
|
||||||
|
break;
|
||||||
|
case '3y':
|
||||||
|
result = await statistics.$list3Y();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
result = await statistics.$list2H();
|
||||||
|
}
|
||||||
res.json(result);
|
res.json(result);
|
||||||
|
} catch (e) {
|
||||||
|
res.status(500).send(e instanceof Error ? e.message : e);
|
||||||
}
|
}
|
||||||
|
|
||||||
public get24HStatistics(req: Request, res: Response) {
|
|
||||||
res.json(statistics.getCache()['24h']);
|
|
||||||
}
|
|
||||||
|
|
||||||
public get1WHStatistics(req: Request, res: Response) {
|
|
||||||
res.json(statistics.getCache()['1w']);
|
|
||||||
}
|
|
||||||
|
|
||||||
public get1MStatistics(req: Request, res: Response) {
|
|
||||||
res.json(statistics.getCache()['1m']);
|
|
||||||
}
|
|
||||||
|
|
||||||
public get3MStatistics(req: Request, res: Response) {
|
|
||||||
res.json(statistics.getCache()['3m']);
|
|
||||||
}
|
|
||||||
|
|
||||||
public get6MStatistics(req: Request, res: Response) {
|
|
||||||
res.json(statistics.getCache()['6m']);
|
|
||||||
}
|
|
||||||
|
|
||||||
public get1YStatistics(req: Request, res: Response) {
|
|
||||||
res.json(statistics.getCache()['1y']);
|
|
||||||
}
|
|
||||||
|
|
||||||
public get2YStatistics(req: Request, res: Response) {
|
|
||||||
res.json(statistics.getCache()['2y']);
|
|
||||||
}
|
|
||||||
|
|
||||||
public get3YStatistics(req: Request, res: Response) {
|
|
||||||
res.json(statistics.getCache()['3y']);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public getInitData(req: Request, res: Response) {
|
public getInitData(req: Request, res: Response) {
|
||||||
@@ -69,7 +79,7 @@ class Routes {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getRecommendedFees(req: Request, res: Response) {
|
public getRecommendedFees(req: Request, res: Response) {
|
||||||
if (!mempool.isInSync()) {
|
if (!mempool.isInSync()) {
|
||||||
res.statusCode = 503;
|
res.statusCode = 503;
|
||||||
res.send('Service Unavailable');
|
res.send('Service Unavailable');
|
||||||
@@ -807,6 +817,26 @@ class Routes {
|
|||||||
: (e.message || 'Error'));
|
: (e.message || 'Error'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getLiquidIcon(req: Request, res: Response) {
|
||||||
|
const result = icons.getIconByAssetId(req.params.assetId);
|
||||||
|
if (result) {
|
||||||
|
res.setHeader('content-type', 'image/png');
|
||||||
|
res.setHeader('content-length', result.length);
|
||||||
|
res.send(result);
|
||||||
|
} else {
|
||||||
|
res.status(404).send('Asset icon not found');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public getAllLiquidIcon(req: Request, res: Response) {
|
||||||
|
const result = icons.getAllIconIds();
|
||||||
|
if (result) {
|
||||||
|
res.json(result);
|
||||||
|
} else {
|
||||||
|
res.status(404).send('Asset icons not found');
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default new Routes();
|
export default new Routes();
|
||||||
|
|||||||
32
backend/src/sync-assets.ts
Normal file
32
backend/src/sync-assets.ts
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
import axios from 'axios';
|
||||||
|
import * as fs from 'fs';
|
||||||
|
const fsPromises = fs.promises;
|
||||||
|
import config from './config';
|
||||||
|
import logger from './logger';
|
||||||
|
|
||||||
|
const PATH = './';
|
||||||
|
|
||||||
|
class SyncAssets {
|
||||||
|
constructor() { }
|
||||||
|
|
||||||
|
public async syncAssets() {
|
||||||
|
for (const url of config.MEMPOOL.EXTERNAL_ASSETS) {
|
||||||
|
await this.downloadFile(url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async downloadFile(url: string) {
|
||||||
|
const fileName = url.split('/').slice(-1)[0];
|
||||||
|
logger.info(`Downloading external asset: ${fileName}...`);
|
||||||
|
try {
|
||||||
|
const response = await axios.get(url, {
|
||||||
|
responseType: 'stream', timeout: 30000
|
||||||
|
});
|
||||||
|
await fsPromises.writeFile(PATH + fileName, response.data);
|
||||||
|
} catch (e: any) {
|
||||||
|
throw new Error(`Failed to download external asset. ` + e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default new SyncAssets();
|
||||||
101
docker/README.md
101
docker/README.md
@@ -1,101 +0,0 @@
|
|||||||
# Docker
|
|
||||||
|
|
||||||
## Initialization
|
|
||||||
|
|
||||||
In an empty dir create 2 sub-dirs
|
|
||||||
|
|
||||||
```bash
|
|
||||||
mkdir -p data mysql/data mysql/db-scripts
|
|
||||||
```
|
|
||||||
|
|
||||||
In the `mysql/db-scripts` sub-dir add the `mariadb-structure.sql` file from the mempool repo
|
|
||||||
|
|
||||||
Your dir should now look like that:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ls -R
|
|
||||||
.:
|
|
||||||
data mysql
|
|
||||||
|
|
||||||
./data:
|
|
||||||
|
|
||||||
./mysql:
|
|
||||||
data db-scripts
|
|
||||||
|
|
||||||
./mysql/data:
|
|
||||||
|
|
||||||
./mysql/db-scripts:
|
|
||||||
mariadb-structure.sql
|
|
||||||
```
|
|
||||||
|
|
||||||
In the main dir add the following `docker-compose.yml`
|
|
||||||
|
|
||||||
```bash
|
|
||||||
version: "3.7"
|
|
||||||
|
|
||||||
services:
|
|
||||||
web:
|
|
||||||
image: mempool/frontend:latest
|
|
||||||
user: "1000:1000"
|
|
||||||
restart: on-failure
|
|
||||||
stop_grace_period: 1m
|
|
||||||
command: "./wait-for db:3306 --timeout=720 -- nginx -g 'daemon off;'"
|
|
||||||
ports:
|
|
||||||
- 80:8080
|
|
||||||
environment:
|
|
||||||
FRONTEND_HTTP_PORT: "8080"
|
|
||||||
BACKEND_MAINNET_HTTP_HOST: "api"
|
|
||||||
api:
|
|
||||||
image: mempool/backend:latest
|
|
||||||
user: "1000:1000"
|
|
||||||
restart: on-failure
|
|
||||||
stop_grace_period: 1m
|
|
||||||
command: "./wait-for-it.sh db:3306 --timeout=720 --strict -- ./start.sh"
|
|
||||||
volumes:
|
|
||||||
- ./data:/backend/cache
|
|
||||||
environment:
|
|
||||||
RPC_HOST: "127.0.0.1"
|
|
||||||
RPC_PORT: "8332"
|
|
||||||
RPC_USER: "mempool"
|
|
||||||
RPC_PASS: "mempool"
|
|
||||||
ELECTRUM_HOST: "127.0.0.1"
|
|
||||||
ELECTRUM_PORT: "50002"
|
|
||||||
ELECTRUM_TLS: "false"
|
|
||||||
MYSQL_HOST: "db"
|
|
||||||
MYSQL_PORT: "3306"
|
|
||||||
MYSQL_DATABASE: "mempool"
|
|
||||||
MYSQL_USER: "mempool"
|
|
||||||
MYSQL_PASS: "mempool"
|
|
||||||
BACKEND_MAINNET_HTTP_PORT: "8999"
|
|
||||||
CACHE_DIR: "/backend/cache"
|
|
||||||
MEMPOOL_CLEAR_PROTECTION_MINUTES: "20"
|
|
||||||
db:
|
|
||||||
image: mariadb:10.5.8
|
|
||||||
user: "1000:1000"
|
|
||||||
restart: on-failure
|
|
||||||
stop_grace_period: 1m
|
|
||||||
volumes:
|
|
||||||
- ./mysql/data:/var/lib/mysql
|
|
||||||
- ./mysql/db-scripts:/docker-entrypoint-initdb.d
|
|
||||||
environment:
|
|
||||||
MYSQL_DATABASE: "mempool"
|
|
||||||
MYSQL_USER: "mempool"
|
|
||||||
MYSQL_PASSWORD: "mempool"
|
|
||||||
MYSQL_ROOT_PASSWORD: "admin"
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
You can update all the environment variables inside the API container, especially the RPC and ELECTRUM ones
|
|
||||||
|
|
||||||
## Run it
|
|
||||||
|
|
||||||
To run our docker-compose use the following cmd:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker-compose up
|
|
||||||
```
|
|
||||||
|
|
||||||
If everything went okay you should see the beautiful mempool :grin:
|
|
||||||
|
|
||||||
If you get stuck on "loading blocks", this means the websocket can't connect.
|
|
||||||
Check your nginx proxy setup, firewalls, etc. and open an issue if you need help.
|
|
||||||
@@ -1,38 +1,62 @@
|
|||||||
{
|
{
|
||||||
"MEMPOOL": {
|
"MEMPOOL": {
|
||||||
"NETWORK": "mainnet",
|
"NETWORK": "__MEMPOOL_NETWORK__",
|
||||||
"BACKEND": "electrum",
|
"BACKEND": "__MEMPOOL_BACKEND__",
|
||||||
"HTTP_PORT": __MEMPOOL_BACKEND_MAINNET_HTTP_PORT__,
|
"HTTP_PORT": __MEMPOOL_HTTP_PORT__,
|
||||||
"SPAWN_CLUSTER_PROCS": 0,
|
"SPAWN_CLUSTER_PROCS": __MEMPOOL_SPAWN_CLUSTER_PROCS__,
|
||||||
"API_URL_PREFIX": "/api/v1/",
|
"API_URL_PREFIX": "__MEMPOOL_API_URL_PREFIX__",
|
||||||
"POLL_RATE_MS": 2000,
|
"POLL_RATE_MS": __MEMPOOL_POLL_RATE_MS__,
|
||||||
"CACHE_DIR": "__MEMPOOL_BACKEND_MAINNET_CACHE_DIR__",
|
"CACHE_DIR": "__MEMPOOL_CACHE_DIR__",
|
||||||
"CLEAR_PROTECTION_MINUTES": __MEMPOOL_BACKEND_CLEAR_PROTECTION_MINUTES__
|
"CLEAR_PROTECTION_MINUTES": __MEMPOOL_CLEAR_PROTECTION_MINUTES__,
|
||||||
|
"RECOMMENDED_FEE_PERCENTILE": __MEMPOOL_RECOMMENDED_FEE_PERCENTILE__,
|
||||||
|
"BLOCK_WEIGHT_UNITS": __MEMPOOL_BLOCK_WEIGHT_UNITS__,
|
||||||
|
"INITIAL_BLOCKS_AMOUNT": __MEMPOOL_INITIAL_BLOCKS_AMOUNT__,
|
||||||
|
"MEMPOOL_BLOCKS_AMOUNT": __MEMPOOL_MEMPOOL_BLOCKS_AMOUNT__,
|
||||||
|
"PRICE_FEED_UPDATE_INTERVAL": __MEMPOOL_PRICE_FEED_UPDATE_INTERVAL__,
|
||||||
|
"USE_SECOND_NODE_FOR_MINFEE": __MEMPOOL_USE_SECOND_NODE_FOR_MINFEE__,
|
||||||
|
"EXTERNAL_ASSETS": __MEMPOOL_EXTERNAL_ASSETS__
|
||||||
},
|
},
|
||||||
"CORE_RPC": {
|
"CORE_RPC": {
|
||||||
"HOST": "__BITCOIN_MAINNET_RPC_HOST__",
|
"HOST": "__CORE_RPC_HOST__",
|
||||||
"PORT": __BITCOIN_MAINNET_RPC_PORT__,
|
"PORT": __CORE_RPC_PORT__,
|
||||||
"USERNAME": "__BITCOIN_MAINNET_RPC_USER__",
|
"USERNAME": "__CORE_RPC_USERNAME__",
|
||||||
"PASSWORD": "__BITCOIN_MAINNET_RPC_PASS__"
|
"PASSWORD": "__CORE_RPC_PASSWORD__"
|
||||||
},
|
},
|
||||||
"ELECTRUM": {
|
"ELECTRUM": {
|
||||||
"HOST": "__ELECTRUM_MAINNET_HTTP_HOST__",
|
"HOST": "__ELECTRUM_HOST__",
|
||||||
"PORT": __ELECTRUM_MAINNET_HTTP_PORT__,
|
"PORT": __ELECTRUM_PORT__,
|
||||||
"TLS_ENABLED": __ELECTRUM_MAINNET_TLS_ENABLED__
|
"TLS_ENABLED": __ELECTRUM_TLS_ENABLED__
|
||||||
},
|
},
|
||||||
"ESPLORA": {
|
"ESPLORA": {
|
||||||
"REST_API_URL": "http://127.0.0.1:3000"
|
"REST_API_URL": "__ESPLORA_REST_API_URL__"
|
||||||
|
},
|
||||||
|
"SECOND_CORE_RPC": {
|
||||||
|
"HOST": "__SECOND_CORE_RPC_HOST__",
|
||||||
|
"PORT": __SECOND_CORE_RPC_PORT__,
|
||||||
|
"USERNAME": "__SECOND_CORE_RPC_USERNAME__",
|
||||||
|
"PASSWORD": "__SECOND_CORE_RPC_PASSWORD__"
|
||||||
},
|
},
|
||||||
"DATABASE": {
|
"DATABASE": {
|
||||||
"ENABLED": true,
|
"ENABLED": __DATABASE_ENABLED__,
|
||||||
"HOST": "__MYSQL_HOST__",
|
"HOST": "__DATABASE_HOST__",
|
||||||
"PORT": __MYSQL_PORT__,
|
"PORT": __DATABASE_PORT__,
|
||||||
"DATABASE": "__MYSQL_DATABASE__",
|
"DATABASE": "__DATABASE_DATABASE__",
|
||||||
"USERNAME": "__MYSQL_USERNAME__",
|
"USERNAME": "__DATABASE_USERNAME__",
|
||||||
"PASSWORD": "__MYSQL_PASSWORD__"
|
"PASSWORD": "__DATABASE_PASSWORD__"
|
||||||
|
},
|
||||||
|
"SYSLOG": {
|
||||||
|
"ENABLED": __SYSLOG_ENABLED__,
|
||||||
|
"HOST": "__SYSLOG_HOST__",
|
||||||
|
"PORT": __SYSLOG_PORT__,
|
||||||
|
"MIN_PRIORITY": "__SYSLOG_MIN_PRIORITY__",
|
||||||
|
"FACILITY": "__SYSLOG_FACILITY__"
|
||||||
},
|
},
|
||||||
"STATISTICS": {
|
"STATISTICS": {
|
||||||
"ENABLED": true,
|
"ENABLED": __STATISTICS_ENABLED__,
|
||||||
"TX_PER_SECOND_SAMPLE_PERIOD": 150
|
"TX_PER_SECOND_SAMPLE_PERIOD": __STATISTICS_TX_PER_SECOND_SAMPLE_PERIOD__
|
||||||
|
},
|
||||||
|
"BISQ": {
|
||||||
|
"ENABLED": __BISQ_ENABLED__,
|
||||||
|
"DATA_PATH": "__BISQ_DATA_PATH__"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,41 +1,116 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
#MEMPOOL
|
# MEMPOOL
|
||||||
__MEMPOOL_BACKEND_MAINNET_HTTP_PORT__=${BACKEND_MAINNET_HTTP_PORT:=8999}
|
__MEMPOOL_NETWORK__=${MEMPOOL_NETWORK:=mainnet}
|
||||||
__MEMPOOL_BACKEND_MAINNET_CACHE_DIR__=${CACHE_DIR:=./cache}
|
__MEMPOOL_BACKEND__=${MEMPOOL_BACKEND:=electrum}
|
||||||
__MEMPOOL_BACKEND_CLEAR_PROTECTION_MINUTES__=${MEMPOOL_CLEAR_PROTECTION_MINUTES:=20}
|
__MEMPOOL_HTTP_PORT__=${BACKEND_HTTP_PORT:=8999}
|
||||||
# BITCOIN
|
__MEMPOOL_SPAWN_CLUSTER_PROCS__=${MEMPOOL_SPAWN_CLUSTER_PROCS:=0}
|
||||||
__BITCOIN_MAINNET_RPC_HOST__=${RPC_HOST:=127.0.0.1}
|
__MEMPOOL_API_URL_PREFIX__=${MEMPOOL_API_URL_PREFIX:=/api/v1/}
|
||||||
__BITCOIN_MAINNET_RPC_PORT__=${RPC_PORT:=8332}
|
__MEMPOOL_POLL_RATE_MS__=${MEMPOOL_POLL_RATE_MS:=2000}
|
||||||
__BITCOIN_MAINNET_RPC_USER__=${RPC_USER:=mempool}
|
__MEMPOOL_CACHE_DIR__=${MEMPOOL_CACHE_DIR:=./cache}
|
||||||
__BITCOIN_MAINNET_RPC_PASS__=${RPC_PASS:=mempool}
|
__MEMPOOL_CLEAR_PROTECTION_MINUTES__=${MEMPOOL_CLEAR_PROTECTION_MINUTES:=20}
|
||||||
|
__MEMPOOL_RECOMMENDED_FEE_PERCENTILE__=${MEMPOOL_RECOMMENDED_FEE_PERCENTILE:=50}
|
||||||
|
__MEMPOOL_BLOCK_WEIGHT_UNITS__=${MEMPOOL_BLOCK_WEIGHT_UNITS:=4000000}
|
||||||
|
__MEMPOOL_INITIAL_BLOCKS_AMOUNT__=${MEMPOOL_INITIAL_BLOCKS_AMOUNT:=8}
|
||||||
|
__MEMPOOL_MEMPOOL_BLOCKS_AMOUNT__=${MEMPOOL_MEMPOOL_BLOCKS_AMOUNT:=8}
|
||||||
|
__MEMPOOL_PRICE_FEED_UPDATE_INTERVAL__=${MEMPOOL_PRICE_FEED_UPDATE_INTERVAL:=3600}
|
||||||
|
__MEMPOOL_USE_SECOND_NODE_FOR_MINFEE__=${MEMPOOL_USE_SECOND_NODE_FOR_MINFEE:=false}
|
||||||
|
__MEMPOOL_EXTERNAL_ASSETS__=${MEMPOOL_EXTERNAL_ASSETS:=[]}
|
||||||
|
|
||||||
|
# CORE_RPC
|
||||||
|
__CORE_RPC_HOST__=${CORE_RPC_HOST:=127.0.0.1}
|
||||||
|
__CORE_RPC_PORT__=${CORE_RPC_PORT:=8332}
|
||||||
|
__CORE_RPC_USERNAME__=${CORE_RPC_USERNAME:=mempool}
|
||||||
|
__CORE_RPC_PASSWORD__=${CORE_RPC_PASSWORD:=mempool}
|
||||||
|
|
||||||
# ELECTRUM
|
# ELECTRUM
|
||||||
__ELECTRUM_MAINNET_HTTP_HOST__=${ELECTRUM_HOST:=127.0.0.1}
|
__ELECTRUM_HOST__=${ELECTRUM_HOST:=127.0.0.1}
|
||||||
__ELECTRUM_MAINNET_HTTP_PORT__=${ELECTRUM_PORT:=50002} # 50001?
|
__ELECTRUM_PORT__=${ELECTRUM_PORT:=50002}
|
||||||
__ELECTRUM_MAINNET_TLS_ENABLED__=${ELECTRUM_TLS:=false}
|
__ELECTRUM_TLS_ENABLED__=${ELECTRUM_TLS:=false}
|
||||||
# MYSQL
|
|
||||||
__MYSQL_HOST__=${MYSQL_HOST:=127.0.0.1}
|
|
||||||
__MYSQL_PORT__=${MYSQL_PORT:=3306}
|
|
||||||
__MYSQL_DATABASE__=${MYSQL_DATABASE:=mempool}
|
|
||||||
__MYSQL_USERNAME__=${MYSQL_USER:=mempool}
|
|
||||||
__MYSQL_PASSWORD__=${MYSQL_PASS:=mempool}
|
|
||||||
|
|
||||||
mkdir -p "${__MEMPOOL_BACKEND_MAINNET_CACHE_DIR__}"
|
# ESPLORA
|
||||||
|
__ESPLORA_REST_API_URL__=${ESPLORA_REST_API_URL:=http://127.0.0.1:3000}
|
||||||
|
|
||||||
sed -i "s/__BITCOIN_MAINNET_RPC_HOST__/${__BITCOIN_MAINNET_RPC_HOST__}/g" mempool-config.json
|
# SECOND_CORE_RPC
|
||||||
sed -i "s/__BITCOIN_MAINNET_RPC_PORT__/${__BITCOIN_MAINNET_RPC_PORT__}/g" mempool-config.json
|
__SECOND_CORE_RPC_HOST__=${SECOND_CORE_RPC_HOST:=127.0.0.1}
|
||||||
sed -i "s/__BITCOIN_MAINNET_RPC_USER__/${__BITCOIN_MAINNET_RPC_USER__}/g" mempool-config.json
|
__SECOND_CORE_RPC_PORT__=${SECOND_CORE_RPC_PORT:=8332}
|
||||||
sed -i "s/__BITCOIN_MAINNET_RPC_PASS__/${__BITCOIN_MAINNET_RPC_PASS__}/g" mempool-config.json
|
__SECOND_CORE_RPC_USERNAME__=${SECOND_CORE_RPC_USERNAME:=mempool}
|
||||||
sed -i "s/__ELECTRUM_MAINNET_HTTP_HOST__/${__ELECTRUM_MAINNET_HTTP_HOST__}/g" mempool-config.json
|
__SECOND_CORE_RPC_PASSWORD__=${SECOND_CORE_RPC_PASSWORD:=mempool}
|
||||||
sed -i "s/__ELECTRUM_MAINNET_HTTP_PORT__/${__ELECTRUM_MAINNET_HTTP_PORT__}/g" mempool-config.json
|
|
||||||
sed -i "s/__ELECTRUM_MAINNET_TLS_ENABLED__/${__ELECTRUM_MAINNET_TLS_ENABLED__}/g" mempool-config.json
|
# DATABASE
|
||||||
sed -i "s/__MYSQL_HOST__/${__MYSQL_HOST__}/g" mempool-config.json
|
__DATABASE_ENABLED__=${DATABASE_ENABLED:=true}
|
||||||
sed -i "s/__MYSQL_PORT__/${__MYSQL_PORT__}/g" mempool-config.json
|
__DATABASE_HOST__=${DATABASE_HOST:=127.0.0.1}
|
||||||
sed -i "s/__MYSQL_DATABASE__/${__MYSQL_DATABASE__}/g" mempool-config.json
|
__DATABASE_PORT__=${DATABASE_PORT:=3306}
|
||||||
sed -i "s/__MYSQL_USERNAME__/${__MYSQL_USERNAME__}/g" mempool-config.json
|
__DATABASE_DATABASE__=${DATABASE_DATABASE:=mempool}
|
||||||
sed -i "s/__MYSQL_PASSWORD__/${__MYSQL_PASSWORD__}/g" mempool-config.json
|
__DATABASE_USERNAME__=${DATABASE_USERNAME:=mempool}
|
||||||
sed -i "s!__MEMPOOL_BACKEND_MAINNET_CACHE_DIR__!${__MEMPOOL_BACKEND_MAINNET_CACHE_DIR__}!g" mempool-config.json
|
__DATABASE_PASSWORD__=${DATABASE_PASSWORD:=mempool}
|
||||||
sed -i "s/__MEMPOOL_BACKEND_MAINNET_HTTP_PORT__/${__MEMPOOL_BACKEND_MAINNET_HTTP_PORT__}/g" mempool-config.json
|
|
||||||
sed -i "s/__MEMPOOL_BACKEND_CLEAR_PROTECTION_MINUTES__/${__MEMPOOL_BACKEND_CLEAR_PROTECTION_MINUTES__}/g" mempool-config.json
|
# SYSLOG
|
||||||
|
__SYSLOG_ENABLED__=${SYSLOG_ENABLED:=false}
|
||||||
|
__SYSLOG_HOST__=${SYSLOG_HOST:=127.0.0.1}
|
||||||
|
__SYSLOG_PORT__=${SYSLOG_PORT:=514}
|
||||||
|
__SYSLOG_MIN_PRIORITY__=${SYSLOG_MIN_PRIORITY:=info}
|
||||||
|
__SYSLOG_FACILITY__=${SYSLOG_FACILITY:=local7}
|
||||||
|
|
||||||
|
# STATISTICS
|
||||||
|
__STATISTICS_ENABLED__=${STATISTICS_ENABLED:=true}
|
||||||
|
__STATISTICS_TX_PER_SECOND_SAMPLE_PERIOD__=${STATISTICS_TX_PER_SECOND_SAMPLE_PERIOD:=150}
|
||||||
|
|
||||||
|
# BISQ
|
||||||
|
__BISQ_ENABLED__=${BISQ_ENABLED:=false}
|
||||||
|
__BISQ_DATA_PATH__=${BISQ_DATA_PATH:=/bisq/statsnode-data/btc_mainnet/db}
|
||||||
|
|
||||||
|
mkdir -p "${__MEMPOOL_CACHE_DIR__}"
|
||||||
|
|
||||||
|
sed -i "s/__MEMPOOL_NETWORK__/${__MEMPOOL_NETWORK__}/g" mempool-config.json
|
||||||
|
sed -i "s/__MEMPOOL_BACKEND__/${__MEMPOOL_BACKEND__}/g" mempool-config.json
|
||||||
|
sed -i "s/__MEMPOOL_HTTP_PORT__/${__MEMPOOL_HTTP_PORT__}/g" mempool-config.json
|
||||||
|
sed -i "s/__MEMPOOL_SPAWN_CLUSTER_PROCS__/${__MEMPOOL_SPAWN_CLUSTER_PROCS__}/g" mempool-config.json
|
||||||
|
sed -i "s!__MEMPOOL_API_URL_PREFIX__!${__MEMPOOL_API_URL_PREFIX__}!g" mempool-config.json
|
||||||
|
sed -i "s/__MEMPOOL_POLL_RATE_MS__/${__MEMPOOL_POLL_RATE_MS__}/g" mempool-config.json
|
||||||
|
sed -i "s!__MEMPOOL_CACHE_DIR__!${__MEMPOOL_CACHE_DIR__}!g" mempool-config.json
|
||||||
|
sed -i "s/__MEMPOOL_CLEAR_PROTECTION_MINUTES__/${__MEMPOOL_CLEAR_PROTECTION_MINUTES__}/g" mempool-config.json
|
||||||
|
sed -i "s/__MEMPOOL_RECOMMENDED_FEE_PERCENTILE__/${__MEMPOOL_RECOMMENDED_FEE_PERCENTILE__}/g" mempool-config.json
|
||||||
|
sed -i "s/__MEMPOOL_BLOCK_WEIGHT_UNITS__/${__MEMPOOL_BLOCK_WEIGHT_UNITS__}/g" mempool-config.json
|
||||||
|
sed -i "s/__MEMPOOL_INITIAL_BLOCKS_AMOUNT__/${__MEMPOOL_INITIAL_BLOCKS_AMOUNT__}/g" mempool-config.json
|
||||||
|
sed -i "s/__MEMPOOL_MEMPOOL_BLOCKS_AMOUNT__/${__MEMPOOL_MEMPOOL_BLOCKS_AMOUNT__}/g" mempool-config.json
|
||||||
|
sed -i "s/__MEMPOOL_PRICE_FEED_UPDATE_INTERVAL__/${__MEMPOOL_PRICE_FEED_UPDATE_INTERVAL__}/g" mempool-config.json
|
||||||
|
sed -i "s/__MEMPOOL_USE_SECOND_NODE_FOR_MINFEE__/${__MEMPOOL_USE_SECOND_NODE_FOR_MINFEE__}/g" mempool-config.json
|
||||||
|
sed -i "s/__MEMPOOL_EXTERNAL_ASSETS__/${__MEMPOOL_EXTERNAL_ASSETS__}/g" mempool-config.json
|
||||||
|
|
||||||
|
sed -i "s/__CORE_RPC_HOST__/${__CORE_RPC_HOST__}/g" mempool-config.json
|
||||||
|
sed -i "s/__CORE_RPC_PORT__/${__CORE_RPC_PORT__}/g" mempool-config.json
|
||||||
|
sed -i "s/__CORE_RPC_USERNAME__/${__CORE_RPC_USERNAME__}/g" mempool-config.json
|
||||||
|
sed -i "s/__CORE_RPC_PASSWORD__/${__CORE_RPC_PASSWORD__}/g" mempool-config.json
|
||||||
|
|
||||||
|
sed -i "s/__ELECTRUM_HOST__/${__ELECTRUM_HOST__}/g" mempool-config.json
|
||||||
|
sed -i "s/__ELECTRUM_PORT__/${__ELECTRUM_PORT__}/g" mempool-config.json
|
||||||
|
sed -i "s/__ELECTRUM_TLS_ENABLED__/${__ELECTRUM_TLS_ENABLED__}/g" mempool-config.json
|
||||||
|
|
||||||
|
sed -i "s!__ESPLORA_REST_API_URL__!${__ESPLORA_REST_API_URL__}!g" mempool-config.json
|
||||||
|
|
||||||
|
sed -i "s/__SECOND_CORE_RPC_HOST__/${__SECOND_CORE_RPC_HOST__}/g" mempool-config.json
|
||||||
|
sed -i "s/__SECOND_CORE_RPC_PORT__/${__SECOND_CORE_RPC_PORT__}/g" mempool-config.json
|
||||||
|
sed -i "s/__SECOND_CORE_RPC_USERNAME__/${__SECOND_CORE_RPC_USERNAME__}/g" mempool-config.json
|
||||||
|
sed -i "s/__SECOND_CORE_RPC_PASSWORD__/${__SECOND_CORE_RPC_PASSWORD__}/g" mempool-config.json
|
||||||
|
|
||||||
|
sed -i "s/__DATABASE_ENABLED__/${__DATABASE_ENABLED__}/g" mempool-config.json
|
||||||
|
sed -i "s/__DATABASE_HOST__/${__DATABASE_HOST__}/g" mempool-config.json
|
||||||
|
sed -i "s/__DATABASE_PORT__/${__DATABASE_PORT__}/g" mempool-config.json
|
||||||
|
sed -i "s/__DATABASE_DATABASE__/${__DATABASE_DATABASE__}/g" mempool-config.json
|
||||||
|
sed -i "s/__DATABASE_USERNAME__/${__DATABASE_USERNAME__}/g" mempool-config.json
|
||||||
|
sed -i "s/__DATABASE_PASSWORD__/${__DATABASE_PASSWORD__}/g" mempool-config.json
|
||||||
|
|
||||||
|
sed -i "s/__SYSLOG_ENABLED__/${__SYSLOG_ENABLED__}/g" mempool-config.json
|
||||||
|
sed -i "s/__SYSLOG_HOST__/${__SYSLOG_HOST__}/g" mempool-config.json
|
||||||
|
sed -i "s/__SYSLOG_PORT__/${__SYSLOG_PORT__}/g" mempool-config.json
|
||||||
|
sed -i "s/__SYSLOG_MIN_PRIORITY__/${__SYSLOG_MIN_PRIORITY__}/g" mempool-config.json
|
||||||
|
sed -i "s/__SYSLOG_FACILITY__/${__SYSLOG_FACILITY__}/g" mempool-config.json
|
||||||
|
|
||||||
|
sed -i "s/__STATISTICS_ENABLED__/${__STATISTICS_ENABLED__}/g" mempool-config.json
|
||||||
|
sed -i "s/__STATISTICS_TX_PER_SECOND_SAMPLE_PERIOD__/${__STATISTICS_TX_PER_SECOND_SAMPLE_PERIOD__}/g" mempool-config.json
|
||||||
|
|
||||||
|
sed -i "s/__BISQ_ENABLED__/${__BISQ_ENABLED__}/g" mempool-config.json
|
||||||
|
sed -i "s!__BISQ_DATA_PATH__!${__BISQ_DATA_PATH__}!g" mempool-config.json
|
||||||
|
|
||||||
node /backend/dist/index.js
|
node /backend/dist/index.js
|
||||||
|
|||||||
0
docker/data/.gitkeep
Normal file
0
docker/data/.gitkeep
Normal file
@@ -1,23 +1,10 @@
|
|||||||
version: "3.7"
|
version: "3.7"
|
||||||
|
|
||||||
services:
|
services:
|
||||||
|
|
||||||
electrum:
|
|
||||||
build:
|
|
||||||
context: .
|
|
||||||
dockerfile: docker/electrum/Dockerfile
|
|
||||||
user: "1000:1000"
|
|
||||||
restart: on-failure
|
|
||||||
command: ""
|
|
||||||
ports:
|
|
||||||
- 50001:50001
|
|
||||||
- 50002:50002
|
|
||||||
- 4224:4224
|
|
||||||
- 8332:8332
|
|
||||||
environment:
|
|
||||||
ELECTRUM: "electrum"
|
|
||||||
# add electrs configs
|
|
||||||
web:
|
web:
|
||||||
|
environment:
|
||||||
|
FRONTEND_HTTP_PORT: "8080"
|
||||||
|
BACKEND_MAINNET_HTTP_HOST: "api"
|
||||||
image: mempool/frontend:latest
|
image: mempool/frontend:latest
|
||||||
user: "1000:1000"
|
user: "1000:1000"
|
||||||
restart: on-failure
|
restart: on-failure
|
||||||
@@ -25,10 +12,19 @@ services:
|
|||||||
command: "./wait-for db:3306 --timeout=720 -- nginx -g 'daemon off;'"
|
command: "./wait-for db:3306 --timeout=720 -- nginx -g 'daemon off;'"
|
||||||
ports:
|
ports:
|
||||||
- 80:8080
|
- 80:8080
|
||||||
environment:
|
|
||||||
FRONTEND_HTTP_PORT: "8080"
|
|
||||||
BACKEND_MAINNET_HTTP_HOST: "api"
|
|
||||||
api:
|
api:
|
||||||
|
environment:
|
||||||
|
MEMPOOL_BACKEND: "none"
|
||||||
|
CORE_RPC_HOST: "172.27.0.1"
|
||||||
|
CORE_RPC_PORT: "8332"
|
||||||
|
CORE_RPC_USERNAME: "mempool"
|
||||||
|
CORE_RPC_PASSWORD: "mempool"
|
||||||
|
DATABASE_ENABLED: "true"
|
||||||
|
DATABASE_HOST: "db"
|
||||||
|
DATABASE_DATABASE: "mempool"
|
||||||
|
DATABASE_USERNAME: "mempool"
|
||||||
|
DATABASE_PASSWORD: "mempool"
|
||||||
|
STATISTICS_ENABLED: "true"
|
||||||
image: mempool/backend:latest
|
image: mempool/backend:latest
|
||||||
user: "1000:1000"
|
user: "1000:1000"
|
||||||
restart: on-failure
|
restart: on-failure
|
||||||
@@ -36,32 +32,15 @@ services:
|
|||||||
command: "./wait-for-it.sh db:3306 --timeout=720 --strict -- ./start.sh"
|
command: "./wait-for-it.sh db:3306 --timeout=720 --strict -- ./start.sh"
|
||||||
volumes:
|
volumes:
|
||||||
- ./data:/backend/cache
|
- ./data:/backend/cache
|
||||||
|
db:
|
||||||
environment:
|
environment:
|
||||||
RPC_HOST: "127.0.0.1"
|
|
||||||
RPC_PORT: "8332"
|
|
||||||
RPC_USER: "mempool"
|
|
||||||
RPC_PASS: "mempool"
|
|
||||||
ELECTRUM_HOST: "127.0.0.1"
|
|
||||||
ELECTRUM_PORT: "50002"
|
|
||||||
ELECTRUM_TLS: "false"
|
|
||||||
MYSQL_HOST: "db"
|
|
||||||
MYSQL_PORT: "3306"
|
|
||||||
MYSQL_DATABASE: "mempool"
|
MYSQL_DATABASE: "mempool"
|
||||||
MYSQL_USER: "mempool"
|
MYSQL_USER: "mempool"
|
||||||
MYSQL_PASS: "mempool"
|
MYSQL_PASSWORD: "mempool"
|
||||||
BACKEND_MAINNET_HTTP_PORT: "8999"
|
MYSQL_ROOT_PASSWORD: "admin"
|
||||||
CACHE_DIR: "/backend/cache"
|
|
||||||
MEMPOOL_CLEAR_PROTECTION_MINUTES: "20"
|
|
||||||
db:
|
|
||||||
image: mariadb:10.5.8
|
image: mariadb:10.5.8
|
||||||
user: "1000:1000"
|
user: "1000:1000"
|
||||||
restart: on-failure
|
restart: on-failure
|
||||||
stop_grace_period: 1m
|
stop_grace_period: 1m
|
||||||
volumes:
|
volumes:
|
||||||
- ./mysql/data:/var/lib/mysql
|
- ./mysql/data:/var/lib/mysql
|
||||||
- ./mysql/db-scripts:/docker-entrypoint-initdb.d
|
|
||||||
environment:
|
|
||||||
MYSQL_DATABASE: "mempool"
|
|
||||||
MYSQL_USER: "mempool"
|
|
||||||
MYSQL_PASSWORD: "mempool"
|
|
||||||
MYSQL_ROOT_PASSWORD: "admin"
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
#backend
|
#backend
|
||||||
gitMaster="\.\.\/\.git\/refs\/heads\/master"
|
gitMaster="\.\.\/\.git\/refs\/heads\/master"
|
||||||
git ls-remote https://github.com/mempool/mempool.git $1 | awk '{ print $1}' > ./backend/master
|
git ls-remote https://github.com/mempool/mempool.git "$1^{}" | awk '{ print $1}' > ./backend/master
|
||||||
cp ./docker/backend/* ./backend/
|
cp ./docker/backend/* ./backend/
|
||||||
sed -i "s/${gitMaster}/master/g" ./backend/src/api/backend-info.ts
|
sed -i "s/${gitMaster}/master/g" ./backend/src/api/backend-info.ts
|
||||||
|
|
||||||
|
|||||||
0
docker/mysql/data/.gitkeep
Normal file
0
docker/mysql/data/.gitkeep
Normal file
2
frontend/.gitignore
vendored
2
frontend/.gitignore
vendored
@@ -50,6 +50,8 @@ Thumbs.db
|
|||||||
|
|
||||||
src/resources/assets.json
|
src/resources/assets.json
|
||||||
src/resources/assets.minimal.json
|
src/resources/assets.minimal.json
|
||||||
|
src/resources/assets-testnet.json
|
||||||
|
src/resources/assets-testnet.minimal.json
|
||||||
src/resources/pools.json
|
src/resources/pools.json
|
||||||
|
|
||||||
# environment config
|
# environment config
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
describe('Bisq', () => {
|
describe('Bisq', () => {
|
||||||
const baseModule = Cypress.env("BASE_MODULE");
|
const baseModule = Cypress.env("BASE_MODULE");
|
||||||
const basePath = (baseModule === 'bisq') ? '' : '/bisq';
|
const basePath = '';
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.intercept('/sockjs-node/info*').as('socket');
|
cy.intercept('/sockjs-node/info*').as('socket');
|
||||||
@@ -23,7 +23,7 @@ describe('Bisq', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
if (baseModule === 'mempool' || baseModule === 'bisq') {
|
if (baseModule === 'bisq') {
|
||||||
|
|
||||||
it('loads the dashboard', () => {
|
it('loads the dashboard', () => {
|
||||||
cy.visit(`${basePath}`);
|
cy.visit(`${basePath}`);
|
||||||
@@ -59,9 +59,8 @@ describe('Bisq', () => {
|
|||||||
cy.visit(`${basePath}`);
|
cy.visit(`${basePath}`);
|
||||||
cy.waitForSkeletonGone();
|
cy.waitForSkeletonGone();
|
||||||
cy.get('li:nth-of-type(5) > a').click().then(() => {
|
cy.get('li:nth-of-type(5) > a').click().then(() => {
|
||||||
cy.get('.card').should('have.length.at.least', 1);
|
cy.get('.section-header').should('have.length.at.least', 1);
|
||||||
cy.get('.card').first().click();
|
cy.get('.endpoint-container').should('have.length.at.least', 1);
|
||||||
cy.get('.card-body');
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
describe('Liquid', () => {
|
describe('Liquid', () => {
|
||||||
const baseModule = Cypress.env("BASE_MODULE");
|
const baseModule = Cypress.env("BASE_MODULE");
|
||||||
const basePath = (baseModule === 'liquid') ? '' : '/liquid';
|
const basePath = '';
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.intercept('/liquid/api/block/**').as('block');
|
cy.intercept('/liquid/api/block/**').as('block');
|
||||||
@@ -16,7 +16,7 @@ describe('Liquid', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
if (baseModule === 'mempool' || baseModule === 'liquid') {
|
if (baseModule === 'liquid') {
|
||||||
|
|
||||||
it('check first mempool block after skeleton loads', () => {
|
it('check first mempool block after skeleton loads', () => {
|
||||||
cy.visit(`${basePath}`);
|
cy.visit(`${basePath}`);
|
||||||
|
|||||||
@@ -296,9 +296,7 @@ describe('Mainnet', () => {
|
|||||||
|
|
||||||
cy.changeNetwork("testnet");
|
cy.changeNetwork("testnet");
|
||||||
cy.changeNetwork("signet");
|
cy.changeNetwork("signet");
|
||||||
cy.changeNetwork("liquid");
|
|
||||||
cy.changeNetwork("mainnet");
|
cy.changeNetwork("mainnet");
|
||||||
cy.changeNetwork("bisq");
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it.skip('loads the dashboard with the skeleton blocks', () => {
|
it.skip('loads the dashboard with the skeleton blocks', () => {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
"TESTNET_ENABLED": false,
|
"TESTNET_ENABLED": false,
|
||||||
"SIGNET_ENABLED": false,
|
"SIGNET_ENABLED": false,
|
||||||
"LIQUID_ENABLED": false,
|
"LIQUID_ENABLED": false,
|
||||||
|
"LIQUID_TESTNET_ENABLED": false,
|
||||||
"BISQ_ENABLED": false,
|
"BISQ_ENABLED": false,
|
||||||
"BISQ_SEPARATE_BACKEND": false,
|
"BISQ_SEPARATE_BACKEND": false,
|
||||||
"ITEMS_PER_PAGE": 10,
|
"ITEMS_PER_PAGE": 10,
|
||||||
@@ -9,7 +10,10 @@
|
|||||||
"NGINX_PROTOCOL": "http",
|
"NGINX_PROTOCOL": "http",
|
||||||
"NGINX_HOSTNAME": "127.0.0.1",
|
"NGINX_HOSTNAME": "127.0.0.1",
|
||||||
"NGINX_PORT": "80",
|
"NGINX_PORT": "80",
|
||||||
"MEMPOOL_BLOCKS_AMOUNT": 8,
|
|
||||||
"BLOCK_WEIGHT_UNITS": 4000000,
|
"BLOCK_WEIGHT_UNITS": 4000000,
|
||||||
"BASE_MODULE": "mempool"
|
"MEMPOOL_BLOCKS_AMOUNT": 8,
|
||||||
|
"BASE_MODULE": "mempool",
|
||||||
|
"MEMPOOL_WEBSITE_URL": "https://mempool.space",
|
||||||
|
"LIQUID_WEBSITE_URL": "https://liquid.network",
|
||||||
|
"BISQ_WEBSITE_URL": "https://bisq.markets"
|
||||||
}
|
}
|
||||||
|
|||||||
4327
frontend/package-lock.json
generated
4327
frontend/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -34,7 +34,10 @@
|
|||||||
"sync-assets": "node sync-assets.js && rsync -av ./dist/mempool/browser/en-US/resources ./dist/mempool/browser/resources",
|
"sync-assets": "node sync-assets.js && rsync -av ./dist/mempool/browser/en-US/resources ./dist/mempool/browser/resources",
|
||||||
"sync-assets-dev": "node sync-assets.js dev",
|
"sync-assets-dev": "node sync-assets.js dev",
|
||||||
"generate-config": "node generate-config.js",
|
"generate-config": "node generate-config.js",
|
||||||
"build-mempool.js": "tsc | browserify -p tinyify ./node_modules/@mempool/mempool.js/lib/index.js --standalone mempoolJS > ./dist/mempool/browser/en-US/mempool.js",
|
"build-mempool.js": "npm run build-mempool-js && npm run build-mempool-liquid-js && npm run build-mempool-bisq-js",
|
||||||
|
"build-mempool-js": "browserify -p tinyify ./node_modules/@mempool/mempool.js/lib/index.js --standalone mempoolJS > ./dist/mempool/browser/en-US/mempool.js",
|
||||||
|
"build-mempool-bisq-js": "browserify -p tinyify ./node_modules/@mempool/mempool.js/lib/index-bisq.js --standalone bisqJS > ./dist/mempool/browser/en-US/bisq.js",
|
||||||
|
"build-mempool-liquid-js": "browserify -p tinyify ./node_modules/@mempool/mempool.js/lib/index-liquid.js --standalone liquidJS > ./dist/mempool/browser/en-US/liquid.js",
|
||||||
"test": "ng test",
|
"test": "ng test",
|
||||||
"lint": "ng lint",
|
"lint": "ng lint",
|
||||||
"e2e": "npm run generate-config && ng e2e",
|
"e2e": "npm run generate-config && ng e2e",
|
||||||
@@ -53,25 +56,25 @@
|
|||||||
"cypress:run:ci": "node update-config.js TESTNET_ENABLED=true SIGNET_ENABLED=true LIQUID_ENABLED=true BISQ_ENABLED=true ITEMS_PER_PAGE=25 && npm run generate-config && start-server-and-test serve:local-prod 4200 cypress:run:record"
|
"cypress:run:ci": "node update-config.js TESTNET_ENABLED=true SIGNET_ENABLED=true LIQUID_ENABLED=true BISQ_ENABLED=true ITEMS_PER_PAGE=25 && npm run generate-config && start-server-and-test serve:local-prod 4200 cypress:run:record"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@angular-devkit/build-angular": "^13.0.4",
|
"@angular-devkit/build-angular": "^13.1.2",
|
||||||
"@angular/animations": "~13.0.3",
|
"@angular/animations": "~13.1.1",
|
||||||
"@angular/cli": "~13.0.4",
|
"@angular/cli": "~13.0.4",
|
||||||
"@angular/common": "~13.0.3",
|
"@angular/common": "~13.1.1",
|
||||||
"@angular/compiler": "~13.0.3",
|
"@angular/compiler": "~13.1.1",
|
||||||
"@angular/core": "~13.0.3",
|
"@angular/core": "~13.1.1",
|
||||||
"@angular/forms": "~13.0.3",
|
"@angular/forms": "~13.1.1",
|
||||||
"@angular/localize": "^13.0.3",
|
"@angular/localize": "^13.1.1",
|
||||||
"@angular/platform-browser": "~13.0.3",
|
"@angular/platform-browser": "~13.1.1",
|
||||||
"@angular/platform-browser-dynamic": "~13.0.3",
|
"@angular/platform-browser-dynamic": "~13.1.1",
|
||||||
"@angular/platform-server": "~13.0.3",
|
"@angular/platform-server": "~13.1.1",
|
||||||
"@angular/router": "~13.0.3",
|
"@angular/router": "~13.1.1",
|
||||||
"@fortawesome/angular-fontawesome": "^0.8.2",
|
"@fortawesome/angular-fontawesome": "^0.8.2",
|
||||||
"@fortawesome/fontawesome-common-types": "^0.2.35",
|
"@fortawesome/fontawesome-common-types": "^0.2.35",
|
||||||
"@fortawesome/fontawesome-svg-core": "^1.2.35",
|
"@fortawesome/fontawesome-svg-core": "^1.2.35",
|
||||||
"@fortawesome/free-solid-svg-icons": "^5.15.3",
|
"@fortawesome/free-solid-svg-icons": "^5.15.3",
|
||||||
"@juggle/resize-observer": "^3.3.1",
|
"@juggle/resize-observer": "^3.3.1",
|
||||||
"@mempool/mempool.js": "^2.2.4",
|
"@mempool/mempool.js": "2.3.0",
|
||||||
"@ng-bootstrap/ng-bootstrap": "^10.0.0",
|
"@ng-bootstrap/ng-bootstrap": "^11.0.0",
|
||||||
"@nguniversal/express-engine": "11.2.1",
|
"@nguniversal/express-engine": "11.2.1",
|
||||||
"@types/qrcode": "1.4.1",
|
"@types/qrcode": "1.4.1",
|
||||||
"bootstrap": "4.5.0",
|
"bootstrap": "4.5.0",
|
||||||
@@ -92,8 +95,8 @@
|
|||||||
"zone.js": "~0.11.4"
|
"zone.js": "~0.11.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@angular/compiler-cli": "~13.0.3",
|
"@angular/compiler-cli": "~13.1.1",
|
||||||
"@angular/language-service": "~13.0.3",
|
"@angular/language-service": "~13.1.1",
|
||||||
"@nguniversal/builders": "^11.2.1",
|
"@nguniversal/builders": "^11.2.1",
|
||||||
"@types/express": "^4.17.0",
|
"@types/express": "^4.17.0",
|
||||||
"@types/jasmine": "~3.6.0",
|
"@types/jasmine": "~3.6.0",
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ PROXY_CONFIG = [
|
|||||||
'/api/**', '!/api/v1/ws',
|
'/api/**', '!/api/v1/ws',
|
||||||
'!/bisq', '!/bisq/**', '!/bisq/',
|
'!/bisq', '!/bisq/**', '!/bisq/',
|
||||||
'!/liquid', '!/liquid/**', '!/liquid/',
|
'!/liquid', '!/liquid/**', '!/liquid/',
|
||||||
|
'!/liquidtestnet', '!/liquidtestnet/**', '!/liquidtestnet/',
|
||||||
'/testnet/api/**', '/signet/api/**'
|
'/testnet/api/**', '/signet/api/**'
|
||||||
],
|
],
|
||||||
target: "https://mempool.space",
|
target: "https://mempool.space",
|
||||||
@@ -57,6 +58,16 @@ PROXY_CONFIG = [
|
|||||||
ws: true,
|
ws: true,
|
||||||
secure: false,
|
secure: false,
|
||||||
changeOrigin: true
|
changeOrigin: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
context: ['/api/liquidtestnet**', '/liquidtestnet/api/**'],
|
||||||
|
target: "https://liquid.network/testnet",
|
||||||
|
pathRewrite: {
|
||||||
|
"^/api/liquidtestnet/": "/liquidtestnet/api"
|
||||||
|
},
|
||||||
|
ws: true,
|
||||||
|
secure: false,
|
||||||
|
changeOrigin: true
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -105,91 +105,6 @@ let routes: Routes = [
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
|
||||||
path: 'liquid',
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
path: '',
|
|
||||||
component: MasterPageComponent,
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
path: 'tx/push',
|
|
||||||
component: PushTransactionComponent,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '',
|
|
||||||
component: StartComponent,
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
path: '',
|
|
||||||
component: DashboardComponent
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'tx/:id',
|
|
||||||
component: TransactionComponent
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'block/:id',
|
|
||||||
component: BlockComponent
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'mempool-block/:id',
|
|
||||||
component: MempoolBlockComponent
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'blocks',
|
|
||||||
component: LatestBlocksComponent,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'graphs',
|
|
||||||
component: StatisticsComponent,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'address/:id',
|
|
||||||
component: AddressComponent
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'asset/:id',
|
|
||||||
component: AssetComponent
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'assets',
|
|
||||||
component: AssetsComponent,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'docs/api/:type',
|
|
||||||
component: DocsComponent
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'docs/api',
|
|
||||||
redirectTo: 'docs/api/rest'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'docs',
|
|
||||||
redirectTo: 'docs/api/rest'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'api',
|
|
||||||
redirectTo: 'docs/api/rest'
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'tv',
|
|
||||||
component: TelevisionComponent
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'status',
|
|
||||||
component: StatusViewComponent
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '**',
|
|
||||||
redirectTo: ''
|
|
||||||
},
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
path: 'testnet',
|
path: 'testnet',
|
||||||
children: [
|
children: [
|
||||||
@@ -346,11 +261,6 @@ let routes: Routes = [
|
|||||||
},
|
},
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
|
||||||
path: 'bisq',
|
|
||||||
component: MasterPageComponent,
|
|
||||||
loadChildren: () => import('./bisq/bisq.module').then(m => m.BisqModule)
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
path: 'tv',
|
path: 'tv',
|
||||||
component: TelevisionComponent,
|
component: TelevisionComponent,
|
||||||
@@ -466,6 +376,94 @@ if (browserWindowEnv && browserWindowEnv.BASE_MODULE === 'liquid') {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: 'testnet',
|
||||||
|
component: LiquidMasterPageComponent,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: '',
|
||||||
|
component: StartComponent,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: '',
|
||||||
|
component: DashboardComponent
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'tx/push',
|
||||||
|
component: PushTransactionComponent,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'tx/:id',
|
||||||
|
component: TransactionComponent
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'block/:id',
|
||||||
|
component: BlockComponent
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'mempool-block/:id',
|
||||||
|
component: MempoolBlockComponent
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'blocks',
|
||||||
|
component: LatestBlocksComponent,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'graphs',
|
||||||
|
component: StatisticsComponent,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'address/:id',
|
||||||
|
component: AddressComponent
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'asset/:id',
|
||||||
|
component: AssetComponent
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'assets',
|
||||||
|
component: AssetsComponent,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'docs/api/:type',
|
||||||
|
component: DocsComponent
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'docs/api',
|
||||||
|
redirectTo: 'docs/api/rest'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'docs',
|
||||||
|
redirectTo: 'docs/api/rest'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'api',
|
||||||
|
redirectTo: 'docs/api/rest'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'about',
|
||||||
|
component: AboutComponent,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'terms-of-service',
|
||||||
|
component: TermsOfServiceComponent
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'privacy-policy',
|
||||||
|
component: PrivacyPolicyComponent
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'trademark-policy',
|
||||||
|
component: TrademarkPolicyComponent
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'sponsor',
|
||||||
|
component: SponsorComponent,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: 'tv',
|
path: 'tv',
|
||||||
component: TelevisionComponent
|
component: TelevisionComponent
|
||||||
|
|||||||
@@ -48,17 +48,20 @@ import { FeesBoxComponent } from './components/fees-box/fees-box.component';
|
|||||||
import { DashboardComponent } from './dashboard/dashboard.component';
|
import { DashboardComponent } from './dashboard/dashboard.component';
|
||||||
import { FontAwesomeModule, FaIconLibrary } from '@fortawesome/angular-fontawesome';
|
import { FontAwesomeModule, FaIconLibrary } from '@fortawesome/angular-fontawesome';
|
||||||
import { faFilter, faAngleDown, faAngleUp, faAngleRight, faAngleLeft, faBolt, faChartArea, faCogs, faCubes, faDatabase, faExchangeAlt, faInfoCircle,
|
import { faFilter, faAngleDown, faAngleUp, faAngleRight, faAngleLeft, faBolt, faChartArea, faCogs, faCubes, faDatabase, faExchangeAlt, faInfoCircle,
|
||||||
faLink, faList, faSearch, faCaretUp, faCaretDown, faTachometerAlt, faThList, faTint, faTv, faAngleDoubleDown, faSortUp, faAngleDoubleUp, faChevronDown, faFileAlt, faRedoAlt, faArrowAltCircleRight, faExternalLinkAlt, faBook } from '@fortawesome/free-solid-svg-icons';
|
faLink, faList, faSearch, faCaretUp, faCaretDown, faTachometerAlt, faThList, faTint, faTv, faAngleDoubleDown, faSortUp, faAngleDoubleUp, faChevronDown, faFileAlt, faRedoAlt, faArrowAltCircleRight, faExternalLinkAlt, faBook, faListUl } from '@fortawesome/free-solid-svg-icons';
|
||||||
import { ApiDocsComponent } from './components/docs/api-docs.component';
|
import { ApiDocsComponent } from './components/docs/api-docs.component';
|
||||||
import { DocsComponent } from './components/docs/docs.component';
|
import { DocsComponent } from './components/docs/docs.component';
|
||||||
|
import { ApiDocsNavComponent } from './components/docs/api-docs-nav.component';
|
||||||
import { CodeTemplateComponent } from './components/docs/code-template.component';
|
import { CodeTemplateComponent } from './components/docs/code-template.component';
|
||||||
import { TermsOfServiceComponent } from './components/terms-of-service/terms-of-service.component';
|
import { TermsOfServiceComponent } from './components/terms-of-service/terms-of-service.component';
|
||||||
import { PrivacyPolicyComponent } from './components/privacy-policy/privacy-policy.component';
|
import { PrivacyPolicyComponent } from './components/privacy-policy/privacy-policy.component';
|
||||||
import { TrademarkPolicyComponent } from './components/trademark-policy/trademark-policy.component';
|
import { TrademarkPolicyComponent } from './components/trademark-policy/trademark-policy.component';
|
||||||
import { StorageService } from './services/storage.service';
|
import { StorageService } from './services/storage.service';
|
||||||
import { HttpCacheInterceptor } from './services/http-cache.interceptor';
|
import { HttpCacheInterceptor } from './services/http-cache.interceptor';
|
||||||
|
import { LanguageService } from './services/language.service';
|
||||||
import { SponsorComponent } from './components/sponsor/sponsor.component';
|
import { SponsorComponent } from './components/sponsor/sponsor.component';
|
||||||
import { PushTransactionComponent } from './components/push-transaction/push-transaction.component';
|
import { PushTransactionComponent } from './components/push-transaction/push-transaction.component';
|
||||||
|
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
@@ -102,6 +105,7 @@ import { PushTransactionComponent } from './components/push-transaction/push-tra
|
|||||||
SponsorComponent,
|
SponsorComponent,
|
||||||
PushTransactionComponent,
|
PushTransactionComponent,
|
||||||
DocsComponent,
|
DocsComponent,
|
||||||
|
ApiDocsNavComponent,
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
BrowserModule.withServerTransition({ appId: 'serverApp' }),
|
BrowserModule.withServerTransition({ appId: 'serverApp' }),
|
||||||
@@ -111,6 +115,7 @@ import { PushTransactionComponent } from './components/push-transaction/push-tra
|
|||||||
BrowserAnimationsModule,
|
BrowserAnimationsModule,
|
||||||
InfiniteScrollModule,
|
InfiniteScrollModule,
|
||||||
NgbTypeaheadModule,
|
NgbTypeaheadModule,
|
||||||
|
NgbModule,
|
||||||
FontAwesomeModule,
|
FontAwesomeModule,
|
||||||
SharedModule,
|
SharedModule,
|
||||||
NgxEchartsModule.forRoot({
|
NgxEchartsModule.forRoot({
|
||||||
@@ -124,6 +129,7 @@ import { PushTransactionComponent } from './components/push-transaction/push-tra
|
|||||||
AudioService,
|
AudioService,
|
||||||
SeoService,
|
SeoService,
|
||||||
StorageService,
|
StorageService,
|
||||||
|
LanguageService,
|
||||||
{ provide: HTTP_INTERCEPTORS, useClass: HttpCacheInterceptor, multi: true }
|
{ provide: HTTP_INTERCEPTORS, useClass: HttpCacheInterceptor, multi: true }
|
||||||
],
|
],
|
||||||
bootstrap: [AppComponent]
|
bootstrap: [AppComponent]
|
||||||
@@ -161,5 +167,6 @@ export class AppModule {
|
|||||||
library.addIcons(faAngleRight);
|
library.addIcons(faAngleRight);
|
||||||
library.addIcons(faAngleLeft);
|
library.addIcons(faAngleLeft);
|
||||||
library.addIcons(faBook);
|
library.addIcons(faBook);
|
||||||
|
library.addIcons(faListUl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { ActivatedRoute, Router } from '@angular/router';
|
|||||||
import { merge, combineLatest, Observable } from 'rxjs';
|
import { merge, combineLatest, Observable } from 'rxjs';
|
||||||
import { AssetExtended } from '../interfaces/electrs.interface';
|
import { AssetExtended } from '../interfaces/electrs.interface';
|
||||||
import { SeoService } from '../services/seo.service';
|
import { SeoService } from '../services/seo.service';
|
||||||
|
import { StateService } from '../services/state.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-assets',
|
selector: 'app-assets',
|
||||||
@@ -15,7 +16,8 @@ import { SeoService } from '../services/seo.service';
|
|||||||
changeDetection: ChangeDetectionStrategy.OnPush
|
changeDetection: ChangeDetectionStrategy.OnPush
|
||||||
})
|
})
|
||||||
export class AssetsComponent implements OnInit {
|
export class AssetsComponent implements OnInit {
|
||||||
nativeAssetId = environment.nativeAssetId;
|
nativeAssetId = this.stateService.network === 'liquidtestnet' ? environment.nativeTestAssetId : environment.nativeAssetId;
|
||||||
|
|
||||||
assets: AssetExtended[];
|
assets: AssetExtended[];
|
||||||
assetsCache: AssetExtended[];
|
assetsCache: AssetExtended[];
|
||||||
searchForm: FormGroup;
|
searchForm: FormGroup;
|
||||||
@@ -34,6 +36,7 @@ export class AssetsComponent implements OnInit {
|
|||||||
private route: ActivatedRoute,
|
private route: ActivatedRoute,
|
||||||
private router: Router,
|
private router: Router,
|
||||||
private seoService: SeoService,
|
private seoService: SeoService,
|
||||||
|
private stateService: StateService,
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
@@ -52,12 +55,22 @@ export class AssetsComponent implements OnInit {
|
|||||||
take(1),
|
take(1),
|
||||||
mergeMap(([assets, qp]) => {
|
mergeMap(([assets, qp]) => {
|
||||||
this.assets = Object.values(assets);
|
this.assets = Object.values(assets);
|
||||||
|
if (this.stateService.network === 'liquid') {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
this.assets.push({
|
this.assets.push({
|
||||||
name: 'Liquid Bitcoin',
|
name: 'Liquid Bitcoin',
|
||||||
ticker: 'L-BTC',
|
ticker: 'L-BTC',
|
||||||
asset_id: this.nativeAssetId,
|
asset_id: this.nativeAssetId,
|
||||||
});
|
});
|
||||||
|
} else if (this.stateService.network === 'liquidtestnet') {
|
||||||
|
// @ts-ignore
|
||||||
|
this.assets.push({
|
||||||
|
name: 'Test Liquid Bitcoin',
|
||||||
|
ticker: 'tL-BTC',
|
||||||
|
asset_id: this.nativeAssetId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
this.assets = this.assets.sort((a: any, b: any) => a.name.localeCompare(b.name));
|
this.assets = this.assets.sort((a: any, b: any) => a.name.localeCompare(b.name));
|
||||||
this.assetsCache = this.assets;
|
this.assetsCache = this.assets;
|
||||||
this.searchForm.get('searchText').enable();
|
this.searchForm.get('searchText').enable();
|
||||||
|
|||||||
@@ -105,10 +105,12 @@
|
|||||||
</ng-container>
|
</ng-container>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<app-language-selector *ngIf="stateService.env.BASE_MODULE !== 'bisq'"></app-language-selector>
|
<app-language-selector></app-language-selector>
|
||||||
|
|
||||||
<div class="text-small text-center mt-3">
|
<div class="text-small text-center mt-3">
|
||||||
<a [routerLink]="['/terms-of-service']" i18n="shared.terms-of-service|Terms of Service">Terms of Service</a>
|
<a [routerLink]="['/terms-of-service']" i18n="shared.terms-of-service|Terms of Service">Terms of Service</a>
|
||||||
|
|
|
||||||
|
<a [routerLink]="['/privacy-policy']" i18n="shared.privacy-policy|Privacy Policy">Privacy Policy</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ export class BisqMainDashboardComponent implements OnInit {
|
|||||||
) { }
|
) { }
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.seoService.setTitle(`Markets`);
|
this.seoService.resetTitle();
|
||||||
this.websocketService.want(['blocks']);
|
this.websocketService.want(['blocks']);
|
||||||
|
|
||||||
this.usdPrice$ = this.stateService.conversions$.asObservable().pipe(
|
this.usdPrice$ = this.stateService.conversions$.asObservable().pipe(
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<span style="margin-left: auto; margin-right: -20px; margin-bottom: -20px">™</span>
|
<span style="margin-left: auto; margin-right: -20px; margin-bottom: -20px">™</span>
|
||||||
<img class="logo" src="./resources/mempool-logo-bigger.png" />
|
<img class="logo" src="./resources/mempool-logo-bigger.png" />
|
||||||
<div class="version">
|
<div class="version">
|
||||||
v{{ packetJsonVersion }} [{{ frontendGitCommitHash }}]
|
v{{ packetJsonVersion }} [<a href="https://github.com/mempool/mempool/commit/{{ frontendGitCommitHash }}">{{ frontendGitCommitHash }}</a>]
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -23,12 +23,12 @@
|
|||||||
<a target="_blank" href="https://twitter.com/mempool">
|
<a target="_blank" href="https://twitter.com/mempool">
|
||||||
<svg aria-hidden="true" focusable="false" data-prefix="fab" data-icon="twitter" class="svg-inline--fa fa-twitter fa-w-16 fa-4x" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M459.37 151.716c.325 4.548.325 9.097.325 13.645 0 138.72-105.583 298.558-298.558 298.558-59.452 0-114.68-17.219-161.137-47.106 8.447.974 16.568 1.299 25.34 1.299 49.055 0 94.213-16.568 130.274-44.832-46.132-.975-84.792-31.188-98.112-72.772 6.498.974 12.995 1.624 19.818 1.624 9.421 0 18.843-1.3 27.614-3.573-48.081-9.747-84.143-51.98-84.143-102.985v-1.299c13.969 7.797 30.214 12.67 47.431 13.319-28.264-18.843-46.781-51.005-46.781-87.391 0-19.492 5.197-37.36 14.294-52.954 51.655 63.675 129.3 105.258 216.365 109.807-1.624-7.797-2.599-15.918-2.599-24.04 0-57.828 46.782-104.934 104.934-104.934 30.213 0 57.502 12.67 76.67 33.137 23.715-4.548 46.456-13.32 66.599-25.34-7.798 24.366-24.366 44.833-46.132 57.827 21.117-2.273 41.584-8.122 60.426-16.243-14.292 20.791-32.161 39.308-52.628 54.253z"></path></svg>
|
<svg aria-hidden="true" focusable="false" data-prefix="fab" data-icon="twitter" class="svg-inline--fa fa-twitter fa-w-16 fa-4x" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M459.37 151.716c.325 4.548.325 9.097.325 13.645 0 138.72-105.583 298.558-298.558 298.558-59.452 0-114.68-17.219-161.137-47.106 8.447.974 16.568 1.299 25.34 1.299 49.055 0 94.213-16.568 130.274-44.832-46.132-.975-84.792-31.188-98.112-72.772 6.498.974 12.995 1.624 19.818 1.624 9.421 0 18.843-1.3 27.614-3.573-48.081-9.747-84.143-51.98-84.143-102.985v-1.299c13.969 7.797 30.214 12.67 47.431 13.319-28.264-18.843-46.781-51.005-46.781-87.391 0-19.492 5.197-37.36 14.294-52.954 51.655 63.675 129.3 105.258 216.365 109.807-1.624-7.797-2.599-15.918-2.599-24.04 0-57.828 46.782-104.934 104.934-104.934 30.213 0 57.502 12.67 76.67 33.137 23.715-4.548 46.456-13.32 66.599-25.34-7.798 24.366-24.366 44.833-46.132 57.827 21.117-2.273 41.584-8.122 60.426-16.243-14.292 20.791-32.161 39.308-52.628 54.253z"></path></svg>
|
||||||
</a>
|
</a>
|
||||||
<a target="_blank" href="https://t.me/mempoolspace">
|
|
||||||
<svg aria-hidden="true" focusable="false" data-prefix="fab" data-icon="telegram-plane" class="svg-inline--fa fa-telegram-plane fa-w-14 fa-4x" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path fill="currentColor" d="M446.7 98.6l-67.6 318.8c-5.1 22.5-18.4 28.1-37.3 17.5l-103-75.9-49.7 47.8c-5.5 5.5-10.1 10.1-20.7 10.1l7.4-104.9 190.9-172.5c8.3-7.4-1.8-11.5-12.9-4.1L117.8 284 16.2 252.2c-22.1-6.9-22.5-22.1 4.6-32.7L418.2 66.4c18.4-6.9 34.5 4.1 28.5 32.2z"></path></svg>
|
|
||||||
</a>
|
|
||||||
<a target="_blank" href="https://keybase.io/team/mempool">
|
<a target="_blank" href="https://keybase.io/team/mempool">
|
||||||
<svg aria-hidden="true" focusable="false" data-prefix="fab" data-icon="keybase" class="svg-inline--fa fa-keybase fa-w-14 fa-4x" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path fill="currentColor" d="M286.17 419a18 18 0 1 0 18 18 18 18 0 0 0-18-18zm111.92-147.6c-9.5-14.62-39.37-52.45-87.26-73.71q-9.1-4.06-18.38-7.27a78.43 78.43 0 0 0-47.88-104.13c-12.41-4.1-23.33-6-32.41-5.77-.6-2-1.89-11 9.4-35L198.66 32l-5.48 7.56c-8.69 12.06-16.92 23.55-24.34 34.89a51 51 0 0 0-8.29-1.25c-41.53-2.45-39-2.33-41.06-2.33-50.61 0-50.75 52.12-50.75 45.88l-2.36 36.68c-1.61 27 19.75 50.21 47.63 51.85l8.93.54a214 214 0 0 0-46.29 35.54C14 304.66 14 374 14 429.77v33.64l23.32-29.8a148.6 148.6 0 0 0 14.56 37.56c5.78 10.13 14.87 9.45 19.64 7.33 4.21-1.87 10-6.92 3.75-20.11a178.29 178.29 0 0 1-15.76-53.13l46.82-59.83-24.66 74.11c58.23-42.4 157.38-61.76 236.25-38.59 34.2 10.05 67.45.69 84.74-23.84.72-1 1.2-2.16 1.85-3.22a156.09 156.09 0 0 1 2.8 28.43c0 23.3-3.69 52.93-14.88 81.64-2.52 6.46 1.76 14.5 8.6 15.74 7.42 1.57 15.33-3.1 18.37-11.15C429 443 434 414 434 382.32c0-38.58-13-77.46-35.91-110.92zM142.37 128.58l-15.7-.93-1.39 21.79 13.13.78a93 93 0 0 0 .32 19.57l-22.38-1.34a12.28 12.28 0 0 1-11.76-12.79L107 119c1-12.17 13.87-11.27 13.26-11.32l29.11 1.73a144.35 144.35 0 0 0-7 19.17zm148.42 172.18a10.51 10.51 0 0 1-14.35-1.39l-9.68-11.49-34.42 27a8.09 8.09 0 0 1-11.13-1.08l-15.78-18.64a7.38 7.38 0 0 1 1.34-10.34l34.57-27.18-14.14-16.74-17.09 13.45a7.75 7.75 0 0 1-10.59-1s-3.72-4.42-3.8-4.53a7.38 7.38 0 0 1 1.37-10.34L214 225.19s-18.51-22-18.6-22.14a9.56 9.56 0 0 1 1.74-13.42 10.38 10.38 0 0 1 14.3 1.37l81.09 96.32a9.58 9.58 0 0 1-1.74 13.44zM187.44 419a18 18 0 1 0 18 18 18 18 0 0 0-18-18z"></path></svg>
|
<svg aria-hidden="true" focusable="false" data-prefix="fab" data-icon="keybase" class="svg-inline--fa fa-keybase fa-w-14 fa-4x" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path fill="currentColor" d="M286.17 419a18 18 0 1 0 18 18 18 18 0 0 0-18-18zm111.92-147.6c-9.5-14.62-39.37-52.45-87.26-73.71q-9.1-4.06-18.38-7.27a78.43 78.43 0 0 0-47.88-104.13c-12.41-4.1-23.33-6-32.41-5.77-.6-2-1.89-11 9.4-35L198.66 32l-5.48 7.56c-8.69 12.06-16.92 23.55-24.34 34.89a51 51 0 0 0-8.29-1.25c-41.53-2.45-39-2.33-41.06-2.33-50.61 0-50.75 52.12-50.75 45.88l-2.36 36.68c-1.61 27 19.75 50.21 47.63 51.85l8.93.54a214 214 0 0 0-46.29 35.54C14 304.66 14 374 14 429.77v33.64l23.32-29.8a148.6 148.6 0 0 0 14.56 37.56c5.78 10.13 14.87 9.45 19.64 7.33 4.21-1.87 10-6.92 3.75-20.11a178.29 178.29 0 0 1-15.76-53.13l46.82-59.83-24.66 74.11c58.23-42.4 157.38-61.76 236.25-38.59 34.2 10.05 67.45.69 84.74-23.84.72-1 1.2-2.16 1.85-3.22a156.09 156.09 0 0 1 2.8 28.43c0 23.3-3.69 52.93-14.88 81.64-2.52 6.46 1.76 14.5 8.6 15.74 7.42 1.57 15.33-3.1 18.37-11.15C429 443 434 414 434 382.32c0-38.58-13-77.46-35.91-110.92zM142.37 128.58l-15.7-.93-1.39 21.79 13.13.78a93 93 0 0 0 .32 19.57l-22.38-1.34a12.28 12.28 0 0 1-11.76-12.79L107 119c1-12.17 13.87-11.27 13.26-11.32l29.11 1.73a144.35 144.35 0 0 0-7 19.17zm148.42 172.18a10.51 10.51 0 0 1-14.35-1.39l-9.68-11.49-34.42 27a8.09 8.09 0 0 1-11.13-1.08l-15.78-18.64a7.38 7.38 0 0 1 1.34-10.34l34.57-27.18-14.14-16.74-17.09 13.45a7.75 7.75 0 0 1-10.59-1s-3.72-4.42-3.8-4.53a7.38 7.38 0 0 1 1.37-10.34L214 225.19s-18.51-22-18.6-22.14a9.56 9.56 0 0 1 1.74-13.42 10.38 10.38 0 0 1 14.3 1.37l81.09 96.32a9.58 9.58 0 0 1-1.74 13.44zM187.44 419a18 18 0 1 0 18 18 18 18 0 0 0-18-18z"></path></svg>
|
||||||
</a>
|
</a>
|
||||||
|
<a target="_blank" href="https://matrix.to/#/#mempool:bitcoin.kyoto">
|
||||||
|
<svg aria-hidden="true" focusable="false" data-prefix="fab" data-icon="matrix" class="svg-inline--fa fa-matrix fa-w-16 fa-4x" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1536 1792"><path fill="currentColor" d="M40.467 163.152v1465.696H145.92V1664H0V128h145.92v35.152zm450.757 464.64v74.14h2.069c19.79-28.356 43.717-50.215 71.483-65.575 27.765-15.656 59.963-23.336 96-23.336 34.56 0 66.165 6.795 94.818 20.086 28.652 13.293 50.216 37.22 65.28 70.893 16.246-23.926 38.4-45.194 66.166-63.507 27.766-18.314 60.848-27.472 98.954-27.472 28.948 0 55.828 3.545 80.64 10.635 24.812 7.088 45.785 18.314 63.508 33.968 17.722 15.656 31.31 35.742 41.354 60.85 9.747 25.107 14.768 55.236 14.768 90.683v366.573h-150.35V865.28c0-18.314-.59-35.741-2.068-51.987-1.476-16.247-5.316-30.426-11.52-42.24-6.499-12.112-15.656-21.563-28.062-28.653-12.405-7.088-29.242-10.634-50.214-10.634-21.268 0-38.4 4.135-51.397 12.112-12.997 8.27-23.336 18.608-30.72 31.901-7.386 12.997-12.407 27.765-14.77 44.602-2.363 16.542-3.84 33.379-3.84 50.216v305.133H692.971v-307.2c0-16.247-.294-32.197-1.18-48.149-.591-15.95-3.84-30.424-9.157-44.011-5.317-13.293-14.178-24.223-26.585-32.197-12.406-7.976-30.425-12.112-54.646-12.112-7.088 0-16.542 1.478-28.062 4.726-11.52 3.25-23.04 9.157-33.968 18.02-10.93 8.86-20.383 21.563-28.063 38.103-7.68 16.543-11.52 38.4-11.52 65.28v317.834H349.44V627.792zm1004.309 1001.056V163.152H1390.08V128H1536v1536h-145.92v-35.152z"/></svg>
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="enterprise-sponsor">
|
<div class="enterprise-sponsor">
|
||||||
@@ -102,6 +102,10 @@
|
|||||||
<img class="image" src="/resources/profile/ronindojo.png" />
|
<img class="image" src="/resources/profile/ronindojo.png" />
|
||||||
<span>RoninDojo</span>
|
<span>RoninDojo</span>
|
||||||
</a>
|
</a>
|
||||||
|
<a href="https://github.com/runcitadel/dashboard" target="_blank" title="Citadel">
|
||||||
|
<img class="image" src="/resources/profile/runcitadel.svg" />
|
||||||
|
<span>Citadel</span>
|
||||||
|
</a>
|
||||||
<a href="https://github.com/spesmilo/electrum" target="_blank" title="Electrum Wallet">
|
<a href="https://github.com/spesmilo/electrum" target="_blank" title="Electrum Wallet">
|
||||||
<img class="image" src="/resources/profile/electrum.jpg" />
|
<img class="image" src="/resources/profile/electrum.jpg" />
|
||||||
<span>Electrum</span>
|
<span>Electrum</span>
|
||||||
@@ -142,10 +146,6 @@
|
|||||||
<img class="image" src="/resources/profile/satpile.jpg" />
|
<img class="image" src="/resources/profile/satpile.jpg" />
|
||||||
<span>Satpile</span>
|
<span>Satpile</span>
|
||||||
</a>
|
</a>
|
||||||
<a href="https://github.com/btcontract/lnwallet" target="_blank" title="Bitcoin Lightning Wallet">
|
|
||||||
<img class="image" src="/resources/profile/blw.png" />
|
|
||||||
<span>BLW</span>
|
|
||||||
</a>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -178,7 +178,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="maintainers" *ngIf="contributors.core.length">
|
<div class="maintainers" *ngIf="contributors.core.length">
|
||||||
<h3 i18n="about.project_staff">Project Staff</h3>
|
<h3 i18n="about.project_members">Project Members</h3>
|
||||||
<div class="wrapper">
|
<div class="wrapper">
|
||||||
<ng-template ngFor let-contributor [ngForOf]="contributors.core">
|
<ng-template ngFor let-contributor [ngForOf]="contributors.core">
|
||||||
<a [href]="'https://github.com/' + contributor.name" target="_blank" [title]="contributor.name">
|
<a [href]="'https://github.com/' + contributor.name" target="_blank" [title]="contributor.name">
|
||||||
@@ -240,7 +240,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="footer-version" *ngIf="officialMempoolSpace">
|
<div class="footer-version" *ngIf="officialMempoolSpace">
|
||||||
{{ (backendInfo$ | async)?.hostname }} (v{{ (backendInfo$ | async )?.version }}) [{{ (backendInfo$ | async )?.gitCommit | slice:0:8 }}]
|
{{ (backendInfo$ | async)?.hostname }} (v{{ (backendInfo$ | async )?.version }}) [<a href="https://github.com/mempool/mempool/commit/{{ (backendInfo$ | async )?.gitCommit | slice:0:8 }}">{{ (backendInfo$ | async )?.gitCommit | slice:0:8 }}</a>]
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -116,7 +116,7 @@
|
|||||||
&:hover {
|
&:hover {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
img {
|
img {
|
||||||
box-shadow: 0px 0px 20px #1bd8f4;
|
transform: scale(1.1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
img, span{
|
img, span{
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ export class AddressComponent implements OnInit, OnDestroy {
|
|||||||
.pipe(
|
.pipe(
|
||||||
filter((address) => !!address),
|
filter((address) => !!address),
|
||||||
tap((address: Address) => {
|
tap((address: Address) => {
|
||||||
if (this.stateService.network === 'liquid' && /^([m-zA-HJ-NP-Z1-9]{26,35}|[a-z]{2,5}1[ac-hj-np-z02-9]{8,100}|[a-km-zA-HJ-NP-Z1-9]{80})$/.test(address.address)) {
|
if ((this.stateService.network === 'liquid' || this.stateService.network === 'liquidtestnet') && /^([m-zA-HJ-NP-Z1-9]{26,35}|[a-z]{2,5}1[ac-hj-np-z02-9]{8,100}|[a-km-zA-HJ-NP-Z1-9]{80})$/.test(address.address)) {
|
||||||
this.apiService.validateAddress$(address.address)
|
this.apiService.validateAddress$(address.address)
|
||||||
.subscribe((addressInfo) => {
|
.subscribe((addressInfo) => {
|
||||||
this.addressInfo = addressInfo;
|
this.addressInfo = addressInfo;
|
||||||
|
|||||||
@@ -2,12 +2,13 @@
|
|||||||
<span class="fiat">{{ conversions.USD * (satoshis / 100000000) | currency:'USD':'symbol':'1.2-2' }}</span>
|
<span class="fiat">{{ conversions.USD * (satoshis / 100000000) | currency:'USD':'symbol':'1.2-2' }}</span>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
<ng-template #viewFiatVin>
|
<ng-template #viewFiatVin>
|
||||||
<ng-template [ngIf]="network === 'liquid' && (satoshis === undefined || satoshis === null)" [ngIfElse]="default">
|
<ng-template [ngIf]="(network === 'liquid' || network === 'liquidtestnet') && (satoshis === undefined || satoshis === null)" [ngIfElse]="default">
|
||||||
<span i18n="shared.confidential">Confidential</span>
|
<span i18n="shared.confidential">Confidential</span>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
<ng-template #default>
|
<ng-template #default>
|
||||||
‎{{ satoshis / 100000000 | number : digitsInfo }}
|
‎{{ satoshis / 100000000 | number : digitsInfo }}
|
||||||
<span class="symbol"><ng-template [ngIf]="network === 'liquid'">L-</ng-template>
|
<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 === 'testnet'">t</ng-template>
|
||||||
<ng-template [ngIf]="network === 'signet'">s</ng-template>BTC</span>
|
<ng-template [ngIf]="network === 'signet'">s</ng-template>BTC</span>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
|||||||
@@ -31,7 +31,7 @@
|
|||||||
<td i18n="asset.issuer|Liquid Asset issuer">Issuer</td>
|
<td i18n="asset.issuer|Liquid Asset issuer">Issuer</td>
|
||||||
<td><a target="_blank" href="{{ 'http://' + assetContract[0] }}">{{ assetContract[0] }}</a></td>
|
<td><a target="_blank" href="{{ 'http://' + assetContract[0] }}">{{ assetContract[0] }}</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr *ngIf="!isNativeAsset">
|
<tr *ngIf="asset.issuance_txin">
|
||||||
<td i18n="asset.issuance-tx|Liquid Asset issuance TX">Issuance TX</td>
|
<td i18n="asset.issuance-tx|Liquid Asset issuance TX">Issuance TX</td>
|
||||||
<td><a [routerLink]="['/tx/' | relativeUrl, asset.issuance_txin.txid]">{{ asset.issuance_txin.txid | shortenString : 13 }}</a> <app-clipboard class="d-none d-sm-inline-block" [text]="asset.issuance_txin.txid"></app-clipboard></td>
|
<td><a [routerLink]="['/tx/' | relativeUrl, asset.issuance_txin.txid]">{{ asset.issuance_txin.txid | shortenString : 13 }}</a> <app-clipboard class="d-none d-sm-inline-block" [text]="asset.issuance_txin.txid"></app-clipboard></td>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -42,15 +42,15 @@
|
|||||||
<div class="col">
|
<div class="col">
|
||||||
<table class="table table-borderless table-striped">
|
<table class="table table-borderless table-striped">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr *ngIf="isNativeAsset">
|
<tr *ngIf="isNativeAsset && asset.chain_stats.peg_in_amount">
|
||||||
<td i18n="asset.pegged-in|Liquid Asset pegged-in amount">Pegged in</td>
|
<td i18n="asset.pegged-in|Liquid Asset pegged-in amount">Pegged in</td>
|
||||||
<td>{{ formatAmount(asset.chain_stats.peg_in_amount, assetContract[3]) | number: '1.0-' + assetContract[3] }} {{ assetContract[1] }}</td>
|
<td>{{ formatAmount(asset.chain_stats.peg_in_amount, assetContract[3]) | number: '1.0-' + assetContract[3] }} {{ assetContract[1] }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr *ngIf="isNativeAsset">
|
<tr *ngIf="isNativeAsset && asset.chain_stats.peg_out_amount">
|
||||||
<td i18n="asset.pegged-out|Liquid Asset pegged-out amount">Pegged out</td>
|
<td i18n="asset.pegged-out|Liquid Asset pegged-out amount">Pegged out</td>
|
||||||
<td>{{ formatAmount(asset.chain_stats.peg_out_amount, assetContract[3]) | number: '1.0-' + assetContract[3] }} {{ assetContract[1] }}</td>
|
<td>{{ formatAmount(asset.chain_stats.peg_out_amount, assetContract[3]) | number: '1.0-' + assetContract[3] }} {{ assetContract[1] }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr *ngIf="!isNativeAsset">
|
<tr *ngIf="asset.chain_stats.issued_amount">
|
||||||
<td i18n="asset.issued-amount|Liquid Asset issued amount">Issued amount</td>
|
<td i18n="asset.issued-amount|Liquid Asset issued amount">Issued amount</td>
|
||||||
<td *ngIf="!blindedIssuance; else confidentialTd">{{ formatAmount(asset.chain_stats.issued_amount, assetContract[3]) | number: '1.0-' + assetContract[3] }} {{ assetContract[1] }}</td>
|
<td *ngIf="!blindedIssuance; else confidentialTd">{{ formatAmount(asset.chain_stats.issued_amount, assetContract[3]) | number: '1.0-' + assetContract[3] }} {{ assetContract[1] }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -58,11 +58,11 @@
|
|||||||
<td i18n="asset.burned-amount|Liquid Asset burned amount">Burned amount</td>
|
<td i18n="asset.burned-amount|Liquid Asset burned amount">Burned amount</td>
|
||||||
<td *ngIf="!blindedIssuance; else confidentialTd">{{ formatAmount(asset.chain_stats.burned_amount, assetContract[3]) | number: '1.0-' + assetContract[3] }} {{ assetContract[1] }}</td>
|
<td *ngIf="!blindedIssuance; else confidentialTd">{{ formatAmount(asset.chain_stats.burned_amount, assetContract[3]) | number: '1.0-' + assetContract[3] }} {{ assetContract[1] }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr *ngIf="!isNativeAsset">
|
<tr *ngIf="asset.chain_stats.issued_amount">
|
||||||
<td i18n="asset.circulating-amount|Liquid Asset circulating amount">Circulating amount</td>
|
<td i18n="asset.circulating-amount|Liquid Asset circulating amount">Circulating amount</td>
|
||||||
<td *ngIf="!blindedIssuance; else confidentialTd">{{ formatAmount(asset.chain_stats.issued_amount - asset.chain_stats.burned_amount, assetContract[3]) | number: '1.0-' + assetContract[3] }} {{ assetContract[1] }}</td>
|
<td *ngIf="!blindedIssuance; else confidentialTd">{{ formatAmount(asset.chain_stats.issued_amount - asset.chain_stats.burned_amount, assetContract[3]) | number: '1.0-' + assetContract[3] }} {{ assetContract[1] }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr *ngIf="isNativeAsset">
|
<tr *ngIf="isNativeAsset && asset.chain_stats.peg_in_amount">
|
||||||
<td i18n="asset.circulating-amount|Liquid Asset circulating amount">Circulating amount</td>
|
<td i18n="asset.circulating-amount|Liquid Asset circulating amount">Circulating amount</td>
|
||||||
<td>{{ formatAmount(asset.chain_stats.peg_in_amount - asset.chain_stats.burned_amount - asset.chain_stats.peg_out_amount, assetContract[3]) | number: '1.0-' + assetContract[3] }} {{ assetContract[1] }}</td>
|
<td>{{ formatAmount(asset.chain_stats.peg_in_amount - asset.chain_stats.burned_amount - asset.chain_stats.peg_out_amount, assetContract[3]) | number: '1.0-' + assetContract[3] }} {{ assetContract[1] }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -78,7 +78,7 @@
|
|||||||
<div class="title-tx">
|
<div class="title-tx">
|
||||||
<h2>
|
<h2>
|
||||||
<ng-template [ngIf]="transactions?.length" i18n="asset.M_of_N">{{ (transactions?.length | number) || '?' }} of {{ txCount | number }} </ng-template>
|
<ng-template [ngIf]="transactions?.length" i18n="asset.M_of_N">{{ (transactions?.length | number) || '?' }} of {{ txCount | number }} </ng-template>
|
||||||
<ng-template [ngIf]="isNativeAsset" [ngIfElse]="defaultAsset" i18n="Liquid native asset transactions title">Peg In/Out and Burn Transactions</ng-template>
|
<ng-template [ngIf]="isNativeAsset && network === 'liquid'" [ngIfElse]="defaultAsset" i18n="Liquid native asset transactions title">Peg In/Out and Burn Transactions</ng-template>
|
||||||
<ng-template #defaultAsset i18n="Default asset transactions title">Issuance and Burn Transactions</ng-template>
|
<ng-template #defaultAsset i18n="Default asset transactions title">Issuance and Burn Transactions</ng-template>
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import { moveDec } from 'src/app/bitcoin.utils';
|
|||||||
})
|
})
|
||||||
export class AssetComponent implements OnInit, OnDestroy {
|
export class AssetComponent implements OnInit, OnDestroy {
|
||||||
network = '';
|
network = '';
|
||||||
nativeAssetId = environment.nativeAssetId;
|
nativeAssetId = this.stateService.network === 'liquidtestnet' ? environment.nativeTestAssetId : environment.nativeAssetId;
|
||||||
|
|
||||||
asset: Asset;
|
asset: Asset;
|
||||||
blindedIssuance: boolean;
|
blindedIssuance: boolean;
|
||||||
|
|||||||
@@ -10,17 +10,18 @@
|
|||||||
</ng-container>
|
</ng-container>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<div ngbDropdown (window:resize)="onResize($event)" class="dropdown-container" *ngIf="env.TESTNET_ENABLED || env.SIGNET_ENABLED || env.LIQUID_ENABLED || env.BISQ_ENABLED">
|
<div ngbDropdown (window:resize)="onResize($event)" class="dropdown-container" *ngIf="env.TESTNET_ENABLED || env.SIGNET_ENABLED || env.LIQUID_ENABLED || env.BISQ_ENABLED || env.LIQUID_TESTNET_ENABLED">
|
||||||
<button ngbDropdownToggle type="button" class="btn btn-secondary dropdown-toggle-split" aria-haspopup="true">
|
<button ngbDropdownToggle type="button" class="btn btn-secondary dropdown-toggle-split" aria-haspopup="true">
|
||||||
<img src="./resources/bisq-logo.png" style="width: 25px; height: 25px;" class="mr-1">
|
<img src="./resources/bisq-logo.png" style="width: 25px; height: 25px;" class="mr-1">
|
||||||
</button>
|
</button>
|
||||||
<div ngbDropdownMenu [ngClass]="{'dropdown-menu-right' : isMobile}">
|
<div ngbDropdownMenu [ngClass]="{'dropdown-menu-right' : isMobile}">
|
||||||
<a href="https://mempool.space" ngbDropdownItem class="mainnet"><img src="./resources/bitcoin-logo.png" style="width: 30px;" class="mr-1"> Mainnet</a>
|
<a [href]="env.MEMPOOL_WEBSITE_URL + urlLanguage" ngbDropdownItem class="mainnet"><img src="./resources/bitcoin-logo.png" style="width: 30px;" class="mr-1"> Mainnet</a>
|
||||||
<a href="https://mempool.space/signet" ngbDropdownItem *ngIf="env.SIGNET_ENABLED" class="signet"><img src="./resources/signet-logo.png" style="width: 30px;" class="mr-1"> Signet</a>
|
<a [href]="env.MEMPOOL_WEBSITE_URL + urlLanguage + '/signet'" ngbDropdownItem *ngIf="env.SIGNET_ENABLED" class="signet"><img src="./resources/signet-logo.png" style="width: 30px;" class="mr-1"> Signet</a>
|
||||||
<a href="https://mempool.space/testnet" ngbDropdownItem *ngIf="env.TESTNET_ENABLED" class="testnet"><img src="./resources/testnet-logo.png" style="width: 30px;" class="mr-1"> Testnet</a>
|
<a [href]="env.MEMPOOL_WEBSITE_URL + urlLanguage + '/testnet'" ngbDropdownItem *ngIf="env.TESTNET_ENABLED" class="testnet"><img src="./resources/testnet-logo.png" style="width: 30px;" class="mr-1"> Testnet</a>
|
||||||
<h6 class="dropdown-header" i18n="master-page.layer2-networks-header">Layer 2 Networks</h6>
|
<h6 class="dropdown-header" i18n="master-page.layer2-networks-header">Layer 2 Networks</h6>
|
||||||
<button ngbDropdownItem class="mainnet active" routerLink="/"><img src="./resources/bisq-logo.png" style="width: 30px;" class="mr-1"> Bisq</button>
|
<button ngbDropdownItem class="mainnet active" routerLink="/"><img src="./resources/bisq-logo.png" style="width: 30px;" class="mr-1"> Bisq</button>
|
||||||
<a href="https://liquid.network" ngbDropdownItem *ngIf="env.LIQUID_ENABLED" class="liquid"><img src="./resources/liquid-logo.png" style="width: 30px;" class="mr-1"> Liquid</a>
|
<a [href]="env.LIQUID_WEBSITE_URL + urlLanguage" ngbDropdownItem *ngIf="env.LIQUID_ENABLED" class="liquid"><img src="./resources/liquid-logo.png" style="width: 30px;" class="mr-1"> Liquid</a>
|
||||||
|
<a [href]="env.LIQUID_WEBSITE_URL + urlLanguage + '/testnet'" ngbDropdownItem *ngIf="env.LIQUID_TESTNET_ENABLED" class="liquidtestnet"><img src="./resources/liquidtestnet-logo.png" style="width: 30px;" class="mr-1"> Liquid Testnet</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -102,6 +102,10 @@ nav {
|
|||||||
background-color: #116761;
|
background-color: #116761;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.liquidtestnet.active {
|
||||||
|
background-color: #494a4a;
|
||||||
|
}
|
||||||
|
|
||||||
.testnet.active {
|
.testnet.active {
|
||||||
background-color: #1d486f;
|
background-color: #1d486f;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import { Env, StateService } from '../../services/state.service';
|
import { Env, StateService } from '../../services/state.service';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
|
import { LanguageService } from 'src/app/services/language.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-bisq-master-page',
|
selector: 'app-bisq-master-page',
|
||||||
@@ -12,14 +13,17 @@ export class BisqMasterPageComponent implements OnInit {
|
|||||||
navCollapsed = false;
|
navCollapsed = false;
|
||||||
env: Env;
|
env: Env;
|
||||||
isMobile = window.innerWidth <= 767.98;
|
isMobile = window.innerWidth <= 767.98;
|
||||||
|
urlLanguage: string;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private stateService: StateService,
|
private stateService: StateService,
|
||||||
|
private languageService: LanguageService,
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.env = this.stateService.env;
|
this.env = this.stateService.env;
|
||||||
this.connectionState$ = this.stateService.connectionState$;
|
this.connectionState$ = this.stateService.connectionState$;
|
||||||
|
this.urlLanguage = this.languageService.getLanguageForUrl();
|
||||||
}
|
}
|
||||||
|
|
||||||
collapse(): void {
|
collapse(): void {
|
||||||
|
|||||||
@@ -81,12 +81,12 @@
|
|||||||
<ng-template [ngIf]="fees !== undefined" [ngIfElse]="loadingFees">
|
<ng-template [ngIf]="fees !== undefined" [ngIfElse]="loadingFees">
|
||||||
<tr>
|
<tr>
|
||||||
<td i18n="block.total-fees|Total fees in a block">Total fees</td>
|
<td i18n="block.total-fees|Total fees in a block">Total fees</td>
|
||||||
<td *ngIf="network !== 'liquid'; else liquidTotalFees"><app-amount [satoshis]="fees * 100000000" digitsInfo="1.2-2" [noFiat]="true"></app-amount> <span class="fiat"><app-fiat [value]="fees * 100000000" digitsInfo="1.0-0"></app-fiat></span></td>
|
<td *ngIf="network !== 'liquid' && network !== 'liquidtestnet'; else liquidTotalFees"><app-amount [satoshis]="fees * 100000000" digitsInfo="1.2-2" [noFiat]="true"></app-amount> <span class="fiat"><app-fiat [value]="fees * 100000000" digitsInfo="1.0-0"></app-fiat></span></td>
|
||||||
<ng-template #liquidTotalFees>
|
<ng-template #liquidTotalFees>
|
||||||
<td>{{ fees * 100000000 | number }} L-sat (<app-fiat [value]="fees * 100000000" digitsInfo="1.2-2"></app-fiat>)</td>
|
<td><app-amount [satoshis]="fees * 100000000" digitsInfo="1.2-2" [noFiat]="true"></app-amount> <app-fiat [value]="fees * 100000000" digitsInfo="1.2-2"></app-fiat></td>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
</tr>
|
</tr>
|
||||||
<tr *ngIf="network !== 'liquid'">
|
<tr *ngIf="network !== 'liquid' && network !== 'liquidtestnet'">
|
||||||
<td i18n="block.subsidy-and-fees|Total subsidy and fees in a block">Subsidy + fees:</td>
|
<td i18n="block.subsidy-and-fees|Total subsidy and fees in a block">Subsidy + fees:</td>
|
||||||
<td>
|
<td>
|
||||||
<app-amount [satoshis]="(blockSubsidy + fees) * 100000000" digitsInfo="1.2-2" [noFiat]="true"></app-amount> <span class="fiat"><app-fiat [value]="(blockSubsidy + fees) * 100000000" digitsInfo="1.0-0"></app-fiat></span>
|
<app-amount [satoshis]="(blockSubsidy + fees) * 100000000" digitsInfo="1.2-2" [noFiat]="true"></app-amount> <span class="fiat"><app-fiat [value]="(blockSubsidy + fees) * 100000000" digitsInfo="1.0-0"></app-fiat></span>
|
||||||
@@ -98,7 +98,7 @@
|
|||||||
<td i18n="block.total-fees|Total fees in a block">Total fees</td>
|
<td i18n="block.total-fees|Total fees in a block">Total fees</td>
|
||||||
<td style="width: 75%;"><span class="skeleton-loader"></span></td>
|
<td style="width: 75%;"><span class="skeleton-loader"></span></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr *ngIf="network !== 'liquid'">
|
<tr *ngIf="network !== 'liquid' && network !== 'liquidtestnet'">
|
||||||
<td i18n="block.subsidy-and-fees|Total subsidy and fees in a block">Subsidy + fees:</td>
|
<td i18n="block.subsidy-and-fees|Total subsidy and fees in a block">Subsidy + fees:</td>
|
||||||
<td><span class="skeleton-loader"></span></td>
|
<td><span class="skeleton-loader"></span></td>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -125,7 +125,7 @@
|
|||||||
<td class="td-width" i18n="transaction.version">Version</td>
|
<td class="td-width" i18n="transaction.version">Version</td>
|
||||||
<td>{{ block.version | decimal2hex }} <span *ngIf="displayTaprootStatus() && hasTaproot(block.version)" class="badge badge-success ml-1" >Taproot</span></td>
|
<td>{{ block.version | decimal2hex }} <span *ngIf="displayTaprootStatus() && hasTaproot(block.version)" class="badge badge-success ml-1" >Taproot</span></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr *ngIf="network !== 'liquid'">
|
<tr *ngIf="network !== 'liquid' && network !== 'liquidtestnet'">
|
||||||
<td i18n="block.bits">Bits</td>
|
<td i18n="block.bits">Bits</td>
|
||||||
<td>{{ block.bits | decimal2hex }}</td>
|
<td>{{ block.bits | decimal2hex }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -136,7 +136,7 @@
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm" *ngIf="network !== 'liquid'">
|
<div class="col-sm" *ngIf="network !== 'liquid' && network !== 'liquidtestnet'">
|
||||||
<table class="table table-borderless table-striped">
|
<table class="table table-borderless table-striped">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import { Observable, of, Subscription } from 'rxjs';
|
|||||||
import { StateService } from '../../services/state.service';
|
import { StateService } from '../../services/state.service';
|
||||||
import { SeoService } from 'src/app/services/seo.service';
|
import { SeoService } from 'src/app/services/seo.service';
|
||||||
import { WebsocketService } from 'src/app/services/websocket.service';
|
import { WebsocketService } from 'src/app/services/websocket.service';
|
||||||
|
import { RelativeUrlPipe } from 'src/app/shared/pipes/relative-url/relative-url.pipe';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-block',
|
selector: 'app-block',
|
||||||
@@ -51,6 +52,7 @@ export class BlockComponent implements OnInit, OnDestroy {
|
|||||||
private stateService: StateService,
|
private stateService: StateService,
|
||||||
private seoService: SeoService,
|
private seoService: SeoService,
|
||||||
private websocketService: WebsocketService,
|
private websocketService: WebsocketService,
|
||||||
|
private relativeUrlPipe: RelativeUrlPipe,
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
@@ -194,7 +196,7 @@ export class BlockComponent implements OnInit, OnDestroy {
|
|||||||
if (this.showNextBlocklink) {
|
if (this.showNextBlocklink) {
|
||||||
this.navigateToNextBlock();
|
this.navigateToNextBlock();
|
||||||
} else {
|
} else {
|
||||||
this.router.navigate([(this.network && this.stateService.env.BASE_MODULE === 'mempool' ? '/' + this.network : '') + '/mempool-block/', '0']);
|
this.router.navigate([this.relativeUrlPipe.transform('/mempool-block'), '0']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -210,7 +212,7 @@ export class BlockComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setBlockSubsidy() {
|
setBlockSubsidy() {
|
||||||
if (this.network === 'liquid') {
|
if (this.network === 'liquid' || this.network === 'liquidtestnet') {
|
||||||
this.blockSubsidy = 0;
|
this.blockSubsidy = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -277,13 +279,13 @@ export class BlockComponent implements OnInit, OnDestroy {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const block = this.latestBlocks.find((b) => b.height === this.nextBlockHeight - 2);
|
const block = this.latestBlocks.find((b) => b.height === this.nextBlockHeight - 2);
|
||||||
this.router.navigate([(this.network && this.stateService.env.BASE_MODULE === 'mempool' ? '/' + this.network : '') + '/block/',
|
this.router.navigate([this.relativeUrlPipe.transform('/block/'),
|
||||||
block ? block.id : this.block.previousblockhash], { state: { data: { block, blockHeight: this.nextBlockHeight - 2 } } });
|
block ? block.id : this.block.previousblockhash], { state: { data: { block, blockHeight: this.nextBlockHeight - 2 } } });
|
||||||
}
|
}
|
||||||
|
|
||||||
navigateToNextBlock() {
|
navigateToNextBlock() {
|
||||||
const block = this.latestBlocks.find((b) => b.height === this.nextBlockHeight);
|
const block = this.latestBlocks.find((b) => b.height === this.nextBlockHeight);
|
||||||
this.router.navigate([(this.network && this.stateService.env.BASE_MODULE === 'mempool' ? '/' + this.network : '') + '/block/',
|
this.router.navigate([this.relativeUrlPipe.transform('/block/'),
|
||||||
block ? block.id : this.nextBlockHeight], { state: { data: { block, blockHeight: this.nextBlockHeight } } });
|
block ? block.id : this.nextBlockHeight], { state: { data: { block, blockHeight: this.nextBlockHeight } } });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
<div class="blocks-container blockchain-blocks-container" *ngIf="(loadingBlocks$ | async) === false; else loadingBlocksTemplate">
|
<div class="blocks-container blockchain-blocks-container" *ngIf="(loadingBlocks$ | async) === false; else loadingBlocksTemplate">
|
||||||
<div *ngFor="let block of blocks; let i = index; trackBy: trackByBlocksFn" >
|
<div *ngFor="let block of blocks; let i = index; trackBy: trackByBlocksFn" >
|
||||||
<div class="text-center bitcoin-block mined-block blockchain-blocks-{{ i }}" id="bitcoin-block-{{ block.height }}" [ngStyle]="blockStyles[i]" [class.blink-bg]="(specialBlocks[block.height] !== undefined)">
|
<div class="text-center bitcoin-block mined-block blockchain-blocks-{{ i }}" id="bitcoin-block-{{ block.height }}" [ngStyle]="blockStyles[i]" [class.blink-bg]="(specialBlocks[block.height] !== undefined)">
|
||||||
<a [routerLink]="['/block/' | relativeUrl, block.id]" [state]="{ data: { block: block } }" class="blockLink"> </a>
|
<a draggable="false" [routerLink]="['/block/' | relativeUrl, block.id]" [state]="{ data: { block: block } }"
|
||||||
|
class="blockLink" [ngClass]="{'disabled': (this.stateService.blockScrolling$ | async)}"> </a>
|
||||||
<div class="block-height">
|
<div class="block-height">
|
||||||
<a [routerLink]="['/block/' | relativeUrl, block.id]" [state]="{ data: { block: block } }">{{ block.height }}</a>
|
<a [routerLink]="['/block/' | relativeUrl, block.id]" [state]="{ data: { block: block } }">{{ block.height }}</a>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -15,6 +15,10 @@
|
|||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.blockLink.disabled {
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
.mined-block {
|
.mined-block {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0px;
|
top: 0px;
|
||||||
|
|||||||
@@ -36,18 +36,19 @@ export class BlockchainBlocksComponent implements OnInit, OnDestroy {
|
|||||||
'': ['#9339f4', '#105fb0'],
|
'': ['#9339f4', '#105fb0'],
|
||||||
bisq: ['#9339f4', '#105fb0'],
|
bisq: ['#9339f4', '#105fb0'],
|
||||||
liquid: ['#116761', '#183550'],
|
liquid: ['#116761', '#183550'],
|
||||||
|
'liquidtestnet': ['#494a4a', '#272e46'],
|
||||||
testnet: ['#1d486f', '#183550'],
|
testnet: ['#1d486f', '#183550'],
|
||||||
signet: ['#6f1d5d', '#471850'],
|
signet: ['#6f1d5d', '#471850'],
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private stateService: StateService,
|
public stateService: StateService,
|
||||||
private router: Router,
|
private router: Router,
|
||||||
private cd: ChangeDetectorRef,
|
private cd: ChangeDetectorRef,
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
if (this.stateService.network === 'liquid') {
|
if (this.stateService.network === 'liquid' || this.stateService.network === 'liquidtestnet') {
|
||||||
this.feeRounding = '1.0-1';
|
this.feeRounding = '1.0-1';
|
||||||
}
|
}
|
||||||
this.emptyBlocks.forEach((b) => this.emptyBlockStyles.push(this.getStyleForEmptyBlock(b)));
|
this.emptyBlocks.forEach((b) => this.emptyBlockStyles.push(this.getStyleForEmptyBlock(b)));
|
||||||
|
|||||||
@@ -18,6 +18,11 @@
|
|||||||
.blockchain-wrapper {
|
.blockchain-wrapper {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
height: 250px;
|
height: 250px;
|
||||||
|
|
||||||
|
-webkit-user-select: none; /* Safari */
|
||||||
|
-moz-user-select: none; /* Firefox */
|
||||||
|
-ms-user-select: none; /* IE10+/Edge */
|
||||||
|
user-select: none; /* Standard */
|
||||||
}
|
}
|
||||||
|
|
||||||
.position-container {
|
.position-container {
|
||||||
@@ -26,7 +31,7 @@
|
|||||||
top: 75px;
|
top: 75px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.position-container.liquid {
|
.position-container.liquid, .position-container.liquidtestnet {
|
||||||
left: 420px;
|
left: 420px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,7 +39,7 @@
|
|||||||
.position-container {
|
.position-container {
|
||||||
left: 95%;
|
left: 95%;
|
||||||
}
|
}
|
||||||
.position-container.liquid {
|
.position-container.liquid, .position-container.liquidtestnet {
|
||||||
left: 50%;
|
left: 50%;
|
||||||
}
|
}
|
||||||
.position-container.loading {
|
.position-container.loading {
|
||||||
|
|||||||
76
frontend/src/app/components/docs/api-docs-nav.component.html
Normal file
76
frontend/src/app/components/docs/api-docs-nav.component.html
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
<ng-template [ngIf]="network.val !== 'bisq' && network.val !== 'liquid' && network.val !== 'liquidtestnet'">
|
||||||
|
<p>General</p>
|
||||||
|
<a [routerLink]="['./']" fragment="get-difficulty-adjustment" (click)="collapseItem.toggle()">GET Difficulty Adjustment</a>
|
||||||
|
</ng-template>
|
||||||
|
|
||||||
|
<ng-template [ngIf]="network.val === 'bisq'">
|
||||||
|
<p>Markets</p>
|
||||||
|
<a [routerLink]="['./']" fragment="get-market-currencies" (click)="collapseItem.toggle()">GET Market Currencies</a>
|
||||||
|
<a [routerLink]="['./']" fragment="get-market-depth" (click)="collapseItem.toggle()">GET Market Depth</a>
|
||||||
|
<a [routerLink]="['./']" fragment="get-market-hloc" (click)="collapseItem.toggle()">GET Market HLOC</a>
|
||||||
|
<a [routerLink]="['./']" fragment="get-markets" (click)="collapseItem.toggle()">GET Markets</a>
|
||||||
|
<a [routerLink]="['./']" fragment="get-market-offers" (click)="collapseItem.toggle()">GET Market Offers</a>
|
||||||
|
<a [routerLink]="['./']" fragment="get-market-ticker" (click)="collapseItem.toggle()">GET Market Ticker</a>
|
||||||
|
<a [routerLink]="['./']" fragment="get-market-trades" (click)="collapseItem.toggle()">GET Market Trades</a>
|
||||||
|
<a [routerLink]="['./']" fragment="get-market-volumes" (click)="collapseItem.toggle()">GET Market Volumes</a>
|
||||||
|
</ng-template>
|
||||||
|
|
||||||
|
<ng-template [ngIf]="network.val === 'bisq'">
|
||||||
|
<p>General</p>
|
||||||
|
<a [routerLink]="['./']" fragment="get-stats" (click)="collapseItem.toggle()">GET Stats</a>
|
||||||
|
</ng-template>
|
||||||
|
|
||||||
|
<p>Addresses</p>
|
||||||
|
<a [routerLink]="['./']" fragment="get-address" (click)="collapseItem.toggle()">GET Address</a>
|
||||||
|
<a *ngIf="network.val !== 'bisq'" [routerLink]="['./']" fragment="get-address-transactions" (click)="collapseItem.toggle()">GET Address Transactions</a>
|
||||||
|
<a *ngIf="network.val !== 'bisq'" [routerLink]="['./']" fragment="get-address-transactions-chain" (click)="collapseItem.toggle()">GET Address Transactions Chain</a>
|
||||||
|
<a *ngIf="network.val !== 'bisq'" [routerLink]="['./']" fragment="get-address-transactions-mempool" (click)="collapseItem.toggle()">GET Address Transactions Mempool</a>
|
||||||
|
<a *ngIf="network.val !== 'bisq'" [routerLink]="['./']" fragment="get-address-utxo" (click)="collapseItem.toggle()">GET Address UTXO</a>
|
||||||
|
|
||||||
|
<ng-template [ngIf]="network.val === 'liquid' || network.val === 'liquidtestnet'">
|
||||||
|
<p>Assets</p>
|
||||||
|
<a [routerLink]="['./']" fragment="get-asset" (click)="collapseItem.toggle()">GET Asset</a>
|
||||||
|
<a [routerLink]="['./']" fragment="get-asset-transactions" (click)="collapseItem.toggle()">GET Asset Transactions</a>
|
||||||
|
<a [routerLink]="['./']" fragment="get-asset-supply" (click)="collapseItem.toggle()">GET Asset Supply</a>
|
||||||
|
<a [routerLink]="['./']" fragment="get-asset-icons" (click)="collapseItem.toggle()">GET Asset Icons</a>
|
||||||
|
<a [routerLink]="['./']" fragment="get-asset-icon" (click)="collapseItem.toggle()">GET Asset Icon</a>
|
||||||
|
</ng-template>
|
||||||
|
|
||||||
|
<p>Blocks</p>
|
||||||
|
<a [routerLink]="['./']" fragment="get-block" (click)="collapseItem.toggle()">GET Block</a>
|
||||||
|
<a *ngIf="network.val !== 'bisq'" [routerLink]="['./']" fragment="get-block-header" (click)="collapseItem.toggle()">GET Block Header</a>
|
||||||
|
<a *ngIf="network.val !== 'bisq'" [routerLink]="['./']" fragment="get-block-height" (click)="collapseItem.toggle()">GET Block Height</a>
|
||||||
|
<a *ngIf="network.val !== 'bisq'" [routerLink]="['./']" fragment="get-block-raw" (click)="collapseItem.toggle()">GET Block Raw</a>
|
||||||
|
<a *ngIf="network.val !== 'bisq'" [routerLink]="['./']" fragment="get-block-status" (click)="collapseItem.toggle()">GET Block Status</a>
|
||||||
|
<a [routerLink]="['./']" fragment="get-block-tip-height" (click)="collapseItem.toggle()">GET Block Tip Height</a>
|
||||||
|
<a *ngIf="network.val !== 'bisq'" [routerLink]="['./']" fragment="get-block-tip-hash" (click)="collapseItem.toggle()">GET Block Tip Hash</a>
|
||||||
|
<a *ngIf="network.val !== 'bisq'" [routerLink]="['./']" fragment="get-block-transaction-id" (click)="collapseItem.toggle()">GET Block Transaction ID</a>
|
||||||
|
<a *ngIf="network.val !== 'bisq'" [routerLink]="['./']" fragment="get-block-transaction-ids" (click)="collapseItem.toggle()">GET Block Transaction IDs</a>
|
||||||
|
<a *ngIf="network.val !== 'bisq'" [routerLink]="['./']" fragment="get-block-transactions" (click)="collapseItem.toggle()">GET Block Transactions</a>
|
||||||
|
<a [routerLink]="['./']" fragment="get-blocks" (click)="collapseItem.toggle()">GET Blocks</a>
|
||||||
|
|
||||||
|
<ng-template [ngIf]="network.val !== 'bisq'">
|
||||||
|
<p>Fees</p>
|
||||||
|
<a [routerLink]="['./']" fragment="get-mempool-blocks-fees" (click)="collapseItem.toggle()">GET Mempool Blocks Fees</a>
|
||||||
|
<a [routerLink]="['./']" fragment="get-recommended-fees" (click)="collapseItem.toggle()">GET Recommended Fees</a>
|
||||||
|
</ng-template>
|
||||||
|
|
||||||
|
<ng-template [ngIf]="network.val !== 'bisq'">
|
||||||
|
<p>Mempool</p>
|
||||||
|
<a [routerLink]="['./']" fragment="get-mempool" (click)="collapseItem.toggle()">GET Mempool</a>
|
||||||
|
<a [routerLink]="['./']" fragment="get-mempool-transaction-ids" (click)="collapseItem.toggle()">GET Mempool Transaction IDs</a>
|
||||||
|
<a [routerLink]="['./']" fragment="get-mempool-recent" (click)="collapseItem.toggle()">GET Mempool Recent</a>
|
||||||
|
</ng-template>
|
||||||
|
|
||||||
|
<p>Transactions</p>
|
||||||
|
<a *ngIf="network.val !== 'bisq'" [routerLink]="['./']" fragment="get-cpfp" (click)="collapseItem.toggle()">GET Children Pay for Parent</a>
|
||||||
|
<a [routerLink]="['./']" fragment="get-transaction" (click)="collapseItem.toggle()">GET Transaction</a>
|
||||||
|
<a *ngIf="network.val !== 'bisq'" [routerLink]="['./']" fragment="get-transaction-hex" (click)="collapseItem.toggle()">GET Transaction Hex</a>
|
||||||
|
<a *ngIf="network.val !== 'bisq' && network.val !== 'liquid' && network.val !== 'liquidtestnet'" [routerLink]="['./']" fragment="get-transaction-merkleblock-proof" (click)="collapseItem.toggle()">GET Transaction Merkleblock Proof</a>
|
||||||
|
<a *ngIf="network.val !== 'bisq'" [routerLink]="['./']" fragment="get-transaction-merkle-proof" (click)="collapseItem.toggle()">GET Transaction Merkle Proof</a>
|
||||||
|
<a *ngIf="network.val !== 'bisq'" [routerLink]="['./']" fragment="get-transaction-outspend" (click)="collapseItem.toggle()">GET Transaction Outspend</a>
|
||||||
|
<a *ngIf="network.val !== 'bisq'" [routerLink]="['./']" fragment="get-transaction-outspends" (click)="collapseItem.toggle()">GET Transaction Outspends</a>
|
||||||
|
<a *ngIf="network.val !== 'bisq'" [routerLink]="['./']" fragment="get-transaction-raw" (click)="collapseItem.toggle()">GET Transaction Raw</a>
|
||||||
|
<a *ngIf="network.val !== 'bisq'" [routerLink]="['./']" fragment="get-transaction-status" (click)="collapseItem.toggle()">GET Transaction Status</a>
|
||||||
|
<a *ngIf="network.val === 'bisq'" [routerLink]="['./']" fragment="get-transactions" (click)="collapseItem.toggle()">GET Transactions</a>
|
||||||
|
<a *ngIf="network.val !== 'bisq'" [routerLink]="['./']" fragment="post-transaction" (click)="collapseItem.toggle()">POST Transaction</a>
|
||||||
17
frontend/src/app/components/docs/api-docs-nav.component.scss
Normal file
17
frontend/src/app/components/docs/api-docs-nav.component.scss
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
p {
|
||||||
|
color: #4a68b9;
|
||||||
|
font-weight: 700;
|
||||||
|
margin: 10px 0;
|
||||||
|
margin: 15px 0 10px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
p:first-child {
|
||||||
|
margin-top: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: #fff;
|
||||||
|
text-decoration: none;
|
||||||
|
display: block;
|
||||||
|
margin: 5px 0;
|
||||||
|
}
|
||||||
18
frontend/src/app/components/docs/api-docs-nav.component.ts
Normal file
18
frontend/src/app/components/docs/api-docs-nav.component.ts
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import { Component, OnInit, Input } from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-api-docs-nav',
|
||||||
|
templateUrl: './api-docs-nav.component.html',
|
||||||
|
styleUrls: ['./api-docs-nav.component.scss']
|
||||||
|
})
|
||||||
|
export class ApiDocsNavComponent implements OnInit {
|
||||||
|
|
||||||
|
@Input() network: any;
|
||||||
|
@Input() collapseItem: any = { toggle: () => {} };
|
||||||
|
|
||||||
|
constructor() { }
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -3,18 +3,31 @@
|
|||||||
|
|
||||||
<div id="restAPI" *ngIf="restTabActivated">
|
<div id="restAPI" *ngIf="restTabActivated">
|
||||||
|
|
||||||
<p>Reference for the {{ network.val === '' ? 'Bitcoin' : network.val.charAt(0).toUpperCase() + network.val.slice(1) }} <ng-container i18n="api-docs.title">API service</ng-container>.</p>
|
<div id="doc-nav-desktop" class="hide-on-mobile" [ngClass]="desktopDocsNavPosition">
|
||||||
|
<app-api-docs-nav [network]="{ val: network$ | async }"></app-api-docs-nav>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="api-category" *ngIf="network.val !== 'bisq' && network.val !== 'liquid'">
|
<div class="doc-content">
|
||||||
<h4 i18n="api-docs.tab.general|API Docs tab for General">General</h4>
|
|
||||||
<ngb-accordion [closeOthers]="true" animated="true" type="dark">
|
|
||||||
|
|
||||||
<ngb-panel id="difficultyAdjustment" *ngIf="network.val !== 'liquid'">
|
<p class="hide-on-mobile no-bottom-space">Reference for the {{ network.val === '' ? 'Bitcoin' : network.val.charAt(0).toUpperCase() + network.val.slice(1) }} <ng-container i18n="api-docs.title">API service</ng-container>.</p>
|
||||||
<ng-template ngbPanelTitle>
|
|
||||||
<span>GET Difficulty Adjustment</span>
|
<div id="doc-nav-mobile" class="hide-on-desktop" *ngIf="showFloatingDocsNav">
|
||||||
</ng-template>
|
<button type="button" class="btn btn-outline-primary" (click)="collapse.toggle()" [attr.aria-expanded]="mobileMenuOpen" aria-controls="collapseExample"><fa-icon [icon]="['fas', 'list-ul']" [fixedWidth]="true"></fa-icon> {{ network.val === '' ? 'Bitcoin' : network.val.charAt(0).toUpperCase() + network.val.slice(1) }} REST API Overview</button>
|
||||||
<ng-template ngbPanelContent>
|
<div #collapse="ngbCollapse" [(ngbCollapse)]="mobileMenuOpen">
|
||||||
<div class="difficulty">
|
<div class="card">
|
||||||
|
<div class="card-body">
|
||||||
|
<app-api-docs-nav [collapseItem]="collapse" [network]="{ val: network$ | async }"></app-api-docs-nav>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="mobile-top-doc-nav" #mobileFixedApiNav class="hide-on-desktop"><app-api-docs-nav [network]="{ val: network$ | async }"></app-api-docs-nav></div>
|
||||||
|
|
||||||
|
<div class="api-category" *ngIf="network.val !== 'bisq' && network.val !== 'liquid' && network.val !== 'liquidtestnet'">
|
||||||
|
|
||||||
|
<div class="endpoint-container" id="get-difficulty-adjustment">
|
||||||
|
<a class="section-header" [routerLink]="['./']" fragment="get-difficulty-adjustment">GET Difficulty Adjustment <span>General</span></a>
|
||||||
<div class="endpoint">
|
<div class="endpoint">
|
||||||
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
||||||
<a [href]="wrapUrl(network.val, code.difficulty)" target="_blank">GET {{ baseNetworkUrl }}/api/v1/difficulty-adjustment</a>
|
<a [href]="wrapUrl(network.val, code.difficulty)" target="_blank">GET {{ baseNetworkUrl }}/api/v1/difficulty-adjustment</a>
|
||||||
@@ -25,21 +38,13 @@
|
|||||||
</div>
|
</div>
|
||||||
<app-code-template [hostname]="hostname" [code]="code.difficulty" [network]="network.val" ></app-code-template>
|
<app-code-template [hostname]="hostname" [code]="code.difficulty" [network]="network.val" ></app-code-template>
|
||||||
</div>
|
</div>
|
||||||
</ng-template>
|
|
||||||
</ngb-panel>
|
|
||||||
|
|
||||||
</ngb-accordion>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="api-category" *ngIf="network.val === 'bisq'">
|
<div class="api-category" *ngIf="network.val === 'bisq'">
|
||||||
<h4 i18n="Bisq All Markets">Markets</h4>
|
|
||||||
<ngb-accordion [closeOthers]="true" animated="true" type="dark" >
|
|
||||||
|
|
||||||
<ngb-panel id="bisqMarketsCurrencies">
|
<div class="endpoint-container" id="get-market-currencies">
|
||||||
<ng-template ngbPanelTitle>
|
<a class="section-header" [routerLink]="['./']" fragment="get-market-currencies">GET Market Currencies <span>Markets</span></a>
|
||||||
<span>GET Market Currencies</span>
|
|
||||||
</ng-template>
|
|
||||||
<ng-template ngbPanelContent>
|
|
||||||
<div class="endpoint">
|
<div class="endpoint">
|
||||||
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
||||||
<a [href]="wrapUrl(network.val, code.marketsCurrencies)" target="_blank">GET {{ baseNetworkUrl }}/api/currencies</a>
|
<a [href]="wrapUrl(network.val, code.marketsCurrencies)" target="_blank">GET {{ baseNetworkUrl }}/api/currencies</a>
|
||||||
@@ -49,14 +54,10 @@
|
|||||||
<div i18n>Provides list of available currencies for a given base currency. </div>
|
<div i18n>Provides list of available currencies for a given base currency. </div>
|
||||||
</div>
|
</div>
|
||||||
<app-code-template [hostname]="hostname" [code]="code.marketsCurrencies" [network]="network.val" ></app-code-template>
|
<app-code-template [hostname]="hostname" [code]="code.marketsCurrencies" [network]="network.val" ></app-code-template>
|
||||||
</ng-template>
|
</div>
|
||||||
</ngb-panel>
|
|
||||||
|
|
||||||
<ngb-panel id="marketDepth">
|
<div class="endpoint-container" id="get-market-depth">
|
||||||
<ng-template ngbPanelTitle>
|
<a class="section-header" [routerLink]="['./']" fragment="get-market-depth">GET Market Depth <span>Markets</span></a>
|
||||||
<span>GET Market Depth</span>
|
|
||||||
</ng-template>
|
|
||||||
<ng-template ngbPanelContent>
|
|
||||||
<div class="endpoint">
|
<div class="endpoint">
|
||||||
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
||||||
<a [href]="wrapUrl(network.val, code.marketDepth)" target="_blank">GET {{ baseNetworkUrl }}/api/depth?market=[:market]</a>
|
<a [href]="wrapUrl(network.val, code.marketDepth)" target="_blank">GET {{ baseNetworkUrl }}/api/depth?market=[:market]</a>
|
||||||
@@ -66,14 +67,10 @@
|
|||||||
<div i18n>Provides list of open offer prices for a single market.</div>
|
<div i18n>Provides list of open offer prices for a single market.</div>
|
||||||
</div>
|
</div>
|
||||||
<app-code-template [hostname]="hostname" [code]="code.marketDepth" [network]="network.val" ></app-code-template>
|
<app-code-template [hostname]="hostname" [code]="code.marketDepth" [network]="network.val" ></app-code-template>
|
||||||
</ng-template>
|
</div>
|
||||||
</ngb-panel>
|
|
||||||
|
|
||||||
<ngb-panel id="bisqMarketsHloc">
|
<div class="endpoint-container" id="get-market-hloc">
|
||||||
<ng-template ngbPanelTitle>
|
<a class="section-header" [routerLink]="['./']" fragment="get-market-hloc">GET Market HLOC <span>Markets</span></a>
|
||||||
<span>GET Market HLOC</span>
|
|
||||||
</ng-template>
|
|
||||||
<ng-template ngbPanelContent>
|
|
||||||
<div class="endpoint">
|
<div class="endpoint">
|
||||||
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
||||||
<a [href]="wrapUrl(network.val, code.marketHloc)" target="_blank">GET {{ baseNetworkUrl }}/api/hloc?market=[:market]</a>
|
<a [href]="wrapUrl(network.val, code.marketHloc)" target="_blank">GET {{ baseNetworkUrl }}/api/hloc?market=[:market]</a>
|
||||||
@@ -83,14 +80,10 @@
|
|||||||
<div i18n>Provides hi/low/open/close data for a given market. This can be used to generate a candlestick chart.</div>
|
<div i18n>Provides hi/low/open/close data for a given market. This can be used to generate a candlestick chart.</div>
|
||||||
</div>
|
</div>
|
||||||
<app-code-template [hostname]="hostname" [code]="code.marketHloc" [network]="network.val" ></app-code-template>
|
<app-code-template [hostname]="hostname" [code]="code.marketHloc" [network]="network.val" ></app-code-template>
|
||||||
</ng-template>
|
</div>
|
||||||
</ngb-panel>
|
|
||||||
|
|
||||||
<ngb-panel id="bisqMarketsMarkets">
|
<div class="endpoint-container" id="get-markets">
|
||||||
<ng-template ngbPanelTitle>
|
<a class="section-header" [routerLink]="['./']" fragment="get-markets">GET Markets <span>Markets</span></a>
|
||||||
<span>GET Markets</span>
|
|
||||||
</ng-template>
|
|
||||||
<ng-template ngbPanelContent>
|
|
||||||
<div class="endpoint">
|
<div class="endpoint">
|
||||||
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
||||||
<a [href]="wrapUrl(network.val, code.markets)" target="_blank">GET {{ baseNetworkUrl }}/api/markets</a>
|
<a [href]="wrapUrl(network.val, code.markets)" target="_blank">GET {{ baseNetworkUrl }}/api/markets</a>
|
||||||
@@ -100,14 +93,10 @@
|
|||||||
<div i18n>Provides list of available markets.</div>
|
<div i18n>Provides list of available markets.</div>
|
||||||
</div>
|
</div>
|
||||||
<app-code-template [hostname]="hostname" [code]="code.markets" [network]="network.val" ></app-code-template>
|
<app-code-template [hostname]="hostname" [code]="code.markets" [network]="network.val" ></app-code-template>
|
||||||
</ng-template>
|
</div>
|
||||||
</ngb-panel>
|
|
||||||
|
|
||||||
<ngb-panel id="bisqMarketsOffers">
|
<div class="endpoint-container" id="get-market-offers">
|
||||||
<ng-template ngbPanelTitle>
|
<a class="section-header" [routerLink]="['./']" fragment="get-market-offers">GET Market Offers <span>Markets</span></a>
|
||||||
<span>GET Market Offers</span>
|
|
||||||
</ng-template>
|
|
||||||
<ng-template ngbPanelContent>
|
|
||||||
<div class="endpoint">
|
<div class="endpoint">
|
||||||
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
||||||
<a [href]="wrapUrl(network.val, code.marketOffers)" target="_blank">GET {{ baseNetworkUrl }}/api/offers?market=[:market]</a>
|
<a [href]="wrapUrl(network.val, code.marketOffers)" target="_blank">GET {{ baseNetworkUrl }}/api/offers?market=[:market]</a>
|
||||||
@@ -117,14 +106,10 @@
|
|||||||
<div i18n>Provides list of open offer details for a single market.</div>
|
<div i18n>Provides list of open offer details for a single market.</div>
|
||||||
</div>
|
</div>
|
||||||
<app-code-template [hostname]="hostname" [code]="code.marketOffers" [network]="network.val" ></app-code-template>
|
<app-code-template [hostname]="hostname" [code]="code.marketOffers" [network]="network.val" ></app-code-template>
|
||||||
</ng-template>
|
</div>
|
||||||
</ngb-panel>
|
|
||||||
|
|
||||||
<ngb-panel id="bisqMarketsTicker">
|
<div class="endpoint-container" id="get-market-ticker">
|
||||||
<ng-template ngbPanelTitle>
|
<a class="section-header" [routerLink]="['./']" fragment="get-market-ticker">GET Market Ticker <span>Markets</span></a>
|
||||||
<span>GET Market Ticker</span>
|
|
||||||
</ng-template>
|
|
||||||
<ng-template ngbPanelContent>
|
|
||||||
<div class="endpoint">
|
<div class="endpoint">
|
||||||
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
||||||
<a [href]="wrapUrl(network.val, code.marketTicker)" target="_blank">GET {{ baseNetworkUrl }}/api/ticker?market=[:market]</a>
|
<a [href]="wrapUrl(network.val, code.marketTicker)" target="_blank">GET {{ baseNetworkUrl }}/api/ticker?market=[:market]</a>
|
||||||
@@ -134,14 +119,10 @@
|
|||||||
<div i18n>Provides 24 hour price ticker for single market or all markets</div>
|
<div i18n>Provides 24 hour price ticker for single market or all markets</div>
|
||||||
</div>
|
</div>
|
||||||
<app-code-template [hostname]="hostname" [code]="code.marketTicker" [network]="network.val" ></app-code-template>
|
<app-code-template [hostname]="hostname" [code]="code.marketTicker" [network]="network.val" ></app-code-template>
|
||||||
</ng-template>
|
</div>
|
||||||
</ngb-panel>
|
|
||||||
|
|
||||||
<ngb-panel id="bisqMarketsTrades">
|
<div class="endpoint-container" id="get-market-trades">
|
||||||
<ng-template ngbPanelTitle>
|
<a class="section-header" [routerLink]="['./']" fragment="get-market-trades">GET Market Trades <span>Markets</span></a>
|
||||||
<span>GET Market Trades</span>
|
|
||||||
</ng-template>
|
|
||||||
<ng-template ngbPanelContent>
|
|
||||||
<div class="endpoint">
|
<div class="endpoint">
|
||||||
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
||||||
<a [href]="wrapUrl(network.val, code.marketTrades)" target="_blank">GET {{ baseNetworkUrl }}/api/trades?market=[:market]&limit=[:limit]</a>
|
<a [href]="wrapUrl(network.val, code.marketTrades)" target="_blank">GET {{ baseNetworkUrl }}/api/trades?market=[:market]&limit=[:limit]</a>
|
||||||
@@ -151,14 +132,10 @@
|
|||||||
<div i18n>Provides list of completed trades for a single market.</div>
|
<div i18n>Provides list of completed trades for a single market.</div>
|
||||||
</div>
|
</div>
|
||||||
<app-code-template [hostname]="hostname" [code]="code.marketTrades" [network]="network.val" ></app-code-template>
|
<app-code-template [hostname]="hostname" [code]="code.marketTrades" [network]="network.val" ></app-code-template>
|
||||||
</ng-template>
|
</div>
|
||||||
</ngb-panel>
|
|
||||||
|
|
||||||
<ngb-panel id="bisqMarketsVolumes">
|
<div class="endpoint-container" id="get-market-volumes">
|
||||||
<ng-template ngbPanelTitle>
|
<a class="section-header" [routerLink]="['./']" fragment="get-market-volumes">GET Market Volumes <span>Markets</span></a>
|
||||||
<span>GET Market Volumes</span>
|
|
||||||
</ng-template>
|
|
||||||
<ng-template ngbPanelContent>
|
|
||||||
<div class="endpoint">
|
<div class="endpoint">
|
||||||
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
||||||
<a [href]="wrapUrl(network.val, code.marketVolumes)" target="_blank">GET {{ baseNetworkUrl }}/api/volumes?basecurrency=[:basecurrency]</a>
|
<a [href]="wrapUrl(network.val, code.marketVolumes)" target="_blank">GET {{ baseNetworkUrl }}/api/volumes?basecurrency=[:basecurrency]</a>
|
||||||
@@ -168,21 +145,14 @@
|
|||||||
<div i18n>Provides periodic volume data in terms of base currency for one or all markets.</div>
|
<div i18n>Provides periodic volume data in terms of base currency for one or all markets.</div>
|
||||||
</div>
|
</div>
|
||||||
<app-code-template [hostname]="hostname" [code]="code.marketVolumes" [network]="network.val" ></app-code-template>
|
<app-code-template [hostname]="hostname" [code]="code.marketVolumes" [network]="network.val" ></app-code-template>
|
||||||
</ng-template>
|
</div>
|
||||||
</ngb-panel>
|
|
||||||
|
|
||||||
</ngb-accordion>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="api-category" *ngIf="network.val === 'bisq'">
|
<div class="api-category" *ngIf="network.val === 'bisq'">
|
||||||
<h4 ngbNavLink i18n="api-docs.tab.bsq|API Docs tab for BSQ">General</h4>
|
|
||||||
<ngb-accordion [closeOthers]="true" animated="true" type="dark" >
|
|
||||||
|
|
||||||
<ngb-panel id="bisqStats">
|
<div class="endpoint-container" id="get-stats">
|
||||||
<ng-template ngbPanelTitle>
|
<a class="section-header" [routerLink]="['./']" fragment="get-stats">GET Stats <span>General</span></a>
|
||||||
<span>GET Stats</span>
|
|
||||||
</ng-template>
|
|
||||||
<ng-template ngbPanelContent>
|
|
||||||
<div class="endpoint">
|
<div class="endpoint">
|
||||||
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
||||||
<a [href]="wrapUrl(network.val, code.stats)" target="_blank'" target="_blank">GET {{ baseNetworkUrl }}/api/stats</a>
|
<a [href]="wrapUrl(network.val, code.stats)" target="_blank'" target="_blank">GET {{ baseNetworkUrl }}/api/stats</a>
|
||||||
@@ -192,21 +162,14 @@
|
|||||||
<div i18n>Returns statistics about all Bisq transactions.</div>
|
<div i18n>Returns statistics about all Bisq transactions.</div>
|
||||||
</div>
|
</div>
|
||||||
<app-code-template [hostname]="hostname" [code]="code.stats" [network]="network.val"></app-code-template>
|
<app-code-template [hostname]="hostname" [code]="code.stats" [network]="network.val"></app-code-template>
|
||||||
</ng-template>
|
</div>
|
||||||
</ngb-panel>
|
|
||||||
|
|
||||||
</ngb-accordion>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="api-category">
|
<div class="api-category">
|
||||||
<h4 i18n="api-docs.tab.addresses|API Docs tab for Addresses">Addresses</h4>
|
|
||||||
<ngb-accordion [closeOthers]="true" animated="true" type="dark" >
|
|
||||||
|
|
||||||
<ngb-panel id="address">
|
<div class="endpoint-container" id="get-address">
|
||||||
<ng-template ngbPanelTitle>
|
<a class="section-header" [routerLink]="['./']" fragment="get-address">GET Address <span>Addresses</span></a>
|
||||||
<span>GET Address</span>
|
|
||||||
</ng-template>
|
|
||||||
<ng-template ngbPanelContent>
|
|
||||||
<div class="endpoint">
|
<div class="endpoint">
|
||||||
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
||||||
<a [href]="wrapUrl(network.val, code.address)" target="_blank">GET {{ baseNetworkUrl }}/api/address/:address</a>
|
<a [href]="wrapUrl(network.val, code.address)" target="_blank">GET {{ baseNetworkUrl }}/api/address/:address</a>
|
||||||
@@ -216,14 +179,10 @@
|
|||||||
<div i18n>Returns details about an address. Available fields: <code>address</code>, <code>chain_stats</code>, and <code>mempool_stats</code>. {{ '{' }}chain,mempool{{ '}' }}_stats each contain an object with <code>tx_count</code>, <code>funded_txo_count</code>, <code>funded_txo_sum</code>, <code>spent_txo_count</code>, and <code>spent_txo_sum</code>.</div>
|
<div i18n>Returns details about an address. Available fields: <code>address</code>, <code>chain_stats</code>, and <code>mempool_stats</code>. {{ '{' }}chain,mempool{{ '}' }}_stats each contain an object with <code>tx_count</code>, <code>funded_txo_count</code>, <code>funded_txo_sum</code>, <code>spent_txo_count</code>, and <code>spent_txo_sum</code>.</div>
|
||||||
</div>
|
</div>
|
||||||
<app-code-template [hostname]="hostname" [code]="code.address" [network]="network.val" ></app-code-template>
|
<app-code-template [hostname]="hostname" [code]="code.address" [network]="network.val" ></app-code-template>
|
||||||
</ng-template>
|
</div>
|
||||||
</ngb-panel>
|
|
||||||
|
|
||||||
<ngb-panel *ngIf="network.val !== 'bisq'" id="addressTransactions">
|
<div class="endpoint-container" *ngIf="network.val !== 'bisq'" id="get-address-transactions">
|
||||||
<ng-template ngbPanelTitle>
|
<a class="section-header" [routerLink]="['./']" fragment="get-address-transactions">GET Address Transactions <span>Addresses</span></a>
|
||||||
<span>GET Address Transactions</span>
|
|
||||||
</ng-template>
|
|
||||||
<ng-template ngbPanelContent>
|
|
||||||
<div class="endpoint">
|
<div class="endpoint">
|
||||||
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
||||||
<a [href]="wrapUrl(network.val, code.addressTransactions)" target="_blank">GET {{ baseNetworkUrl }}/api/address/:address/txs</a>
|
<a [href]="wrapUrl(network.val, code.addressTransactions)" target="_blank">GET {{ baseNetworkUrl }}/api/address/:address/txs</a>
|
||||||
@@ -233,14 +192,10 @@
|
|||||||
<div i18n>Get transaction history for the specified address/scripthash, sorted with newest first. Returns up to 50 mempool transactions plus the first 25 confirmed transactions. You can request more confirmed transactions using <code>:last_seen_txid</code> (see below).</div>
|
<div i18n>Get transaction history for the specified address/scripthash, sorted with newest first. Returns up to 50 mempool transactions plus the first 25 confirmed transactions. You can request more confirmed transactions using <code>:last_seen_txid</code> (see below).</div>
|
||||||
</div>
|
</div>
|
||||||
<app-code-template [hostname]="hostname" [code]="code.addressTransactions" [network]="network.val" ></app-code-template>
|
<app-code-template [hostname]="hostname" [code]="code.addressTransactions" [network]="network.val" ></app-code-template>
|
||||||
</ng-template>
|
</div>
|
||||||
</ngb-panel>
|
|
||||||
|
|
||||||
<ngb-panel *ngIf="network.val !== 'bisq'" id="addressTransactionsChain">
|
<div class="endpoint-container" *ngIf="network.val !== 'bisq'" id="get-address-transactions-chain">
|
||||||
<ng-template ngbPanelTitle>
|
<a class="section-header" [routerLink]="['./']" fragment="get-address-transactions-chain">GET Address Transactions Chain <span>Addresses</span></a>
|
||||||
<span>GET Address Transactions Chain</span>
|
|
||||||
</ng-template>
|
|
||||||
<ng-template ngbPanelContent>
|
|
||||||
<div class="endpoint">
|
<div class="endpoint">
|
||||||
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
||||||
<a [href]="wrapUrl(network.val, code.addressTransactionsChain)" target="_blank">GET {{ baseNetworkUrl }}/api/address/:address/txs/chain</a>
|
<a [href]="wrapUrl(network.val, code.addressTransactionsChain)" target="_blank">GET {{ baseNetworkUrl }}/api/address/:address/txs/chain</a>
|
||||||
@@ -250,14 +205,10 @@
|
|||||||
<div i18n>Get confirmed transaction history for the specified address/scripthash, sorted with newest first. Returns 25 transactions per page. More can be requested by specifying the last txid seen by the previous query.</div>
|
<div i18n>Get confirmed transaction history for the specified address/scripthash, sorted with newest first. Returns 25 transactions per page. More can be requested by specifying the last txid seen by the previous query.</div>
|
||||||
</div>
|
</div>
|
||||||
<app-code-template [hostname]="hostname" [code]="code.addressTransactionsChain" [network]="network.val" ></app-code-template>
|
<app-code-template [hostname]="hostname" [code]="code.addressTransactionsChain" [network]="network.val" ></app-code-template>
|
||||||
</ng-template>
|
</div>
|
||||||
</ngb-panel>
|
|
||||||
|
|
||||||
<ngb-panel *ngIf="network.val !== 'bisq'" id="addressTransactionsMempool">
|
<div class="endpoint-container" *ngIf="network.val !== 'bisq'" id="get-address-transactions-mempool">
|
||||||
<ng-template ngbPanelTitle>
|
<a class="section-header" [routerLink]="['./']" fragment="get-address-transactions-mempool">GET Address Transactions Mempool <span>Addresses</span></a>
|
||||||
<span>GET Address Transactions Mempool</span>
|
|
||||||
</ng-template>
|
|
||||||
<ng-template ngbPanelContent>
|
|
||||||
<div class="endpoint">
|
<div class="endpoint">
|
||||||
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
||||||
<a [href]="wrapUrl(network.val, code.addressTransactionsMempool)" target="_blank">GET {{ baseNetworkUrl }}/api/address/:address/txs/mempool</a>
|
<a [href]="wrapUrl(network.val, code.addressTransactionsMempool)" target="_blank">GET {{ baseNetworkUrl }}/api/address/:address/txs/mempool</a>
|
||||||
@@ -267,112 +218,108 @@
|
|||||||
<div i18n>Get unconfirmed transaction history for the specified address/scripthash. Returns up to 50 transactions (no paging).</div>
|
<div i18n>Get unconfirmed transaction history for the specified address/scripthash. Returns up to 50 transactions (no paging).</div>
|
||||||
</div>
|
</div>
|
||||||
<app-code-template [hostname]="hostname" [code]="code.addressTransactionsMempool" [network]="network.val" ></app-code-template>
|
<app-code-template [hostname]="hostname" [code]="code.addressTransactionsMempool" [network]="network.val" ></app-code-template>
|
||||||
</ng-template>
|
</div>
|
||||||
</ngb-panel>
|
|
||||||
|
|
||||||
<ngb-panel *ngIf="network.val !== 'bisq'" id="addressUTXO">
|
<div class="endpoint-container" *ngIf="network.val !== 'bisq'" id="get-address-utxo">
|
||||||
<ng-template ngbPanelTitle>
|
<a class="section-header" [routerLink]="['./']" fragment="get-address-utxo">GET Address UTXO <span>Addresses</span></a>
|
||||||
<span>GET Address UTXO</span>
|
|
||||||
</ng-template>
|
|
||||||
<ng-template ngbPanelContent>
|
|
||||||
<div class="endpoint">
|
<div class="endpoint">
|
||||||
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
||||||
<a [href]="wrapUrl(network.val, code.addressUTXO)" target="_blank">GET {{ baseNetworkUrl }}/api/address/:address/utxo</a>
|
<a [href]="wrapUrl(network.val, code.addressUTXO)" target="_blank">GET {{ baseNetworkUrl }}/api/address/:address/utxo</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="description">
|
<div class="description">
|
||||||
<div class="subtitle" i18n>Description</div>
|
<div class="subtitle" i18n>Description</div>
|
||||||
<div i18n>Get the list of unspent transaction outputs associated with the address/scripthash. Available fields: <code>txid</code>, <code>vout</code>, <code>value</code>, and <code>status</code> (with the status of the funding tx).<ng-container *ngIf="network.val === 'liquid'">There is also a <code>valuecommitment</code> field that may appear in place of <code>value</code>, plus the following additional fields: <code>asset</code>/<code>assetcommitment</code>, <code>nonce</code>/<code>noncecommitment</code>, <code>surjection_proof</code>, and <code>range_proof</code>.</ng-container></div>
|
<div i18n>Get the list of unspent transaction outputs associated with the address/scripthash. Available fields: <code>txid</code>, <code>vout</code>, <code>value</code>, and <code>status</code> (with the status of the funding tx).<ng-container *ngIf="network.val === 'liquid' || network.val === 'liquidtestnet'">There is also a <code>valuecommitment</code> field that may appear in place of <code>value</code>, plus the following additional fields: <code>asset</code>/<code>assetcommitment</code>, <code>nonce</code>/<code>noncecommitment</code>, <code>surjection_proof</code>, and <code>range_proof</code>.</ng-container></div>
|
||||||
</div>
|
</div>
|
||||||
<app-code-template [hostname]="hostname" [code]="code.addressUTXO" [network]="network.val" ></app-code-template>
|
<app-code-template [hostname]="hostname" [code]="code.addressUTXO" [network]="network.val" ></app-code-template>
|
||||||
</ng-template>
|
|
||||||
</ngb-panel>
|
|
||||||
|
|
||||||
</ngb-accordion>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="api-category" *ngIf="network.val === 'liquid'">
|
</div>
|
||||||
<h4 i18n="api-docs.tab.assets|API Docs tab for Assets">Assets</h4>
|
|
||||||
<ngb-accordion [closeOthers]="true" animated="true" type="dark" >
|
|
||||||
|
|
||||||
<ngb-panel id="assets">
|
<div class="api-category" *ngIf="network.val === 'liquid' || network.val === 'liquidtestnet'">
|
||||||
<ng-template ngbPanelTitle>
|
|
||||||
<span>GET Assets</span>
|
<div class="endpoint-container" id="get-asset">
|
||||||
</ng-template>
|
<a class="section-header" [routerLink]="['./']" fragment="get-assets">GET Asset <span>Assets</span></a>
|
||||||
<ng-template ngbPanelContent>
|
|
||||||
<div class="endpoint">
|
<div class="endpoint">
|
||||||
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
||||||
<a [href]="wrapUrl(network.val, code.assets)" target="_blank">GET /liquid/api/asset/:asset_id</a>
|
<a [href]="wrapUrl(network.val, code.assets)" target="_blank">GET {{ baseNetworkUrl }}/api/asset/:asset_id</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="description">
|
<div class="description">
|
||||||
<div class="subtitle" i18n>Description</div>
|
<div class="subtitle" i18n>Description</div>
|
||||||
<div i18n>Returns information about a Liquid asset.</div>
|
<div i18n>Returns information about a Liquid asset.</div>
|
||||||
</div>
|
</div>
|
||||||
<app-code-template [hostname]="hostname" [code]="code.assets" [network]="network.val" ></app-code-template>
|
<app-code-template [hostname]="hostname" [code]="code.assets" [network]="network.val" ></app-code-template>
|
||||||
</ng-template>
|
</div>
|
||||||
</ngb-panel>
|
|
||||||
|
|
||||||
<ngb-panel id="assetTransactions">
|
<div class="endpoint-container" id="get-asset-transactions">
|
||||||
<ng-template ngbPanelTitle>
|
<a class="section-header" [routerLink]="['./']" fragment="get-asset-transactions">GET Asset Transactions <span>Assets</span></a>
|
||||||
<span>GET Asset Transactions</span>
|
|
||||||
</ng-template>
|
|
||||||
<ng-template ngbPanelContent>
|
|
||||||
<div class="endpoint">
|
<div class="endpoint">
|
||||||
<a [href]="wrapUrl(network.val, code.assetTransactions)" target="_blank">GET /liquid/api/asset/:asset_id/txs[/mempool|/chain]</a>
|
<a [href]="wrapUrl(network.val, code.assetTransactions)" target="_blank">GET {{ baseNetworkUrl }}/api/asset/:asset_id/txs[/mempool|/chain]</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="description">
|
<div class="description">
|
||||||
<div class="subtitle" i18n>Description</div>
|
<div class="subtitle" i18n>Description</div>
|
||||||
<div i18n>Returns transactions associated with the specified Liquid asset. For the network's native asset, returns a list of peg in, peg out, and burn transactions. For user-issued assets, returns a list of issuance, reissuance, and burn transactions. Does not include regular transactions transferring this asset.</div>
|
<div i18n>Returns transactions associated with the specified Liquid asset. For the network's native asset, returns a list of peg in, peg out, and burn transactions. For user-issued assets, returns a list of issuance, reissuance, and burn transactions. Does not include regular transactions transferring this asset.</div>
|
||||||
</div>
|
</div>
|
||||||
<app-code-template [hostname]="hostname" [code]="code.assetTransactions" [network]="network.val" ></app-code-template>
|
<app-code-template [hostname]="hostname" [code]="code.assetTransactions" [network]="network.val" ></app-code-template>
|
||||||
</ng-template>
|
</div>
|
||||||
</ngb-panel>
|
|
||||||
|
|
||||||
<ngb-panel id="assetSupply">
|
<div class="endpoint-container" id="get-asset-supply">
|
||||||
<ng-template ngbPanelTitle>
|
<a class="section-header" [routerLink]="['./']" fragment="get-asset-supply">GET Asset Supply <span>Assets</span></a>
|
||||||
<span>GET Asset Supply</span>
|
|
||||||
</ng-template>
|
|
||||||
<ng-template ngbPanelContent>
|
|
||||||
<div class="endpoint">
|
<div class="endpoint">
|
||||||
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
||||||
<a [href]="wrapUrl(network.val, code.assetSupply)" target="_blank">GET /liquid/api/asset/:asset_id/supply[/decimal]</a>
|
<a [href]="wrapUrl(network.val, code.assetSupply)" target="_blank">GET {{ baseNetworkUrl }}/api/asset/:asset_id/supply[/decimal]</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="description">
|
<div class="description">
|
||||||
<div class="subtitle" i18n>Description</div>
|
<div class="subtitle" i18n>Description</div>
|
||||||
<div i18n>Get the current total supply of the specified asset. For the native asset (L-BTC), this is calculated as [chain,mempool]_stats.peg_in_amount - [chain,mempool]_stats.peg_out_amount - [chain,mempool]_stats.burned_amount. For issued assets, this is calculated as [chain,mempool]_stats.issued_amount - [chain,mempool]_stats.burned_amount. Not available for assets with blinded issuances. If /decimal is specified, returns the supply as a decimal according to the asset's divisibility. Otherwise, returned in base units.</div>
|
<div i18n>Get the current total supply of the specified asset. For the native asset (L-BTC), this is calculated as [chain,mempool]_stats.peg_in_amount - [chain,mempool]_stats.peg_out_amount - [chain,mempool]_stats.burned_amount. For issued assets, this is calculated as [chain,mempool]_stats.issued_amount - [chain,mempool]_stats.burned_amount. Not available for assets with blinded issuances. If /decimal is specified, returns the supply as a decimal according to the asset's divisibility. Otherwise, returned in base units.</div>
|
||||||
</div>
|
</div>
|
||||||
<app-code-template [hostname]="hostname" [code]="code.assetSupply" [network]="network.val" ></app-code-template>
|
<app-code-template [hostname]="hostname" [code]="code.assetSupply" [network]="network.val" ></app-code-template>
|
||||||
</ng-template>
|
</div>
|
||||||
</ngb-panel>
|
|
||||||
|
<div class="endpoint-container" id="get-asset-icons">
|
||||||
|
<a class="section-header" [routerLink]="['./']" fragment="get-assets-icons">GET Asset Icons <span>Assets</span></a>
|
||||||
|
<div class="endpoint">
|
||||||
|
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
||||||
|
<a [href]="wrapUrl(network.val, code.assetIcons)" target="_blank">GET {{ baseNetworkUrl }}/api/v1/assets/icons</a>
|
||||||
|
</div>
|
||||||
|
<div class="description">
|
||||||
|
<div class="subtitle" i18n>Description</div>
|
||||||
|
<div>Get all the Asset IDs that have icons.</div>
|
||||||
|
</div>
|
||||||
|
<app-code-template [hostname]="hostname" [code]="code.assetIcons" [network]="network.val" ></app-code-template>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="endpoint-container" id="get-asset-icon">
|
||||||
|
<a class="section-header" [routerLink]="['./']" fragment="get-asset-icon">GET Asset Icon <span>Assets</span></a>
|
||||||
|
<div class="endpoint">
|
||||||
|
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
||||||
|
<a [href]="wrapUrl(network.val, code.assetIcon)" target="_blank">GET {{ baseNetworkUrl }}/api/v1/asset/:asset_id/icon</a>
|
||||||
|
</div>
|
||||||
|
<div class="description">
|
||||||
|
<div class="subtitle" i18n>Description</div>
|
||||||
|
<div>Get the icon of the specified asset.</div>
|
||||||
|
</div>
|
||||||
|
<app-code-template [hostname]="hostname" [code]="code.assetIcon" [network]="network.val" ></app-code-template>
|
||||||
|
</div>
|
||||||
|
|
||||||
</ngb-accordion>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="api-category">
|
<div class="api-category">
|
||||||
<h4 i18n="api-docs.tab.blocks|API Docs tab for Blocks">Blocks</h4>
|
|
||||||
<ngb-accordion [closeOthers]="true" animated="true" type="dark" >
|
|
||||||
|
|
||||||
<ngb-panel id="block">
|
<div class="endpoint-container" id="get-block">
|
||||||
<ng-template ngbPanelTitle>
|
<a class="section-header" [routerLink]="['./']" fragment="get-block">GET Block <span>Blocks</span></a>
|
||||||
<span>GET Block</span>
|
|
||||||
</ng-template>
|
|
||||||
<ng-template ngbPanelContent>
|
|
||||||
<div class="endpoint">
|
<div class="endpoint">
|
||||||
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
||||||
<a [href]="wrapUrl(network.val, code.block)" target="_blank">GET {{ baseNetworkUrl }}/api/block/:hash</a>
|
<a [href]="wrapUrl(network.val, code.block)" target="_blank">GET {{ baseNetworkUrl }}/api/block/:hash</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="description">
|
<div class="description">
|
||||||
<div class="subtitle" i18n>Description</div>
|
<div class="subtitle" i18n>Description</div>
|
||||||
<div i18n>Returns details about a block. Available fields: <code>id</code>, <code>height</code>, <code>version</code>, <code>timestamp</code>, <code>bits</code>, <code>nonce</code>, <code>merkle_root</code>, <code>tx_count</code>, <code>size</code>, <code>weight</code>,<ng-container *ngIf="network.val === 'liquid'"> <code>proof</code>,</ng-container> and <code>previousblockhash</code>.</div>
|
<div i18n>Returns details about a block. Available fields: <code>id</code>, <code>height</code>, <code>version</code>, <code>timestamp</code>, <code>bits</code>, <code>nonce</code>, <code>merkle_root</code>, <code>tx_count</code>, <code>size</code>, <code>weight</code>,<ng-container *ngIf="network.val === 'liquid' || network.val === 'liquidtestnet'"> <code>proof</code>,</ng-container> and <code>previousblockhash</code>.</div>
|
||||||
</div>
|
</div>
|
||||||
<app-code-template [hostname]="hostname" [code]="code.block" [network]="network.val" ></app-code-template>
|
<app-code-template [hostname]="hostname" [code]="code.block" [network]="network.val" ></app-code-template>
|
||||||
</ng-template>
|
</div>
|
||||||
</ngb-panel>
|
|
||||||
|
|
||||||
<ngb-panel *ngIf="network.val !== 'bisq'" id="blockHeader">
|
<div class="endpoint-container" *ngIf="network.val !== 'bisq'" id="get-block-header">
|
||||||
<ng-template ngbPanelTitle>
|
<a class="section-header" [routerLink]="['./']" fragment="get-block-header">GET Block Header <span>Blocks</span></a>
|
||||||
<span>GET Block Header</span>
|
|
||||||
</ng-template>
|
|
||||||
<ng-template ngbPanelContent>
|
|
||||||
<div class="endpoint">
|
<div class="endpoint">
|
||||||
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
||||||
<a [href]="wrapUrl(network.val, code.blockHeader)" target="_blank">GET {{ baseNetworkUrl }}/api/block/:hash/header</a>
|
<a [href]="wrapUrl(network.val, code.blockHeader)" target="_blank">GET {{ baseNetworkUrl }}/api/block/:hash/header</a>
|
||||||
@@ -382,32 +329,25 @@
|
|||||||
<div i18n>Returns the hex-encoded block header.</div>
|
<div i18n>Returns the hex-encoded block header.</div>
|
||||||
</div>
|
</div>
|
||||||
<app-code-template [hostname]="hostname" [code]="code.blockHeader" [network]="network.val" ></app-code-template>
|
<app-code-template [hostname]="hostname" [code]="code.blockHeader" [network]="network.val" ></app-code-template>
|
||||||
</ng-template>
|
</div>
|
||||||
</ngb-panel>
|
|
||||||
|
|
||||||
<ngb-panel *ngIf="network.val !== 'bisq'" id="blockHeight">
|
<div class="endpoint-container" *ngIf="network.val !== 'bisq'" id="get-block-height">
|
||||||
<ng-template ngbPanelTitle>
|
<a class="section-header" [routerLink]="['./']" fragment="get-block-height">GET Block Height <span>Blocks</span></a>
|
||||||
<span>GET Block Height</span>
|
|
||||||
</ng-template>
|
|
||||||
<ng-template ngbPanelContent>
|
|
||||||
<div class="endpoint">
|
<div class="endpoint">
|
||||||
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
||||||
<a [href]="wrapUrl(network.val, code.blockHeader)" target="_blank">GET {{ baseNetworkUrl }}/api/block-height/:height</a>
|
<a [href]="wrapUrl(network.val, code.blockHeight)" target="_blank">GET {{ baseNetworkUrl }}/api/block-height/:height</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="description">
|
<div class="description">
|
||||||
<div class="subtitle" i18n>Description</div>
|
<div class="subtitle" i18n>Description</div>
|
||||||
<div i18n>Returns the hash of the block currently at <code>:height</code>.</div>
|
<div i18n>Returns the hash of the block currently at <code>:height</code>.</div>
|
||||||
</div>
|
</div>
|
||||||
<app-code-template [hostname]="hostname" [code]="code.blockHeight" [network]="network.val" ></app-code-template>
|
<app-code-template [hostname]="hostname" [code]="code.blockHeight" [network]="network.val" ></app-code-template>
|
||||||
</ng-template>
|
</div>
|
||||||
</ngb-panel>
|
|
||||||
|
|
||||||
<ngb-panel *ngIf="network.val !== 'bisq'" id="blockRaw">
|
<div class="endpoint-container" *ngIf="network.val !== 'bisq'" id="get-block-raw">
|
||||||
<ng-template ngbPanelTitle>
|
<a class="section-header" [routerLink]="['./']" fragment="get-block-raw">GET Block Raw <span>Blocks</span></a>
|
||||||
<span>GET Block Raw</span>
|
|
||||||
</ng-template>
|
|
||||||
<ng-template ngbPanelContent>
|
|
||||||
<div class="endpoint">
|
<div class="endpoint">
|
||||||
|
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
||||||
<a [href]="wrapUrl(network.val, code.blockRaw)" target="_blank">GET {{ baseNetworkUrl }}/api/block/:hash/raw</a>
|
<a [href]="wrapUrl(network.val, code.blockRaw)" target="_blank">GET {{ baseNetworkUrl }}/api/block/:hash/raw</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="description">
|
<div class="description">
|
||||||
@@ -415,15 +355,10 @@
|
|||||||
<div i18n>Returns the raw block representation in binary.</div>
|
<div i18n>Returns the raw block representation in binary.</div>
|
||||||
</div>
|
</div>
|
||||||
<app-code-template [hostname]="hostname" [code]="code.blockRaw" [network]="network.val" ></app-code-template>
|
<app-code-template [hostname]="hostname" [code]="code.blockRaw" [network]="network.val" ></app-code-template>
|
||||||
</ng-template>
|
</div>
|
||||||
</ngb-panel>
|
|
||||||
|
|
||||||
<ngb-panel *ngIf="network.val !== 'bisq'" id="blockStatus">
|
<div class="endpoint-container" *ngIf="network.val !== 'bisq'" id="get-block-status">
|
||||||
<ng-template ngbPanelTitle>
|
<a class="section-header" [routerLink]="['./']" fragment="get-block-status">GET Block Status <span>Blocks</span></a>
|
||||||
<span>GET Block Status</span>
|
|
||||||
</ng-template>
|
|
||||||
<ng-template ngbPanelContent>
|
|
||||||
<div class="title">Get Block Status</div>
|
|
||||||
<div class="endpoint">
|
<div class="endpoint">
|
||||||
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
||||||
<a [href]="wrapUrl(network.val, code.blockStatus)" target="_blank">GET {{ baseNetworkUrl }}/api/block/:hash/status</a>
|
<a [href]="wrapUrl(network.val, code.blockStatus)" target="_blank">GET {{ baseNetworkUrl }}/api/block/:hash/status</a>
|
||||||
@@ -433,14 +368,10 @@
|
|||||||
<div i18n>Returns the confirmation status of a block. Available fields: <code>in_best_chain</code> (boolean, false for orphaned blocks), <code>next_best</code> (the hash of the next block, only available for blocks in the best chain).</div>
|
<div i18n>Returns the confirmation status of a block. Available fields: <code>in_best_chain</code> (boolean, false for orphaned blocks), <code>next_best</code> (the hash of the next block, only available for blocks in the best chain).</div>
|
||||||
</div>
|
</div>
|
||||||
<app-code-template [hostname]="hostname" [code]="code.blockStatus" [network]="network.val" ></app-code-template>
|
<app-code-template [hostname]="hostname" [code]="code.blockStatus" [network]="network.val" ></app-code-template>
|
||||||
</ng-template>
|
</div>
|
||||||
</ngb-panel>
|
|
||||||
|
|
||||||
<ngb-panel id="blockTipHeight">
|
<div class="endpoint-container" id="get-block-tip-height">
|
||||||
<ng-template ngbPanelTitle>
|
<a class="section-header" [routerLink]="['./']" fragment="get-block-tip-height">GET Block Tip Height <span>Blocks</span></a>
|
||||||
<span>GET Block Tip Height</span>
|
|
||||||
</ng-template>
|
|
||||||
<ng-template ngbPanelContent>
|
|
||||||
<div class="endpoint">
|
<div class="endpoint">
|
||||||
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
||||||
<a [href]="wrapUrl(network.val, code.blockTipHeight)" target="_blank">GET {{ baseNetworkUrl }}/api/blocks/tip/height</a>
|
<a [href]="wrapUrl(network.val, code.blockTipHeight)" target="_blank">GET {{ baseNetworkUrl }}/api/blocks/tip/height</a>
|
||||||
@@ -450,14 +381,10 @@
|
|||||||
<div i18n>Returns the height of the last block.</div>
|
<div i18n>Returns the height of the last block.</div>
|
||||||
</div>
|
</div>
|
||||||
<app-code-template [hostname]="hostname" [code]="code.blockTipHeight" [network]="network.val" ></app-code-template>
|
<app-code-template [hostname]="hostname" [code]="code.blockTipHeight" [network]="network.val" ></app-code-template>
|
||||||
</ng-template>
|
</div>
|
||||||
</ngb-panel>
|
|
||||||
|
|
||||||
<ngb-panel *ngIf="network.val !== 'bisq'" id="blockTipHash">
|
<div class="endpoint-container" *ngIf="network.val !== 'bisq'" id="get-block-tip-hash">
|
||||||
<ng-template ngbPanelTitle>
|
<a class="section-header" [routerLink]="['./']" fragment="get-block-tip-hash">GET Block Tip Hash <span>Blocks</span></a>
|
||||||
<span>GET Block Tip Hash</span>
|
|
||||||
</ng-template>
|
|
||||||
<ng-template ngbPanelContent>
|
|
||||||
<div class="endpoint">
|
<div class="endpoint">
|
||||||
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
||||||
<a [href]="wrapUrl(network.val, code.blockTipHash)" target="_blank">GET {{ baseNetworkUrl }}/api/blocks/tip/hash</a>
|
<a [href]="wrapUrl(network.val, code.blockTipHash)" target="_blank">GET {{ baseNetworkUrl }}/api/blocks/tip/hash</a>
|
||||||
@@ -467,14 +394,10 @@
|
|||||||
<div i18n>Returns the hash of the last block.</div>
|
<div i18n>Returns the hash of the last block.</div>
|
||||||
</div>
|
</div>
|
||||||
<app-code-template [hostname]="hostname" [code]="code.blockTipHash" [network]="network.val" ></app-code-template>
|
<app-code-template [hostname]="hostname" [code]="code.blockTipHash" [network]="network.val" ></app-code-template>
|
||||||
</ng-template>
|
</div>
|
||||||
</ngb-panel>
|
|
||||||
|
|
||||||
<ngb-panel *ngIf="network.val !== 'bisq'" id="blockTxId">
|
<div class="endpoint-container" *ngIf="network.val !== 'bisq'" id="get-block-transaction-id">
|
||||||
<ng-template ngbPanelTitle>
|
<a class="section-header" [routerLink]="['./']" fragment="get-block-transaction-id">GET Block Transaction ID <span>Blocks</span></a>
|
||||||
<span>GET Block Transaction ID</span>
|
|
||||||
</ng-template>
|
|
||||||
<ng-template ngbPanelContent>
|
|
||||||
<div class="endpoint">
|
<div class="endpoint">
|
||||||
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
||||||
<a [href]="wrapUrl(network.val, code.blockTxId)" target="_blank">GET {{ baseNetworkUrl }}/api/block/:hash/txid/:index</a>
|
<a [href]="wrapUrl(network.val, code.blockTxId)" target="_blank">GET {{ baseNetworkUrl }}/api/block/:hash/txid/:index</a>
|
||||||
@@ -484,14 +407,10 @@
|
|||||||
<div i18n>Returns the transaction at index <code>:index</code> within the specified block.</div>
|
<div i18n>Returns the transaction at index <code>:index</code> within the specified block.</div>
|
||||||
</div>
|
</div>
|
||||||
<app-code-template [hostname]="hostname" [code]="code.blockTxId" [network]="network.val" ></app-code-template>
|
<app-code-template [hostname]="hostname" [code]="code.blockTxId" [network]="network.val" ></app-code-template>
|
||||||
</ng-template>
|
</div>
|
||||||
</ngb-panel>
|
|
||||||
|
|
||||||
<ngb-panel *ngIf="network.val !== 'bisq'" id="blockTxIds">
|
<div class="endpoint-container" *ngIf="network.val !== 'bisq'" id="get-block-transaction-ids">
|
||||||
<ng-template ngbPanelTitle>
|
<a class="section-header" [routerLink]="['./']" fragment="get-block-transaction-ids">GET Block Transaction IDs <span>Blocks</span></a>
|
||||||
<span>GET Block Transaction IDs</span>
|
|
||||||
</ng-template>
|
|
||||||
<ng-template ngbPanelContent>
|
|
||||||
<div class="endpoint">
|
<div class="endpoint">
|
||||||
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
||||||
<a [href]="wrapUrl(network.val, code.blockTxIds)" target="_blank">GET {{ baseNetworkUrl }}/api/block/:hash/txids</a>
|
<a [href]="wrapUrl(network.val, code.blockTxIds)" target="_blank">GET {{ baseNetworkUrl }}/api/block/:hash/txids</a>
|
||||||
@@ -501,14 +420,10 @@
|
|||||||
<div i18n>Returns a list of all txids in the block.</div>
|
<div i18n>Returns a list of all txids in the block.</div>
|
||||||
</div>
|
</div>
|
||||||
<app-code-template [hostname]="hostname" [code]="code.blockTxIds" [network]="network.val" ></app-code-template>
|
<app-code-template [hostname]="hostname" [code]="code.blockTxIds" [network]="network.val" ></app-code-template>
|
||||||
</ng-template>
|
</div>
|
||||||
</ngb-panel>
|
|
||||||
|
|
||||||
<ngb-panel *ngIf="network.val !== 'bisq'" id="blockTxs">
|
<div class="endpoint-container" *ngIf="network.val !== 'bisq'" id="get-block-transactions">
|
||||||
<ng-template ngbPanelTitle>
|
<a class="section-header" [routerLink]="['./']" fragment="get-block-transactions">GET Block Transactions <span>Blocks</span></a>
|
||||||
<span>GET Block Transactions</span>
|
|
||||||
</ng-template>
|
|
||||||
<ng-template ngbPanelContent>
|
|
||||||
<div class="endpoint">
|
<div class="endpoint">
|
||||||
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
||||||
<a [href]="wrapUrl(network.val, code.blockTxs)" target="_blank">GET {{ baseNetworkUrl }}/api/block/:hash/txs[/:start_index]</a>
|
<a [href]="wrapUrl(network.val, code.blockTxs)" target="_blank">GET {{ baseNetworkUrl }}/api/block/:hash/txs[/:start_index]</a>
|
||||||
@@ -518,14 +433,10 @@
|
|||||||
<div i18n>Returns a list of transactions in the block (up to 25 transactions beginning at <code>start_index</code>). Transactions returned here do not have the <code>status</code> field, since all the transactions share the same block and confirmation status.</div>
|
<div i18n>Returns a list of transactions in the block (up to 25 transactions beginning at <code>start_index</code>). Transactions returned here do not have the <code>status</code> field, since all the transactions share the same block and confirmation status.</div>
|
||||||
</div>
|
</div>
|
||||||
<app-code-template [hostname]="hostname" [code]="code.blockTxs" [network]="network.val" ></app-code-template>
|
<app-code-template [hostname]="hostname" [code]="code.blockTxs" [network]="network.val" ></app-code-template>
|
||||||
</ng-template>
|
</div>
|
||||||
</ngb-panel>
|
|
||||||
|
|
||||||
<ngb-panel *ngIf="network.val !== 'bisq'" id="blocks">
|
<div class="endpoint-container" *ngIf="network.val !== 'bisq'" id="get-blocks">
|
||||||
<ng-template ngbPanelTitle>
|
<a class="section-header" [routerLink]="['./']" fragment="get-blocks">GET Blocks <span>Blocks</span></a>
|
||||||
<span>GET Blocks</span>
|
|
||||||
</ng-template>
|
|
||||||
<ng-template ngbPanelContent>
|
|
||||||
<div class="endpoint">
|
<div class="endpoint">
|
||||||
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
||||||
<a [href]="wrapUrl(network.val, code.blocks)" target="_blank">GET {{ baseNetworkUrl }}/api/blocks[/:start_height]</a>
|
<a [href]="wrapUrl(network.val, code.blocks)" target="_blank">GET {{ baseNetworkUrl }}/api/blocks[/:start_height]</a>
|
||||||
@@ -535,14 +446,10 @@
|
|||||||
<div i18n>Returns the 10 newest blocks starting at the tip or at <code>:start_height</code> if specified.</div>
|
<div i18n>Returns the 10 newest blocks starting at the tip or at <code>:start_height</code> if specified.</div>
|
||||||
</div>
|
</div>
|
||||||
<app-code-template [hostname]="hostname" [code]="code.blocks" [network]="network.val" ></app-code-template>
|
<app-code-template [hostname]="hostname" [code]="code.blocks" [network]="network.val" ></app-code-template>
|
||||||
</ng-template>
|
</div>
|
||||||
</ngb-panel>
|
|
||||||
|
|
||||||
<ngb-panel *ngIf="network.val === 'bisq'" id="blocks">
|
<div class="endpoint-container" *ngIf="network.val === 'bisq'" id="get-blocks">
|
||||||
<ng-template ngbPanelTitle>
|
<a class="section-header" [routerLink]="['./']" fragment="get-blocks">GET Blocks <span>Blocks</span></a>
|
||||||
<span>GET Blocks</span>
|
|
||||||
</ng-template>
|
|
||||||
<ng-template ngbPanelContent>
|
|
||||||
<div class="endpoint">
|
<div class="endpoint">
|
||||||
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
||||||
<a [href]="wrapUrl(network.val, code.blocksBisq)" target="_blank">GET {{ baseNetworkUrl }}/api/blocks/:index/:length</a>
|
<a [href]="wrapUrl(network.val, code.blocksBisq)" target="_blank">GET {{ baseNetworkUrl }}/api/blocks/:index/:length</a>
|
||||||
@@ -552,21 +459,14 @@
|
|||||||
<div i18n>Returns the 10 newest blocks starting at the tip or at <code>:start_height</code> if specified.</div>
|
<div i18n>Returns the 10 newest blocks starting at the tip or at <code>:start_height</code> if specified.</div>
|
||||||
</div>
|
</div>
|
||||||
<app-code-template [hostname]="hostname" [code]="code.blocksBisq" [network]="network.val" ></app-code-template>
|
<app-code-template [hostname]="hostname" [code]="code.blocksBisq" [network]="network.val" ></app-code-template>
|
||||||
</ng-template>
|
</div>
|
||||||
</ngb-panel>
|
|
||||||
|
|
||||||
</ngb-accordion>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="api-category" *ngIf="network.val !== 'bisq'">
|
<div class="api-category" *ngIf="network.val !== 'bisq'">
|
||||||
<h4 i18n="api-docs.tab.fees|API Docs tab for Fees">Fees</h4>
|
|
||||||
<ngb-accordion [closeOthers]="true" animated="true" type="dark">
|
|
||||||
|
|
||||||
<ngb-panel id="feeMempoolBlocks">
|
<div class="endpoint-container" id="get-mempool-blocks-fees">
|
||||||
<ng-template ngbPanelTitle>
|
<a class="section-header" [routerLink]="['./']" fragment="get-mempool-blocks-fees">GET Mempool Blocks Fees <span>Fees</span></a>
|
||||||
<span>GET Mempool Blocks Fees</span>
|
|
||||||
</ng-template>
|
|
||||||
<ng-template ngbPanelContent>
|
|
||||||
<div class="endpoint">
|
<div class="endpoint">
|
||||||
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
||||||
<a [href]="wrapUrl(network.val, code.feeMempoolBlocks)" target="_blank">GET {{ baseNetworkUrl }}/api/v1/fees/mempool-blocks</a>
|
<a [href]="wrapUrl(network.val, code.feeMempoolBlocks)" target="_blank">GET {{ baseNetworkUrl }}/api/v1/fees/mempool-blocks</a>
|
||||||
@@ -576,14 +476,10 @@
|
|||||||
<div i18n="api-docs.fees.mempool-blocks|API Docs for /api/v1/fees/mempool-blocks">Returns current mempool as projected blocks.</div>
|
<div i18n="api-docs.fees.mempool-blocks|API Docs for /api/v1/fees/mempool-blocks">Returns current mempool as projected blocks.</div>
|
||||||
</div>
|
</div>
|
||||||
<app-code-template [hostname]="hostname" [code]="code.feeMempoolBlocks" [network]="network.val" ></app-code-template>
|
<app-code-template [hostname]="hostname" [code]="code.feeMempoolBlocks" [network]="network.val" ></app-code-template>
|
||||||
</ng-template>
|
</div>
|
||||||
</ngb-panel>
|
|
||||||
|
|
||||||
<ngb-panel id="feeRecommended">
|
<div class="endpoint-container" id="get-recommended-fees">
|
||||||
<ng-template ngbPanelTitle>
|
<a class="section-header" [routerLink]="['./']" fragment="get-recommended-fees">GET Recommended Fees <span>Fees</span></a>
|
||||||
<span>GET Recommended Fees</span>
|
|
||||||
</ng-template>
|
|
||||||
<ng-template ngbPanelContent>
|
|
||||||
<div class="endpoint">
|
<div class="endpoint">
|
||||||
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
||||||
<a [href]="wrapUrl(network.val, code.feeRecommended)" target="_blank">GET {{ baseNetworkUrl }}/api/v1/fees/recommended</a>
|
<a [href]="wrapUrl(network.val, code.feeRecommended)" target="_blank">GET {{ baseNetworkUrl }}/api/v1/fees/recommended</a>
|
||||||
@@ -593,21 +489,14 @@
|
|||||||
<div i18n="api-docs.fees.recommended|API Docs for /api/v1/fees/recommended">Returns our currently suggested fees for new transactions.</div>
|
<div i18n="api-docs.fees.recommended|API Docs for /api/v1/fees/recommended">Returns our currently suggested fees for new transactions.</div>
|
||||||
</div>
|
</div>
|
||||||
<app-code-template [hostname]="hostname" [code]="code.feeRecommended" [network]="network.val" ></app-code-template>
|
<app-code-template [hostname]="hostname" [code]="code.feeRecommended" [network]="network.val" ></app-code-template>
|
||||||
</ng-template>
|
</div>
|
||||||
</ngb-panel>
|
|
||||||
|
|
||||||
</ngb-accordion>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="api-category" *ngIf="network.val !== 'bisq'">
|
<div class="api-category" *ngIf="network.val !== 'bisq'">
|
||||||
<h4 i18n="api-docs.tab.mempool|API Docs tab for Mempool">Mempool</h4>
|
|
||||||
<ngb-accordion [closeOthers]="true" animated="true" type="dark" >
|
|
||||||
|
|
||||||
<ngb-panel id="mempool">
|
<div class="endpoint-container" id="get-mempool">
|
||||||
<ng-template ngbPanelTitle>
|
<a class="section-header" [routerLink]="['./']" fragment="get-mempool">GET Mempool <span>Fees</span></a>
|
||||||
<span>GET Mempool</span>
|
|
||||||
</ng-template>
|
|
||||||
<ng-template ngbPanelContent>
|
|
||||||
<div class="endpoint">
|
<div class="endpoint">
|
||||||
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
||||||
<a [href]="wrapUrl(network.val, code.mempool)" target="_blank">GET {{ baseNetworkUrl }}/api/mempool</a>
|
<a [href]="wrapUrl(network.val, code.mempool)" target="_blank">GET {{ baseNetworkUrl }}/api/mempool</a>
|
||||||
@@ -617,14 +506,10 @@
|
|||||||
<div i18n="api-docs.mempool.mempool|API Docs for /api/mempool">Returns current mempool backlog statistics.</div>
|
<div i18n="api-docs.mempool.mempool|API Docs for /api/mempool">Returns current mempool backlog statistics.</div>
|
||||||
</div>
|
</div>
|
||||||
<app-code-template [hostname]="hostname" [code]="code.mempool" [network]="network.val" ></app-code-template>
|
<app-code-template [hostname]="hostname" [code]="code.mempool" [network]="network.val" ></app-code-template>
|
||||||
</ng-template>
|
</div>
|
||||||
</ngb-panel>
|
|
||||||
|
|
||||||
<ngb-panel id="mempoolTxs">
|
<div class="endpoint-container" id="get-mempool-transaction-ids">
|
||||||
<ng-template ngbPanelTitle>
|
<a class="section-header" [routerLink]="['./']" fragment="get-mempool-transaction-ids">GET Mempool Transactions IDs <span>Fees</span></a>
|
||||||
<span>GET Mempool Transactions IDs</span>
|
|
||||||
</ng-template>
|
|
||||||
<ng-template ngbPanelContent>
|
|
||||||
<div class="endpoint">
|
<div class="endpoint">
|
||||||
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
||||||
<a [href]="wrapUrl(network.val, code.mempoolTxs)" target="_blank">GET {{ baseNetworkUrl }}/api/mempool/txids</a>
|
<a [href]="wrapUrl(network.val, code.mempoolTxs)" target="_blank">GET {{ baseNetworkUrl }}/api/mempool/txids</a>
|
||||||
@@ -634,14 +519,10 @@
|
|||||||
<div i18n="api-docs.mempool.txids|API Docs for /api/mempool/txids">Get the full list of txids in the mempool as an array. The order of the txids is arbitrary and does not match bitcoind.</div>
|
<div i18n="api-docs.mempool.txids|API Docs for /api/mempool/txids">Get the full list of txids in the mempool as an array. The order of the txids is arbitrary and does not match bitcoind.</div>
|
||||||
</div>
|
</div>
|
||||||
<app-code-template [hostname]="hostname" [code]="code.mempoolTxs" [network]="network.val" ></app-code-template>
|
<app-code-template [hostname]="hostname" [code]="code.mempoolTxs" [network]="network.val" ></app-code-template>
|
||||||
</ng-template>
|
</div>
|
||||||
</ngb-panel>
|
|
||||||
|
|
||||||
<ngb-panel id="mempoolRecent">
|
<div class="endpoint-container" id="get-mempool-recent">
|
||||||
<ng-template ngbPanelTitle>
|
<a class="section-header" [routerLink]="['./']" fragment="get-mempool-recent">GET Mempool Recent <span>Fees</span></a>
|
||||||
<span>GET Mempool Recent</span>
|
|
||||||
</ng-template>
|
|
||||||
<ng-template ngbPanelContent>
|
|
||||||
<div class="endpoint">
|
<div class="endpoint">
|
||||||
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
||||||
<a [href]="wrapUrl(network.val, code.mempoolRecent)" target="_blank">GET {{ baseNetworkUrl }}/api/mempool/recent</a>
|
<a [href]="wrapUrl(network.val, code.mempoolRecent)" target="_blank">GET {{ baseNetworkUrl }}/api/mempool/recent</a>
|
||||||
@@ -651,21 +532,14 @@
|
|||||||
<div i18n="api-docs.mempool.recent|API Docs for /api/mempool/recent">Get a list of the last 10 transactions to enter the mempool. Each transaction object contains simplified overview data, with the following fields: <code>txid</code>, <code>fee</code>, <code>vsize</code>, and <code>value</code>.</div>
|
<div i18n="api-docs.mempool.recent|API Docs for /api/mempool/recent">Get a list of the last 10 transactions to enter the mempool. Each transaction object contains simplified overview data, with the following fields: <code>txid</code>, <code>fee</code>, <code>vsize</code>, and <code>value</code>.</div>
|
||||||
</div>
|
</div>
|
||||||
<app-code-template [hostname]="hostname" [code]="code.mempoolRecent" [network]="network.val" ></app-code-template>
|
<app-code-template [hostname]="hostname" [code]="code.mempoolRecent" [network]="network.val" ></app-code-template>
|
||||||
</ng-template>
|
</div>
|
||||||
</ngb-panel>
|
|
||||||
|
|
||||||
</ngb-accordion>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="api-category">
|
<div class="api-category">
|
||||||
<h4 i18n="api-docs.tab.transactions|API Docs tab for Transactions">Transactions</h4>
|
|
||||||
<ngb-accordion [closeOthers]="true" animated="true" type="dark" >
|
|
||||||
|
|
||||||
<ngb-panel *ngIf="network.val !== 'bisq'" id="cpfp">
|
<div class="endpoint-container" *ngIf="network.val !== 'bisq'" id="get-cpfp">
|
||||||
<ng-template ngbPanelTitle>
|
<a class="section-header" [routerLink]="['./']" fragment="get-cpfp">GET Children Pay for Parent <span>Transactions</span></a>
|
||||||
<span>GET Children Pay for Parent</span>
|
|
||||||
</ng-template>
|
|
||||||
<ng-template ngbPanelContent>
|
|
||||||
<div class="endpoint">
|
<div class="endpoint">
|
||||||
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
||||||
<a [href]="wrapUrl(network.val, code.transactionCpfp)" target="_blank">GET {{ baseNetworkUrl }}/api/v1/cpfp/:txid</a>
|
<a [href]="wrapUrl(network.val, code.transactionCpfp)" target="_blank">GET {{ baseNetworkUrl }}/api/v1/cpfp/:txid</a>
|
||||||
@@ -675,15 +549,12 @@
|
|||||||
<div i18n="api-docs.fees.cpfp|API Docs for /api/v1/fees/cpfp">Returns the ancestors and the best descendant fees for a transaction.</div>
|
<div i18n="api-docs.fees.cpfp|API Docs for /api/v1/fees/cpfp">Returns the ancestors and the best descendant fees for a transaction.</div>
|
||||||
</div>
|
</div>
|
||||||
<app-code-template [hostname]="hostname" [code]="code.transactionCpfp" [network]="network.val" ></app-code-template>
|
<app-code-template [hostname]="hostname" [code]="code.transactionCpfp" [network]="network.val" ></app-code-template>
|
||||||
</ng-template>
|
</div>
|
||||||
</ngb-panel>
|
|
||||||
|
|
||||||
<ngb-panel id="transaction">
|
<div class="endpoint-container" id="get-transaction">
|
||||||
<ng-template ngbPanelTitle>
|
<a class="section-header" [routerLink]="['./']" fragment="get-transaction">GET Transaction <span>Transactions</span></a>
|
||||||
<span>GET Transaction</span>
|
|
||||||
</ng-template>
|
|
||||||
<ng-template ngbPanelContent>
|
|
||||||
<div class="endpoint">
|
<div class="endpoint">
|
||||||
|
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
||||||
<a [href]="wrapUrl(network.val, code.transaction)" target="_blank">GET {{ baseNetworkUrl }}/api/tx/:txid</a>
|
<a [href]="wrapUrl(network.val, code.transaction)" target="_blank">GET {{ baseNetworkUrl }}/api/tx/:txid</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="description">
|
<div class="description">
|
||||||
@@ -691,14 +562,10 @@
|
|||||||
<div i18n>Returns details about a transaction. Available fields: <code>txid</code>, <code>version</code>, <code>locktime</code>, <code>size</code>, <code>weight</code>, <code>fee</code>, <code>vin</code>, <code>vout</code>, and <code>status</code>.</div>
|
<div i18n>Returns details about a transaction. Available fields: <code>txid</code>, <code>version</code>, <code>locktime</code>, <code>size</code>, <code>weight</code>, <code>fee</code>, <code>vin</code>, <code>vout</code>, and <code>status</code>.</div>
|
||||||
</div>
|
</div>
|
||||||
<app-code-template [hostname]="hostname" [code]="code.transaction" [network]="network.val" ></app-code-template>
|
<app-code-template [hostname]="hostname" [code]="code.transaction" [network]="network.val" ></app-code-template>
|
||||||
</ng-template>
|
</div>
|
||||||
</ngb-panel>
|
|
||||||
|
|
||||||
<ngb-panel *ngIf="network.val !== 'bisq'" id="transactionHex">
|
<div class="endpoint-container" *ngIf="network.val !== 'bisq'" id="get-transaction-hex">
|
||||||
<ng-template ngbPanelTitle>
|
<a class="section-header" [routerLink]="['./']" fragment="get-transaction-hex">GET Transaction Hex <span>Transactions</span></a>
|
||||||
<span>GET Transaction Hex</span>
|
|
||||||
</ng-template>
|
|
||||||
<ng-template ngbPanelContent>
|
|
||||||
<div class="endpoint">
|
<div class="endpoint">
|
||||||
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
||||||
<a [href]="wrapUrl(network.val, code.transactionHex)" target="_blank">GET {{ baseNetworkUrl }}/api/tx/:txid/hex</a>
|
<a [href]="wrapUrl(network.val, code.transactionHex)" target="_blank">GET {{ baseNetworkUrl }}/api/tx/:txid/hex</a>
|
||||||
@@ -708,14 +575,10 @@
|
|||||||
<div i18n>Returns a transaction serialized as hex.</div>
|
<div i18n>Returns a transaction serialized as hex.</div>
|
||||||
</div>
|
</div>
|
||||||
<app-code-template [hostname]="hostname" [code]="code.transactionHex" [network]="network.val" ></app-code-template>
|
<app-code-template [hostname]="hostname" [code]="code.transactionHex" [network]="network.val" ></app-code-template>
|
||||||
</ng-template>
|
</div>
|
||||||
</ngb-panel>
|
|
||||||
|
|
||||||
<ngb-panel *ngIf="network.val !== 'bisq' && network.val !== 'liquid'" id="transactionMerkleBlockProof">
|
<div class="endpoint-container" *ngIf="network.val !== 'bisq' && network.val !== 'liquid' && network.val !== 'liquidtestnet'" id="get-transaction-merkleblock-proof">
|
||||||
<ng-template ngbPanelTitle>
|
<a class="section-header" [routerLink]="['./']" fragment="get-transaction-merkleblock-proof">GET Transaction Merkleblock Proof <span>Transactions</span></a>
|
||||||
<span>GET Transaction Merkleblock Proof</span>
|
|
||||||
</ng-template>
|
|
||||||
<ng-template ngbPanelContent>
|
|
||||||
<div class="endpoint">
|
<div class="endpoint">
|
||||||
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
||||||
<a [href]="wrapUrl(network.val, code.transactionMerkleBlockProof)" target="_blank">GET {{ baseNetworkUrl }}/api/tx/:txid/merkleblock-proof</a>
|
<a [href]="wrapUrl(network.val, code.transactionMerkleBlockProof)" target="_blank">GET {{ baseNetworkUrl }}/api/tx/:txid/merkleblock-proof</a>
|
||||||
@@ -725,14 +588,10 @@
|
|||||||
<div i18n>Returns a merkle inclusion proof for the transaction using <a href="https://bitcoin.org/en/glossary/merkle-block">bitcoind's merkleblock</a> format.</div>
|
<div i18n>Returns a merkle inclusion proof for the transaction using <a href="https://bitcoin.org/en/glossary/merkle-block">bitcoind's merkleblock</a> format.</div>
|
||||||
</div>
|
</div>
|
||||||
<app-code-template [hostname]="hostname" [code]="code.transactionMerkleBlockProof" [network]="network.val" ></app-code-template>
|
<app-code-template [hostname]="hostname" [code]="code.transactionMerkleBlockProof" [network]="network.val" ></app-code-template>
|
||||||
</ng-template>
|
</div>
|
||||||
</ngb-panel>
|
|
||||||
|
|
||||||
<ngb-panel *ngIf="network.val !== 'bisq'" id="transactionMerkleProof">
|
<div class="endpoint-container" *ngIf="network.val !== 'bisq'" id="get-transaction-merkle-proof">
|
||||||
<ng-template ngbPanelTitle>
|
<a class="section-header" [routerLink]="['./']" fragment="get-transaction-merkle-proof">GET Transaction Merkle Proof <span>Transactions</span></a>
|
||||||
<span>GET Transaction Merkle Proof</span>
|
|
||||||
</ng-template>
|
|
||||||
<ng-template ngbPanelContent>
|
|
||||||
<div class="endpoint">
|
<div class="endpoint">
|
||||||
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
||||||
<a [href]="wrapUrl(network.val, code.transactionMerkleProof)" target="_blank">GET {{ baseNetworkUrl }}/api/tx/:txid/merkle-proof</a>
|
<a [href]="wrapUrl(network.val, code.transactionMerkleProof)" target="_blank">GET {{ baseNetworkUrl }}/api/tx/:txid/merkle-proof</a>
|
||||||
@@ -742,14 +601,10 @@
|
|||||||
<div i18n>Returns a merkle inclusion proof for the transaction using <a href="https://electrumx.readthedocs.io/en/latest/protocol-methods.html#blockchain-transaction-get-merkle">Electrum's blockchain.transaction.get_merkle format.</a></div>
|
<div i18n>Returns a merkle inclusion proof for the transaction using <a href="https://electrumx.readthedocs.io/en/latest/protocol-methods.html#blockchain-transaction-get-merkle">Electrum's blockchain.transaction.get_merkle format.</a></div>
|
||||||
</div>
|
</div>
|
||||||
<app-code-template [hostname]="hostname" [code]="code.transactionMerkleProof" [network]="network.val" ></app-code-template>
|
<app-code-template [hostname]="hostname" [code]="code.transactionMerkleProof" [network]="network.val" ></app-code-template>
|
||||||
</ng-template>
|
</div>
|
||||||
</ngb-panel>
|
|
||||||
|
|
||||||
<ngb-panel *ngIf="network.val !== 'bisq'" id="transactionOutspend">
|
<div class="endpoint-container" *ngIf="network.val !== 'bisq'" id="get-transaction-outspend">
|
||||||
<ng-template ngbPanelTitle>
|
<a class="section-header" [routerLink]="['./']" fragment="get-transaction-outspend">GET Transaction Outspend <span>Transactions</span></a>
|
||||||
<span>GET Transaction Outspend</span>
|
|
||||||
</ng-template>
|
|
||||||
<ng-template ngbPanelContent>
|
|
||||||
<div class="endpoint">
|
<div class="endpoint">
|
||||||
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
||||||
<a [href]="wrapUrl(network.val, code.transactionOutspend)" target="_blank">GET {{ baseNetworkUrl }}/api/tx/:txid/outspend/:vout</a>
|
<a [href]="wrapUrl(network.val, code.transactionOutspend)" target="_blank">GET {{ baseNetworkUrl }}/api/tx/:txid/outspend/:vout</a>
|
||||||
@@ -759,14 +614,10 @@
|
|||||||
<div i18n>Returns the spending status of a transaction output. Available fields: <code>spent</code> (boolean), <code>txid</code> (optional), <code>vin</code> (optional), and <code>status</code> (optional, the status of the spending tx).</div>
|
<div i18n>Returns the spending status of a transaction output. Available fields: <code>spent</code> (boolean), <code>txid</code> (optional), <code>vin</code> (optional), and <code>status</code> (optional, the status of the spending tx).</div>
|
||||||
</div>
|
</div>
|
||||||
<app-code-template [hostname]="hostname" [code]="code.transactionOutspend" [network]="network.val" ></app-code-template>
|
<app-code-template [hostname]="hostname" [code]="code.transactionOutspend" [network]="network.val" ></app-code-template>
|
||||||
</ng-template>
|
</div>
|
||||||
</ngb-panel>
|
|
||||||
|
|
||||||
<ngb-panel *ngIf="network.val !== 'bisq'" id="transactionOutspends">
|
<div class="endpoint-container" *ngIf="network.val !== 'bisq'" id="get-transaction-outspends">
|
||||||
<ng-template ngbPanelTitle>
|
<a class="section-header" [routerLink]="['./']" fragment="get-transaction-outspends">GET Transaction Outspends <span>Transactions</span></a>
|
||||||
<span>GET Transaction Outspends</span>
|
|
||||||
</ng-template>
|
|
||||||
<ng-template ngbPanelContent>
|
|
||||||
<div class="endpoint">
|
<div class="endpoint">
|
||||||
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
||||||
<a [href]="wrapUrl(network.val, code.transactionOutspends)" target="_blank">GET {{ baseNetworkUrl }}/api/tx/:txid/outspends</a>
|
<a [href]="wrapUrl(network.val, code.transactionOutspends)" target="_blank">GET {{ baseNetworkUrl }}/api/tx/:txid/outspends</a>
|
||||||
@@ -776,14 +627,10 @@
|
|||||||
<div i18n>Returns the spending status of all transaction outputs.</div>
|
<div i18n>Returns the spending status of all transaction outputs.</div>
|
||||||
</div>
|
</div>
|
||||||
<app-code-template [hostname]="hostname" [code]="code.transactionOutspends" [network]="network.val" ></app-code-template>
|
<app-code-template [hostname]="hostname" [code]="code.transactionOutspends" [network]="network.val" ></app-code-template>
|
||||||
</ng-template>
|
</div>
|
||||||
</ngb-panel>
|
|
||||||
|
|
||||||
<ngb-panel *ngIf="network.val !== 'bisq'" id="transactionRaw">
|
<div class="endpoint-container" *ngIf="network.val !== 'bisq'" id="get-transaction-raw">
|
||||||
<ng-template ngbPanelTitle>
|
<a class="section-header" [routerLink]="['./']" fragment="get-transaction-raw">GET Transaction Raw <span>Transactions</span></a>
|
||||||
<span>GET Transaction Raw</span>
|
|
||||||
</ng-template>
|
|
||||||
<ng-template ngbPanelContent>
|
|
||||||
<div class="endpoint">
|
<div class="endpoint">
|
||||||
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
||||||
<a [href]="wrapUrl(network.val, code.transactionRaw)" target="_blank">GET {{ baseNetworkUrl }}/api/tx/:txid/raw</a>
|
<a [href]="wrapUrl(network.val, code.transactionRaw)" target="_blank">GET {{ baseNetworkUrl }}/api/tx/:txid/raw</a>
|
||||||
@@ -793,14 +640,10 @@
|
|||||||
<div i18n>Returns a transaction as binary data.</div>
|
<div i18n>Returns a transaction as binary data.</div>
|
||||||
</div>
|
</div>
|
||||||
<app-code-template [hostname]="hostname" [code]="code.transactionRaw" [network]="network.val" ></app-code-template>
|
<app-code-template [hostname]="hostname" [code]="code.transactionRaw" [network]="network.val" ></app-code-template>
|
||||||
</ng-template>
|
</div>
|
||||||
</ngb-panel>
|
|
||||||
|
|
||||||
<ngb-panel *ngIf="network.val !== 'bisq'" id="transactionStatus">
|
<div class="endpoint-container" *ngIf="network.val !== 'bisq'" id="get-transaction-status">
|
||||||
<ng-template ngbPanelTitle>
|
<a class="section-header" [routerLink]="['./']" fragment="get-transaction-status">GET Transaction Status <span>Transactions</span></a>
|
||||||
<span>GET Transaction Status</span>
|
|
||||||
</ng-template>
|
|
||||||
<ng-template ngbPanelContent>
|
|
||||||
<div class="endpoint">
|
<div class="endpoint">
|
||||||
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
||||||
<a [href]="wrapUrl(network.val, code.transactionStatus)" target="_blank">GET {{ baseNetworkUrl }}/api/tx/:txid/status</a>
|
<a [href]="wrapUrl(network.val, code.transactionStatus)" target="_blank">GET {{ baseNetworkUrl }}/api/tx/:txid/status</a>
|
||||||
@@ -810,15 +653,10 @@
|
|||||||
<div i18n>Returns the confirmation status of a transaction. Available fields: <code>confirmed</code> (boolean), <code>block_height</code> (optional), and <code>block_hash</code> (optional).</div>
|
<div i18n>Returns the confirmation status of a transaction. Available fields: <code>confirmed</code> (boolean), <code>block_height</code> (optional), and <code>block_hash</code> (optional).</div>
|
||||||
</div>
|
</div>
|
||||||
<app-code-template [hostname]="hostname" [code]="code.transactionStatus" [network]="network.val" ></app-code-template>
|
<app-code-template [hostname]="hostname" [code]="code.transactionStatus" [network]="network.val" ></app-code-template>
|
||||||
</ng-template>
|
</div>
|
||||||
</ngb-panel>
|
|
||||||
|
|
||||||
<ngb-panel *ngIf="network.val === 'bisq'" id="transactionsBisq">
|
<div class="endpoint-container" *ngIf="network.val === 'bisq'" id="get-transactions">
|
||||||
<ng-template ngbPanelTitle>
|
<a class="section-header" [routerLink]="['./']" fragment="get-transactions">GET Transactions <span>Transactions</span></a>
|
||||||
<span>GET Transactions</span>
|
|
||||||
</ng-template>
|
|
||||||
<ng-template ngbPanelContent>
|
|
||||||
<div class="title">Get Mempool Txids</div>
|
|
||||||
<div class="endpoint">
|
<div class="endpoint">
|
||||||
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
||||||
<a [href]="wrapUrl(network.val, code.transactionsBisq)" target="_blank">GET {{ baseNetworkUrl }}/api/txs/:index/:length</a>
|
<a [href]="wrapUrl(network.val, code.transactionsBisq)" target="_blank">GET {{ baseNetworkUrl }}/api/txs/:index/:length</a>
|
||||||
@@ -828,27 +666,22 @@
|
|||||||
<div i18n>Returns :length of latest Bisq transactions, starting from :index.</div>
|
<div i18n>Returns :length of latest Bisq transactions, starting from :index.</div>
|
||||||
</div>
|
</div>
|
||||||
<app-code-template [hostname]="hostname" [code]="code.transactionsBisq" [network]="network.val" ></app-code-template>
|
<app-code-template [hostname]="hostname" [code]="code.transactionsBisq" [network]="network.val" ></app-code-template>
|
||||||
</ng-template>
|
</div>
|
||||||
</ngb-panel>
|
|
||||||
|
|
||||||
<ngb-panel *ngIf="network.val !== 'bisq'" id="postTransaction">
|
<div class="endpoint-container" *ngIf="network.val !== 'bisq'" id="post-transaction">
|
||||||
<ng-template ngbPanelTitle>
|
<a class="section-header" [routerLink]="['./']" fragment="post-transaction">POST Transaction <span>Transactions</span></a>
|
||||||
<span>POST Transaction</span>
|
|
||||||
</ng-template>
|
|
||||||
<ng-template ngbPanelContent>
|
|
||||||
<div class="endpoint">
|
<div class="endpoint">
|
||||||
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
<div class="subtitle" i18n="Api docs endpoint">Endpoint</div>
|
||||||
<div>POST /api/tx</div>
|
<div>POST {{ baseNetworkUrl }}/api/tx</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="description">
|
<div class="description">
|
||||||
<div class="subtitle" i18n>Description</div>
|
<div class="subtitle" i18n>Description</div>
|
||||||
<div i18n>Broadcast a raw transaction to the network. The transaction should be provided as hex in the request body. The <code>txid</code> will be returned on success.</div>
|
<div i18n>Broadcast a raw transaction to the network. The transaction should be provided as hex in the request body. The <code>txid</code> will be returned on success.</div>
|
||||||
</div>
|
</div>
|
||||||
<app-code-template [method]="'post'" [hostname]="hostname" [code]="code.transactionPost" [network]="network.val" ></app-code-template>
|
<app-code-template [method]="'post'" [hostname]="hostname" [code]="code.transactionPost" [network]="network.val" ></app-code-template>
|
||||||
</ng-template>
|
</div>
|
||||||
</ngb-panel>
|
|
||||||
|
|
||||||
</ngb-accordion>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -868,13 +701,5 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<br>
|
|
||||||
|
|
||||||
<div class="text-center">
|
|
||||||
<a [routerLink]="['/terms-of-service']" i18n="shared.terms-of-service|Terms of Service">Terms of Service</a>
|
|
||||||
|
|
|
||||||
<a [routerLink]="['/privacy-policy']" i18n="shared.privacy-policy|Privacy Policy">Privacy Policy</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|||||||
@@ -22,6 +22,10 @@ li.nav-item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.no-bottom-space {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.nav-tabs .nav-link.active {
|
.nav-tabs .nav-link.active {
|
||||||
border-bottom: 1px solid #fff;
|
border-bottom: 1px solid #fff;
|
||||||
@media (min-width: 676px){
|
@media (min-width: 676px){
|
||||||
@@ -72,10 +76,131 @@ li.nav-item {
|
|||||||
padding: 15px;
|
padding: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#restAPI .api-category {
|
#doc-nav-desktop {
|
||||||
margin: 30px 0;
|
width: 300px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.api-category h4 {
|
#doc-nav-desktop.relative {
|
||||||
margin-bottom: 15px;
|
float: left;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
#doc-nav-desktop.fixed {
|
||||||
|
float: unset;
|
||||||
|
position: fixed;
|
||||||
|
top: 20px;
|
||||||
|
overflow-y: auto;
|
||||||
|
height: calc(100vh - 50px);
|
||||||
|
scrollbar-color: #2d3348 #11131f;
|
||||||
|
scrollbar-width: thin;
|
||||||
|
}
|
||||||
|
::-webkit-scrollbar {
|
||||||
|
width: 3px;
|
||||||
|
}
|
||||||
|
::-webkit-scrollbar-track {
|
||||||
|
background: #11131f;
|
||||||
|
}
|
||||||
|
::-webkit-scrollbar-thumb {
|
||||||
|
background-color: #2d3348;
|
||||||
|
border-radius: 5px;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.doc-content {
|
||||||
|
width: calc(100% - 330px);
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.endpoint-container:before {
|
||||||
|
display: block;
|
||||||
|
content: " ";
|
||||||
|
height: 1px;
|
||||||
|
margin-top: -1px;
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.endpoint-container .section-header {
|
||||||
|
display: block;
|
||||||
|
background-color: #2d3348;
|
||||||
|
color: #1bd8f4;
|
||||||
|
padding: 1rem 1.3rem 1rem 1.3rem;
|
||||||
|
font-weight: bold;
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
margin: 20px 0 20px 0;
|
||||||
|
font-size: 24px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.endpoint-container .section-header:hover {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.endpoint-container .section-header span {
|
||||||
|
color: #fff;
|
||||||
|
background-color: #653b9c;
|
||||||
|
font-size: 12px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
font-weight: 400;
|
||||||
|
padding: 8px 10px;
|
||||||
|
letter-spacing: 1px;
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
font-family: monospace;
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
#doc-nav-mobile {
|
||||||
|
position: fixed;
|
||||||
|
top: 20px;
|
||||||
|
width: calc(100% - 60px);
|
||||||
|
z-index: 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
#doc-nav-mobile > div {
|
||||||
|
background-color: #2d3348;
|
||||||
|
z-index: 100;
|
||||||
|
border-radius: 0 0 0.5rem 0.5rem;
|
||||||
|
height: 55vh;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
#doc-nav-mobile button {
|
||||||
|
width: 100%;
|
||||||
|
background-color: #105fb0;
|
||||||
|
color: #fff;
|
||||||
|
border-color: #105fb0;
|
||||||
|
border-radius: 0.5rem 0.5rem 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 992px) {
|
||||||
|
|
||||||
|
.hide-on-mobile {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.doc-content {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.endpoint-container .section-header {
|
||||||
|
margin: 40px 0 70px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.endpoint-container .section-header span {
|
||||||
|
float: none;
|
||||||
|
position: absolute;
|
||||||
|
top: unset;
|
||||||
|
left: 0;
|
||||||
|
bottom: -50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.endpoint-container:before {
|
||||||
|
height: 30px;
|
||||||
|
margin-top: -12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 992px) {
|
||||||
|
.hide-on-desktop {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -7,7 +7,7 @@
|
|||||||
<pre><code [innerText]="wrapCurlTemplate(code)"></code></pre>
|
<pre><code [innerText]="wrapCurlTemplate(code)"></code></pre>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
</li>
|
</li>
|
||||||
<li ngbNavItem>
|
<li ngbNavItem *ngIf="network !== 'liquidtestnet'">
|
||||||
<a ngbNavLink>CommonJS</a>
|
<a ngbNavLink>CommonJS</a>
|
||||||
<ng-template ngbNavContent>
|
<ng-template ngbNavContent>
|
||||||
<div class="subtitle"><ng-container i18n="API Docs code example">Code Example</ng-container> <app-clipboard [text]="wrapCommonJS(code)"></app-clipboard></div>
|
<div class="subtitle"><ng-container i18n="API Docs code example">Code Example</ng-container> <app-clipboard [text]="wrapCommonJS(code)"></app-clipboard></div>
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
</ng-template>
|
</ng-template>
|
||||||
</li>
|
</li>
|
||||||
<li ngbNavItem>
|
<li ngbNavItem>
|
||||||
<a ngbNavLink>ES Module</a>
|
<a ngbNavLink *ngIf="network !== 'liquidtestnet'">ES Module</a>
|
||||||
<ng-template ngbNavContent>
|
<ng-template ngbNavContent>
|
||||||
<div class="subtitle"><ng-container i18n="API Docs install lib">Install Package</ng-container> <app-clipboard [text]="wrapImportTemplate()"></app-clipboard></div>
|
<div class="subtitle"><ng-container i18n="API Docs install lib">Install Package</ng-container> <app-clipboard [text]="wrapImportTemplate()"></app-clipboard></div>
|
||||||
<div class="links">
|
<div class="links">
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ export class CodeTemplateComponent implements OnInit {
|
|||||||
if (this.network === 'bisq') {
|
if (this.network === 'bisq') {
|
||||||
npmLink = `https://github.com/mempool/mempool.js/tree/main/npm-bisq-js`;
|
npmLink = `https://github.com/mempool/mempool.js/tree/main/npm-bisq-js`;
|
||||||
}
|
}
|
||||||
if (this.network === 'liquid') {
|
if (this.network === 'liquid' || this.network === 'liquidtestnet') {
|
||||||
npmLink = `https://github.com/mempool/mempool.js/tree/main/npm-liquid-js`;
|
npmLink = `https://github.com/mempool/mempool.js/tree/main/npm-liquid-js`;
|
||||||
}
|
}
|
||||||
return npmLink;
|
return npmLink;
|
||||||
@@ -37,7 +37,7 @@ export class CodeTemplateComponent implements OnInit {
|
|||||||
if (this.network === 'bisq') {
|
if (this.network === 'bisq') {
|
||||||
npmLink = `https://www.npmjs.org/package/@mempool/bisq.js`;
|
npmLink = `https://www.npmjs.org/package/@mempool/bisq.js`;
|
||||||
}
|
}
|
||||||
if (this.network === 'liquid') {
|
if (this.network === 'liquid' || this.network === 'liquidtestnet') {
|
||||||
npmLink = `https://www.npmjs.org/package/@mempool/liquid.js`;
|
npmLink = `https://www.npmjs.org/package/@mempool/liquid.js`;
|
||||||
}
|
}
|
||||||
return npmLink;
|
return npmLink;
|
||||||
@@ -50,7 +50,7 @@ export class CodeTemplateComponent implements OnInit {
|
|||||||
} else {
|
} else {
|
||||||
codeText = codeText.replace('%{0}', 'bitcoin');
|
codeText = codeText.replace('%{0}', 'bitcoin');
|
||||||
}
|
}
|
||||||
if(['', 'main', 'liquid', 'bisq'].includes(this.network)) {
|
if(['', 'main', 'liquid', 'bisq', 'liquidtestnet'].includes(this.network)) {
|
||||||
codeText = codeText.replace('mempoolJS();', `mempoolJS({
|
codeText = codeText.replace('mempoolJS();', `mempoolJS({
|
||||||
hostname: '${document.location.hostname}'
|
hostname: '${document.location.hostname}'
|
||||||
});`);
|
});`);
|
||||||
@@ -119,7 +119,7 @@ export class CodeTemplateComponent implements OnInit {
|
|||||||
if (this.network === 'signet') {
|
if (this.network === 'signet') {
|
||||||
codeText = this.replaceJSPlaceholder(codeText, code.codeSampleSignet.esModule);
|
codeText = this.replaceJSPlaceholder(codeText, code.codeSampleSignet.esModule);
|
||||||
}
|
}
|
||||||
if (this.network === 'liquid') {
|
if (this.network === 'liquid' || this.network === 'liquidtestnet') {
|
||||||
codeText = this.replaceJSPlaceholder(codeText, code.codeSampleLiquid.esModule);
|
codeText = this.replaceJSPlaceholder(codeText, code.codeSampleLiquid.esModule);
|
||||||
}
|
}
|
||||||
if (this.network === 'bisq') {
|
if (this.network === 'bisq') {
|
||||||
@@ -157,13 +157,17 @@ init();`;
|
|||||||
if (this.network === 'signet') {
|
if (this.network === 'signet') {
|
||||||
codeText = this.replaceJSPlaceholder(codeText, code.codeSampleSignet.esModule);
|
codeText = this.replaceJSPlaceholder(codeText, code.codeSampleSignet.esModule);
|
||||||
}
|
}
|
||||||
if (this.network === 'liquid') {
|
if (this.network === 'liquid' || this.network === 'liquidtestnet') {
|
||||||
codeText = this.replaceJSPlaceholder(codeText, code.codeSampleLiquid.esModule);
|
codeText = this.replaceJSPlaceholder(codeText, code.codeSampleLiquid.esModule);
|
||||||
}
|
}
|
||||||
if (this.network === 'bisq') {
|
if (this.network === 'bisq') {
|
||||||
codeText = this.replaceJSPlaceholder(codeText, code.codeSampleBisq.esModule);
|
codeText = this.replaceJSPlaceholder(codeText, code.codeSampleBisq.esModule);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (code.noWrap) {
|
||||||
|
return codeText;
|
||||||
|
}
|
||||||
|
|
||||||
let importText = `<script src="https://mempool.space/mempool.js"></script>`;
|
let importText = `<script src="https://mempool.space/mempool.js"></script>`;
|
||||||
if (this.env.BASE_MODULE === 'bisq') {
|
if (this.env.BASE_MODULE === 'bisq') {
|
||||||
importText = `<script src="https://bisq.markets/bisq.js"></script>`;
|
importText = `<script src="https://bisq.markets/bisq.js"></script>`;
|
||||||
@@ -236,6 +240,9 @@ yarn add @mempool/liquid.js`;
|
|||||||
if (this.network === 'liquid') {
|
if (this.network === 'liquid') {
|
||||||
return this.replaceCurlPlaceholder(code.codeTemplate.curl, code.codeSampleLiquid);
|
return this.replaceCurlPlaceholder(code.codeTemplate.curl, code.codeSampleLiquid);
|
||||||
}
|
}
|
||||||
|
if (this.network === 'liquidtestnet') {
|
||||||
|
return this.replaceCurlPlaceholder(code.codeTemplate.curl, code.codeSampleLiquidTestnet);
|
||||||
|
}
|
||||||
if (this.network === 'bisq') {
|
if (this.network === 'bisq') {
|
||||||
return this.replaceCurlPlaceholder(code.codeTemplate.curl, code.codeSampleBisq);
|
return this.replaceCurlPlaceholder(code.codeTemplate.curl, code.codeSampleBisq);
|
||||||
}
|
}
|
||||||
@@ -258,6 +265,9 @@ yarn add @mempool/liquid.js`;
|
|||||||
if (this.network === 'liquid') {
|
if (this.network === 'liquid') {
|
||||||
return code.codeSampleLiquid.response;
|
return code.codeSampleLiquid.response;
|
||||||
}
|
}
|
||||||
|
if (this.network === 'liquidtestnet') {
|
||||||
|
return code.codeSampleLiquidTestnet.response;
|
||||||
|
}
|
||||||
if (this.network === 'bisq') {
|
if (this.network === 'bisq') {
|
||||||
return code.codeSampleBisq.response;
|
return code.codeSampleBisq.response;
|
||||||
}
|
}
|
||||||
@@ -293,10 +303,18 @@ yarn add @mempool/liquid.js`;
|
|||||||
return `curl -X POST -sSLd "${text}"`;
|
return `curl -X POST -sSLd "${text}"`;
|
||||||
}
|
}
|
||||||
return `curl -sSL "${this.hostname}/${this.network}${text}"`;
|
return `curl -sSL "${this.hostname}/${this.network}${text}"`;
|
||||||
|
} else if (this.env.BASE_MODULE === 'liquid') {
|
||||||
|
if (this.method === 'post') {
|
||||||
|
if (this.network !== 'liquid') {
|
||||||
|
text = text.replace('/api', `/${this.network}/api`);
|
||||||
}
|
}
|
||||||
if (this.env.BASE_MODULE !== 'mempool') {
|
return `curl -X POST -sSLd "${text}"`;
|
||||||
|
}
|
||||||
|
return ( this.network === 'liquid' ? `curl -sSL "${this.hostname}${text}"` : `curl -sSL "${this.hostname}/${this.network}${text}"` );
|
||||||
|
} else {
|
||||||
return `curl -sSL "${this.hostname}${text}"`;
|
return `curl -sSL "${this.hostname}${text}"`;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,5 +27,13 @@
|
|||||||
|
|
||||||
<div id="main-tab-content" [ngbNavOutlet]="nav" class="mt-2"></div>
|
<div id="main-tab-content" [ngbNavOutlet]="nav" class="mt-2"></div>
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<div id="footer" class="text-center">
|
||||||
|
<a [routerLink]="['/terms-of-service']" i18n="shared.terms-of-service|Terms of Service">Terms of Service</a>
|
||||||
|
|
|
||||||
|
<a [routerLink]="['/privacy-policy']" i18n="shared.privacy-policy|Privacy Policy">Privacy Policy</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,4 +1,9 @@
|
|||||||
#main-tab-content {
|
#main-tab-content {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
padding-top: 10px;
|
padding-top: 10px;
|
||||||
|
scroll-behavior: smooth;
|
||||||
|
}
|
||||||
|
|
||||||
|
#footer {
|
||||||
|
clear: both;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,6 @@ export class DocsComponent implements OnInit {
|
|||||||
const url = this.route.snapshot.url;
|
const url = this.route.snapshot.url;
|
||||||
this.activeTab = ( url[2].path === "rest" ) ? 0 : 1;
|
this.activeTab = ( url[2].path === "rest" ) ? 0 : 1;
|
||||||
this.env = this.stateService.env;
|
this.env = this.stateService.env;
|
||||||
this.showWebSocketTab = ( ! ( ( this.env.BASE_MODULE === "bisq" ) || ( this.stateService.network === "bisq" ) ) );
|
this.showWebSocketTab = ( ! ( ( this.env.BASE_MODULE === "bisq" ) || ( this.stateService.network === "bisq" ) || ( this.stateService.network === "liquidtestnet" ) ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ export class FeesBoxComponent implements OnInit {
|
|||||||
) { }
|
) { }
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.defaultFee = this.stateService.network === 'liquid' ? 0.1 : 1;
|
this.defaultFee = this.stateService.network === 'liquid' || this.stateService.network === 'liquidtestnet' ? 0.1 : 1;
|
||||||
|
|
||||||
this.isLoadingWebSocket$ = this.stateService.isLoadingWebSocket$;
|
this.isLoadingWebSocket$ = this.stateService.isLoadingWebSocket$;
|
||||||
this.feeEstimations$ = this.stateService.mempoolBlocks$
|
this.feeEstimations$ = this.stateService.mempoolBlocks$
|
||||||
|
|||||||
@@ -67,10 +67,12 @@ export class IncomingTransactionsGraphComponent implements OnInit, OnChanges {
|
|||||||
left: this.left,
|
left: this.left,
|
||||||
},
|
},
|
||||||
animation: false,
|
animation: false,
|
||||||
dataZoom: [{
|
dataZoom: (this.template === 'widget' && this.isMobile()) ? null : [{
|
||||||
type: 'inside',
|
type: 'inside',
|
||||||
realtime: true,
|
realtime: true,
|
||||||
|
zoomLock: (this.template === 'widget') ? true : false,
|
||||||
zoomOnMouseWheel: (this.template === 'advanced') ? true : false,
|
zoomOnMouseWheel: (this.template === 'advanced') ? true : false,
|
||||||
|
moveOnMouseMove: (this.template === 'widget') ? true : false,
|
||||||
maxSpan: 100,
|
maxSpan: 100,
|
||||||
minSpan: 10,
|
minSpan: 10,
|
||||||
}, {
|
}, {
|
||||||
@@ -91,6 +93,7 @@ export class IncomingTransactionsGraphComponent implements OnInit, OnChanges {
|
|||||||
},
|
},
|
||||||
}],
|
}],
|
||||||
tooltip: {
|
tooltip: {
|
||||||
|
show: !this.isMobile(),
|
||||||
trigger: 'axis',
|
trigger: 'axis',
|
||||||
position: (pos, params, el, elRect, size) => {
|
position: (pos, params, el, elRect, size) => {
|
||||||
const obj = { top: -20 };
|
const obj = { top: -20 };
|
||||||
@@ -217,4 +220,8 @@ export class IncomingTransactionsGraphComponent implements OnInit, OnChanges {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isMobile() {
|
||||||
|
return window.innerWidth <= 767.98;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { DOCUMENT } from '@angular/common';
|
import { DOCUMENT } from '@angular/common';
|
||||||
import { ChangeDetectionStrategy, Component, Inject, OnInit } from '@angular/core';
|
import { ChangeDetectionStrategy, Component, Inject, OnInit } from '@angular/core';
|
||||||
import { FormBuilder, FormGroup } from '@angular/forms';
|
import { FormBuilder, FormGroup } from '@angular/forms';
|
||||||
import { Language, languages } from 'src/app/app.constants';
|
import { languages } from 'src/app/app.constants';
|
||||||
import { StateService } from 'src/app/services/state.service';
|
import { LanguageService } from 'src/app/services/language.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-language-selector',
|
selector: 'app-language-selector',
|
||||||
@@ -12,42 +12,25 @@ import { StateService } from 'src/app/services/state.service';
|
|||||||
})
|
})
|
||||||
export class LanguageSelectorComponent implements OnInit {
|
export class LanguageSelectorComponent implements OnInit {
|
||||||
languageForm: FormGroup;
|
languageForm: FormGroup;
|
||||||
languages: Language[];
|
languages = languages;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
|
@Inject(DOCUMENT) private document: Document,
|
||||||
private formBuilder: FormBuilder,
|
private formBuilder: FormBuilder,
|
||||||
private stateService: StateService,
|
private languageService: LanguageService,
|
||||||
@Inject(DOCUMENT) private document: Document
|
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.languages = languages;
|
|
||||||
|
|
||||||
this.languageForm = this.formBuilder.group({
|
this.languageForm = this.formBuilder.group({
|
||||||
language: ['']
|
language: ['en']
|
||||||
});
|
});
|
||||||
this.setLanguageFromUrl();
|
this.languageForm.get('language').setValue(this.languageService.getLanguage());
|
||||||
}
|
|
||||||
|
|
||||||
setLanguageFromUrl() {
|
|
||||||
const urlLanguage = this.document.location.pathname.split('/')[1];
|
|
||||||
if (this.languages.map((lang) => lang.code).indexOf(urlLanguage) > -1) {
|
|
||||||
this.languageForm.get('language').setValue(urlLanguage);
|
|
||||||
} else {
|
|
||||||
this.languageForm.get('language').setValue('en');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
changeLanguage() {
|
changeLanguage() {
|
||||||
const language = this.languageForm.get('language').value;
|
const newLang = this.languageForm.get('language').value;
|
||||||
try {
|
this.languageService.setLanguage(newLang);
|
||||||
document.cookie = `lang=${language}; expires=Thu, 18 Dec 2050 12:00:00 UTC; path=/`;
|
const rawUrlPath = this.languageService.stripLanguageFromUrl(null);
|
||||||
} catch (e) { }
|
this.document.location.href = (newLang !== 'en' ? `/${newLang}` : '') + rawUrlPath;
|
||||||
|
|
||||||
if (this.stateService.env.BASE_MODULE === 'mempool') {
|
|
||||||
this.document.location.href = `/${language}/${this.stateService.network}`;
|
|
||||||
} else {
|
|
||||||
this.document.location.href = `/${language}`;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
<ng-container *ngIf="{ val: network$ | async } as network">
|
||||||
<header>
|
<header>
|
||||||
<nav class="navbar navbar-expand-md navbar-dark bg-dark">
|
<nav class="navbar navbar-expand-md navbar-dark bg-dark">
|
||||||
<a class="navbar-brand" [routerLink]="['/' | relativeUrl]" style="position: relative;">
|
<a class="navbar-brand" [routerLink]="['/' | relativeUrl]" style="position: relative;">
|
||||||
@@ -10,22 +11,23 @@
|
|||||||
</ng-container>
|
</ng-container>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<div ngbDropdown (window:resize)="onResize($event)" class="dropdown-container" *ngIf="env.TESTNET_ENABLED || env.SIGNET_ENABLED || env.LIQUID_ENABLED || env.BISQ_ENABLED">
|
<div ngbDropdown (window:resize)="onResize($event)" class="dropdown-container" *ngIf="env.TESTNET_ENABLED || env.SIGNET_ENABLED || env.LIQUID_ENABLED || env.BISQ_ENABLED || env.LIQUID_TESTNET_ENABLED">
|
||||||
<button ngbDropdownToggle type="button" class="btn btn-secondary dropdown-toggle-split" aria-haspopup="true">
|
<button ngbDropdownToggle type="button" class="btn btn-secondary dropdown-toggle-split" aria-haspopup="true">
|
||||||
<img src="./resources/liquid-logo.png" style="width: 25px; height: 25px;" class="mr-1">
|
<img src="./resources/{{ network.val === '' ? 'liquid' : network.val }}-logo.png" style="width: 25px; height: 25px;" class="mr-1">
|
||||||
</button>
|
</button>
|
||||||
<div ngbDropdownMenu [ngClass]="{'dropdown-menu-right' : isMobile}">
|
<div ngbDropdownMenu [ngClass]="{'dropdown-menu-right' : isMobile}">
|
||||||
<a href="https://mempool.space" ngbDropdownItem class="mainnet"><img src="./resources/bitcoin-logo.png" style="width: 30px;" class="mr-1"> Mainnet</a>
|
<a [href]="env.MEMPOOL_WEBSITE_URL + urlLanguage" ngbDropdownItem class="mainnet"><img src="./resources/bitcoin-logo.png" style="width: 30px;" class="mr-1"> Mainnet</a>
|
||||||
<a href="https://mempool.space/signet" ngbDropdownItem *ngIf="env.SIGNET_ENABLED" class="signet"><img src="./resources/signet-logo.png" style="width: 30px;" class="mr-1"> Signet</a>
|
<a [href]="env.MEMPOOL_WEBSITE_URL + urlLanguage + '/signet'" ngbDropdownItem *ngIf="env.SIGNET_ENABLED" class="signet"><img src="./resources/signet-logo.png" style="width: 30px;" class="mr-1"> Signet</a>
|
||||||
<a href="https://mempool.space/testnet" ngbDropdownItem *ngIf="env.TESTNET_ENABLED" class="testnet"><img src="./resources/testnet-logo.png" style="width: 30px;" class="mr-1"> Testnet</a>
|
<a [href]="env.MEMPOOL_WEBSITE_URL + urlLanguage + '/testnet'" ngbDropdownItem *ngIf="env.TESTNET_ENABLED" class="testnet"><img src="./resources/testnet-logo.png" style="width: 30px;" class="mr-1"> Testnet</a>
|
||||||
<h6 class="dropdown-header" i18n="master-page.layer2-networks-header">Layer 2 Networks</h6>
|
<h6 class="dropdown-header" i18n="master-page.layer2-networks-header">Layer 2 Networks</h6>
|
||||||
<a href="https://bisq.markets" ngbDropdownItem class="mainnet"><img src="./resources/bisq-logo.png" style="width: 30px;" class="mr-1"> Bisq</a>
|
<a [href]="env.BISQ_WEBSITE_URL + urlLanguage" ngbDropdownItem class="mainnet"><img src="./resources/bisq-logo.png" style="width: 30px;" class="mr-1"> Bisq</a>
|
||||||
<button ngbDropdownItem class="liquid active" routerLink="/"><img src="./resources/liquid-logo.png" style="width: 30px;" class="mr-1"> Liquid</button>
|
<button ngbDropdownItem class="liquid" [class.active]="network.val === 'liquid'" routerLink="/"><img src="./resources/liquid-logo.png" style="width: 30px;" class="mr-1"> Liquid</button>
|
||||||
|
<button ngbDropdownItem *ngIf="env.LIQUID_TESTNET_ENABLED" class="liquidtestnet" [class.active]="network.val === 'liquidtestnet'" routerLink="/testnet"><img src="./resources/liquidtestnet-logo.png" style="width: 30px;" class="mr-1"> Liquid Testnet</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="navbar-collapse" id="navbarCollapse">
|
<div class="navbar-collapse" id="navbarCollapse">
|
||||||
<ul class="navbar-nav liquid">
|
<ul class="navbar-nav {{ network.val }}">
|
||||||
<li class="nav-item" routerLinkActive="active" [routerLinkActiveOptions]="{exact: true}">
|
<li class="nav-item" routerLinkActive="active" [routerLinkActiveOptions]="{exact: true}">
|
||||||
<a class="nav-link" [routerLink]="['/' | relativeUrl]" (click)="collapse()"><fa-icon [icon]="['fas', 'tachometer-alt']" [fixedWidth]="true" i18n-title="master-page.dashboard" title="Dashboard"></fa-icon></a>
|
<a class="nav-link" [routerLink]="['/' | relativeUrl]" (click)="collapse()"><fa-icon [icon]="['fas', 'tachometer-alt']" [fixedWidth]="true" i18n-title="master-page.dashboard" title="Dashboard"></fa-icon></a>
|
||||||
</li>
|
</li>
|
||||||
@@ -41,7 +43,7 @@
|
|||||||
</li>
|
</li>
|
||||||
-->
|
-->
|
||||||
<li class="nav-item" routerLinkActive="active">
|
<li class="nav-item" routerLinkActive="active">
|
||||||
<a class="nav-link" [routerLink]="['/assets']" (click)="collapse()"><fa-icon [icon]="['fas', 'database']" [fixedWidth]="true" i18n-title="master-page.assets" title="Assets"></fa-icon></a>
|
<a class="nav-link" [routerLink]="['/assets' | relativeUrl]" (click)="collapse()"><fa-icon [icon]="['fas', 'database']" [fixedWidth]="true" i18n-title="master-page.assets" title="Assets"></fa-icon></a>
|
||||||
</li>
|
</li>
|
||||||
<li [hidden]="isMobile" class="nav-item mr-2" routerLinkActive="active">
|
<li [hidden]="isMobile" class="nav-item mr-2" routerLinkActive="active">
|
||||||
<a class="nav-link" [routerLink]="['/docs' | relativeUrl]" (click)="collapse()"><fa-icon [icon]="['fas', 'book']" [fixedWidth]="true" i18n-title="master-page.docs" title="Docs"></fa-icon></a>
|
<a class="nav-link" [routerLink]="['/docs' | relativeUrl]" (click)="collapse()"><fa-icon [icon]="['fas', 'book']" [fixedWidth]="true" i18n-title="master-page.docs" title="Docs"></fa-icon></a>
|
||||||
@@ -60,3 +62,4 @@
|
|||||||
<router-outlet></router-outlet>
|
<router-outlet></router-outlet>
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
</ng-container>
|
||||||
@@ -102,6 +102,10 @@ nav {
|
|||||||
background-color: #116761;
|
background-color: #116761;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.liquidtestnet.active {
|
||||||
|
background-color: #494a4a;
|
||||||
|
}
|
||||||
|
|
||||||
.testnet.active {
|
.testnet.active {
|
||||||
background-color: #1d486f;
|
background-color: #1d486f;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import { Env, StateService } from '../../services/state.service';
|
import { Env, StateService } from '../../services/state.service';
|
||||||
import { Observable} from 'rxjs';
|
import { merge, Observable, of} from 'rxjs';
|
||||||
|
import { LanguageService } from 'src/app/services/language.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-liquid-master-page',
|
selector: 'app-liquid-master-page',
|
||||||
@@ -13,14 +14,19 @@ export class LiquidMasterPageComponent implements OnInit {
|
|||||||
navCollapsed = false;
|
navCollapsed = false;
|
||||||
isMobile = window.innerWidth <= 767.98;
|
isMobile = window.innerWidth <= 767.98;
|
||||||
officialMempoolSpace = this.stateService.env.OFFICIAL_MEMPOOL_SPACE;
|
officialMempoolSpace = this.stateService.env.OFFICIAL_MEMPOOL_SPACE;
|
||||||
|
network$: Observable<string>;
|
||||||
|
urlLanguage: string;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private stateService: StateService,
|
private stateService: StateService,
|
||||||
|
private languageService: LanguageService,
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.env = this.stateService.env;
|
this.env = this.stateService.env;
|
||||||
this.connectionState$ = this.stateService.connectionState$;
|
this.connectionState$ = this.stateService.connectionState$;
|
||||||
|
this.network$ = merge(of(''), this.stateService.networkChanged$);
|
||||||
|
this.urlLanguage = this.languageService.getLanguageForUrl();
|
||||||
}
|
}
|
||||||
|
|
||||||
collapse(): void {
|
collapse(): void {
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
</ng-container>
|
</ng-container>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<div (window:resize)="onResize($event)" ngbDropdown class="dropdown-container" *ngIf="env.TESTNET_ENABLED || env.SIGNET_ENABLED || env.LIQUID_ENABLED || env.BISQ_ENABLED">
|
<div (window:resize)="onResize($event)" ngbDropdown class="dropdown-container" *ngIf="env.TESTNET_ENABLED || env.SIGNET_ENABLED || env.LIQUID_ENABLED || env.BISQ_ENABLED || env.LIQUID_TESTNET_ENABLED">
|
||||||
<button ngbDropdownToggle type="button" class="btn btn-secondary dropdown-toggle-split" aria-haspopup="true">
|
<button ngbDropdownToggle type="button" class="btn btn-secondary dropdown-toggle-split" aria-haspopup="true">
|
||||||
<img src="./resources/{{ network.val === '' ? 'bitcoin' : network.val }}-logo.png" style="width: 25px; height: 25px;" class="mr-1">
|
<img src="./resources/{{ network.val === '' ? 'bitcoin' : network.val }}-logo.png" style="width: 25px; height: 25px;" class="mr-1">
|
||||||
</button>
|
</button>
|
||||||
@@ -20,10 +20,9 @@
|
|||||||
<button ngbDropdownItem *ngIf="env.SIGNET_ENABLED" class="signet" [class.active]="network.val === 'signet'" routerLink="/signet"><img src="./resources/signet-logo.png" style="width: 30px;" class="mr-1"> Signet</button>
|
<button ngbDropdownItem *ngIf="env.SIGNET_ENABLED" class="signet" [class.active]="network.val === 'signet'" routerLink="/signet"><img src="./resources/signet-logo.png" style="width: 30px;" class="mr-1"> Signet</button>
|
||||||
<button ngbDropdownItem *ngIf="env.TESTNET_ENABLED" class="testnet" [class.active]="network.val === 'testnet'" routerLink="/testnet"><img src="./resources/testnet-logo.png" style="width: 30px;" class="mr-1"> Testnet</button>
|
<button ngbDropdownItem *ngIf="env.TESTNET_ENABLED" class="testnet" [class.active]="network.val === 'testnet'" routerLink="/testnet"><img src="./resources/testnet-logo.png" style="width: 30px;" class="mr-1"> Testnet</button>
|
||||||
<h6 *ngIf="env.LIQUID_ENABLED || env.BISQ_ENABLED" class="dropdown-header" i18n="master-page.layer2-networks-header">Layer 2 Networks</h6>
|
<h6 *ngIf="env.LIQUID_ENABLED || env.BISQ_ENABLED" class="dropdown-header" i18n="master-page.layer2-networks-header">Layer 2 Networks</h6>
|
||||||
<a href="https://bisq.markets" ngbDropdownItem *ngIf="env.BISQ_ENABLED && env.OFFICIAL_MEMPOOL_SPACE" class="bisq"><img src="./resources/bisq-logo.png" style="width: 30px;" class="mr-1"> Bisq</a>
|
<a [href]="env.BISQ_WEBSITE_URL + urlLanguage" ngbDropdownItem *ngIf="env.BISQ_ENABLED" class="bisq"><img src="./resources/bisq-logo.png" style="width: 30px;" class="mr-1"> Bisq</a>
|
||||||
<button ngbDropdownItem *ngIf="env.BISQ_ENABLED && !env.OFFICIAL_MEMPOOL_SPACE" class="bisq" [class.active]="network.val === 'bisq'" routerLink="/bisq"><img src="./resources/bisq-logo.png" style="width: 30px;" class="mr-1"> Bisq</button>
|
<a [href]="env.LIQUID_WEBSITE_URL + urlLanguage" ngbDropdownItem *ngIf="env.LIQUID_ENABLED" class="liquid" [class.active]="network.val === 'liquid'"><img src="./resources/liquid-logo.png" style="width: 30px;" class="mr-1"> Liquid</a>
|
||||||
<a href="https://liquid.network" ngbDropdownItem *ngIf="env.LIQUID_ENABLED && env.OFFICIAL_MEMPOOL_SPACE" class="liquid" [class.active]="network.val === 'liquid'"><img src="./resources/liquid-logo.png" style="width: 30px;" class="mr-1"> Liquid</a>
|
<a [href]="env.LIQUID_WEBSITE_URL + urlLanguage + '/testnet'" ngbDropdownItem *ngIf="env.LIQUID_TESTNET_ENABLED" class="liquidtestnet" [class.active]="network.val === 'liquid'"><img src="./resources/liquidtestnet-logo.png" style="width: 30px;" class="mr-1"> Liquid Testnet</a>
|
||||||
<button ngbDropdownItem *ngIf="env.LIQUID_ENABLED && !env.OFFICIAL_MEMPOOL_SPACE" class="liquid" [class.active]="network.val === 'liquid'" routerLink="/liquid"><img src="./resources/liquid-logo.png" style="width: 30px;" class="mr-1"> Liquid</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -54,8 +53,8 @@
|
|||||||
<a class="nav-link" [routerLink]="['/tv' | relativeUrl]" (click)="collapse()"><fa-icon [icon]="['fas', 'tv']" [fixedWidth]="true" i18n-title="master-page.tvview" title="TV view"></fa-icon></a>
|
<a class="nav-link" [routerLink]="['/tv' | relativeUrl]" (click)="collapse()"><fa-icon [icon]="['fas', 'tv']" [fixedWidth]="true" i18n-title="master-page.tvview" title="TV view"></fa-icon></a>
|
||||||
</li>
|
</li>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
<li *ngIf="network.val === 'liquid'" class="nav-item" routerLinkActive="active">
|
<li *ngIf="network.val === 'liquid' || network.val === 'liquidtestnet'" class="nav-item" routerLinkActive="active">
|
||||||
<a class="nav-link" [routerLink]="['/liquid/assets']" (click)="collapse()"><fa-icon [icon]="['fas', 'database']" [fixedWidth]="true" i18n-title="master-page.assets" title="Assets"></fa-icon></a>
|
<a class="nav-link" [routerLink]="['/assets' | relativeUrl]" (click)="collapse()"><fa-icon [icon]="['fas', 'database']" [fixedWidth]="true" i18n-title="master-page.assets" title="Assets"></fa-icon></a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item" routerLinkActive="active">
|
<li class="nav-item" routerLinkActive="active">
|
||||||
<a class="nav-link" [routerLink]="['/docs' | relativeUrl ]" (click)="collapse()"><fa-icon [icon]="['fas', 'book']" [fixedWidth]="true" i18n-title="documentation.title" title="Documentation"></fa-icon></a>
|
<a class="nav-link" [routerLink]="['/docs' | relativeUrl ]" (click)="collapse()"><fa-icon [icon]="['fas', 'book']" [fixedWidth]="true" i18n-title="documentation.title" title="Documentation"></fa-icon></a>
|
||||||
|
|||||||
@@ -110,6 +110,10 @@ nav {
|
|||||||
background-color: #116761;
|
background-color: #116761;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.liquidtestnet.active {
|
||||||
|
background-color: #494a4a;
|
||||||
|
}
|
||||||
|
|
||||||
.testnet.active {
|
.testnet.active {
|
||||||
background-color: #1d486f;
|
background-color: #1d486f;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import { Env, StateService } from '../../services/state.service';
|
import { Env, StateService } from '../../services/state.service';
|
||||||
import { Observable, merge, of } from 'rxjs';
|
import { Observable, merge, of } from 'rxjs';
|
||||||
|
import { LanguageService } from 'src/app/services/language.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-master-page',
|
selector: 'app-master-page',
|
||||||
@@ -14,15 +15,18 @@ export class MasterPageComponent implements OnInit {
|
|||||||
navCollapsed = false;
|
navCollapsed = false;
|
||||||
isMobile = window.innerWidth <= 767.98;
|
isMobile = window.innerWidth <= 767.98;
|
||||||
officialMempoolSpace = this.stateService.env.OFFICIAL_MEMPOOL_SPACE;
|
officialMempoolSpace = this.stateService.env.OFFICIAL_MEMPOOL_SPACE;
|
||||||
|
urlLanguage: string;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private stateService: StateService,
|
private stateService: StateService,
|
||||||
|
private languageService: LanguageService,
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.env = this.stateService.env;
|
this.env = this.stateService.env;
|
||||||
this.connectionState$ = this.stateService.connectionState$;
|
this.connectionState$ = this.stateService.connectionState$;
|
||||||
this.network$ = merge(of(''), this.stateService.networkChanged$);
|
this.network$ = merge(of(''), this.stateService.networkChanged$);
|
||||||
|
this.urlLanguage = this.languageService.getLanguageForUrl();
|
||||||
}
|
}
|
||||||
|
|
||||||
collapse(): void {
|
collapse(): void {
|
||||||
|
|||||||
@@ -3,7 +3,8 @@
|
|||||||
<div class="flashing">
|
<div class="flashing">
|
||||||
<ng-template ngFor let-projectedBlock [ngForOf]="mempoolBlocks$ | async" let-i="index" [ngForTrackBy]="trackByFn">
|
<ng-template ngFor let-projectedBlock [ngForOf]="mempoolBlocks$ | async" let-i="index" [ngForTrackBy]="trackByFn">
|
||||||
<div class="bitcoin-block text-center mempool-block" id="mempool-block-{{ i }}" [ngStyle]="mempoolBlockStyles[i]" [class.blink-bg]="projectedBlock.blink">
|
<div class="bitcoin-block text-center mempool-block" id="mempool-block-{{ i }}" [ngStyle]="mempoolBlockStyles[i]" [class.blink-bg]="projectedBlock.blink">
|
||||||
<a [routerLink]="['/mempool-block/' | relativeUrl, i]" class="blockLink"> </a>
|
<a draggable="false" [routerLink]="['/mempool-block/' | relativeUrl, i]"
|
||||||
|
class="blockLink" [ngClass]="{'disabled': (this.stateService.blockScrolling$ | async)}"> </a>
|
||||||
<div class="block-body">
|
<div class="block-body">
|
||||||
<div class="fees">
|
<div class="fees">
|
||||||
~{{ projectedBlock.medianFee | number:feeRounding }} <span i18n="shared.sat-vbyte|sat/vB">sat/vB</span>
|
~{{ projectedBlock.medianFee | number:feeRounding }} <span i18n="shared.sat-vbyte|sat/vB">sat/vB</span>
|
||||||
@@ -18,7 +19,7 @@
|
|||||||
<ng-template #transactionsPlural let-i i18n="shared.transaction-count.plural">{{ i }} transactions</ng-template>
|
<ng-template #transactionsPlural let-i i18n="shared.transaction-count.plural">{{ i }} transactions</ng-template>
|
||||||
</div>
|
</div>
|
||||||
<div class="time-difference" *ngIf="projectedBlock.blockVSize <= stateService.blockVSize; else mergedBlock">
|
<div class="time-difference" *ngIf="projectedBlock.blockVSize <= stateService.blockVSize; else mergedBlock">
|
||||||
<ng-template [ngIf]="network === 'liquid'" [ngIfElse]="timeDiffMainnet">
|
<ng-template [ngIf]="network === 'liquid' || network === 'liquidtestnet'" [ngIfElse]="timeDiffMainnet">
|
||||||
<app-time-until [time]="(1 * i) + now + 61000" [fastRender]="false" [fixedRender]="true"></app-time-until>
|
<app-time-until [time]="(1 * i) + now + 61000" [fastRender]="false" [fixedRender]="true"></app-time-until>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
<ng-template #timeDiffMainnet>
|
<ng-template #timeDiffMainnet>
|
||||||
|
|||||||
@@ -117,6 +117,10 @@
|
|||||||
z-index: 10;
|
z-index: 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.blockLink.disabled {
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
.blockLink:hover {
|
.blockLink:hover {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { Router } from '@angular/router';
|
|||||||
import { take, map, switchMap } from 'rxjs/operators';
|
import { take, map, switchMap } from 'rxjs/operators';
|
||||||
import { feeLevels, mempoolFeeColors } from 'src/app/app.constants';
|
import { feeLevels, mempoolFeeColors } from 'src/app/app.constants';
|
||||||
import { specialBlocks } from 'src/app/app.constants';
|
import { specialBlocks } from 'src/app/app.constants';
|
||||||
|
import { RelativeUrlPipe } from 'src/app/shared/pipes/relative-url/relative-url.pipe';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-mempool-blocks',
|
selector: 'app-mempool-blocks',
|
||||||
@@ -52,10 +53,11 @@ export class MempoolBlocksComponent implements OnInit, OnDestroy {
|
|||||||
private router: Router,
|
private router: Router,
|
||||||
public stateService: StateService,
|
public stateService: StateService,
|
||||||
private cd: ChangeDetectorRef,
|
private cd: ChangeDetectorRef,
|
||||||
|
private relativeUrlPipe: RelativeUrlPipe,
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
if (this.stateService.network === 'liquid') {
|
if (this.stateService.network === 'liquid' || this.stateService.network === 'liquidtestnet') {
|
||||||
this.feeRounding = '1.0-1';
|
this.feeRounding = '1.0-1';
|
||||||
}
|
}
|
||||||
this.mempoolEmptyBlocks.forEach((b) => {
|
this.mempoolEmptyBlocks.forEach((b) => {
|
||||||
@@ -166,19 +168,19 @@ export class MempoolBlocksComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
if (event.key === 'ArrowRight') {
|
if (event.key === 'ArrowRight') {
|
||||||
if (this.mempoolBlocks[this.markIndex - 1]) {
|
if (this.mempoolBlocks[this.markIndex - 1]) {
|
||||||
this.router.navigate([(this.network ? '/' + this.network : '') + '/mempool-block/', this.markIndex - 1]);
|
this.router.navigate([this.relativeUrlPipe.transform('mempool-block/'), this.markIndex - 1]);
|
||||||
} else {
|
} else {
|
||||||
this.stateService.blocks$
|
this.stateService.blocks$
|
||||||
.pipe(take(this.stateService.env.MEMPOOL_BLOCKS_AMOUNT))
|
.pipe(take(this.stateService.env.MEMPOOL_BLOCKS_AMOUNT))
|
||||||
.subscribe(([block]) => {
|
.subscribe(([block]) => {
|
||||||
if (this.stateService.latestBlockHeight === block.height) {
|
if (this.stateService.latestBlockHeight === block.height) {
|
||||||
this.router.navigate([(this.network ? '/' + this.network : '') + '/block/', block.id], { state: { data: { block } }});
|
this.router.navigate([this.relativeUrlPipe.transform('/block/'), block.id], { state: { data: { block } }});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else if (event.key === 'ArrowLeft') {
|
} else if (event.key === 'ArrowLeft') {
|
||||||
if (this.mempoolBlocks[this.markIndex + 1]) {
|
if (this.mempoolBlocks[this.markIndex + 1]) {
|
||||||
this.router.navigate([(this.network ? '/' + this.network : '') + '/mempool-block/', this.markIndex + 1]);
|
this.router.navigate([this.relativeUrlPipe.transform('/mempool-block/'), this.markIndex + 1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -170,7 +170,7 @@ export class MempoolGraphComponent implements OnInit, OnChanges {
|
|||||||
hover: true,
|
hover: true,
|
||||||
color: this.inverted ? [...newColors].reverse() : newColors,
|
color: this.inverted ? [...newColors].reverse() : newColors,
|
||||||
tooltip: {
|
tooltip: {
|
||||||
show: (window.innerWidth >= 768) ? true : false,
|
show: !this.isMobile(),
|
||||||
trigger: 'axis',
|
trigger: 'axis',
|
||||||
alwaysShowContent: false,
|
alwaysShowContent: false,
|
||||||
position: (pos, params, el, elRect, size) => {
|
position: (pos, params, el, elRect, size) => {
|
||||||
@@ -282,10 +282,12 @@ export class MempoolGraphComponent implements OnInit, OnChanges {
|
|||||||
</div>`;
|
</div>`;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
dataZoom: [{
|
dataZoom: (this.template === 'widget' && this.isMobile()) ? null : [{
|
||||||
type: 'inside',
|
type: 'inside',
|
||||||
realtime: true,
|
realtime: true,
|
||||||
|
zoomLock: (this.template === 'widget') ? true : false,
|
||||||
zoomOnMouseWheel: (this.template === 'advanced') ? true : false,
|
zoomOnMouseWheel: (this.template === 'advanced') ? true : false,
|
||||||
|
moveOnMouseMove: (this.template === 'widget') ? true : false,
|
||||||
maxSpan: 100,
|
maxSpan: 100,
|
||||||
minSpan: 10,
|
minSpan: 10,
|
||||||
}, {
|
}, {
|
||||||
@@ -371,7 +373,7 @@ export class MempoolGraphComponent implements OnInit, OnChanges {
|
|||||||
this.feeLimitIndex = i;
|
this.feeLimitIndex = i;
|
||||||
}
|
}
|
||||||
if (feeLevels[i] <= this.limitFee) {
|
if (feeLevels[i] <= this.limitFee) {
|
||||||
if (this.stateService.network === 'liquid') {
|
if (this.stateService.network === 'liquid' || this.stateService.network === 'liquidtestnet') {
|
||||||
this.feeLevelsOrdered.push(`${(feeLevels[i] / 10).toFixed(1)} - ${(feeLevels[i + 1] / 10).toFixed(1)}`);
|
this.feeLevelsOrdered.push(`${(feeLevels[i] / 10).toFixed(1)} - ${(feeLevels[i + 1] / 10).toFixed(1)}`);
|
||||||
} else {
|
} else {
|
||||||
this.feeLevelsOrdered.push(`${feeLevels[i]} - ${feeLevels[i + 1]}`);
|
this.feeLevelsOrdered.push(`${feeLevels[i]} - ${feeLevels[i + 1]}`);
|
||||||
@@ -380,5 +382,9 @@ export class MempoolGraphComponent implements OnInit, OnChanges {
|
|||||||
}
|
}
|
||||||
this.chartColorsOrdered = chartColors.slice(0, this.feeLevelsOrdered.length);
|
this.chartColorsOrdered = chartColors.slice(0, this.feeLevelsOrdered.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isMobile() {
|
||||||
|
return window.innerWidth <= 767.98;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { Observable, of, Subject, merge } from 'rxjs';
|
|||||||
import { debounceTime, distinctUntilChanged, switchMap, filter, catchError, map } from 'rxjs/operators';
|
import { debounceTime, distinctUntilChanged, switchMap, filter, catchError, map } from 'rxjs/operators';
|
||||||
import { ElectrsApiService } from 'src/app/services/electrs-api.service';
|
import { ElectrsApiService } from 'src/app/services/electrs-api.service';
|
||||||
import { NgbTypeahead } from '@ng-bootstrap/ng-bootstrap';
|
import { NgbTypeahead } from '@ng-bootstrap/ng-bootstrap';
|
||||||
|
import { RelativeUrlPipe } from 'src/app/shared/pipes/relative-url/relative-url.pipe';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-search-form',
|
selector: 'app-search-form',
|
||||||
@@ -38,6 +39,7 @@ export class SearchFormComponent implements OnInit {
|
|||||||
private assetsService: AssetsService,
|
private assetsService: AssetsService,
|
||||||
private stateService: StateService,
|
private stateService: StateService,
|
||||||
private electrsApiService: ElectrsApiService,
|
private electrsApiService: ElectrsApiService,
|
||||||
|
private relativeUrlPipe: RelativeUrlPipe,
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
@@ -48,7 +50,7 @@ export class SearchFormComponent implements OnInit {
|
|||||||
searchText: ['', Validators.required],
|
searchText: ['', Validators.required],
|
||||||
});
|
});
|
||||||
|
|
||||||
if (this.network === 'liquid') {
|
if (this.network === 'liquid' || this.network === 'liquidtestnet') {
|
||||||
this.assetsService.getAssetsMinimalJson$
|
this.assetsService.getAssetsMinimalJson$
|
||||||
.subscribe((assets) => {
|
.subscribe((assets) => {
|
||||||
this.assets = assets;
|
this.assets = assets;
|
||||||
@@ -101,7 +103,7 @@ export class SearchFormComponent implements OnInit {
|
|||||||
this.navigate('/block/', searchText);
|
this.navigate('/block/', searchText);
|
||||||
} else if (this.regexTransaction.test(searchText)) {
|
} else if (this.regexTransaction.test(searchText)) {
|
||||||
const matches = this.regexTransaction.exec(searchText);
|
const matches = this.regexTransaction.exec(searchText);
|
||||||
if (this.network === 'liquid') {
|
if (this.network === 'liquid' || this.network === 'liquidtestnet') {
|
||||||
if (this.assets[matches[1]]) {
|
if (this.assets[matches[1]]) {
|
||||||
this.navigate('/asset/', matches[1]);
|
this.navigate('/asset/', matches[1]);
|
||||||
}
|
}
|
||||||
@@ -125,7 +127,7 @@ export class SearchFormComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
navigate(url: string, searchText: string, extras?: any) {
|
navigate(url: string, searchText: string, extras?: any) {
|
||||||
this.router.navigate([(this.network && this.stateService.env.BASE_MODULE === 'mempool' ? '/' + this.network : '') + url, searchText], extras);
|
this.router.navigate([this.relativeUrlPipe.transform(url), searchText], extras);
|
||||||
this.searchTriggered.emit();
|
this.searchTriggered.emit();
|
||||||
this.searchForm.setValue({
|
this.searchForm.setValue({
|
||||||
searchText: '',
|
searchText: '',
|
||||||
|
|||||||
@@ -117,7 +117,7 @@
|
|||||||
|
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
|
||||||
<ng-template [ngIf]="paymentForm.get('method').value === 'lbtc'">
|
<ng-template [ngIf]="paymentForm.get('method').value === 'lbtc' || paymentForm.get('method').value === 'tlbtc'">
|
||||||
|
|
||||||
<div class="qr-wrapper">
|
<div class="qr-wrapper">
|
||||||
<a [href]="bypassSecurityTrustUrl('liquidnetwork:' + donationObj.addresses.LBTC + '?amount=' + donationObj.amount + '&assetid=6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d')" target="_blank">
|
<a [href]="bypassSecurityTrustUrl('liquidnetwork:' + donationObj.addresses.LBTC + '?amount=' + donationObj.amount + '&assetid=6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d')" target="_blank">
|
||||||
|
|||||||
@@ -8,8 +8,11 @@
|
|||||||
|
|
||||||
<div *ngIf="countdown > 0" class="warning-label">{{ eventName }} in {{ countdown | number }} block{{ countdown === 1 ? '' : 's' }}!</div>
|
<div *ngIf="countdown > 0" class="warning-label">{{ eventName }} in {{ countdown | number }} block{{ countdown === 1 ? '' : 's' }}!</div>
|
||||||
|
|
||||||
<div id="blockchain-container" dir="ltr">
|
<div id="blockchain-container" dir="ltr" #blockchainContainer
|
||||||
<app-blockchain></app-blockchain>
|
(mousedown)="onMouseDown($event)"
|
||||||
|
(dragstart)="onDragStart($event)"
|
||||||
|
>
|
||||||
|
<app-blockchain></app-blockchain>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<router-outlet></router-outlet>
|
<router-outlet></router-outlet>
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, ElementRef, HostListener, OnInit, ViewChild } from '@angular/core';
|
||||||
import { WebsocketService } from 'src/app/services/websocket.service';
|
import { WebsocketService } from 'src/app/services/websocket.service';
|
||||||
import { StateService } from 'src/app/services/state.service';
|
import { StateService } from 'src/app/services/state.service';
|
||||||
import { specialBlocks } from 'src/app/app.constants';
|
import { specialBlocks } from 'src/app/app.constants';
|
||||||
import { takeLast } from 'rxjs/operators';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-start',
|
selector: 'app-start',
|
||||||
@@ -16,6 +15,9 @@ export class StartComponent implements OnInit {
|
|||||||
countdown = 0;
|
countdown = 0;
|
||||||
specialEvent = false;
|
specialEvent = false;
|
||||||
eventName = '';
|
eventName = '';
|
||||||
|
mouseDragStartX: number;
|
||||||
|
blockchainScrollLeftInit: number;
|
||||||
|
@ViewChild('blockchainContainer') blockchainContainer: ElementRef;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private websocketService: WebsocketService,
|
private websocketService: WebsocketService,
|
||||||
@@ -50,4 +52,27 @@ export class StartComponent implements OnInit {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onMouseDown(event: MouseEvent) {
|
||||||
|
this.mouseDragStartX = event.clientX;
|
||||||
|
this.blockchainScrollLeftInit = this.blockchainContainer.nativeElement.scrollLeft;
|
||||||
|
}
|
||||||
|
onDragStart(event: MouseEvent) { // Ignore Firefox annoying default drag behavior
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
// We're catching the whole page event here because we still want to scroll blocks
|
||||||
|
// even if the mouse leave the blockchain blocks container. Same idea for mouseup below.
|
||||||
|
@HostListener('document:mousemove', ['$event'])
|
||||||
|
onMouseMove(event: MouseEvent): void {
|
||||||
|
if (this.mouseDragStartX != null) {
|
||||||
|
this.stateService.setBlockScrollingInProgress(true);
|
||||||
|
this.blockchainContainer.nativeElement.scrollLeft =
|
||||||
|
this.blockchainScrollLeftInit + this.mouseDragStartX - event.clientX
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@HostListener('document:mouseup', [])
|
||||||
|
onMouseUp() {
|
||||||
|
this.mouseDragStartX = null;
|
||||||
|
this.stateService.setBlockScrollingInProgress(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,17 +41,11 @@
|
|||||||
</button>
|
</button>
|
||||||
<div class="dropdown-fees" ngbDropdownMenu aria-labelledby="dropdownFees">
|
<div class="dropdown-fees" ngbDropdownMenu aria-labelledby="dropdownFees">
|
||||||
<ul>
|
<ul>
|
||||||
<ng-template ngFor let-fee let-i="index" [ngForOf]="feeLevels">
|
<ng-template ngFor let-feeData let-i="index" [ngForOf]="feeLevelDropdownData">
|
||||||
<ng-template [ngIf]="fee <= 400">
|
<ng-template [ngIf]="feeData.fee <= 400">
|
||||||
<li (click)="filterFees(fee)" [class]="filterFeeIndex > fee ? 'inactive' : ''">
|
<li (click)="filterFeeIndex = feeData.fee" [class]="filterFeeIndex > feeData.fee ? 'inactive' : ''">
|
||||||
<ng-template [ngIf]="inverted">
|
<span class="square" [ngStyle]="{'backgroundColor': feeData.color}"></span>
|
||||||
<span class="square" [ngStyle]="{'backgroundColor': chartColors[i]}"></span>
|
<span class="fee-text">{{ feeData.range }}</span>
|
||||||
<span class="fee-text" >{{feeLevels[i]}} - {{ feeLevels[i + 1] }}</span>
|
|
||||||
</ng-template>
|
|
||||||
<ng-template [ngIf]="!inverted">
|
|
||||||
<span class="square" [ngStyle]="{'backgroundColor': chartColors[i - 1]}"></span>
|
|
||||||
<span class="fee-text" >{{feeLevels[i]}} - {{ feeLevels[i - 1] }}</span>
|
|
||||||
</ng-template>
|
|
||||||
</li>
|
</li>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ export class StatisticsComponent implements OnInit {
|
|||||||
radioGroupForm: FormGroup;
|
radioGroupForm: FormGroup;
|
||||||
graphWindowPreference: string;
|
graphWindowPreference: string;
|
||||||
inverted: boolean;
|
inverted: boolean;
|
||||||
|
feeLevelDropdownData = [];
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@Inject(LOCALE_ID) private locale: string,
|
@Inject(LOCALE_ID) private locale: string,
|
||||||
@@ -51,19 +52,10 @@ export class StatisticsComponent implements OnInit {
|
|||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.inverted = this.storageService.getValue('inverted-graph') === 'true';
|
this.inverted = this.storageService.getValue('inverted-graph') === 'true';
|
||||||
if (!this.inverted) {
|
this.setFeeLevelDropdownData();
|
||||||
this.feeLevels = [...feeLevels].reverse();
|
|
||||||
this.chartColors = [...chartColors].reverse();
|
|
||||||
}
|
|
||||||
this.seoService.setTitle($localize`:@@5d4f792f048fcaa6df5948575d7cb325c9393383:Graphs`);
|
this.seoService.setTitle($localize`:@@5d4f792f048fcaa6df5948575d7cb325c9393383:Graphs`);
|
||||||
this.stateService.networkChanged$.subscribe((network) => this.network = network);
|
this.stateService.networkChanged$.subscribe((network) => this.network = network);
|
||||||
this.graphWindowPreference = this.storageService.getValue('graphWindowPreference') ? this.storageService.getValue('graphWindowPreference').trim() : '2h';
|
this.graphWindowPreference = this.storageService.getValue('graphWindowPreference') ? this.storageService.getValue('graphWindowPreference').trim() : '2h';
|
||||||
const isMobile = window.innerWidth <= 767.98;
|
|
||||||
let labelHops = isMobile ? 48 : 24;
|
|
||||||
|
|
||||||
if (isMobile) {
|
|
||||||
labelHops = 96;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.radioGroupForm = this.formBuilder.group({
|
this.radioGroupForm = this.formBuilder.group({
|
||||||
dateSpan: this.graphWindowPreference
|
dateSpan: this.graphWindowPreference
|
||||||
@@ -132,6 +124,8 @@ export class StatisticsComponent implements OnInit {
|
|||||||
mempoolStats.reverse();
|
mempoolStats.reverse();
|
||||||
const labels = mempoolStats.map(stats => stats.added);
|
const labels = mempoolStats.map(stats => stats.added);
|
||||||
|
|
||||||
|
this.capExtremeVbytesValues();
|
||||||
|
|
||||||
this.mempoolTransactionsWeightPerSecondData = {
|
this.mempoolTransactionsWeightPerSecondData = {
|
||||||
labels: labels,
|
labels: labels,
|
||||||
series: [mempoolStats.map((stats) => [stats.added * 1000, stats.vbytes_per_second])],
|
series: [mempoolStats.map((stats) => [stats.added * 1000, stats.vbytes_per_second])],
|
||||||
@@ -147,11 +141,54 @@ export class StatisticsComponent implements OnInit {
|
|||||||
document.location.reload();
|
document.location.reload();
|
||||||
}
|
}
|
||||||
|
|
||||||
filterFees(index: number) {
|
setFeeLevelDropdownData() {
|
||||||
this.filterFeeIndex = index;
|
let _feeLevels = feeLevels
|
||||||
|
let _chartColors = chartColors;
|
||||||
|
if (!this.inverted) {
|
||||||
|
_feeLevels = [...feeLevels].reverse();
|
||||||
|
_chartColors = [...chartColors].reverse();
|
||||||
|
}
|
||||||
|
_feeLevels.forEach((fee, i) => {
|
||||||
|
if (this.inverted) {
|
||||||
|
this.feeLevelDropdownData.push({
|
||||||
|
fee: fee,
|
||||||
|
range: this.stateService.isLiquid() ? `${(_feeLevels[i] / 10).toFixed(1)} - ${(_feeLevels[i + 1] / 10).toFixed(1)}` : `${_feeLevels[i]} - ${_feeLevels[i + 1]}`,
|
||||||
|
color: _chartColors[i],
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.feeLevelDropdownData.push({
|
||||||
|
fee: fee,
|
||||||
|
range: this.stateService.isLiquid() ? `${(_feeLevels[i] / 10).toFixed(1)} - ${(_feeLevels[i - 1] / 10).toFixed(1)}` : `${_feeLevels[i]} - ${_feeLevels[i - 1]}`,
|
||||||
|
color: _chartColors[i - 1],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
filterClick() {
|
/**
|
||||||
this.dropDownOpen = !this.dropDownOpen;
|
* All value higher that "median * capRatio" are capped
|
||||||
|
*/
|
||||||
|
capExtremeVbytesValues() {
|
||||||
|
let capRatio = 10;
|
||||||
|
if (['1m', '3m', '6m', '1y', '2y', '3y'].includes(this.graphWindowPreference)) {
|
||||||
|
capRatio = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find median value
|
||||||
|
let vBytes : number[] = [];
|
||||||
|
for (let i = 0; i < this.mempoolStats.length; ++i) {
|
||||||
|
vBytes.push(this.mempoolStats[i].vbytes_per_second);
|
||||||
|
}
|
||||||
|
const sorted = vBytes.slice().sort((a, b) => a - b);
|
||||||
|
const middle = Math.floor(sorted.length / 2);
|
||||||
|
let median = sorted[middle];
|
||||||
|
if (sorted.length % 2 === 0) {
|
||||||
|
median = (sorted[middle - 1] + sorted[middle]) / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cap
|
||||||
|
for (let i = 0; i < this.mempoolStats.length; ++i) {
|
||||||
|
this.mempoolStats[i].vbytes_per_second = Math.min(median * capRatio, this.mempoolStats[i].vbytes_per_second);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,7 +66,7 @@
|
|||||||
<td><app-time-span [time]="tx.status.block_time - transactionTime" [fastRender]="true"></app-time-span></td>
|
<td><app-time-span [time]="tx.status.block_time - transactionTime" [fastRender]="true"></app-time-span></td>
|
||||||
</tr>
|
</tr>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
<tr *ngIf="network !== 'liquid'">
|
<tr *ngIf="network !== 'liquid' && network !== 'liquidtestnet'">
|
||||||
<td class="td-width" i18n="transaction.features|Transaction features">Features</td>
|
<td class="td-width" i18n="transaction.features|Transaction features">Features</td>
|
||||||
<td>
|
<td>
|
||||||
<app-tx-features [tx]="tx"></app-tx-features>
|
<app-tx-features [tx]="tx"></app-tx-features>
|
||||||
@@ -114,7 +114,7 @@
|
|||||||
<span i18n="transaction.eta.in-several-hours|Transaction ETA in several hours or more">In several hours (or more)</span>
|
<span i18n="transaction.eta.in-several-hours|Transaction ETA in several hours or more">In several hours (or more)</span>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
<ng-template #belowBlockLimit>
|
<ng-template #belowBlockLimit>
|
||||||
<ng-template [ngIf]="network === 'liquid'" [ngIfElse]="timeEstimateDefault">
|
<ng-template [ngIf]="network === 'liquid' || network === 'liquidtestnet'" [ngIfElse]="timeEstimateDefault">
|
||||||
<app-time-until [time]="(60 * 1000 * txInBlockIndex) + now" [fastRender]="false" [fixedRender]="true"></app-time-until>
|
<app-time-until [time]="(60 * 1000 * txInBlockIndex) + now" [fastRender]="false" [fixedRender]="true"></app-time-until>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
<ng-template #timeEstimateDefault>
|
<ng-template #timeEstimateDefault>
|
||||||
@@ -124,7 +124,7 @@
|
|||||||
</ng-template>
|
</ng-template>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr *ngIf="network !== 'liquid'">
|
<tr *ngIf="network !== 'liquid' && network !== 'liquidtestnet'">
|
||||||
<td class="td-width" i18n="transaction.features|Transaction Features">Features</td>
|
<td class="td-width" i18n="transaction.features|Transaction Features">Features</td>
|
||||||
<td>
|
<td>
|
||||||
<app-tx-features [tx]="tx"></app-tx-features>
|
<app-tx-features [tx]="tx"></app-tx-features>
|
||||||
|
|||||||
@@ -159,7 +159,7 @@ export class TransactionComponent implements OnInit, OnDestroy {
|
|||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
switchMap((tx) => {
|
switchMap((tx) => {
|
||||||
if (this.network === 'liquid') {
|
if (this.network === 'liquid' || this.network === 'liquidtestnet') {
|
||||||
return from(this.liquidUnblinding.checkUnblindedTx(tx))
|
return from(this.liquidUnblinding.checkUnblindedTx(tx))
|
||||||
.pipe(
|
.pipe(
|
||||||
catchError((error) => {
|
catchError((error) => {
|
||||||
|
|||||||
@@ -48,7 +48,7 @@
|
|||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<div [ngSwitch]="true">
|
<div [ngSwitch]="true">
|
||||||
<ng-container *ngSwitchCase="vin.is_coinbase"><span i18n="transactions-list.coinbase">Coinbase</span><ng-template [ngIf]="network !== 'liquid'"> <span i18n="transactions-list.newly-generated-coins">(Newly Generated Coins)</span></ng-template><br /><a placement="bottom" [ngbTooltip]="vin.scriptsig | hex2ascii"><span class="badge badge-secondary scriptmessage longer">{{ vin.scriptsig | hex2ascii }}</span></a></ng-container>
|
<ng-container *ngSwitchCase="vin.is_coinbase"><span i18n="transactions-list.coinbase">Coinbase</span><ng-template [ngIf]="network !== 'liquid' && network !== 'liquidtestnet'"> <span i18n="transactions-list.newly-generated-coins">(Newly Generated Coins)</span></ng-template><br /><a placement="bottom" [ngbTooltip]="vin.scriptsig | hex2ascii"><span class="badge badge-secondary scriptmessage longer">{{ vin.scriptsig | hex2ascii }}</span></a></ng-container>
|
||||||
<ng-container *ngSwitchCase="vin.is_pegin">
|
<ng-container *ngSwitchCase="vin.is_pegin">
|
||||||
<span i18n="transactions-list.peg-in">Peg-in</span>
|
<span i18n="transactions-list.peg-in">Peg-in</span>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
@@ -56,6 +56,10 @@
|
|||||||
<span>P2PK</span>
|
<span>P2PK</span>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
<ng-container *ngSwitchDefault>
|
<ng-container *ngSwitchDefault>
|
||||||
|
<ng-template [ngIf]="!vin.prevout" [ngIfElse]="defaultAddress">
|
||||||
|
<span>{{ vin.issuance ? 'Issuance' : 'UNKNOWN' }}</span>
|
||||||
|
</ng-template>
|
||||||
|
<ng-template #defaultAddress>
|
||||||
<a [routerLink]="['/address/' | relativeUrl, vin.prevout.scriptpubkey_address]" title="{{ vin.prevout.scriptpubkey_address }}">
|
<a [routerLink]="['/address/' | relativeUrl, vin.prevout.scriptpubkey_address]" title="{{ vin.prevout.scriptpubkey_address }}">
|
||||||
<span class="d-block d-lg-none">{{ vin.prevout.scriptpubkey_address | shortenString : 16 }}</span>
|
<span class="d-block d-lg-none">{{ vin.prevout.scriptpubkey_address | shortenString : 16 }}</span>
|
||||||
<span class="d-none d-lg-block">{{ vin.prevout.scriptpubkey_address | shortenString : 35 }}</span>
|
<span class="d-none d-lg-block">{{ vin.prevout.scriptpubkey_address | shortenString : 35 }}</span>
|
||||||
@@ -63,6 +67,7 @@
|
|||||||
<div>
|
<div>
|
||||||
<app-address-labels [vin]="vin"></app-address-labels>
|
<app-address-labels [vin]="vin"></app-address-labels>
|
||||||
</div>
|
</div>
|
||||||
|
</ng-template>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
@@ -244,7 +249,7 @@
|
|||||||
|
|
||||||
</span>
|
</span>
|
||||||
<button type="button" class="btn btn-sm btn-primary mt-2" (click)="switchCurrency()">
|
<button type="button" class="btn btn-sm btn-primary mt-2" (click)="switchCurrency()">
|
||||||
<ng-template [ngIf]="network === 'liquid'" [ngIfElse]="defaultAmount" i18n="shared.confidential">Confidential</ng-template>
|
<ng-template [ngIf]="network === 'liquid' || network === 'liquidtestnet'" [ngIfElse]="defaultAmount" i18n="shared.confidential">Confidential</ng-template>
|
||||||
<ng-template #defaultAmount>
|
<ng-template #defaultAmount>
|
||||||
<app-amount [satoshis]="getTotalTxOutput(tx)"></app-amount>
|
<app-amount [satoshis]="getTotalTxOutput(tx)"></app-amount>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import { map } from 'rxjs/operators';
|
|||||||
})
|
})
|
||||||
export class TransactionsListComponent implements OnInit, OnChanges {
|
export class TransactionsListComponent implements OnInit, OnChanges {
|
||||||
network = '';
|
network = '';
|
||||||
nativeAssetId = environment.nativeAssetId;
|
nativeAssetId = this.stateService.network === 'liquidtestnet' ? environment.nativeTestAssetId : environment.nativeAssetId;
|
||||||
displayDetails = false;
|
displayDetails = false;
|
||||||
|
|
||||||
@Input() transactions: Transaction[];
|
@Input() transactions: Transaction[];
|
||||||
@@ -41,7 +41,7 @@ export class TransactionsListComponent implements OnInit, OnChanges {
|
|||||||
this.latestBlock$ = this.stateService.blocks$.pipe(map(([block]) => block));
|
this.latestBlock$ = this.stateService.blocks$.pipe(map(([block]) => block));
|
||||||
this.stateService.networkChanged$.subscribe((network) => this.network = network);
|
this.stateService.networkChanged$.subscribe((network) => this.network = network);
|
||||||
|
|
||||||
if (this.network === 'liquid') {
|
if (this.network === 'liquid' || this.network === 'liquidtestnet') {
|
||||||
this.assetsService.getAssetsMinimalJson$.subscribe((assets) => {
|
this.assetsService.getAssetsMinimalJson$.subscribe((assets) => {
|
||||||
this.assetsMinimal = assets;
|
this.assetsMinimal = assets;
|
||||||
});
|
});
|
||||||
@@ -99,7 +99,7 @@ export class TransactionsListComponent implements OnInit, OnChanges {
|
|||||||
}
|
}
|
||||||
|
|
||||||
switchCurrency() {
|
switchCurrency() {
|
||||||
if (this.network === 'liquid') {
|
if (this.network === 'liquid' || this.network === 'liquidtestnet') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const oldvalue = !this.stateService.viewFiat$.value;
|
const oldvalue = !this.stateService.viewFiat$.value;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<div class="container-xl dashboard-container">
|
<div class="container-xl dashboard-container">
|
||||||
<div class="row row-cols-1 row-cols-md-2" *ngIf="{ value: (mempoolInfoData$ | async) } as mempoolInfoData">
|
<div class="row row-cols-1 row-cols-md-2" *ngIf="{ value: (mempoolInfoData$ | async) } as mempoolInfoData">
|
||||||
<ng-template [ngIf]="collapseLevel === 'three'" [ngIfElse]="expanded">
|
<ng-template [ngIf]="collapseLevel === 'three'" [ngIfElse]="expanded">
|
||||||
<div class="col card-wrapper" *ngIf="(network$ | async) !== 'liquid'">
|
<div class="col card-wrapper" *ngIf="(network$ | async) !== 'liquid' && (network$ | async) !== 'liquidtestnet'">
|
||||||
<div class="main-title" i18n="fees-box.transaction-fees">Transaction Fees</div>
|
<div class="main-title" i18n="fees-box.transaction-fees">Transaction Fees</div>
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col" *ngIf="(network$ | async) !== 'liquid'">
|
<div class="col" *ngIf="(network$ | async) !== 'liquid' && (network$ | async) !== 'liquidtestnet'">
|
||||||
<ng-container *ngTemplateOutlet="difficultyEpoch"></ng-container>
|
<ng-container *ngTemplateOutlet="difficultyEpoch"></ng-container>
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
@@ -29,7 +29,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
<ng-template #expanded>
|
<ng-template #expanded>
|
||||||
<div class="col card-wrapper" *ngIf="(network$ | async) !== 'liquid'">
|
<div class="col card-wrapper" *ngIf="(network$ | async) !== 'liquid' && (network$ | async) !== 'liquidtestnet'">
|
||||||
<div class="main-title" i18n="fees-box.transaction-fees">Transaction Fees</div>
|
<div class="main-title" i18n="fees-box.transaction-fees">Transaction Fees</div>
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
@@ -37,7 +37,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col" *ngIf="(network$ | async) !== 'liquid'">
|
<div class="col" *ngIf="(network$ | async) !== 'liquid' && (network$ | async) !== 'liquidtestnet'">
|
||||||
<ng-container *ngTemplateOutlet="difficultyEpoch"></ng-container>
|
<ng-container *ngTemplateOutlet="difficultyEpoch"></ng-container>
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
@@ -125,7 +125,7 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
<tr *ngFor="let transaction of transactions$ | async; let i = index;">
|
<tr *ngFor="let transaction of transactions$ | async; let i = index;">
|
||||||
<td class="table-cell-txid"><a [routerLink]="['/tx' | relativeUrl, transaction.txid]">{{ transaction.txid | shortenString : 10 }}</a></td>
|
<td class="table-cell-txid"><a [routerLink]="['/tx' | relativeUrl, transaction.txid]">{{ transaction.txid | shortenString : 10 }}</a></td>
|
||||||
<td class="table-cell-satoshis"><app-amount *ngIf="(network$ | async) !== 'liquid'; else liquidAmount" [satoshis]="transaction.value" digitsInfo="1.2-4" [noFiat]="true"></app-amount><ng-template #liquidAmount i18n="shared.confidential">Confidential</ng-template></td>
|
<td class="table-cell-satoshis"><app-amount *ngIf="(network$ | async) !== 'liquid' && (network$ | async) !== 'liquidtestnet'; else liquidAmount" [satoshis]="transaction.value" digitsInfo="1.2-4" [noFiat]="true"></app-amount><ng-template #liquidAmount i18n="shared.confidential">Confidential</ng-template></td>
|
||||||
<td class="table-cell-fiat" *ngIf="(network$ | async) === ''" ><app-fiat [value]="transaction.value" digitsInfo="1.0-0"></app-fiat></td>
|
<td class="table-cell-fiat" *ngIf="(network$ | async) === ''" ><app-fiat [value]="transaction.value" digitsInfo="1.0-0"></app-fiat></td>
|
||||||
<td class="table-cell-fees">{{ transaction.fee / transaction.vsize | feeRounding }} <span class="symbol" i18n="shared.sat-vbyte|sat/vB">sat/vB</span></td>
|
<td class="table-cell-fees">{{ transaction.fee / transaction.vsize | feeRounding }} <span class="symbol" i18n="shared.sat-vbyte|sat/vB">sat/vB</span></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
@@ -262,7 +262,7 @@ export class DashboardComponent implements OnInit {
|
|||||||
share(),
|
share(),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (this.stateService.network === 'liquid') {
|
if (this.stateService.network === 'liquid' || this.stateService.network === 'liquidtestnet') {
|
||||||
this.liquidPegsMonth$ = this.apiService.listLiquidPegsMonth$()
|
this.liquidPegsMonth$ = this.apiService.listLiquidPegsMonth$()
|
||||||
.pipe(
|
.pipe(
|
||||||
map((pegs) => {
|
map((pegs) => {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { HttpClient } from '@angular/common/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
import { shareReplay } from 'rxjs/operators';
|
import { map, shareReplay, switchMap } from 'rxjs/operators';
|
||||||
import { StateService } from './state.service';
|
import { StateService } from './state.service';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
@@ -21,8 +21,23 @@ export class AssetsService {
|
|||||||
apiBaseUrl = this.stateService.env.NGINX_PROTOCOL + '://' + this.stateService.env.NGINX_HOSTNAME + ':' + this.stateService.env.NGINX_PORT;
|
apiBaseUrl = this.stateService.env.NGINX_PROTOCOL + '://' + this.stateService.env.NGINX_HOSTNAME + ':' + this.stateService.env.NGINX_PORT;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.getAssetsJson$ = this.httpClient.get(apiBaseUrl + '/resources/assets.json').pipe(shareReplay());
|
this.getAssetsJson$ = this.stateService.networkChanged$
|
||||||
this.getAssetsMinimalJson$ = this.httpClient.get(apiBaseUrl + '/resources/assets.minimal.json').pipe(shareReplay());
|
.pipe(
|
||||||
this.getMiningPools$ = this.httpClient.get(apiBaseUrl + '/resources/pools.json').pipe(shareReplay());
|
switchMap(() => this.httpClient.get(`${apiBaseUrl}/resources/assets${this.stateService.network === 'liquidtestnet' ? '-testnet' : ''}.json`)),
|
||||||
|
shareReplay(1),
|
||||||
|
);
|
||||||
|
this.getAssetsMinimalJson$ = this.stateService.networkChanged$
|
||||||
|
.pipe(
|
||||||
|
switchMap(() => this.httpClient.get(`${apiBaseUrl}/resources/assets${this.stateService.network === 'liquidtestnet' ? '-testnet' : ''}.minimal.json`)),
|
||||||
|
map((assetsMinimal) => {
|
||||||
|
if (this.stateService.network === 'liquidtestnet') {
|
||||||
|
// Hard coding the Liquid Testnet native asset
|
||||||
|
assetsMinimal['144c654344aa716d6f3abcc1ca90e5641e4e2a7f633bc09fe3baf64585819a49'] = [null, "tL-BTC", "Test Liquid Bitcoin", 8];
|
||||||
|
}
|
||||||
|
return assetsMinimal;
|
||||||
|
}),
|
||||||
|
shareReplay(1),
|
||||||
|
);
|
||||||
|
this.getMiningPools$ = this.httpClient.get(apiBaseUrl + '/resources/pools.json').pipe(shareReplay(1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
40
frontend/src/app/services/language.service.ts
Normal file
40
frontend/src/app/services/language.service.ts
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
import { DOCUMENT, getLocaleId } from '@angular/common';
|
||||||
|
import { LOCALE_ID, Inject, Injectable } from '@angular/core';
|
||||||
|
import { languages } from 'src/app/app.constants';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class LanguageService {
|
||||||
|
private language = 'en';
|
||||||
|
private languages = languages;
|
||||||
|
constructor(
|
||||||
|
@Inject(DOCUMENT) private document: Document,
|
||||||
|
@Inject(LOCALE_ID) private locale: string,
|
||||||
|
) {
|
||||||
|
this.language = getLocaleId(this.locale).substring(0, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
getLanguage(): string {
|
||||||
|
return this.language;
|
||||||
|
}
|
||||||
|
|
||||||
|
stripLanguageFromUrl(urlPath: string) {
|
||||||
|
let rawUrlPath = urlPath ? urlPath : document.location.pathname;
|
||||||
|
const urlLanguage = this.document.location.pathname.split('/')[1];
|
||||||
|
if (this.languages.map((lang) => lang.code).indexOf(urlLanguage) != -1) {
|
||||||
|
rawUrlPath = rawUrlPath.substring(3);
|
||||||
|
}
|
||||||
|
return rawUrlPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
getLanguageForUrl(): string {
|
||||||
|
return this.language === 'en' ? '' : '/' + this.language;
|
||||||
|
}
|
||||||
|
|
||||||
|
setLanguage(language: string): void {
|
||||||
|
try {
|
||||||
|
document.cookie = `lang=${language}; expires=Thu, 18 Dec 2050 12:00:00 UTC; path=/`;
|
||||||
|
} catch (e) { }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -27,8 +27,14 @@ export class SeoService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getTitle(): string {
|
getTitle(): string {
|
||||||
|
if (this.network === 'testnet')
|
||||||
|
return 'mempool - Bitcoin Testnet';
|
||||||
|
if (this.network === 'signet')
|
||||||
|
return 'mempool - Bitcoin Signet';
|
||||||
if (this.network === 'liquid')
|
if (this.network === 'liquid')
|
||||||
return 'mempool - Liquid Network';
|
return 'mempool - Liquid Network';
|
||||||
|
if (this.network === 'liquidtestnet')
|
||||||
|
return 'mempool - Liquid Testnet';
|
||||||
if (this.network === 'bisq')
|
if (this.network === 'bisq')
|
||||||
return 'mempool - Bisq Markets';
|
return 'mempool - Bisq Markets';
|
||||||
return 'mempool - ' + (this.network ? this.ucfirst(this.network) : 'Bitcoin') + ' Explorer';
|
return 'mempool - ' + (this.network ? this.ucfirst(this.network) : 'Bitcoin') + ' Explorer';
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ export interface Env {
|
|||||||
TESTNET_ENABLED: boolean;
|
TESTNET_ENABLED: boolean;
|
||||||
SIGNET_ENABLED: boolean;
|
SIGNET_ENABLED: boolean;
|
||||||
LIQUID_ENABLED: boolean;
|
LIQUID_ENABLED: boolean;
|
||||||
|
LIQUID_TESTNET_ENABLED: boolean;
|
||||||
BISQ_ENABLED: boolean;
|
BISQ_ENABLED: boolean;
|
||||||
BISQ_SEPARATE_BACKEND: boolean;
|
BISQ_SEPARATE_BACKEND: boolean;
|
||||||
ITEMS_PER_PAGE: number;
|
ITEMS_PER_PAGE: number;
|
||||||
@@ -32,12 +33,16 @@ export interface Env {
|
|||||||
MEMPOOL_BLOCKS_AMOUNT: number;
|
MEMPOOL_BLOCKS_AMOUNT: number;
|
||||||
GIT_COMMIT_HASH: string;
|
GIT_COMMIT_HASH: string;
|
||||||
PACKAGE_JSON_VERSION: string;
|
PACKAGE_JSON_VERSION: string;
|
||||||
|
MEMPOOL_WEBSITE_URL: string;
|
||||||
|
LIQUID_WEBSITE_URL: string;
|
||||||
|
BISQ_WEBSITE_URL: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultEnv: Env = {
|
const defaultEnv: Env = {
|
||||||
'TESTNET_ENABLED': false,
|
'TESTNET_ENABLED': false,
|
||||||
'SIGNET_ENABLED': false,
|
'SIGNET_ENABLED': false,
|
||||||
'LIQUID_ENABLED': false,
|
'LIQUID_ENABLED': false,
|
||||||
|
'LIQUID_TESTNET_ENABLED': false,
|
||||||
'BASE_MODULE': 'mempool',
|
'BASE_MODULE': 'mempool',
|
||||||
'BISQ_ENABLED': false,
|
'BISQ_ENABLED': false,
|
||||||
'BISQ_SEPARATE_BACKEND': false,
|
'BISQ_SEPARATE_BACKEND': false,
|
||||||
@@ -51,6 +56,9 @@ const defaultEnv: Env = {
|
|||||||
'MEMPOOL_BLOCKS_AMOUNT': 8,
|
'MEMPOOL_BLOCKS_AMOUNT': 8,
|
||||||
'GIT_COMMIT_HASH': '',
|
'GIT_COMMIT_HASH': '',
|
||||||
'PACKAGE_JSON_VERSION': '',
|
'PACKAGE_JSON_VERSION': '',
|
||||||
|
'MEMPOOL_WEBSITE_URL': 'https://mempool.space',
|
||||||
|
'LIQUID_WEBSITE_URL': 'https://liquid.network',
|
||||||
|
'BISQ_WEBSITE_URL': 'https://bisq.markets',
|
||||||
};
|
};
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
@@ -89,6 +97,8 @@ export class StateService {
|
|||||||
markBlock$ = new ReplaySubject<MarkBlockState>();
|
markBlock$ = new ReplaySubject<MarkBlockState>();
|
||||||
keyNavigation$ = new Subject<KeyboardEvent>();
|
keyNavigation$ = new Subject<KeyboardEvent>();
|
||||||
|
|
||||||
|
blockScrolling$: Subject<boolean> = new Subject<boolean>();
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@Inject(PLATFORM_ID) private platformId: any,
|
@Inject(PLATFORM_ID) private platformId: any,
|
||||||
private router: Router,
|
private router: Router,
|
||||||
@@ -114,7 +124,7 @@ export class StateService {
|
|||||||
|
|
||||||
this.blocks$ = new ReplaySubject<[Block, boolean]>(this.env.KEEP_BLOCKS_AMOUNT);
|
this.blocks$ = new ReplaySubject<[Block, boolean]>(this.env.KEEP_BLOCKS_AMOUNT);
|
||||||
|
|
||||||
if (this.env.BASE_MODULE !== 'mempool') {
|
if (this.env.BASE_MODULE === 'bisq') {
|
||||||
this.network = this.env.BASE_MODULE;
|
this.network = this.env.BASE_MODULE;
|
||||||
this.networkChanged$.next(this.env.BASE_MODULE);
|
this.networkChanged$.next(this.env.BASE_MODULE);
|
||||||
}
|
}
|
||||||
@@ -123,10 +133,10 @@ export class StateService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setNetworkBasedonUrl(url: string) {
|
setNetworkBasedonUrl(url: string) {
|
||||||
if (this.env.BASE_MODULE !== 'mempool') {
|
if (this.env.BASE_MODULE !== 'mempool' && this.env.BASE_MODULE !== 'liquid') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const networkMatches = url.match(/\/(bisq|testnet|liquid|signet)/);
|
const networkMatches = url.match(/\/(bisq|testnet|liquidtestnet|liquid|signet)/);
|
||||||
switch (networkMatches && networkMatches[1]) {
|
switch (networkMatches && networkMatches[1]) {
|
||||||
case 'liquid':
|
case 'liquid':
|
||||||
if (this.network !== 'liquid') {
|
if (this.network !== 'liquid') {
|
||||||
@@ -134,6 +144,12 @@ export class StateService {
|
|||||||
this.networkChanged$.next('liquid');
|
this.networkChanged$.next('liquid');
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
case 'liquidtestnet':
|
||||||
|
if (this.network !== 'liquidtestnet') {
|
||||||
|
this.network = 'liquidtestnet';
|
||||||
|
this.networkChanged$.next('liquidtestnet');
|
||||||
|
}
|
||||||
|
return;
|
||||||
case 'signet':
|
case 'signet':
|
||||||
if (this.network !== 'signet') {
|
if (this.network !== 'signet') {
|
||||||
this.network = 'signet';
|
this.network = 'signet';
|
||||||
@@ -142,9 +158,14 @@ export class StateService {
|
|||||||
return;
|
return;
|
||||||
case 'testnet':
|
case 'testnet':
|
||||||
if (this.network !== 'testnet') {
|
if (this.network !== 'testnet') {
|
||||||
|
if (this.env.BASE_MODULE === 'liquid') {
|
||||||
|
this.network = 'liquidtestnet';
|
||||||
|
this.networkChanged$.next('liquidtestnet');
|
||||||
|
} else {
|
||||||
this.network = 'testnet';
|
this.network = 'testnet';
|
||||||
this.networkChanged$.next('testnet');
|
this.networkChanged$.next('testnet');
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
case 'bisq':
|
case 'bisq':
|
||||||
if (this.network !== 'bisq') {
|
if (this.network !== 'bisq') {
|
||||||
@@ -153,7 +174,12 @@ export class StateService {
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
default:
|
default:
|
||||||
if (this.network !== '') {
|
if (this.env.BASE_MODULE !== 'mempool') {
|
||||||
|
if (this.network !== this.env.BASE_MODULE) {
|
||||||
|
this.network = this.env.BASE_MODULE;
|
||||||
|
this.networkChanged$.next(this.env.BASE_MODULE);
|
||||||
|
}
|
||||||
|
} else if (this.network !== '') {
|
||||||
this.network = '';
|
this.network = '';
|
||||||
this.networkChanged$.next('');
|
this.networkChanged$.next('');
|
||||||
}
|
}
|
||||||
@@ -176,4 +202,12 @@ export class StateService {
|
|||||||
if (!prop) { return false; }
|
if (!prop) { return false; }
|
||||||
return document[prop];
|
return document[prop];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setBlockScrollingInProgress(value: boolean) {
|
||||||
|
this.blockScrolling$.next(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
isLiquid() {
|
||||||
|
return this.network === 'liquid' || this.network === 'liquidtestnet';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,10 +11,13 @@ export class RelativeUrlPipe implements PipeTransform {
|
|||||||
) { }
|
) { }
|
||||||
|
|
||||||
transform(value: string): string {
|
transform(value: string): string {
|
||||||
if (this.stateService.env.BASE_MODULE !== 'mempool') {
|
let network = this.stateService.network;
|
||||||
return '/' + value;
|
if (this.stateService.env.BASE_MODULE === 'liquid' && network === 'liquidtestnet') {
|
||||||
|
network = 'testnet';
|
||||||
|
} else if (this.stateService.env.BASE_MODULE !== 'mempool') {
|
||||||
|
network = '';
|
||||||
}
|
}
|
||||||
return (this.stateService.network ? '/' + this.stateService.network : '') + value;
|
return (network ? '/' + network : '') + value;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ import { ColoredPriceDirective } from './directives/colored-price.directive';
|
|||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
VbytesPipe,
|
VbytesPipe,
|
||||||
|
RelativeUrlPipe,
|
||||||
],
|
],
|
||||||
exports: [
|
exports: [
|
||||||
NgbAccordionModule,
|
NgbAccordionModule,
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
export const environment = {
|
export const environment = {
|
||||||
production: true,
|
production: true,
|
||||||
nativeAssetId: '6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d',
|
nativeAssetId: '6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d',
|
||||||
|
nativeTestAssetId: '144c654344aa716d6f3abcc1ca90e5641e4e2a7f633bc09fe3baf64585819a49',
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
export const environment = {
|
export const environment = {
|
||||||
production: false,
|
production: false,
|
||||||
nativeAssetId: '6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d',
|
nativeAssetId: '6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d',
|
||||||
|
nativeTestAssetId: '144c654344aa716d6f3abcc1ca90e5641e4e2a7f633bc09fe3baf64585819a49',
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
<title>mempool - Bisq Markets</title>
|
<title>mempool - Bisq Markets</title>
|
||||||
<base href="/">
|
<base href="/">
|
||||||
|
|
||||||
<meta name="description" content="An open-source explorer developed for the Bisq community.">
|
<meta name="description" content="The Mempool Open Source Project™ - our self-hosted explorer for the Bisq Network.">
|
||||||
|
|
||||||
<meta property="og:image" content="https://bisq.markets/resources/bisq/bisq-markets-preview.png" />
|
<meta property="og:image" content="https://bisq.markets/resources/bisq/bisq-markets-preview.png" />
|
||||||
<meta property="og:image:type" content="image/jpeg" />
|
<meta property="og:image:type" content="image/jpeg" />
|
||||||
@@ -13,8 +13,8 @@
|
|||||||
<meta property="twitter:card" content="summary_large_image">
|
<meta property="twitter:card" content="summary_large_image">
|
||||||
<meta property="twitter:site" content="https://bisq.markets/">
|
<meta property="twitter:site" content="https://bisq.markets/">
|
||||||
<meta property="twitter:creator" content="@bisq_network">
|
<meta property="twitter:creator" content="@bisq_network">
|
||||||
<meta property="twitter:title" content="mempool - Bisq Markets">
|
<meta property="twitter:title" content="The Mempool Open Source Project™">
|
||||||
<meta property="twitter:description" content="An open-source explorer developed for the Bisq community.">
|
<meta property="twitter:description" content="Our self-hosted markets explorer for the Bisq community.">
|
||||||
<meta property="twitter:image:src" content="https://bisq.markets/resources/bisq/bisq-markets-preview.png" />
|
<meta property="twitter:image:src" content="https://bisq.markets/resources/bisq/bisq-markets-preview.png" />
|
||||||
<meta property="twitter:domain" content="bisq.markets">
|
<meta property="twitter:domain" content="bisq.markets">
|
||||||
|
|
||||||
@@ -45,7 +45,7 @@
|
|||||||
_paq.push(['trackPageView']);
|
_paq.push(['trackPageView']);
|
||||||
_paq.push(['enableLinkTracking']);
|
_paq.push(['enableLinkTracking']);
|
||||||
(function() {
|
(function() {
|
||||||
var u="//stats.mempool.space/";
|
var u="//stats.bisq.markets/";
|
||||||
_paq.push(['setTrackerUrl', u+'m.php']);
|
_paq.push(['setTrackerUrl', u+'m.php']);
|
||||||
_paq.push(['setSiteId', '7']);
|
_paq.push(['setSiteId', '7']);
|
||||||
var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
|
var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
<title>mempool - Liquid Network</title>
|
<title>mempool - Liquid Network</title>
|
||||||
<base href="/">
|
<base href="/">
|
||||||
|
|
||||||
<meta name="description" content="An open-source explorer developed for the Liquid Network.">
|
<meta name="description" content="The Mempool Open Source Project™ - our self-hosted explorer for the Liquid Network.">
|
||||||
<meta property="og:image" content="https://liquid.network/resources/liquid/liquid-network-preview.png" />
|
<meta property="og:image" content="https://liquid.network/resources/liquid/liquid-network-preview.png" />
|
||||||
<meta property="og:image:type" content="image/png" />
|
<meta property="og:image:type" content="image/png" />
|
||||||
<meta property="og:image:width" content="1000" />
|
<meta property="og:image:width" content="1000" />
|
||||||
@@ -13,8 +13,8 @@
|
|||||||
<meta property="twitter:card" content="summary_large_image">
|
<meta property="twitter:card" content="summary_large_image">
|
||||||
<meta property="twitter:site" content="@mempool">
|
<meta property="twitter:site" content="@mempool">
|
||||||
<meta property="twitter:creator" content="@mempool">
|
<meta property="twitter:creator" content="@mempool">
|
||||||
<meta property="twitter:title" content="mempool - Liquid Network">
|
<meta property="twitter:title" content="The Mempool Open Source Project™">
|
||||||
<meta property="twitter:description" content="An open-source explorer developed for the Liquid Network.">
|
<meta property="twitter:description" content="Our self-hosted network explorer for the Liquid community.">
|
||||||
<meta property="twitter:image:src" content="https://liquid.network/resources/liquid/liquid-network-preview.png" />
|
<meta property="twitter:image:src" content="https://liquid.network/resources/liquid/liquid-network-preview.png" />
|
||||||
<meta property="twitter:domain" content="liquid.network">
|
<meta property="twitter:domain" content="liquid.network">
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
<title>mempool - Bitcoin Explorer</title>
|
<title>mempool - Bitcoin Explorer</title>
|
||||||
<base href="/">
|
<base href="/">
|
||||||
|
|
||||||
<meta name="description" content="An open-source explorer developed for the Bitcoin community, focusing on the emerging transaction fee market to help our transition into a multi-layer ecosystem." />
|
<meta name="description" content="The Mempool Open Source Project™ - our self-hosted explorer for the Bitcoin community." />
|
||||||
<meta property="og:image" content="https://mempool.space/resources/mempool-space-preview.png" />
|
<meta property="og:image" content="https://mempool.space/resources/mempool-space-preview.png" />
|
||||||
<meta property="og:image:type" content="image/png" />
|
<meta property="og:image:type" content="image/png" />
|
||||||
<meta property="og:image:width" content="1000" />
|
<meta property="og:image:width" content="1000" />
|
||||||
@@ -13,8 +13,8 @@
|
|||||||
<meta property="twitter:card" content="summary_large_image">
|
<meta property="twitter:card" content="summary_large_image">
|
||||||
<meta property="twitter:site" content="@mempool">
|
<meta property="twitter:site" content="@mempool">
|
||||||
<meta property="twitter:creator" content="@mempool">
|
<meta property="twitter:creator" content="@mempool">
|
||||||
<meta property="twitter:title" content="mempool">
|
<meta property="twitter:title" content="The Mempool Open Source Project™">
|
||||||
<meta property="twitter:description" content="An open-source explorer developed for the Bitcoin community, focusing on the transition into a multi-layer ecosystem." />
|
<meta property="twitter:description" content="Our self-hosted mempool explorer for the Bitcoin community." />
|
||||||
<meta property="twitter:image:src" content="https://mempool.space/resources/mempool-space-preview.png" />
|
<meta property="twitter:image:src" content="https://mempool.space/resources/mempool-space-preview.png" />
|
||||||
<meta property="twitter:domain" content="mempool.space">
|
<meta property="twitter:domain" content="mempool.space">
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user