Add series for burned BSQ from btc fees and arbitration

This commit is contained in:
chimp1984 2022-05-15 23:42:18 +02:00
parent cb4eacdb64
commit 0ed03fc790
No known key found for this signature in database
GPG Key ID: 9801B4EC591F90E3
7 changed files with 232 additions and 51 deletions

View File

@ -2601,7 +2601,6 @@ dao.factsAndFigures.supply.reimbursementAmount=BSQ issued for reimbursement requ
dao.factsAndFigures.supply.totalIssued=Total issued BSQ
dao.factsAndFigures.supply.totalBurned=Total burned BSQ
dao.factsAndFigures.supply.totalBsqSupply=Total BSQ supply
dao.factsAndFigures.supply.revenue=Total trade fees
dao.factsAndFigures.supply.chart.tradeFee.toolTip={0}\n{1}
dao.factsAndFigures.supply.burnt=BSQ burnt
@ -2618,10 +2617,12 @@ dao.factsAndFigures.supply.totalLockedUpAmount=Locked up in bonds
dao.factsAndFigures.supply.totalUnlockingAmount=Unlocking BSQ from bonds
dao.factsAndFigures.supply.totalUnlockedAmount=Unlocked BSQ from bonds
dao.factsAndFigures.supply.totalConfiscatedAmount=Confiscated BSQ from bonds
dao.factsAndFigures.supply.proofOfBurn=Proof of Burn
dao.factsAndFigures.supply.totalTradeFees=Total trade fees
dao.factsAndFigures.supply.bsqTradeFee=BSQ Trade fees
dao.factsAndFigures.supply.btcTradeFee=BTC Trade fees
dao.factsAndFigures.supply.btcFees=BTC trade fees (proof of Burn)
dao.factsAndFigures.supply.arbitration=From arbitration (proof of Burn))
dao.factsAndFigures.supply.proofOfBurn=Proof of Burn
dao.factsAndFigures.supply.proofOfBurnReimbursementDiff=Diff total burned-reimbursement
dao.factsAndFigures.transactions.genesis=Genesis transaction
dao.factsAndFigures.transactions.genesisBlockHeight=Genesis block height
dao.factsAndFigures.transactions.genesisTxId=Genesis transaction ID

View File

@ -1809,6 +1809,31 @@ textfield */
-fx-background-color: -bs-chart-dao-line8, -bs-chart-dao-line8;
}
#charts-dao .default-color8.chart-series-line {
-fx-stroke: -bs-chart-dao-line9;
}
#charts-dao .default-color8.chart-line-symbol {
-fx-background-color: -bs-chart-dao-line9, -bs-chart-dao-line9;
}
#charts-dao .default-color9.chart-series-line {
-fx-stroke: -bs-chart-dao-line10;
}
#charts-dao .default-color9.chart-line-symbol {
-fx-background-color: -bs-chart-dao-line10, -bs-chart-dao-line10;
}
#charts-dao .default-color10.chart-series-line {
-fx-stroke: -bs-chart-dao-line11;
}
#charts-dao .default-color10.chart-line-symbol {
-fx-background-color: -bs-chart-dao-line11, -bs-chart-dao-line11;
}
#charts-legend-toggle0 {
-jfx-toggle-color: -bs-chart-dao-line1
}
@ -1841,6 +1866,18 @@ textfield */
-jfx-toggle-color: -bs-chart-dao-line8;
}
#charts-legend-toggle8 {
-jfx-toggle-color: -bs-chart-dao-line9;
}
#charts-legend-toggle9 {
-jfx-toggle-color: -bs-chart-dao-line10;
}
#charts-legend-toggle10 {
-jfx-toggle-color: -bs-chart-dao-line11;
}
#charts-dao .chart-series-line {
-fx-stroke-width: 2px;
}

View File

@ -25,6 +25,8 @@ import bisq.core.dao.state.model.governance.BsqSupplyChange;
import bisq.core.dao.state.model.governance.Issuance;
import bisq.core.dao.state.model.governance.IssuanceType;
import bisq.common.util.Hex;
import javax.inject.Inject;
import javax.inject.Singleton;
@ -32,9 +34,11 @@ import java.time.Instant;
import java.util.Collection;
import java.util.Comparator;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.TimeZone;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Function;
@ -47,11 +51,19 @@ import lombok.extern.slf4j.Slf4j;
@Slf4j
@Singleton
public class DaoChartDataModel extends ChartDataModel {
// Date when we started to use tags for separating proof of burn txs
private static final GregorianCalendar TAG_DATE = new GregorianCalendar(2021, GregorianCalendar.NOVEMBER, 3, 13, 0);
private final DaoStateService daoStateService;
private final Function<Issuance, Long> blockTimeOfIssuanceFunction;
private Map<Long, Long> totalSupplyByInterval, totalIssuedByInterval, compensationByInterval, reimbursementByInterval,
totalBurnedByInterval, bsqTradeFeeByInterval, proofOfBurnByInterval, revenueByInterval;
totalBurnedByInterval, bsqTradeFeeByInterval, proofOfBurnByInterval,
proofOfBurnFromBtcFeesByInterval, proofOfBurnFromArbitrationByInterval,
proofOfBurnReimbursementDiffByInterval, totalTradeFeesByInterval;
static {
TAG_DATE.setTimeZone(TimeZone.getTimeZone("UTC"));
}
///////////////////////////////////////////////////////////////////////////////////////////
// Constructor
@ -79,7 +91,10 @@ public class DaoChartDataModel extends ChartDataModel {
totalBurnedByInterval = null;
bsqTradeFeeByInterval = null;
proofOfBurnByInterval = null;
revenueByInterval = null;
proofOfBurnFromBtcFeesByInterval = null;
proofOfBurnFromArbitrationByInterval = null;
proofOfBurnReimbursementDiffByInterval = null;
totalTradeFeesByInterval = null;
}
@ -128,15 +143,38 @@ public class DaoChartDataModel extends ChartDataModel {
return totalSupplyByInterval;
}
Map<Long, Long> getRevenueByInterval() {
if (revenueByInterval != null) {
return revenueByInterval;
Map<Long, Long> getProofOfBurnReimbursementDiffByInterval() {
if (proofOfBurnReimbursementDiffByInterval != null) {
return proofOfBurnReimbursementDiffByInterval;
}
// By subtracting the reimbursement amounts from the total burned amount we derive the total trade fees.
// Reimbursements have not been used in early days, so those periods do not reflect the value correctly.
// Due to time delays between reimbursements and burning there is not a very good temporal match.
// For shorter time periods we even get negative values if reimbursement was larger than accumulated
// burned BSQ in that time frame.
// It is an alternative view on the revenue to the total fee data which we only support since Nov 2021
Map<Long, Long> burnedMap = getTotalBurnedByInterval();
Map<Long, Long> reimbursementMap = getReimbursementByInterval();
revenueByInterval = getMergedMap(burnedMap, reimbursementMap, (a, b) -> a - b);
return revenueByInterval;
proofOfBurnReimbursementDiffByInterval = getMergedMap(burnedMap, reimbursementMap, (a, b) -> a - b);
return proofOfBurnReimbursementDiffByInterval;
}
Map<Long, Long> getTotalTradeFeesByInterval() {
if (totalTradeFeesByInterval != null) {
return totalTradeFeesByInterval;
}
// From Nov 2021 we use tags for the burned BSQ from BTC fees and for those from delayed payout txs.
// By that we can filter out the burned BSQ from BTC fees.
Map<Long, Long> tradeFee = getBsqTradeFeeByInterval();
Map<Long, Long> proofOfBurn = getProofOfBurnFromBtcFeesByInterval();
Map<Long, Long> merged = getMergedMap(tradeFee, proofOfBurn, Long::sum);
totalTradeFeesByInterval = merged.entrySet().stream()
.filter(entry -> entry.getKey() * 1000 >= TAG_DATE.getTimeInMillis())
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
return totalTradeFeesByInterval;
}
Map<Long, Long> getTotalIssuedByInterval() {
@ -202,6 +240,37 @@ public class DaoChartDataModel extends ChartDataModel {
return proofOfBurnByInterval;
}
Map<Long, Long> getProofOfBurnFromBtcFeesByInterval() {
if (proofOfBurnFromBtcFeesByInterval != null) {
return proofOfBurnFromBtcFeesByInterval;
}
// Tagging started Nov 2021
// opReturn data from BTC fees: 1701721206fe6b40777763de1c741f4fd2706d94775d
Set<Tx> proofOfBurnTxs = daoStateService.getProofOfBurnTxs();
Set<Tx> feeTxs = proofOfBurnTxs.stream()
.filter(tx -> "1701721206fe6b40777763de1c741f4fd2706d94775d".equals(Hex.encode(tx.getLastTxOutput().getOpReturnData())))
.collect(Collectors.toSet());
proofOfBurnFromBtcFeesByInterval = getBurntBsqByInterval(feeTxs, getDateFilter());
return proofOfBurnFromBtcFeesByInterval;
}
Map<Long, Long> getProofOfBurnFromArbitrationByInterval() {
if (proofOfBurnFromArbitrationByInterval != null) {
return proofOfBurnFromArbitrationByInterval;
}
// Tagging started Nov 2021
// opReturn data from delayed payout txs: 1701e47e5d8030f444c182b5e243871ebbaeadb5e82f
// opReturn data from BM trades with a trade who got reimbursed by the DAO : 1701293c488822f98e70e047012f46f5f1647f37deb7
Set<Tx> feeTxs = daoStateService.getProofOfBurnTxs().stream()
.filter(e -> "1701e47e5d8030f444c182b5e243871ebbaeadb5e82f".equals(Hex.encode(e.getLastTxOutput().getOpReturnData())) ||
"1701293c488822f98e70e047012f46f5f1647f37deb7".equals(Hex.encode(e.getLastTxOutput().getOpReturnData())))
.collect(Collectors.toSet());
proofOfBurnFromArbitrationByInterval = getBurntBsqByInterval(feeTxs, getDateFilter());
return proofOfBurnFromArbitrationByInterval;
}
///////////////////////////////////////////////////////////////////////////////////////////
// Aggregated collection data by interval

View File

@ -46,7 +46,9 @@ public class DaoChartView extends ChartView<DaoChartViewModel> {
private final LongProperty proofOfBurnAmountProperty = new SimpleLongProperty();
private XYChart.Series<Number, Number> seriesBsqTradeFee, seriesProofOfBurn, seriesCompensation,
seriesReimbursement, seriesTotalSupply, seriesTotalIssued, seriesTotalBurned, seriesRevenue;
seriesReimbursement, seriesTotalSupply, seriesTotalIssued, seriesTotalBurned,
seriesTotalTradeFees, seriesProofOfBurnFromBtcFees,
seriesProofOfBurnFromArbitration, seriesProofOfBurnReimbursementDiff;
@Inject
@ -87,12 +89,12 @@ public class DaoChartView extends ChartView<DaoChartViewModel> {
@Override
protected Collection<XYChart.Series<Number, Number>> getSeriesForLegend2() {
return List.of(seriesTotalBurned, seriesBsqTradeFee, seriesProofOfBurn);
return List.of(seriesTotalBurned, seriesBsqTradeFee, seriesProofOfBurnFromBtcFees, seriesProofOfBurnFromArbitration, seriesProofOfBurn);
}
@Override
protected Collection<XYChart.Series<Number, Number>> getSeriesForLegend3() {
return List.of(seriesRevenue, seriesTotalSupply);
return List.of(seriesTotalTradeFees, seriesTotalSupply, seriesProofOfBurnReimbursementDiff);
}
@ -140,9 +142,21 @@ public class DaoChartView extends ChartView<DaoChartViewModel> {
seriesTotalSupply.setName(Res.get("dao.factsAndFigures.supply.totalBsqSupply"));
seriesIndexMap.put(getSeriesId(seriesTotalSupply), 6);
seriesRevenue = new XYChart.Series<>();
seriesRevenue.setName(Res.get("dao.factsAndFigures.supply.revenue"));
seriesIndexMap.put(getSeriesId(seriesRevenue), 7);
seriesTotalTradeFees = new XYChart.Series<>();
seriesTotalTradeFees.setName(Res.get("dao.factsAndFigures.supply.totalTradeFees"));
seriesIndexMap.put(getSeriesId(seriesTotalTradeFees), 7);
seriesProofOfBurnFromBtcFees = new XYChart.Series<>();
seriesProofOfBurnFromBtcFees.setName(Res.get("dao.factsAndFigures.supply.btcFees"));
seriesIndexMap.put(getSeriesId(seriesProofOfBurnFromBtcFees), 8);
seriesProofOfBurnFromArbitration = new XYChart.Series<>();
seriesProofOfBurnFromArbitration.setName(Res.get("dao.factsAndFigures.supply.arbitration"));
seriesIndexMap.put(getSeriesId(seriesProofOfBurnFromArbitration), 9);
seriesProofOfBurnReimbursementDiff = new XYChart.Series<>();
seriesProofOfBurnReimbursementDiff.setName(Res.get("dao.factsAndFigures.supply.proofOfBurnReimbursementDiff"));
seriesIndexMap.put(getSeriesId(seriesProofOfBurnReimbursementDiff), 10);
}
@Override
@ -160,44 +174,59 @@ public class DaoChartView extends ChartView<DaoChartViewModel> {
protected CompletableFuture<Boolean> applyData() {
List<CompletableFuture<Boolean>> allFutures = new ArrayList<>();
if (activeSeries.contains(seriesTotalIssued)) {
CompletableFuture<Boolean> task1Done = new CompletableFuture<>();
allFutures.add(task1Done);
applyTotalIssued(task1Done);
CompletableFuture<Boolean> future = new CompletableFuture<>();
allFutures.add(future);
applyTotalIssued(future);
}
if (activeSeries.contains(seriesCompensation)) {
CompletableFuture<Boolean> task2Done = new CompletableFuture<>();
allFutures.add(task2Done);
applyCompensation(task2Done);
CompletableFuture<Boolean> future = new CompletableFuture<>();
allFutures.add(future);
applyCompensation(future);
}
if (activeSeries.contains(seriesReimbursement)) {
CompletableFuture<Boolean> task3Done = new CompletableFuture<>();
allFutures.add(task3Done);
applyReimbursement(task3Done);
CompletableFuture<Boolean> future = new CompletableFuture<>();
allFutures.add(future);
applyReimbursement(future);
}
if (activeSeries.contains(seriesTotalBurned)) {
CompletableFuture<Boolean> task4Done = new CompletableFuture<>();
allFutures.add(task4Done);
applyTotalBurned(task4Done);
CompletableFuture<Boolean> future = new CompletableFuture<>();
allFutures.add(future);
applyTotalBurned(future);
}
if (activeSeries.contains(seriesBsqTradeFee)) {
CompletableFuture<Boolean> task5Done = new CompletableFuture<>();
allFutures.add(task5Done);
applyBsqTradeFee(task5Done);
CompletableFuture<Boolean> future = new CompletableFuture<>();
allFutures.add(future);
applyBsqTradeFee(future);
}
if (activeSeries.contains(seriesProofOfBurn)) {
CompletableFuture<Boolean> task6Done = new CompletableFuture<>();
allFutures.add(task6Done);
applyProofOfBurn(task6Done);
CompletableFuture<Boolean> future = new CompletableFuture<>();
allFutures.add(future);
applyProofOfBurn(future);
}
if (activeSeries.contains(seriesTotalSupply)) {
CompletableFuture<Boolean> taskTotalSupplyDone = new CompletableFuture<>();
allFutures.add(taskTotalSupplyDone);
applyTotalSupply(taskTotalSupplyDone);
CompletableFuture<Boolean> future = new CompletableFuture<>();
allFutures.add(future);
applyTotalSupply(future);
}
if (activeSeries.contains(seriesRevenue)) {
CompletableFuture<Boolean> taskRevenueDone = new CompletableFuture<>();
allFutures.add(taskRevenueDone);
applyRevenue(taskRevenueDone);
if (activeSeries.contains(seriesTotalTradeFees)) {
CompletableFuture<Boolean> future = new CompletableFuture<>();
allFutures.add(future);
applyTotalTradeFees(future);
}
if (activeSeries.contains(seriesProofOfBurnFromBtcFees)) {
CompletableFuture<Boolean> future = new CompletableFuture<>();
allFutures.add(future);
applyProofOfBurnFromBtcFees(future);
}
if (activeSeries.contains(seriesProofOfBurnFromArbitration)) {
CompletableFuture<Boolean> future = new CompletableFuture<>();
allFutures.add(future);
applyProofOfBurnFromArbitration(future);
}
if (activeSeries.contains(seriesProofOfBurnReimbursementDiff)) {
CompletableFuture<Boolean> future = new CompletableFuture<>();
allFutures.add(future);
applyProofOfBurnReimbursementDiff(future);
}
CompletableFuture<Boolean> task7Done = new CompletableFuture<>();
@ -248,11 +277,38 @@ public class DaoChartView extends ChartView<DaoChartViewModel> {
}));
}
private void applyRevenue(CompletableFuture<Boolean> completeFuture) {
model.getRevenueChartData()
private void applyTotalTradeFees(CompletableFuture<Boolean> completeFuture) {
model.getTotalTradeFeesChartData()
.whenComplete((data, t) ->
mapToUserThread(() -> {
seriesRevenue.getData().setAll(data);
seriesTotalTradeFees.getData().setAll(data);
completeFuture.complete(true);
}));
}
private void applyProofOfBurnFromBtcFees(CompletableFuture<Boolean> completeFuture) {
model.getProofOfBurnFromBtcFeesChartData()
.whenComplete((data, t) ->
mapToUserThread(() -> {
seriesProofOfBurnFromBtcFees.getData().setAll(data);
completeFuture.complete(true);
}));
}
private void applyProofOfBurnFromArbitration(CompletableFuture<Boolean> completeFuture) {
model.getProofOfBurnFromArbitrationChartData()
.whenComplete((data, t) ->
mapToUserThread(() -> {
seriesProofOfBurnFromArbitration.getData().setAll(data);
completeFuture.complete(true);
}));
}
private void applyProofOfBurnReimbursementDiff(CompletableFuture<Boolean> completeFuture) {
model.getProofOfBurnReimbursementDiffChartData()
.whenComplete((data, t) ->
mapToUserThread(() -> {
seriesProofOfBurnReimbursementDiff.getData().setAll(data);
completeFuture.complete(true);
}));
}

View File

@ -58,8 +58,20 @@ public class DaoChartViewModel extends ChartViewModel<DaoChartDataModel> {
return CompletableFuture.supplyAsync(() -> toChartData(dataModel.getTotalSupplyByInterval()));
}
CompletableFuture<List<XYChart.Data<Number, Number>>> getRevenueChartData() {
return CompletableFuture.supplyAsync(() -> toChartData(dataModel.getRevenueByInterval()));
CompletableFuture<List<XYChart.Data<Number, Number>>> getTotalTradeFeesChartData() {
return CompletableFuture.supplyAsync(() -> toChartData(dataModel.getTotalTradeFeesByInterval()));
}
CompletableFuture<List<XYChart.Data<Number, Number>>> getProofOfBurnFromBtcFeesChartData() {
return CompletableFuture.supplyAsync(() -> toChartData(dataModel.getProofOfBurnFromBtcFeesByInterval()));
}
CompletableFuture<List<XYChart.Data<Number, Number>>> getProofOfBurnFromArbitrationChartData() {
return CompletableFuture.supplyAsync(() -> toChartData(dataModel.getProofOfBurnFromArbitrationByInterval()));
}
CompletableFuture<List<XYChart.Data<Number, Number>>> getProofOfBurnReimbursementDiffChartData() {
return CompletableFuture.supplyAsync(() -> toChartData(dataModel.getProofOfBurnReimbursementDiffByInterval()));
}
CompletableFuture<List<XYChart.Data<Number, Number>>> getTotalIssuedChartData() {

View File

@ -142,11 +142,14 @@
-bs-chart-dao-line1: -bs-color-blue-5;
-bs-chart-dao-line2: -bs-color-green-3;
-bs-chart-dao-line3: #0195fe;
-bs-chart-dao-line4: -bs-turquoise-light;
-bs-chart-dao-line4: -bs-soft-red;
-bs-chart-dao-line5: -bs-yellow;
-bs-chart-dao-line6: -bs-soft-red;
-bs-chart-dao-line6: -bs-turquoise-light;
-bs-chart-dao-line7: #ff6c00;
-bs-chart-dao-line8: -bs-turquoise;
-bs-chart-dao-line9: #7fad01;
-bs-chart-dao-line10: #420080;
-bs-chart-dao-line11: #ff3939;
/* Monero orange color code */
-xmr-orange: #f26822;

View File

@ -109,11 +109,14 @@
-bs-chart-dao-line1: -bs-color-blue-5;
-bs-chart-dao-line2: -bs-color-green-3;
-bs-chart-dao-line3: #0195fe;
-bs-chart-dao-line4: -bs-turquoise-light;
-bs-chart-dao-line4: -bs-soft-red;
-bs-chart-dao-line5: -bs-yellow;
-bs-chart-dao-line6: -bs-soft-red;
-bs-chart-dao-line6: -bs-turquoise-light;
-bs-chart-dao-line7: #ff6c00;
-bs-chart-dao-line8: -bs-turquoise;
-bs-chart-dao-line9: #7fad01;
-bs-chart-dao-line10: #420080;
-bs-chart-dao-line11: #ff3939;
/* Monero orange color code */
-xmr-orange: #f26822;